# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1169559560 0
# Node ID 914304b3a3da6fc5bad12f742bae3893b53d20bc
# Parent ee7c422c5f7b79e0cc0ae5670af81b400a72357f
linux: Fix enable_irq() crash by removing a BUG_ON() assumption in our
event-channel retrigger() function. Also clean up bitmap usages.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
linux-2.6-xen-sparse/drivers/xen/core/evtchn.c | 52 ++++++++++++-------------
linux-2.6-xen-sparse/include/xen/evtchn.h | 2
2 files changed, 26 insertions(+), 28 deletions(-)
diff -r ee7c422c5f7b -r 914304b3a3da
linux-2.6-xen-sparse/drivers/xen/core/evtchn.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c Tue Jan 23 11:39:32
2007 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c Tue Jan 23 13:39:20
2007 +0000
@@ -60,8 +60,6 @@ static int evtchn_to_irq[NR_EVENT_CHANNE
/* Packed IRQ information: binding type, sub-type index, and event channel. */
static u32 irq_info[NR_IRQS];
-static int resend_irq_on_evtchn(unsigned int);
-
/* Binding types. */
enum {
IRQT_UNBOUND,
@@ -113,7 +111,7 @@ static int irq_bindcount[NR_IRQS];
static int irq_bindcount[NR_IRQS];
/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
-static unsigned long pirq_needs_eoi[NR_PIRQS/sizeof(unsigned long)];
+static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS);
#ifdef CONFIG_SMP
@@ -613,6 +611,22 @@ static void set_affinity_irq(unsigned ir
rebind_irq_to_cpu(irq, tcpu);
}
#endif
+
+static int resend_irq_on_evtchn(unsigned int i)
+{
+ int masked, evtchn = evtchn_from_irq(i);
+ shared_info_t *s = HYPERVISOR_shared_info;
+
+ if (!VALID_EVTCHN(evtchn))
+ return 1;
+
+ masked = synch_test_and_set_bit(evtchn, s->evtchn_mask);
+ synch_set_bit(evtchn, s->evtchn_pending);
+ if (!masked)
+ unmask_evtchn(evtchn);
+
+ return 1;
+}
/*
* Interface to generic handling in irq.c
@@ -688,7 +702,7 @@ static inline void pirq_unmask_notify(in
static inline void pirq_unmask_notify(int pirq)
{
struct physdev_eoi eoi = { .irq = pirq };
- if (unlikely(test_bit(pirq, &pirq_needs_eoi[0])))
+ if (unlikely(test_bit(pirq, pirq_needs_eoi)))
(void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
}
@@ -697,9 +711,9 @@ static inline void pirq_query_unmask(int
struct physdev_irq_status_query irq_status;
irq_status.irq = pirq;
(void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
- clear_bit(pirq, &pirq_needs_eoi[0]);
+ clear_bit(pirq, pirq_needs_eoi);
if (irq_status.flags & XENIRQSTAT_needs_eoi)
- set_bit(pirq, &pirq_needs_eoi[0]);
+ set_bit(pirq, pirq_needs_eoi);
}
/*
@@ -824,18 +838,6 @@ int irq_ignore_unhandled(unsigned int ir
return !!(irq_status.flags & XENIRQSTAT_shared);
}
-static int resend_irq_on_evtchn(unsigned int i)
-{
- int evtchn = evtchn_from_irq(i);
- shared_info_t *s = HYPERVISOR_shared_info;
- if (!VALID_EVTCHN(evtchn))
- return 0;
- BUG_ON(!synch_test_bit(evtchn, &s->evtchn_mask[0]));
- synch_set_bit(evtchn, &s->evtchn_pending[0]);
-
- return 1;
-}
-
void notify_remote_via_irq(int irq)
{
int evtchn = evtchn_from_irq(irq);
@@ -854,7 +856,7 @@ void mask_evtchn(int port)
void mask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
- synch_set_bit(port, &s->evtchn_mask[0]);
+ synch_set_bit(port, s->evtchn_mask);
}
EXPORT_SYMBOL_GPL(mask_evtchn);
@@ -873,14 +875,10 @@ void unmask_evtchn(int port)
return;
}
- synch_clear_bit(port, &s->evtchn_mask[0]);
-
- /*
- * The following is basically the equivalent of 'hw_resend_irq'. Just
- * like a real IO-APIC we 'lose the interrupt edge' if the channel is
- * masked.
- */
- if (synch_test_bit(port, &s->evtchn_pending[0]) &&
+ synch_clear_bit(port, s->evtchn_mask);
+
+ /* Did we miss an interrupt 'edge'? Re-fire if so. */
+ if (synch_test_bit(port, s->evtchn_pending) &&
!synch_test_and_set_bit(port / BITS_PER_LONG,
&vcpu_info->evtchn_pending_sel))
vcpu_info->evtchn_upcall_pending = 1;
diff -r ee7c422c5f7b -r 914304b3a3da linux-2.6-xen-sparse/include/xen/evtchn.h
--- a/linux-2.6-xen-sparse/include/xen/evtchn.h Tue Jan 23 11:39:32 2007 +0000
+++ b/linux-2.6-xen-sparse/include/xen/evtchn.h Tue Jan 23 13:39:20 2007 +0000
@@ -108,7 +108,7 @@ static inline void clear_evtchn(int port
static inline void clear_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
- synch_clear_bit(port, &s->evtchn_pending[0]);
+ synch_clear_bit(port, s->evtchn_pending);
}
static inline void notify_remote_via_evtchn(int port)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|