diff options
-rw-r--r-- | arch/x86/include/asm/irq_vectors.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 3 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 3 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 28 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 2 | ||||
-rw-r--r-- | drivers/xen/events.c | 70 | ||||
-rw-r--r-- | include/xen/events.h | 7 | ||||
-rw-r--r-- | include/xen/hvm.h | 6 | ||||
-rw-r--r-- | include/xen/interface/features.h | 3 |
9 files changed, 118 insertions, 7 deletions
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 8767d99c4f64..e2ca30092557 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h | |||
@@ -125,6 +125,9 @@ | |||
125 | */ | 125 | */ |
126 | #define MCE_SELF_VECTOR 0xeb | 126 | #define MCE_SELF_VECTOR 0xeb |
127 | 127 | ||
128 | /* Xen vector callback to receive events in a HVM domain */ | ||
129 | #define XEN_HVM_EVTCHN_CALLBACK 0xe9 | ||
130 | |||
128 | #define NR_VECTORS 256 | 131 | #define NR_VECTORS 256 |
129 | 132 | ||
130 | #define FPU_IRQ 13 | 133 | #define FPU_IRQ 13 |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index cd49141cf153..6b196834a0dd 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -1166,6 +1166,9 @@ ENTRY(xen_failsafe_callback) | |||
1166 | .previous | 1166 | .previous |
1167 | ENDPROC(xen_failsafe_callback) | 1167 | ENDPROC(xen_failsafe_callback) |
1168 | 1168 | ||
1169 | BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK, | ||
1170 | xen_evtchn_do_upcall) | ||
1171 | |||
1169 | #endif /* CONFIG_XEN */ | 1172 | #endif /* CONFIG_XEN */ |
1170 | 1173 | ||
1171 | #ifdef CONFIG_FUNCTION_TRACER | 1174 | #ifdef CONFIG_FUNCTION_TRACER |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 0697ff139837..490ae2bb18a8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1329,6 +1329,9 @@ ENTRY(xen_failsafe_callback) | |||
1329 | CFI_ENDPROC | 1329 | CFI_ENDPROC |
1330 | END(xen_failsafe_callback) | 1330 | END(xen_failsafe_callback) |
1331 | 1331 | ||
1332 | apicinterrupt XEN_HVM_EVTCHN_CALLBACK \ | ||
1333 | xen_hvm_callback_vector xen_evtchn_do_upcall | ||
1334 | |||
1332 | #endif /* CONFIG_XEN */ | 1335 | #endif /* CONFIG_XEN */ |
1333 | 1336 | ||
1334 | /* | 1337 | /* |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 09b36e9d507a..b211a04c4b2c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 | 11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/cpu.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
@@ -38,6 +39,7 @@ | |||
38 | #include <xen/interface/memory.h> | 39 | #include <xen/interface/memory.h> |
39 | #include <xen/features.h> | 40 | #include <xen/features.h> |
40 | #include <xen/page.h> | 41 | #include <xen/page.h> |
42 | #include <xen/hvm.h> | ||
41 | #include <xen/hvc-console.h> | 43 | #include <xen/hvc-console.h> |
42 | 44 | ||
43 | #include <asm/paravirt.h> | 45 | #include <asm/paravirt.h> |
@@ -80,6 +82,8 @@ struct shared_info xen_dummy_shared_info; | |||
80 | void *xen_initial_gdt; | 82 | void *xen_initial_gdt; |
81 | 83 | ||
82 | RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); | 84 | RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); |
85 | __read_mostly int xen_have_vector_callback; | ||
86 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); | ||
83 | 87 | ||
84 | /* | 88 | /* |
85 | * Point at some empty memory to start with. We map the real shared_info | 89 | * Point at some empty memory to start with. We map the real shared_info |
@@ -1277,6 +1281,24 @@ static void __init init_shared_info(void) | |||
1277 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; | 1281 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; |
1278 | } | 1282 | } |
1279 | 1283 | ||
1284 | static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | ||
1285 | unsigned long action, void *hcpu) | ||
1286 | { | ||
1287 | int cpu = (long)hcpu; | ||
1288 | switch (action) { | ||
1289 | case CPU_UP_PREPARE: | ||
1290 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1291 | break; | ||
1292 | default: | ||
1293 | break; | ||
1294 | } | ||
1295 | return NOTIFY_OK; | ||
1296 | } | ||
1297 | |||
1298 | static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { | ||
1299 | .notifier_call = xen_hvm_cpu_notify, | ||
1300 | }; | ||
1301 | |||
1280 | static void __init xen_hvm_guest_init(void) | 1302 | static void __init xen_hvm_guest_init(void) |
1281 | { | 1303 | { |
1282 | int r; | 1304 | int r; |
@@ -1287,6 +1309,12 @@ static void __init xen_hvm_guest_init(void) | |||
1287 | return; | 1309 | return; |
1288 | 1310 | ||
1289 | init_shared_info(); | 1311 | init_shared_info(); |
1312 | |||
1313 | if (xen_feature(XENFEAT_hvm_callback_vector)) | ||
1314 | xen_have_vector_callback = 1; | ||
1315 | register_cpu_notifier(&xen_hvm_cpu_notifier); | ||
1316 | have_vcpu_info_placement = 0; | ||
1317 | x86_init.irqs.intr_init = xen_init_IRQ; | ||
1290 | } | 1318 | } |
1291 | 1319 | ||
1292 | static bool __init xen_hvm_platform(void) | 1320 | static bool __init xen_hvm_platform(void) |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index f9153a300bce..0d0e0e6a7479 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -38,6 +38,8 @@ void xen_enable_sysenter(void); | |||
38 | void xen_enable_syscall(void); | 38 | void xen_enable_syscall(void); |
39 | void xen_vcpu_restore(void); | 39 | void xen_vcpu_restore(void); |
40 | 40 | ||
41 | void xen_callback_vector(void); | ||
42 | |||
41 | void __init xen_build_dynamic_phys_to_machine(void); | 43 | void __init xen_build_dynamic_phys_to_machine(void); |
42 | 44 | ||
43 | void xen_init_irq_ops(void); | 45 | void xen_init_irq_ops(void); |
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 | } |
diff --git a/include/xen/events.h b/include/xen/events.h index e68d59a90ca8..a15d93262e30 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
@@ -56,4 +56,11 @@ void xen_poll_irq(int irq); | |||
56 | /* Determine the IRQ which is bound to an event channel */ | 56 | /* Determine the IRQ which is bound to an event channel */ |
57 | unsigned irq_from_evtchn(unsigned int evtchn); | 57 | unsigned irq_from_evtchn(unsigned int evtchn); |
58 | 58 | ||
59 | /* Xen HVM evtchn vector callback */ | ||
60 | extern void xen_hvm_callback_vector(void); | ||
61 | extern int xen_have_vector_callback; | ||
62 | int xen_set_callback_via(uint64_t via); | ||
63 | void xen_evtchn_do_upcall(struct pt_regs *regs); | ||
64 | void xen_hvm_evtchn_do_upcall(void); | ||
65 | |||
59 | #endif /* _XEN_EVENTS_H */ | 66 | #endif /* _XEN_EVENTS_H */ |
diff --git a/include/xen/hvm.h b/include/xen/hvm.h index 5dfe8fb86e67..b193fa2f9fdd 100644 --- a/include/xen/hvm.h +++ b/include/xen/hvm.h | |||
@@ -3,6 +3,7 @@ | |||
3 | #define XEN_HVM_H__ | 3 | #define XEN_HVM_H__ |
4 | 4 | ||
5 | #include <xen/interface/hvm/params.h> | 5 | #include <xen/interface/hvm/params.h> |
6 | #include <asm/xen/hypercall.h> | ||
6 | 7 | ||
7 | static inline int hvm_get_parameter(int idx, uint64_t *value) | 8 | static inline int hvm_get_parameter(int idx, uint64_t *value) |
8 | { | 9 | { |
@@ -21,4 +22,9 @@ static inline int hvm_get_parameter(int idx, uint64_t *value) | |||
21 | return r; | 22 | return r; |
22 | } | 23 | } |
23 | 24 | ||
25 | #define HVM_CALLBACK_VIA_TYPE_VECTOR 0x2 | ||
26 | #define HVM_CALLBACK_VIA_TYPE_SHIFT 56 | ||
27 | #define HVM_CALLBACK_VECTOR(x) (((uint64_t)HVM_CALLBACK_VIA_TYPE_VECTOR)<<\ | ||
28 | HVM_CALLBACK_VIA_TYPE_SHIFT | (x)) | ||
29 | |||
24 | #endif /* XEN_HVM_H__ */ | 30 | #endif /* XEN_HVM_H__ */ |
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h index f51b6413b054..8ab08b91bf6f 100644 --- a/include/xen/interface/features.h +++ b/include/xen/interface/features.h | |||
@@ -41,6 +41,9 @@ | |||
41 | /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ | 41 | /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ |
42 | #define XENFEAT_mmu_pt_update_preserve_ad 5 | 42 | #define XENFEAT_mmu_pt_update_preserve_ad 5 |
43 | 43 | ||
44 | /* x86: Does this Xen host support the HVM callback vector type? */ | ||
45 | #define XENFEAT_hvm_callback_vector 8 | ||
46 | |||
44 | #define XENFEAT_NR_SUBMAPS 1 | 47 | #define XENFEAT_NR_SUBMAPS 1 |
45 | 48 | ||
46 | #endif /* __XEN_PUBLIC_FEATURES_H__ */ | 49 | #endif /* __XEN_PUBLIC_FEATURES_H__ */ |