summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/events/events_base.c25
-rw-r--r--drivers/xen/events/events_internal.h1
2 files changed, 18 insertions, 8 deletions
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 8c702a46ea4c..2adf54119677 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -702,6 +702,12 @@ static void xen_evtchn_close(unsigned int port)
BUG();
}
+static void event_handler_exit(struct irq_info *info)
+{
+ smp_store_release(&info->is_active, 0);
+ clear_evtchn(info->evtchn);
+}
+
static void pirq_query_unmask(int irq)
{
struct physdev_irq_status_query irq_status;
@@ -732,13 +738,13 @@ static void eoi_pirq(struct irq_data *data)
likely(!irqd_irq_disabled(data))) {
do_mask(info, EVT_MASK_REASON_TEMPORARY);
- clear_evtchn(evtchn);
+ event_handler_exit(info);
irq_move_masked_irq(data);
do_unmask(info, EVT_MASK_REASON_TEMPORARY);
} else
- clear_evtchn(evtchn);
+ event_handler_exit(info);
if (pirq_needs_eoi(data->irq)) {
rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
@@ -1574,6 +1580,8 @@ void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl)
}
info = info_for_irq(irq);
+ if (xchg_acquire(&info->is_active, 1))
+ return;
if (ctrl->defer_eoi) {
info->eoi_cpu = smp_processor_id();
@@ -1750,13 +1758,13 @@ static void ack_dynirq(struct irq_data *data)
likely(!irqd_irq_disabled(data))) {
do_mask(info, EVT_MASK_REASON_TEMPORARY);
- clear_evtchn(evtchn);
+ event_handler_exit(info);
irq_move_masked_irq(data);
do_unmask(info, EVT_MASK_REASON_TEMPORARY);
} else
- clear_evtchn(evtchn);
+ event_handler_exit(info);
}
static void mask_ack_dynirq(struct irq_data *data)
@@ -1772,7 +1780,7 @@ static void lateeoi_ack_dynirq(struct irq_data *data)
if (VALID_EVTCHN(evtchn)) {
do_mask(info, EVT_MASK_REASON_EOI_PENDING);
- clear_evtchn(evtchn);
+ event_handler_exit(info);
}
}
@@ -1783,7 +1791,7 @@ static void lateeoi_mask_ack_dynirq(struct irq_data *data)
if (VALID_EVTCHN(evtchn)) {
do_mask(info, EVT_MASK_REASON_EXPLICIT);
- clear_evtchn(evtchn);
+ event_handler_exit(info);
}
}
@@ -1892,10 +1900,11 @@ static void restore_cpu_ipis(unsigned int cpu)
/* Clear an irq's pending state, in preparation for polling on it */
void xen_clear_irq_pending(int irq)
{
- int evtchn = evtchn_from_irq(irq);
+ struct irq_info *info = info_for_irq(irq);
+ evtchn_port_t evtchn = info ? info->evtchn : 0;
if (VALID_EVTCHN(evtchn))
- clear_evtchn(evtchn);
+ event_handler_exit(info);
}
EXPORT_SYMBOL(xen_clear_irq_pending);
void xen_set_irq_pending(int irq)
diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h
index 65a08c374329..3df6f28b75e6 100644
--- a/drivers/xen/events/events_internal.h
+++ b/drivers/xen/events/events_internal.h
@@ -40,6 +40,7 @@ struct irq_info {
#define EVT_MASK_REASON_EXPLICIT 0x01
#define EVT_MASK_REASON_TEMPORARY 0x02
#define EVT_MASK_REASON_EOI_PENDING 0x04
+ u8 is_active; /* Is event just being handled? */
unsigned irq;
unsigned int evtchn; /* event channel */
unsigned short cpu; /* cpu bound */