aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/xen/events.c46
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
556out:
543 put_cpu(); 557 put_cpu();
544} 558}
545 559