diff options
-rw-r--r-- | arch/x86/xen/Makefile | 3 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 122 | ||||
-rw-r--r-- | arch/x86/xen/irq.c | 143 | ||||
-rw-r--r-- | arch/x86/xen/xen-asm_32.S | 2 | ||||
-rw-r--r-- | arch/x86/xen/xen-asm_64.S | 2 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 1 | ||||
-rw-r--r-- | drivers/xen/events.c | 11 |
7 files changed, 150 insertions, 134 deletions
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 5bfee243cf9a..9ee745fa5527 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
@@ -2,9 +2,10 @@ ifdef CONFIG_FTRACE | |||
2 | # Do not profile debug and lowlevel utilities | 2 | # Do not profile debug and lowlevel utilities |
3 | CFLAGS_REMOVE_spinlock.o = -pg | 3 | CFLAGS_REMOVE_spinlock.o = -pg |
4 | CFLAGS_REMOVE_time.o = -pg | 4 | CFLAGS_REMOVE_time.o = -pg |
5 | CFLAGS_REMOVE_irq.o = -pg | ||
5 | endif | 6 | endif |
6 | 7 | ||
7 | obj-y := enlighten.o setup.o multicalls.o mmu.o \ | 8 | obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ |
8 | time.o xen-asm_$(BITS).o grant-table.o suspend.o | 9 | time.o xen-asm_$(BITS).o grant-table.o suspend.o |
9 | 10 | ||
10 | obj-$(CONFIG_SMP) += smp.o spinlock.o | 11 | obj-$(CONFIG_SMP) += smp.o spinlock.o |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index b795470ec069..cf8b3a93122b 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <xen/interface/xen.h> | 30 | #include <xen/interface/xen.h> |
31 | #include <xen/interface/physdev.h> | 31 | #include <xen/interface/physdev.h> |
32 | #include <xen/interface/vcpu.h> | 32 | #include <xen/interface/vcpu.h> |
33 | #include <xen/interface/sched.h> | ||
34 | #include <xen/features.h> | 33 | #include <xen/features.h> |
35 | #include <xen/page.h> | 34 | #include <xen/page.h> |
36 | #include <xen/hvc-console.h> | 35 | #include <xen/hvc-console.h> |
@@ -226,94 +225,6 @@ static unsigned long xen_get_debugreg(int reg) | |||
226 | return HYPERVISOR_get_debugreg(reg); | 225 | return HYPERVISOR_get_debugreg(reg); |
227 | } | 226 | } |
228 | 227 | ||
229 | static unsigned long xen_save_fl(void) | ||
230 | { | ||
231 | struct vcpu_info *vcpu; | ||
232 | unsigned long flags; | ||
233 | |||
234 | vcpu = x86_read_percpu(xen_vcpu); | ||
235 | |||
236 | /* flag has opposite sense of mask */ | ||
237 | flags = !vcpu->evtchn_upcall_mask; | ||
238 | |||
239 | /* convert to IF type flag | ||
240 | -0 -> 0x00000000 | ||
241 | -1 -> 0xffffffff | ||
242 | */ | ||
243 | return (-flags) & X86_EFLAGS_IF; | ||
244 | } | ||
245 | |||
246 | static void xen_restore_fl(unsigned long flags) | ||
247 | { | ||
248 | struct vcpu_info *vcpu; | ||
249 | |||
250 | /* convert from IF type flag */ | ||
251 | flags = !(flags & X86_EFLAGS_IF); | ||
252 | |||
253 | /* There's a one instruction preempt window here. We need to | ||
254 | make sure we're don't switch CPUs between getting the vcpu | ||
255 | pointer and updating the mask. */ | ||
256 | preempt_disable(); | ||
257 | vcpu = x86_read_percpu(xen_vcpu); | ||
258 | vcpu->evtchn_upcall_mask = flags; | ||
259 | preempt_enable_no_resched(); | ||
260 | |||
261 | /* Doesn't matter if we get preempted here, because any | ||
262 | pending event will get dealt with anyway. */ | ||
263 | |||
264 | if (flags == 0) { | ||
265 | preempt_check_resched(); | ||
266 | barrier(); /* unmask then check (avoid races) */ | ||
267 | if (unlikely(vcpu->evtchn_upcall_pending)) | ||
268 | force_evtchn_callback(); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void xen_irq_disable(void) | ||
273 | { | ||
274 | /* There's a one instruction preempt window here. We need to | ||
275 | make sure we're don't switch CPUs between getting the vcpu | ||
276 | pointer and updating the mask. */ | ||
277 | preempt_disable(); | ||
278 | x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1; | ||
279 | preempt_enable_no_resched(); | ||
280 | } | ||
281 | |||
282 | static void xen_irq_enable(void) | ||
283 | { | ||
284 | struct vcpu_info *vcpu; | ||
285 | |||
286 | /* We don't need to worry about being preempted here, since | ||
287 | either a) interrupts are disabled, so no preemption, or b) | ||
288 | the caller is confused and is trying to re-enable interrupts | ||
289 | on an indeterminate processor. */ | ||
290 | |||
291 | vcpu = x86_read_percpu(xen_vcpu); | ||
292 | vcpu->evtchn_upcall_mask = 0; | ||
293 | |||
294 | /* Doesn't matter if we get preempted here, because any | ||
295 | pending event will get dealt with anyway. */ | ||
296 | |||
297 | barrier(); /* unmask then check (avoid races) */ | ||
298 | if (unlikely(vcpu->evtchn_upcall_pending)) | ||
299 | force_evtchn_callback(); | ||
300 | } | ||
301 | |||
302 | static void xen_safe_halt(void) | ||
303 | { | ||
304 | /* Blocking includes an implicit local_irq_enable(). */ | ||
305 | if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0) | ||
306 | BUG(); | ||
307 | } | ||
308 | |||
309 | static void xen_halt(void) | ||
310 | { | ||
311 | if (irqs_disabled()) | ||
312 | HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); | ||
313 | else | ||
314 | xen_safe_halt(); | ||
315 | } | ||
316 | |||
317 | static void xen_leave_lazy(void) | 228 | static void xen_leave_lazy(void) |
318 | { | 229 | { |
319 | paravirt_leave_lazy(paravirt_get_lazy_mode()); | 230 | paravirt_leave_lazy(paravirt_get_lazy_mode()); |
@@ -1308,36 +1219,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
1308 | }, | 1219 | }, |
1309 | }; | 1220 | }; |
1310 | 1221 | ||
1311 | static void __init __xen_init_IRQ(void) | ||
1312 | { | ||
1313 | #ifdef CONFIG_X86_64 | ||
1314 | int i; | ||
1315 | |||
1316 | /* Create identity vector->irq map */ | ||
1317 | for(i = 0; i < NR_VECTORS; i++) { | ||
1318 | int cpu; | ||
1319 | |||
1320 | for_each_possible_cpu(cpu) | ||
1321 | per_cpu(vector_irq, cpu)[i] = i; | ||
1322 | } | ||
1323 | #endif /* CONFIG_X86_64 */ | ||
1324 | |||
1325 | xen_init_IRQ(); | ||
1326 | } | ||
1327 | |||
1328 | static const struct pv_irq_ops xen_irq_ops __initdata = { | ||
1329 | .init_IRQ = __xen_init_IRQ, | ||
1330 | .save_fl = xen_save_fl, | ||
1331 | .restore_fl = xen_restore_fl, | ||
1332 | .irq_disable = xen_irq_disable, | ||
1333 | .irq_enable = xen_irq_enable, | ||
1334 | .safe_halt = xen_safe_halt, | ||
1335 | .halt = xen_halt, | ||
1336 | #ifdef CONFIG_X86_64 | ||
1337 | .adjust_exception_frame = xen_adjust_exception_frame, | ||
1338 | #endif | ||
1339 | }; | ||
1340 | |||
1341 | static const struct pv_apic_ops xen_apic_ops __initdata = { | 1222 | static const struct pv_apic_ops xen_apic_ops __initdata = { |
1342 | #ifdef CONFIG_X86_LOCAL_APIC | 1223 | #ifdef CONFIG_X86_LOCAL_APIC |
1343 | .apic_write = xen_apic_write, | 1224 | .apic_write = xen_apic_write, |
@@ -1740,10 +1621,11 @@ asmlinkage void __init xen_start_kernel(void) | |||
1740 | pv_init_ops = xen_init_ops; | 1621 | pv_init_ops = xen_init_ops; |
1741 | pv_time_ops = xen_time_ops; | 1622 | pv_time_ops = xen_time_ops; |
1742 | pv_cpu_ops = xen_cpu_ops; | 1623 | pv_cpu_ops = xen_cpu_ops; |
1743 | pv_irq_ops = xen_irq_ops; | ||
1744 | pv_apic_ops = xen_apic_ops; | 1624 | pv_apic_ops = xen_apic_ops; |
1745 | pv_mmu_ops = xen_mmu_ops; | 1625 | pv_mmu_ops = xen_mmu_ops; |
1746 | 1626 | ||
1627 | xen_init_irq_ops(); | ||
1628 | |||
1747 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { | 1629 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { |
1748 | pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; | 1630 | pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; |
1749 | pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; | 1631 | pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; |
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c new file mode 100644 index 000000000000..28b85ab8422e --- /dev/null +++ b/arch/x86/xen/irq.c | |||
@@ -0,0 +1,143 @@ | |||
1 | #include <linux/hardirq.h> | ||
2 | |||
3 | #include <xen/interface/xen.h> | ||
4 | #include <xen/interface/sched.h> | ||
5 | #include <xen/interface/vcpu.h> | ||
6 | |||
7 | #include <asm/xen/hypercall.h> | ||
8 | #include <asm/xen/hypervisor.h> | ||
9 | |||
10 | #include "xen-ops.h" | ||
11 | |||
12 | /* | ||
13 | * Force a proper event-channel callback from Xen after clearing the | ||
14 | * callback mask. We do this in a very simple manner, by making a call | ||
15 | * down into Xen. The pending flag will be checked by Xen on return. | ||
16 | */ | ||
17 | void xen_force_evtchn_callback(void) | ||
18 | { | ||
19 | (void)HYPERVISOR_xen_version(0, NULL); | ||
20 | } | ||
21 | |||
22 | static void __init __xen_init_IRQ(void) | ||
23 | { | ||
24 | #ifdef CONFIG_X86_64 | ||
25 | int i; | ||
26 | |||
27 | /* Create identity vector->irq map */ | ||
28 | for(i = 0; i < NR_VECTORS; i++) { | ||
29 | int cpu; | ||
30 | |||
31 | for_each_possible_cpu(cpu) | ||
32 | per_cpu(vector_irq, cpu)[i] = i; | ||
33 | } | ||
34 | #endif /* CONFIG_X86_64 */ | ||
35 | |||
36 | xen_init_IRQ(); | ||
37 | } | ||
38 | |||
39 | static unsigned long xen_save_fl(void) | ||
40 | { | ||
41 | struct vcpu_info *vcpu; | ||
42 | unsigned long flags; | ||
43 | |||
44 | vcpu = x86_read_percpu(xen_vcpu); | ||
45 | |||
46 | /* flag has opposite sense of mask */ | ||
47 | flags = !vcpu->evtchn_upcall_mask; | ||
48 | |||
49 | /* convert to IF type flag | ||
50 | -0 -> 0x00000000 | ||
51 | -1 -> 0xffffffff | ||
52 | */ | ||
53 | return (-flags) & X86_EFLAGS_IF; | ||
54 | } | ||
55 | |||
56 | static void xen_restore_fl(unsigned long flags) | ||
57 | { | ||
58 | struct vcpu_info *vcpu; | ||
59 | |||
60 | /* convert from IF type flag */ | ||
61 | flags = !(flags & X86_EFLAGS_IF); | ||
62 | |||
63 | /* There's a one instruction preempt window here. We need to | ||
64 | make sure we're don't switch CPUs between getting the vcpu | ||
65 | pointer and updating the mask. */ | ||
66 | preempt_disable(); | ||
67 | vcpu = x86_read_percpu(xen_vcpu); | ||
68 | vcpu->evtchn_upcall_mask = flags; | ||
69 | preempt_enable_no_resched(); | ||
70 | |||
71 | /* Doesn't matter if we get preempted here, because any | ||
72 | pending event will get dealt with anyway. */ | ||
73 | |||
74 | if (flags == 0) { | ||
75 | preempt_check_resched(); | ||
76 | barrier(); /* unmask then check (avoid races) */ | ||
77 | if (unlikely(vcpu->evtchn_upcall_pending)) | ||
78 | xen_force_evtchn_callback(); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void xen_irq_disable(void) | ||
83 | { | ||
84 | /* There's a one instruction preempt window here. We need to | ||
85 | make sure we're don't switch CPUs between getting the vcpu | ||
86 | pointer and updating the mask. */ | ||
87 | preempt_disable(); | ||
88 | x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1; | ||
89 | preempt_enable_no_resched(); | ||
90 | } | ||
91 | |||
92 | static void xen_irq_enable(void) | ||
93 | { | ||
94 | struct vcpu_info *vcpu; | ||
95 | |||
96 | /* We don't need to worry about being preempted here, since | ||
97 | either a) interrupts are disabled, so no preemption, or b) | ||
98 | the caller is confused and is trying to re-enable interrupts | ||
99 | on an indeterminate processor. */ | ||
100 | |||
101 | vcpu = x86_read_percpu(xen_vcpu); | ||
102 | vcpu->evtchn_upcall_mask = 0; | ||
103 | |||
104 | /* Doesn't matter if we get preempted here, because any | ||
105 | pending event will get dealt with anyway. */ | ||
106 | |||
107 | barrier(); /* unmask then check (avoid races) */ | ||
108 | if (unlikely(vcpu->evtchn_upcall_pending)) | ||
109 | xen_force_evtchn_callback(); | ||
110 | } | ||
111 | |||
112 | static void xen_safe_halt(void) | ||
113 | { | ||
114 | /* Blocking includes an implicit local_irq_enable(). */ | ||
115 | if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0) | ||
116 | BUG(); | ||
117 | } | ||
118 | |||
119 | static void xen_halt(void) | ||
120 | { | ||
121 | if (irqs_disabled()) | ||
122 | HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); | ||
123 | else | ||
124 | xen_safe_halt(); | ||
125 | } | ||
126 | |||
127 | static const struct pv_irq_ops xen_irq_ops __initdata = { | ||
128 | .init_IRQ = __xen_init_IRQ, | ||
129 | .save_fl = xen_save_fl, | ||
130 | .restore_fl = xen_restore_fl, | ||
131 | .irq_disable = xen_irq_disable, | ||
132 | .irq_enable = xen_irq_enable, | ||
133 | .safe_halt = xen_safe_halt, | ||
134 | .halt = xen_halt, | ||
135 | #ifdef CONFIG_X86_64 | ||
136 | .adjust_exception_frame = xen_adjust_exception_frame, | ||
137 | #endif | ||
138 | }; | ||
139 | |||
140 | void __init xen_init_irq_ops() | ||
141 | { | ||
142 | pv_irq_ops = xen_irq_ops; | ||
143 | } | ||
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index 2497a30f41de..42786f59d9c0 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S | |||
@@ -298,7 +298,7 @@ check_events: | |||
298 | push %eax | 298 | push %eax |
299 | push %ecx | 299 | push %ecx |
300 | push %edx | 300 | push %edx |
301 | call force_evtchn_callback | 301 | call xen_force_evtchn_callback |
302 | pop %edx | 302 | pop %edx |
303 | pop %ecx | 303 | pop %ecx |
304 | pop %eax | 304 | pop %eax |
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S index 7f58304fafb3..3b9bda46487a 100644 --- a/arch/x86/xen/xen-asm_64.S +++ b/arch/x86/xen/xen-asm_64.S | |||
@@ -122,7 +122,7 @@ check_events: | |||
122 | push %r9 | 122 | push %r9 |
123 | push %r10 | 123 | push %r10 |
124 | push %r11 | 124 | push %r11 |
125 | call force_evtchn_callback | 125 | call xen_force_evtchn_callback |
126 | pop %r11 | 126 | pop %r11 |
127 | pop %r10 | 127 | pop %r10 |
128 | pop %r9 | 128 | pop %r9 |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 8847fb34f17e..3c70ebc50b1b 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -31,6 +31,7 @@ void xen_vcpu_restore(void); | |||
31 | 31 | ||
32 | void __init xen_build_dynamic_phys_to_machine(void); | 32 | void __init xen_build_dynamic_phys_to_machine(void); |
33 | 33 | ||
34 | void xen_init_irq_ops(void); | ||
34 | void xen_setup_timer(int cpu); | 35 | void xen_setup_timer(int cpu); |
35 | void xen_setup_cpu_clockevents(void); | 36 | void xen_setup_cpu_clockevents(void); |
36 | unsigned long xen_tsc_khz(void); | 37 | unsigned long xen_tsc_khz(void); |
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0e0c28574af8..a0837036d898 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -84,17 +84,6 @@ static int irq_bindcount[NR_IRQS]; | |||
84 | /* Xen will never allocate port zero for any purpose. */ | 84 | /* Xen will never allocate port zero for any purpose. */ |
85 | #define VALID_EVTCHN(chn) ((chn) != 0) | 85 | #define VALID_EVTCHN(chn) ((chn) != 0) |
86 | 86 | ||
87 | /* | ||
88 | * Force a proper event-channel callback from Xen after clearing the | ||
89 | * callback mask. We do this in a very simple manner, by making a call | ||
90 | * down into Xen. The pending flag will be checked by Xen on return. | ||
91 | */ | ||
92 | void force_evtchn_callback(void) | ||
93 | { | ||
94 | (void)HYPERVISOR_xen_version(0, NULL); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(force_evtchn_callback); | ||
97 | |||
98 | static struct irq_chip xen_dynamic_chip; | 87 | static struct irq_chip xen_dynamic_chip; |
99 | 88 | ||
100 | /* Constructor for packed IRQ information. */ | 89 | /* Constructor for packed IRQ information. */ |