diff options
Diffstat (limited to 'arch/i386/kernel/smp.c')
-rw-r--r-- | arch/i386/kernel/smp.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 68be7d0c7238..35f521612b20 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mc146818rtc.h> | 19 | #include <linux/mc146818rtc.h> |
20 | #include <linux/cache.h> | 20 | #include <linux/cache.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/cpu.h> | ||
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | 24 | ||
24 | #include <asm/mtrr.h> | 25 | #include <asm/mtrr.h> |
@@ -164,7 +165,7 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) | |||
164 | unsigned long flags; | 165 | unsigned long flags; |
165 | 166 | ||
166 | local_irq_save(flags); | 167 | local_irq_save(flags); |
167 | 168 | WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); | |
168 | /* | 169 | /* |
169 | * Wait for idle. | 170 | * Wait for idle. |
170 | */ | 171 | */ |
@@ -346,21 +347,21 @@ out: | |||
346 | static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | 347 | static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, |
347 | unsigned long va) | 348 | unsigned long va) |
348 | { | 349 | { |
349 | cpumask_t tmp; | ||
350 | /* | 350 | /* |
351 | * A couple of (to be removed) sanity checks: | 351 | * A couple of (to be removed) sanity checks: |
352 | * | 352 | * |
353 | * - we do not send IPIs to not-yet booted CPUs. | ||
354 | * - current CPU must not be in mask | 353 | * - current CPU must not be in mask |
355 | * - mask must exist :) | 354 | * - mask must exist :) |
356 | */ | 355 | */ |
357 | BUG_ON(cpus_empty(cpumask)); | 356 | BUG_ON(cpus_empty(cpumask)); |
358 | |||
359 | cpus_and(tmp, cpumask, cpu_online_map); | ||
360 | BUG_ON(!cpus_equal(cpumask, tmp)); | ||
361 | BUG_ON(cpu_isset(smp_processor_id(), cpumask)); | 357 | BUG_ON(cpu_isset(smp_processor_id(), cpumask)); |
362 | BUG_ON(!mm); | 358 | BUG_ON(!mm); |
363 | 359 | ||
360 | /* If a CPU which we ran on has gone down, OK. */ | ||
361 | cpus_and(cpumask, cpumask, cpu_online_map); | ||
362 | if (cpus_empty(cpumask)) | ||
363 | return; | ||
364 | |||
364 | /* | 365 | /* |
365 | * i'm not happy about this global shared spinlock in the | 366 | * i'm not happy about this global shared spinlock in the |
366 | * MM hot path, but we'll see how contended it is. | 367 | * MM hot path, but we'll see how contended it is. |
@@ -476,6 +477,7 @@ void flush_tlb_all(void) | |||
476 | */ | 477 | */ |
477 | void smp_send_reschedule(int cpu) | 478 | void smp_send_reschedule(int cpu) |
478 | { | 479 | { |
480 | WARN_ON(cpu_is_offline(cpu)); | ||
479 | send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); | 481 | send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); |
480 | } | 482 | } |
481 | 483 | ||
@@ -516,10 +518,15 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, | |||
516 | */ | 518 | */ |
517 | { | 519 | { |
518 | struct call_data_struct data; | 520 | struct call_data_struct data; |
519 | int cpus = num_online_cpus()-1; | 521 | int cpus; |
520 | 522 | ||
521 | if (!cpus) | 523 | /* Holding any lock stops cpus from going down. */ |
524 | spin_lock(&call_lock); | ||
525 | cpus = num_online_cpus() - 1; | ||
526 | if (!cpus) { | ||
527 | spin_unlock(&call_lock); | ||
522 | return 0; | 528 | return 0; |
529 | } | ||
523 | 530 | ||
524 | /* Can deadlock when called with interrupts disabled */ | 531 | /* Can deadlock when called with interrupts disabled */ |
525 | WARN_ON(irqs_disabled()); | 532 | WARN_ON(irqs_disabled()); |
@@ -531,7 +538,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, | |||
531 | if (wait) | 538 | if (wait) |
532 | atomic_set(&data.finished, 0); | 539 | atomic_set(&data.finished, 0); |
533 | 540 | ||
534 | spin_lock(&call_lock); | ||
535 | call_data = &data; | 541 | call_data = &data; |
536 | mb(); | 542 | mb(); |
537 | 543 | ||