diff options
Diffstat (limited to 'arch/x86/xen/smp.c')
-rw-r--r-- | arch/x86/xen/smp.c | 135 |
1 files changed, 47 insertions, 88 deletions
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index d2e3c20127d7..233156f39b7f 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -36,27 +36,14 @@ | |||
36 | #include "mmu.h" | 36 | #include "mmu.h" |
37 | 37 | ||
38 | cpumask_t xen_cpu_initialized_map; | 38 | cpumask_t xen_cpu_initialized_map; |
39 | static DEFINE_PER_CPU(int, resched_irq) = -1; | ||
40 | static DEFINE_PER_CPU(int, callfunc_irq) = -1; | ||
41 | static DEFINE_PER_CPU(int, debug_irq) = -1; | ||
42 | |||
43 | /* | ||
44 | * Structure and data for smp_call_function(). This is designed to minimise | ||
45 | * static memory requirements. It also looks cleaner. | ||
46 | */ | ||
47 | static DEFINE_SPINLOCK(call_lock); | ||
48 | 39 | ||
49 | struct call_data_struct { | 40 | static DEFINE_PER_CPU(int, resched_irq); |
50 | void (*func) (void *info); | 41 | static DEFINE_PER_CPU(int, callfunc_irq); |
51 | void *info; | 42 | static DEFINE_PER_CPU(int, callfuncsingle_irq); |
52 | atomic_t started; | 43 | static DEFINE_PER_CPU(int, debug_irq) = -1; |
53 | atomic_t finished; | ||
54 | int wait; | ||
55 | }; | ||
56 | 44 | ||
57 | static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id); | 45 | static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id); |
58 | 46 | static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id); | |
59 | static struct call_data_struct *call_data; | ||
60 | 47 | ||
61 | /* | 48 | /* |
62 | * Reschedule call back. Nothing to do, | 49 | * Reschedule call back. Nothing to do, |
@@ -128,6 +115,17 @@ static int xen_smp_intr_init(unsigned int cpu) | |||
128 | goto fail; | 115 | goto fail; |
129 | per_cpu(debug_irq, cpu) = rc; | 116 | per_cpu(debug_irq, cpu) = rc; |
130 | 117 | ||
118 | callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu); | ||
119 | rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR, | ||
120 | cpu, | ||
121 | xen_call_function_single_interrupt, | ||
122 | IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING, | ||
123 | callfunc_name, | ||
124 | NULL); | ||
125 | if (rc < 0) | ||
126 | goto fail; | ||
127 | per_cpu(callfuncsingle_irq, cpu) = rc; | ||
128 | |||
131 | return 0; | 129 | return 0; |
132 | 130 | ||
133 | fail: | 131 | fail: |
@@ -137,6 +135,9 @@ static int xen_smp_intr_init(unsigned int cpu) | |||
137 | unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); | 135 | unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); |
138 | if (per_cpu(debug_irq, cpu) >= 0) | 136 | if (per_cpu(debug_irq, cpu) >= 0) |
139 | unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL); | 137 | unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL); |
138 | if (per_cpu(callfuncsingle_irq, cpu) >= 0) | ||
139 | unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL); | ||
140 | |||
140 | return rc; | 141 | return rc; |
141 | } | 142 | } |
142 | 143 | ||
@@ -336,7 +337,7 @@ static void stop_self(void *v) | |||
336 | 337 | ||
337 | void xen_smp_send_stop(void) | 338 | void xen_smp_send_stop(void) |
338 | { | 339 | { |
339 | smp_call_function(stop_self, NULL, 0, 0); | 340 | smp_call_function(stop_self, NULL, 0); |
340 | } | 341 | } |
341 | 342 | ||
342 | void xen_smp_send_reschedule(int cpu) | 343 | void xen_smp_send_reschedule(int cpu) |
@@ -344,7 +345,6 @@ void xen_smp_send_reschedule(int cpu) | |||
344 | xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR); | 345 | xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR); |
345 | } | 346 | } |
346 | 347 | ||
347 | |||
348 | static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) | 348 | static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) |
349 | { | 349 | { |
350 | unsigned cpu; | 350 | unsigned cpu; |
@@ -355,83 +355,42 @@ static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) | |||
355 | xen_send_IPI_one(cpu, vector); | 355 | xen_send_IPI_one(cpu, vector); |
356 | } | 356 | } |
357 | 357 | ||
358 | void xen_smp_send_call_function_ipi(cpumask_t mask) | ||
359 | { | ||
360 | int cpu; | ||
361 | |||
362 | xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR); | ||
363 | |||
364 | /* Make sure other vcpus get a chance to run if they need to. */ | ||
365 | for_each_cpu_mask(cpu, mask) { | ||
366 | if (xen_vcpu_stolen(cpu)) { | ||
367 | HYPERVISOR_sched_op(SCHEDOP_yield, 0); | ||
368 | break; | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | |||
373 | void xen_smp_send_call_function_single_ipi(int cpu) | ||
374 | { | ||
375 | xen_send_IPI_mask(cpumask_of_cpu(cpu), XEN_CALL_FUNCTION_SINGLE_VECTOR); | ||
376 | } | ||
377 | |||
358 | static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id) | 378 | static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id) |
359 | { | 379 | { |
360 | void (*func) (void *info) = call_data->func; | ||
361 | void *info = call_data->info; | ||
362 | int wait = call_data->wait; | ||
363 | |||
364 | /* | ||
365 | * Notify initiating CPU that I've grabbed the data and am | ||
366 | * about to execute the function | ||
367 | */ | ||
368 | mb(); | ||
369 | atomic_inc(&call_data->started); | ||
370 | /* | ||
371 | * At this point the info structure may be out of scope unless wait==1 | ||
372 | */ | ||
373 | irq_enter(); | 380 | irq_enter(); |
374 | (*func)(info); | 381 | generic_smp_call_function_interrupt(); |
375 | __get_cpu_var(irq_stat).irq_call_count++; | 382 | __get_cpu_var(irq_stat).irq_call_count++; |
376 | irq_exit(); | 383 | irq_exit(); |
377 | 384 | ||
378 | if (wait) { | ||
379 | mb(); /* commit everything before setting finished */ | ||
380 | atomic_inc(&call_data->finished); | ||
381 | } | ||
382 | |||
383 | return IRQ_HANDLED; | 385 | return IRQ_HANDLED; |
384 | } | 386 | } |
385 | 387 | ||
386 | int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *), | 388 | static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id) |
387 | void *info, int wait) | ||
388 | { | 389 | { |
389 | struct call_data_struct data; | 390 | irq_enter(); |
390 | int cpus, cpu; | 391 | generic_smp_call_function_single_interrupt(); |
391 | bool yield; | 392 | __get_cpu_var(irq_stat).irq_call_count++; |
392 | 393 | irq_exit(); | |
393 | /* Holding any lock stops cpus from going down. */ | ||
394 | spin_lock(&call_lock); | ||
395 | |||
396 | cpu_clear(smp_processor_id(), mask); | ||
397 | |||
398 | cpus = cpus_weight(mask); | ||
399 | if (!cpus) { | ||
400 | spin_unlock(&call_lock); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | /* Can deadlock when called with interrupts disabled */ | ||
405 | WARN_ON(irqs_disabled()); | ||
406 | |||
407 | data.func = func; | ||
408 | data.info = info; | ||
409 | atomic_set(&data.started, 0); | ||
410 | data.wait = wait; | ||
411 | if (wait) | ||
412 | atomic_set(&data.finished, 0); | ||
413 | |||
414 | call_data = &data; | ||
415 | mb(); /* write everything before IPI */ | ||
416 | |||
417 | /* Send a message to other CPUs and wait for them to respond */ | ||
418 | xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR); | ||
419 | |||
420 | /* Make sure other vcpus get a chance to run if they need to. */ | ||
421 | yield = false; | ||
422 | for_each_cpu_mask(cpu, mask) | ||
423 | if (xen_vcpu_stolen(cpu)) | ||
424 | yield = true; | ||
425 | |||
426 | if (yield) | ||
427 | HYPERVISOR_sched_op(SCHEDOP_yield, 0); | ||
428 | |||
429 | /* Wait for response */ | ||
430 | while (atomic_read(&data.started) != cpus || | ||
431 | (wait && atomic_read(&data.finished) != cpus)) | ||
432 | cpu_relax(); | ||
433 | |||
434 | spin_unlock(&call_lock); | ||
435 | 394 | ||
436 | return 0; | 395 | return IRQ_HANDLED; |
437 | } | 396 | } |