On Fri, 22 Oct 2010, Ian Campbell wrote:
> On Fri, 2010-10-22 at 09:29 +0100, Jan Beulich wrote:
> > >>> On 22.10.10 at 10:07, Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx> wrote:
> > > On Fri, 2010-10-22 at 08:41 +0100, Jan Beulich wrote:
> > >> >>> On 21.10.10 at 15:36, Stefano Stabellini
> > >> >>> <stefano.stabellini@xxxxxxxxxxxxx> wrote:
> > >> > --- a/drivers/xen/events.c
> > >> > +++ b/drivers/xen/events.c
> > >> > @@ -436,21 +436,50 @@ 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;
> > >> >
> > >> > - need_eoi = pirq_needs_eoi(irq);
> > >> > + if (!VALID_EVTCHN(evtchn))
> > >> > + return;
> > >> >
> > >> > - if (!need_eoi || !pirq_eoi_does_unmask)
> > >> > - unmask_evtchn(info->evtchn);
> > >> > + move_masked_irq(irq);
> > >>
> > >> It's not clear whether calling this function is valid when the IRQ isn't
> > >> really masked.
> > >>
> > >> In any case I'd suggest adding an IRQ_DISABLED check matching
> > >> move_native_irq()'s.
> > >
> > > Why not just call move_native_irq instead of move_masked_irq as
> > > appropriate?
> >
> > That was what I implied with the first part of my response.
>
> Too subtle for me ;-)
>
> > But I think the second part applies if a (the conditional) call to
> > move_masked_irq() would stay.
>
> Agreed, although I suspect we should know if the evtchn is masked or not
> at this point depending on the already known properties of the
> particular pirq (need_eoi, pirq_eoi_does_unmask etc).
>
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).
---
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..30224c8 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -436,21 +436,53 @@ 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;
-
- need_eoi = pirq_needs_eoi(irq);
+ int evtchn = evtchn_from_irq(irq);
+ int rc = 0, need_mask = 0;
+ struct shared_info *s = HYPERVISOR_shared_info;
- if (!need_eoi || !pirq_eoi_does_unmask)
- unmask_evtchn(info->evtchn);
+ if (!VALID_EVTCHN(evtchn))
+ return;
- if (need_eoi) {
- int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
+ if (unlikely(sync_test_bit(evtchn, &s->evtchn_mask[0])))
+ move_masked_irq(irq);
+ else
+ move_native_irq(irq);
+
+ /* 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 +513,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 +543,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 +588,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 +777,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 +1101,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 +1222,23 @@ 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;
- move_masked_irq(irq);
+ if (!VALID_EVTCHN(evtchn))
+ return;
- if (VALID_EVTCHN(evtchn))
- unmask_evtchn(evtchn);
+ 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 +1420,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 +1445,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
|