diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2010-05-14 07:40:51 -0400 |
|---|---|---|
| committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-07-22 19:45:59 -0400 |
| commit | 38e20b07efd541a959de367dc90a17f92ce2e8a6 (patch) | |
| tree | bb087e243bf6e707dd063be2024a3b90de2f9413 | |
| parent | bee6ab53e652a414af20392899879b58cd80d033 (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.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 8767d99c4f6..e2ca3009255 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 cd49141cf15..6b196834a0d 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 0697ff13983..490ae2bb18a 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 09b36e9d507..b211a04c4b2 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 f9153a300bc..0d0e0e6a747 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 db8f506817f..d659480125f 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 | } | ||
