[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] xen: do not unmask disabled IRQ on eoi.
On Fri, 22 Oct 2010, Jan Beulich wrote: > >>> On 22.10.10 at 15:57, Stefano Stabellini > >>> <stefano.stabellini@xxxxxxxxxxxxx> wrote: > > In none of these cases the evtchn would be masked for sure, so I'll have > > to test if the evtchn is masked and call move_masked_irq or > > move_native_irq accordingly. I preferred to test the evtchn_mask > > directly as opposed to the irq flags because the test is easier to > > understand (we could arrive in eoi_pirq from both handle_edge_irq or > > handle_fasteoi_irq, the latter doesn't set IRQ_MASKED when masks > > an irq). > > But you still didn't add and IRQ_DISABLED check around the call > to move_masked_irq() - do you have any particular reason not to? > Yes, you are right, a check for IRQ_DISABLED is also needed. --- xen: use do not clear and mask evtchns in __xen_evtchn_do_upcall Switch virqs and pirqs that don't need EOI (in Xen acktype == ACKTYPE_NONE, that means the machine irq is actually edge) to handle_edge_irq. Use handle_fasteoi_irq for pirqs that need eoi (they generally correspond to level triggered irqs), no risk in loosing interrupts because we have to EOI the irq anyway. This change has the following benefits: - it uses the very same handlers that Linux would use on native for the same irqs; - it uses these handlers in the same way Linux would use them: it let Linux mask\unmask and ack the irq when Linux want to mask\unmask and ack the irq; However it is obviously not easy to understand and it has to work around the limitations of PHYSDEVOP_pirq_eoi_gmfn. Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 175e931..61bc35c 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -436,21 +436,56 @@ static bool identity_mapped_irq(unsigned irq) return irq < get_nr_hw_irqs(); } -static void pirq_eoi(unsigned int irq) +static void eoi_pirq(unsigned int irq) { struct irq_info *info = info_for_irq(irq); struct physdev_eoi eoi = { .irq = info->u.pirq.gsi }; - bool need_eoi; + int evtchn = evtchn_from_irq(irq); + int rc = 0, need_mask = 0; + struct shared_info *s = HYPERVISOR_shared_info; + struct irq_desc *desc = irq_to_desc(irq); - need_eoi = pirq_needs_eoi(irq); + if (!VALID_EVTCHN(evtchn)) + return; - if (!need_eoi || !pirq_eoi_does_unmask) - unmask_evtchn(info->evtchn); + if (likely(!(desc->status & IRQ_DISABLED))) { + if (unlikely(sync_test_bit(evtchn, &s->evtchn_mask[0]))) + move_masked_irq(irq); + else + move_native_irq(irq); + } - if (need_eoi) { - int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); + /* If the pirq doesn't need an eoi, just clear the evtchn and exit. + * If the pirq is currently unmasked, or !pirq_eoi_does_unmask, + * clear the evtchn and continue because the hypercall won't affect + * us anyway. + * If the pirq needs an eoi AND pirq_eoi_does_unmask AND the pirq is + * currently masked than we have a problem because the eoi hypercall + * will automatically unmasked the pirq. That means we cannot clear + * the evtchn right away because we could receive an unwanted evtchn + * notification after the hypercall and before masking the pirq + * again. Therefore in this case we clear the evtchn after the + * hypercall. */ + if (pirq_needs_eoi(irq)) { + if (pirq_eoi_does_unmask) + need_mask = sync_test_bit(evtchn, &s->evtchn_mask[0]); + if (!need_mask) + clear_evtchn(evtchn); + + rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); WARN_ON(rc); - } + if (need_mask) { + mask_evtchn(evtchn); + clear_evtchn(evtchn); + } + } else + clear_evtchn(evtchn); +} + +static void mask_ack_pirq(unsigned int irq) +{ + mask_irq(irq); + eoi_pirq(irq); } static void pirq_query_unmask(int irq) @@ -481,6 +516,7 @@ static bool probing_irq(int irq) static unsigned int startup_pirq(unsigned int irq) { + struct irq_desc *desc; struct evtchn_bind_pirq bind_pirq; struct irq_info *info = info_for_irq(irq); int evtchn = evtchn_from_irq(irq); @@ -510,8 +546,25 @@ static unsigned int startup_pirq(unsigned int irq) bind_evtchn_to_cpu(evtchn, 0); info->evtchn = evtchn; + /* If the pirq does not need an eoi than we can use handle_edge_irq + * and ack it right away, clearing the evtchn before calling + * handle_IRQ_event. If the pirq does need an eoi than we can use + * the fasteoi handler without loosing any interrupts because the + * physical interrupt will still be waiting for an eoi as well. + * + * Only after EVTCHNOP_bind_pirq Xen reliably tells us what + * kind of pirq this is, so we have to wait until now to make the + * choice. + * Afterwards Xen might temporarily set the needs_eoi flag for a + * particular pirq, but that doesn't affect our choice here that + * depends on the nature of the interrupt. */ + desc = irq_to_desc(irq); + if (!pirq_needs_eoi(irq)) + desc->handle_irq = handle_edge_irq; + out: - pirq_eoi(irq); + eoi_pirq(irq); + unmask_irq(irq); return 0; } @@ -538,29 +591,6 @@ static void shutdown_pirq(unsigned int irq) info->evtchn = 0; } -static void ack_pirq(unsigned int irq) -{ - move_masked_irq(irq); - - pirq_eoi(irq); -} - -static void end_pirq(unsigned int irq) -{ - int evtchn = evtchn_from_irq(irq); - struct irq_desc *desc = irq_to_desc(irq); - - if (WARN_ON(!desc)) - return; - - if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) == - (IRQ_DISABLED|IRQ_PENDING)) { - shutdown_pirq(irq); - } else if (VALID_EVTCHN(evtchn)) { - pirq_eoi(irq); - } -} - static int find_irq_by_gsi(unsigned gsi) { int irq; @@ -750,7 +780,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) irq = find_unbound_irq(); set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, - handle_fasteoi_irq, "event"); + handle_edge_irq, "event"); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_evtchn_info(evtchn); @@ -1074,9 +1104,6 @@ static void __xen_evtchn_do_upcall(struct pt_regs *regs) int irq = evtchn_to_irq[port]; struct irq_desc *desc; - mask_evtchn(port); - clear_evtchn(port); - if (irq != -1) { desc = irq_to_desc(irq); if (desc) @@ -1198,11 +1225,26 @@ int resend_irq_on_evtchn(unsigned int irq) static void ack_dynirq(unsigned int irq) { int evtchn = evtchn_from_irq(irq); + struct shared_info *s = HYPERVISOR_shared_info; + struct irq_desc *desc = irq_to_desc(irq); - move_masked_irq(irq); + if (!VALID_EVTCHN(evtchn)) + return; - if (VALID_EVTCHN(evtchn)) - unmask_evtchn(evtchn); + if (likely(!(desc->status & IRQ_DISABLED))) { + if (unlikely(sync_test_bit(evtchn, &s->evtchn_mask[0]))) + move_masked_irq(irq); + else + move_native_irq(irq); + } + + clear_evtchn(evtchn); +} + +static void mask_ack_dynirq(unsigned int irq) +{ + mask_irq(irq); + ack_dynirq(irq); } static int retrigger_irq(unsigned int irq) @@ -1384,11 +1426,11 @@ void xen_irq_resume(void) static struct irq_chip xen_dynamic_chip __read_mostly = { .name = "xen-dyn", - .disable = mask_irq, .mask = mask_irq, .unmask = unmask_irq, - .eoi = ack_dynirq, + .ack = ack_dynirq, + .mask_ack = mask_ack_dynirq, .set_affinity = set_affinity_irq, .retrigger = retrigger_irq, }; @@ -1409,14 +1451,12 @@ static struct irq_chip xen_pirq_chip __read_mostly = { .startup = startup_pirq, .shutdown = shutdown_pirq, - .enable = pirq_eoi, - .unmask = unmask_irq, - - .disable = mask_irq, .mask = mask_irq, + .unmask = unmask_irq, - .eoi = ack_pirq, - .end = end_pirq, + .ack = eoi_pirq, + .eoi = eoi_pirq, + .mask_ack = mask_ack_pirq, .set_affinity = set_affinity_irq, _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |