aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/events.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r--drivers/xen/events.c95
1 files changed, 84 insertions, 11 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index db8f506817f0..5e1f34892dcc 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -29,6 +29,7 @@
29#include <linux/bootmem.h> 29#include <linux/bootmem.h>
30#include <linux/slab.h> 30#include <linux/slab.h>
31 31
32#include <asm/desc.h>
32#include <asm/ptrace.h> 33#include <asm/ptrace.h>
33#include <asm/irq.h> 34#include <asm/irq.h>
34#include <asm/idle.h> 35#include <asm/idle.h>
@@ -36,10 +37,14 @@
36#include <asm/xen/hypercall.h> 37#include <asm/xen/hypercall.h>
37#include <asm/xen/hypervisor.h> 38#include <asm/xen/hypervisor.h>
38 39
40#include <xen/xen.h>
41#include <xen/hvm.h>
39#include <xen/xen-ops.h> 42#include <xen/xen-ops.h>
40#include <xen/events.h> 43#include <xen/events.h>
41#include <xen/interface/xen.h> 44#include <xen/interface/xen.h>
42#include <xen/interface/event_channel.h> 45#include <xen/interface/event_channel.h>
46#include <xen/interface/hvm/hvm_op.h>
47#include <xen/interface/hvm/params.h>
43 48
44/* 49/*
45 * This lock protects updates to the following mapping and reference-count 50 * This lock protects updates to the following mapping and reference-count
@@ -335,9 +340,18 @@ static int find_unbound_irq(void)
335 int irq; 340 int irq;
336 struct irq_desc *desc; 341 struct irq_desc *desc;
337 342
338 for (irq = 0; irq < nr_irqs; irq++) 343 for (irq = 0; irq < nr_irqs; irq++) {
344 desc = irq_to_desc(irq);
345 /* only 0->15 have init'd desc; handle irq > 16 */
346 if (desc == NULL)
347 break;
348 if (desc->chip == &no_irq_chip)
349 break;
350 if (desc->chip != &xen_dynamic_chip)
351 continue;
339 if (irq_info[irq].type == IRQT_UNBOUND) 352 if (irq_info[irq].type == IRQT_UNBOUND)
340 break; 353 break;
354 }
341 355
342 if (irq == nr_irqs) 356 if (irq == nr_irqs)
343 panic("No available IRQ to bind to: increase nr_irqs!\n"); 357 panic("No available IRQ to bind to: increase nr_irqs!\n");
@@ -346,7 +360,7 @@ static int find_unbound_irq(void)
346 if (WARN_ON(desc == NULL)) 360 if (WARN_ON(desc == NULL))
347 return -1; 361 return -1;
348 362
349 dynamic_irq_init(irq); 363 dynamic_irq_init_keep_chip_data(irq);
350 364
351 return irq; 365 return irq;
352} 366}
@@ -617,17 +631,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count);
617 * a bitset of words which contain pending event bits. The second 631 * a bitset of words which contain pending event bits. The second
618 * level is a bitset of pending events themselves. 632 * level is a bitset of pending events themselves.
619 */ 633 */
620void xen_evtchn_do_upcall(struct pt_regs *regs) 634static void __xen_evtchn_do_upcall(void)
621{ 635{
622 int cpu = get_cpu(); 636 int cpu = get_cpu();
623 struct pt_regs *old_regs = set_irq_regs(regs);
624 struct shared_info *s = HYPERVISOR_shared_info; 637 struct shared_info *s = HYPERVISOR_shared_info;
625 struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); 638 struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
626 unsigned count; 639 unsigned count;
627 640
628 exit_idle();
629 irq_enter();
630
631 do { 641 do {
632 unsigned long pending_words; 642 unsigned long pending_words;
633 643
@@ -664,14 +674,31 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
664 674
665 count = __get_cpu_var(xed_nesting_count); 675 count = __get_cpu_var(xed_nesting_count);
666 __get_cpu_var(xed_nesting_count) = 0; 676 __get_cpu_var(xed_nesting_count) = 0;
667 } while(count != 1); 677 } while (count != 1 || vcpu_info->evtchn_upcall_pending);
668 678
669out: 679out:
680
681 put_cpu();
682}
683
684void xen_evtchn_do_upcall(struct pt_regs *regs)
685{
686 struct pt_regs *old_regs = set_irq_regs(regs);
687
688 exit_idle();
689 irq_enter();
690
691 __xen_evtchn_do_upcall();
692
670 irq_exit(); 693 irq_exit();
671 set_irq_regs(old_regs); 694 set_irq_regs(old_regs);
695}
672 696
673 put_cpu(); 697void xen_hvm_evtchn_do_upcall(void)
698{
699 __xen_evtchn_do_upcall();
674} 700}
701EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);
675 702
676/* Rebind a new event channel to an existing irq. */ 703/* Rebind a new event channel to an existing irq. */
677void rebind_evtchn_irq(int evtchn, int irq) 704void rebind_evtchn_irq(int evtchn, int irq)
@@ -708,7 +735,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
708 struct evtchn_bind_vcpu bind_vcpu; 735 struct evtchn_bind_vcpu bind_vcpu;
709 int evtchn = evtchn_from_irq(irq); 736 int evtchn = evtchn_from_irq(irq);
710 737
711 if (!VALID_EVTCHN(evtchn)) 738 /* events delivered via platform PCI interrupts are always
739 * routed to vcpu 0 */
740 if (!VALID_EVTCHN(evtchn) ||
741 (xen_hvm_domain() && !xen_have_vector_callback))
712 return -1; 742 return -1;
713 743
714 /* Send future instances of this interrupt to other vcpu. */ 744 /* Send future instances of this interrupt to other vcpu. */
@@ -933,6 +963,44 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
933 .retrigger = retrigger_dynirq, 963 .retrigger = retrigger_dynirq,
934}; 964};
935 965
966int xen_set_callback_via(uint64_t via)
967{
968 struct xen_hvm_param a;
969 a.domid = DOMID_SELF;
970 a.index = HVM_PARAM_CALLBACK_IRQ;
971 a.value = via;
972 return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
973}
974EXPORT_SYMBOL_GPL(xen_set_callback_via);
975
976#ifdef CONFIG_XEN_PVHVM
977/* Vector callbacks are better than PCI interrupts to receive event
978 * channel notifications because we can receive vector callbacks on any
979 * vcpu and we don't need PCI support or APIC interactions. */
980void xen_callback_vector(void)
981{
982 int rc;
983 uint64_t callback_via;
984 if (xen_have_vector_callback) {
985 callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK);
986 rc = xen_set_callback_via(callback_via);
987 if (rc) {
988 printk(KERN_ERR "Request for Xen HVM callback vector"
989 " failed.\n");
990 xen_have_vector_callback = 0;
991 return;
992 }
993 printk(KERN_INFO "Xen HVM callback vector for event delivery is "
994 "enabled\n");
995 /* in the restore case the vector has already been allocated */
996 if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors))
997 alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector);
998 }
999}
1000#else
1001void xen_callback_vector(void) {}
1002#endif
1003
936void __init xen_init_IRQ(void) 1004void __init xen_init_IRQ(void)
937{ 1005{
938 int i; 1006 int i;
@@ -947,5 +1015,10 @@ void __init xen_init_IRQ(void)
947 for (i = 0; i < NR_EVENT_CHANNELS; i++) 1015 for (i = 0; i < NR_EVENT_CHANNELS; i++)
948 mask_evtchn(i); 1016 mask_evtchn(i);
949 1017
950 irq_ctx_init(smp_processor_id()); 1018 if (xen_hvm_domain()) {
1019 xen_callback_vector();
1020 native_init_IRQ();
1021 } else {
1022 irq_ctx_init(smp_processor_id());
1023 }
951} 1024}