diff options
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r-- | drivers/xen/events.c | 70 |
1 files changed, 63 insertions, 7 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index db8f506817f0..d659480125f0 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 |
@@ -617,17 +622,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); | |||
617 | * a bitset of words which contain pending event bits. The second | 622 | * a bitset of words which contain pending event bits. The second |
618 | * level is a bitset of pending events themselves. | 623 | * level is a bitset of pending events themselves. |
619 | */ | 624 | */ |
620 | void xen_evtchn_do_upcall(struct pt_regs *regs) | 625 | static void __xen_evtchn_do_upcall(void) |
621 | { | 626 | { |
622 | int cpu = get_cpu(); | 627 | int cpu = get_cpu(); |
623 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
624 | struct shared_info *s = HYPERVISOR_shared_info; | 628 | struct shared_info *s = HYPERVISOR_shared_info; |
625 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); | 629 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); |
626 | unsigned count; | 630 | unsigned count; |
627 | 631 | ||
628 | exit_idle(); | ||
629 | irq_enter(); | ||
630 | |||
631 | do { | 632 | do { |
632 | unsigned long pending_words; | 633 | unsigned long pending_words; |
633 | 634 | ||
@@ -667,10 +668,26 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) | |||
667 | } while(count != 1); | 668 | } while(count != 1); |
668 | 669 | ||
669 | out: | 670 | out: |
671 | |||
672 | put_cpu(); | ||
673 | } | ||
674 | |||
675 | void xen_evtchn_do_upcall(struct pt_regs *regs) | ||
676 | { | ||
677 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
678 | |||
679 | exit_idle(); | ||
680 | irq_enter(); | ||
681 | |||
682 | __xen_evtchn_do_upcall(); | ||
683 | |||
670 | irq_exit(); | 684 | irq_exit(); |
671 | set_irq_regs(old_regs); | 685 | set_irq_regs(old_regs); |
686 | } | ||
672 | 687 | ||
673 | put_cpu(); | 688 | void xen_hvm_evtchn_do_upcall(void) |
689 | { | ||
690 | __xen_evtchn_do_upcall(); | ||
674 | } | 691 | } |
675 | 692 | ||
676 | /* Rebind a new event channel to an existing irq. */ | 693 | /* Rebind a new event channel to an existing irq. */ |
@@ -933,6 +950,40 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { | |||
933 | .retrigger = retrigger_dynirq, | 950 | .retrigger = retrigger_dynirq, |
934 | }; | 951 | }; |
935 | 952 | ||
953 | int xen_set_callback_via(uint64_t via) | ||
954 | { | ||
955 | struct xen_hvm_param a; | ||
956 | a.domid = DOMID_SELF; | ||
957 | a.index = HVM_PARAM_CALLBACK_IRQ; | ||
958 | a.value = via; | ||
959 | return HYPERVISOR_hvm_op(HVMOP_set_param, &a); | ||
960 | } | ||
961 | EXPORT_SYMBOL_GPL(xen_set_callback_via); | ||
962 | |||
963 | /* Vector callbacks are better than PCI interrupts to receive event | ||
964 | * channel notifications because we can receive vector callbacks on any | ||
965 | * vcpu and we don't need PCI support or APIC interactions. */ | ||
966 | void xen_callback_vector(void) | ||
967 | { | ||
968 | int rc; | ||
969 | uint64_t callback_via; | ||
970 | if (xen_have_vector_callback) { | ||
971 | callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); | ||
972 | rc = xen_set_callback_via(callback_via); | ||
973 | if (rc) { | ||
974 | printk(KERN_ERR "Request for Xen HVM callback vector" | ||
975 | " failed.\n"); | ||
976 | xen_have_vector_callback = 0; | ||
977 | return; | ||
978 | } | ||
979 | printk(KERN_INFO "Xen HVM callback vector for event delivery is " | ||
980 | "enabled\n"); | ||
981 | /* in the restore case the vector has already been allocated */ | ||
982 | if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) | ||
983 | alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); | ||
984 | } | ||
985 | } | ||
986 | |||
936 | void __init xen_init_IRQ(void) | 987 | void __init xen_init_IRQ(void) |
937 | { | 988 | { |
938 | int i; | 989 | int i; |
@@ -947,5 +998,10 @@ void __init xen_init_IRQ(void) | |||
947 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | 998 | for (i = 0; i < NR_EVENT_CHANNELS; i++) |
948 | mask_evtchn(i); | 999 | mask_evtchn(i); |
949 | 1000 | ||
950 | irq_ctx_init(smp_processor_id()); | 1001 | if (xen_hvm_domain()) { |
1002 | xen_callback_vector(); | ||
1003 | native_init_IRQ(); | ||
1004 | } else { | ||
1005 | irq_ctx_init(smp_processor_id()); | ||
1006 | } | ||
951 | } | 1007 | } |