diff options
-rw-r--r-- | arch/x86/xen/events.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/arch/x86/xen/events.c b/arch/x86/xen/events.c index f73b53bd65b7..85bac298b3cb 100644 --- a/arch/x86/xen/events.c +++ b/arch/x86/xen/events.c | |||
@@ -517,29 +517,43 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) | |||
517 | int cpu = get_cpu(); | 517 | int cpu = get_cpu(); |
518 | struct shared_info *s = HYPERVISOR_shared_info; | 518 | struct shared_info *s = HYPERVISOR_shared_info; |
519 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); | 519 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); |
520 | unsigned long pending_words; | 520 | static DEFINE_PER_CPU(unsigned, nesting_count); |
521 | unsigned count; | ||
521 | 522 | ||
522 | vcpu_info->evtchn_upcall_pending = 0; | 523 | do { |
524 | unsigned long pending_words; | ||
523 | 525 | ||
524 | /* NB. No need for a barrier here -- XCHG is a barrier on x86. */ | 526 | vcpu_info->evtchn_upcall_pending = 0; |
525 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); | ||
526 | while (pending_words != 0) { | ||
527 | unsigned long pending_bits; | ||
528 | int word_idx = __ffs(pending_words); | ||
529 | pending_words &= ~(1UL << word_idx); | ||
530 | 527 | ||
531 | while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { | 528 | if (__get_cpu_var(nesting_count)++) |
532 | int bit_idx = __ffs(pending_bits); | 529 | goto out; |
533 | int port = (word_idx * BITS_PER_LONG) + bit_idx; | ||
534 | int irq = evtchn_to_irq[port]; | ||
535 | 530 | ||
536 | if (irq != -1) { | 531 | /* NB. No need for a barrier here -- XCHG is a barrier on x86. */ |
537 | regs->orig_ax = ~irq; | 532 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); |
538 | do_IRQ(regs); | 533 | while (pending_words != 0) { |
534 | unsigned long pending_bits; | ||
535 | int word_idx = __ffs(pending_words); | ||
536 | pending_words &= ~(1UL << word_idx); | ||
537 | |||
538 | while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { | ||
539 | int bit_idx = __ffs(pending_bits); | ||
540 | int port = (word_idx * BITS_PER_LONG) + bit_idx; | ||
541 | int irq = evtchn_to_irq[port]; | ||
542 | |||
543 | if (irq != -1) { | ||
544 | regs->orig_ax = ~irq; | ||
545 | do_IRQ(regs); | ||
546 | } | ||
539 | } | 547 | } |
540 | } | 548 | } |
541 | } | ||
542 | 549 | ||
550 | BUG_ON(!irqs_disabled()); | ||
551 | |||
552 | count = __get_cpu_var(nesting_count); | ||
553 | __get_cpu_var(nesting_count) = 0; | ||
554 | } while(count != 1); | ||
555 | |||
556 | out: | ||
543 | put_cpu(); | 557 | put_cpu(); |
544 | } | 558 | } |
545 | 559 | ||