From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: <43EC48FE.705@domain.hid> Date: Fri, 10 Feb 2006 09:04:14 +0100 From: Anders Blomdell MIME-Version: 1.0 Subject: Re: [Xenomai-core] More on Shared interrupts References: <43E86F4D.4050400@domain.hid> <43E8DFC4.4010805@domain.hid> <43E9CE95.3070806@domain.hid> <43EAFD8B.7020400@domain.hid> <43EB1279.3040902@domain.hid> <43EB1741.9080809@domain.hid> <43EB63D7.2080507@domain.hid> <43EB703C.2090704@domain.hid> In-Reply-To: <43EB703C.2090704@domain.hid> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit List-Id: "Xenomai life and development \(bug reports, patches, discussions\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Jan Kiszka Cc: xenomai@xenomai.org Jan Kiszka wrote: > Anders Blomdell wrote: > >>For the last few days, I have tried to figure out a good way to share >>interrupts between RT and non-RT domains. This has included looking >>through Dmitry's patch, correcting bugs and testing what is possible in >>my specific case. I'll therefore try to summarize at least a few of my >>thoughts. >> >>1. When looking through Dmitry's patch I get the impression that the >>iack handler has very little to do with each interrupt (the test >>'prev->iack != intr->iack' is a dead giveaway), but is more of a >>domain-specific function (or perhaps even just a placeholder for the >>hijacked Linux ack-function). >> >> >>2. Somewhat inspired by the figure in "Life with Adeos", I have >>identified the following cases: >> >> irq K | ----------- | ---o | // Linux only >> ... >> irq L | ---o | | // RT-only >> ... >> irq M | ---o------- | ---o | // Shared between domains >> ... >> irq N | ---o---o--- | | // Shared inside single domain >> ... >> irq O | ---o---o--- | ---o | // Shared between and inside single >>domain >> >>Xenomai currently handles the K & L cases, Dmitrys patch addresses the N >>case, with edge triggered interrupts the M (and O after Dmitry's patch) >>case(s) might be handled by returning RT_INTR_CHAINED | RT_INTR_ENABLE >>from the interrupt handler, for level triggered interrupt the M and O >>cases can't be handled. > > > I guess you mean it the other way around: for the edge-triggered > cross-domain case we would actually have to loop over both the RT and > the Linux handlers until we are sure, that the IRQ line was released once. I obviously has misunderstood edge triggered :-( > Luckily, I never saw such a scenario which were unavoidable (it hits you > with ISA hardware which tend to have nice IRQ jumpers or other means - > it's just that you often cannot divide several controllers on the same > extension card IRQ-wise apart). > > >>If one looks more closely at the K case (Linux only interrupt), it works >>by when an interrupt occurs, the call to irq_end is postponed until the >>Linux interrupt handler has run, i.e. further interrupts are disabled. >>This can be seen as a lazy version of Philippe's idea of disabling all >>non-RT interrupts until the RT-domain is idle, i.e. the interrupt is >>disabled only if it indeed occurs. >> >>If this idea should be generalized to the M (and O) case(s), one can't >>rely on postponing the irq_end call (since the interrupt is still needed >>in the RT-domain), but has to rely on some function that disables all >>non-RT hardware that generates interrupts on that irq-line; such a >>function naturally has to have intimate knowledge of all hardware that >>can generate interrupts in order to be able to disable those interrupt >>sources that are non-RT. >> >>If we then take Jan's observation about the many (Linux-only) interrupts >>present in an ordinary PC and add it to Philippe's idea of disabling all >>non-RT interrupts while executing in the RT-domain, I think that the >>following is a workable (and fairly efficient) way of handling this: >> >>Add hardware dependent enable/disable functions, where the enable is >>called just before normal execution in a domain starts (i.e. when >>playing back interrupts, the disable is still in effect), and disable is >>called when normal domain execution end. This does effectively handle >>the K case above, with the added benefit that NO non-RT interrupts will >>occur during RT execution. >> >>In the 8259 case, the disable function could look something like: >> >> domain_irq_disable(uint irqmask) { >> if (irqmask & 0xff00 != 0xff00) { >> irqmask &= ~0x0004; // Cascaded interrupt is still needed >> outb(irqmask >> 8, PIC_SLAVE_IMR); >> } >> outb(irqmask, PIC_MASTER_IMR); >> } >> >>If we should extend this to handle the M (and O) case(s), the disable >>function could look like: >> >> domain_irq_disable(uint irqmask, shared_irq_t *shared[]) { >> int i; >> >> for (i = 0 ; i < MAX_IRQ ; i++) { >> if (shared[i]) { >> shared_irq_t *next = shared[i]; >> irqmask &= ~(1<> while (next) { >> next->disable(); >> next = next->next; >> } > > > This obviously means that all non-RT IRQ handlers sharing a line with > the RT domain would have to be registered in that shared[]-list. This > gets close to my old suggestion. Just raises the question how to > organise these interface, both on the RT and the Linux side. > > >> } >> } >> if (irqmask & 0xff00 != 0xff00) { >> irqmask &= ~0x0004; // Cascaded interrupt is still needed >> outb(irqmask >> 8, PIC_SLAVE_IMR); >> } >> outb(irqmask, PIC_MASTER_IMR); >> } >> >>An obvious optimization of the above scheme, is to never call the >>disable (or enable) function for the RT-domain, since there all >>interrupt processing is protected by the hardware. > > > Another point is to avoid that looping over disable handlers for IRQs of > the K case. Otherwise, too many device-specific disable handlers had to > be implemented even if only a single Linux device hogs a RT IRQ. You only have to spin over those IRQ that are actually shared across domains (probably just a few in most cases), those IRQ that stays in one domain fets handled in the interrupt controller. Setting up the appropriate [per domain] lists can be done as irqhandlers gets registered/unregistred (which is usually quite seldom). >>Comments, anyone? >> > > > I see your need, we just have to keep in mind that we are currently > discussing the corner case (shared RT/non-RT IRQs) of the corner case > (shared RT IRQs). Whatever will be defined, the normal use case should > define how an efficient interface has to look like. Or we have to add a > lot of #ifdef's... My current need can simply be handled by disabling the UART interrupt and have a low priority RT task polling the interrupt and handing it over to Linux. It was just that I thought that now might be a good time to try to bring together those three somewhat overlapping issues: 1. Shared RT-interrupts (which Dimitry has already done) 2. Philippe's suggestion of disabling all interrupts for lower priority domains. 3. Interrupts shared between domains As previously said, my current needs are covered by #3, but since I have RT plans for some of my ordinary PCs as well, I feel that #2 is worth some effort as well. My feeling right now, is that execution time of #2 will be shorter than it takes to handle a single non-RT interrupt in the current codebase, and hence it ought to improve RT performance (avoiding I-cache pressure from non-RT handlers for instance), and #3 is a small addition once #2 is in place. -- Anders