aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSheng Yang <sheng@linux.intel.com>2010-05-14 07:40:51 -0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-07-22 19:45:59 -0400
commit38e20b07efd541a959de367dc90a17f92ce2e8a6 (patch)
treebb087e243bf6e707dd063be2024a3b90de2f9413
parentbee6ab53e652a414af20392899879b58cd80d033 (diff)
x86/xen: event channels delivery on HVM.
Set the callback to receive evtchns from Xen, using the callback vector delivery mechanism. The traditional way for receiving event channel notifications from Xen is via the interrupts from the platform PCI device. The callback vector is a newer alternative that allow us to receive notifications on any vcpu and doesn't need any PCI support: we allocate a vector exclusively to receive events, in the vector handler we don't need to interact with the vlapic, therefore we avoid a VMEXIT. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
-rw-r--r--arch/x86/include/asm/irq_vectors.h3
-rw-r--r--arch/x86/kernel/entry_32.S3
-rw-r--r--arch/x86/kernel/entry_64.S3
-rw-r--r--arch/x86/xen/enlighten.c28
-rw-r--r--arch/x86/xen/xen-ops.h2
-rw-r--r--drivers/xen/events.c70
-rw-r--r--include/xen/events.h7
-rw-r--r--include/xen/hvm.h6
-rw-r--r--include/xen/interface/features.h3
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
1167ENDPROC(xen_failsafe_callback) 1167ENDPROC(xen_failsafe_callback)
1168 1168
1169BUILD_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
1330END(xen_failsafe_callback) 1330END(xen_failsafe_callback)
1331 1331
1332apicinterrupt 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;
80void *xen_initial_gdt; 82void *xen_initial_gdt;
81 83
82RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); 84RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
85__read_mostly int xen_have_vector_callback;
86EXPORT_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
1284static 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
1298static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
1299 .notifier_call = xen_hvm_cpu_notify,
1300};
1301
1280static void __init xen_hvm_guest_init(void) 1302static 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
1292static bool __init xen_hvm_platform(void) 1320static 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);
38void xen_enable_syscall(void); 38void xen_enable_syscall(void);
39void xen_vcpu_restore(void); 39void xen_vcpu_restore(void);
40 40
41void xen_callback_vector(void);
42
41void __init xen_build_dynamic_phys_to_machine(void); 43void __init xen_build_dynamic_phys_to_machine(void);
42 44
43void xen_init_irq_ops(void); 45void 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 */
620void xen_evtchn_do_upcall(struct pt_regs *regs) 625static 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
669out: 670out:
671
672 put_cpu();
673}
674
675void 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(); 688void 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
953int 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}
961EXPORT_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. */
966void 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
936void __init xen_init_IRQ(void) 987void __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 */
57unsigned irq_from_evtchn(unsigned int evtchn); 57unsigned irq_from_evtchn(unsigned int evtchn);
58 58
59/* Xen HVM evtchn vector callback */
60extern void xen_hvm_callback_vector(void);
61extern int xen_have_vector_callback;
62int xen_set_callback_via(uint64_t via);
63void xen_evtchn_do_upcall(struct pt_regs *regs);
64void 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
7static inline int hvm_get_parameter(int idx, uint64_t *value) 8static 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__ */