aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/smp.c')
-rw-r--r--arch/i386/kernel/smp.c68
1 files changed, 38 insertions, 30 deletions
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 0e8977871b1f..0cd459baad68 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -515,35 +515,14 @@ void unlock_ipi_call_lock(void)
515 515
516static struct call_data_struct *call_data; 516static struct call_data_struct *call_data;
517 517
518/** 518static void __smp_call_function(void (*func) (void *info), void *info,
519 * smp_call_function(): Run a function on all other CPUs. 519 int nonatomic, int wait)
520 * @func: The function to run. This must be fast and non-blocking.
521 * @info: An arbitrary pointer to pass to the function.
522 * @nonatomic: currently unused.
523 * @wait: If true, wait (atomically) until function has completed on other CPUs.
524 *
525 * Returns 0 on success, else a negative status code. Does not return until
526 * remote CPUs are nearly ready to execute <<func>> or are or have executed.
527 *
528 * You must not call this function with disabled interrupts or from a
529 * hardware interrupt handler or from a bottom half handler.
530 */
531int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
532 int wait)
533{ 520{
534 struct call_data_struct data; 521 struct call_data_struct data;
535 int cpus; 522 int cpus = num_online_cpus() - 1;
536
537 /* Holding any lock stops cpus from going down. */
538 spin_lock(&call_lock);
539 cpus = num_online_cpus() - 1;
540 if (!cpus) {
541 spin_unlock(&call_lock);
542 return 0;
543 }
544 523
545 /* Can deadlock when called with interrupts disabled */ 524 if (!cpus)
546 WARN_ON(irqs_disabled()); 525 return;
547 526
548 data.func = func; 527 data.func = func;
549 data.info = info; 528 data.info = info;
@@ -565,6 +544,30 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
565 if (wait) 544 if (wait)
566 while (atomic_read(&data.finished) != cpus) 545 while (atomic_read(&data.finished) != cpus)
567 cpu_relax(); 546 cpu_relax();
547}
548
549/**
550 * smp_call_function(): Run a function on all other CPUs.
551 * @func: The function to run. This must be fast and non-blocking.
552 * @info: An arbitrary pointer to pass to the function.
553 * @nonatomic: currently unused.
554 * @wait: If true, wait (atomically) until function has completed on other CPUs.
555 *
556 * Returns 0 on success, else a negative status code. Does not return until
557 * remote CPUs are nearly ready to execute <<func>> or are or have executed.
558 *
559 * You must not call this function with disabled interrupts or from a
560 * hardware interrupt handler or from a bottom half handler.
561 */
562int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
563 int wait)
564{
565 /* Can deadlock when called with interrupts disabled */
566 WARN_ON(irqs_disabled());
567
568 /* Holding any lock stops cpus from going down. */
569 spin_lock(&call_lock);
570 __smp_call_function(func, info, nonatomic, wait);
568 spin_unlock(&call_lock); 571 spin_unlock(&call_lock);
569 572
570 return 0; 573 return 0;
@@ -573,11 +576,11 @@ EXPORT_SYMBOL(smp_call_function);
573 576
574static void stop_this_cpu (void * dummy) 577static void stop_this_cpu (void * dummy)
575{ 578{
579 local_irq_disable();
576 /* 580 /*
577 * Remove this CPU: 581 * Remove this CPU:
578 */ 582 */
579 cpu_clear(smp_processor_id(), cpu_online_map); 583 cpu_clear(smp_processor_id(), cpu_online_map);
580 local_irq_disable();
581 disable_local_APIC(); 584 disable_local_APIC();
582 if (cpu_data[smp_processor_id()].hlt_works_ok) 585 if (cpu_data[smp_processor_id()].hlt_works_ok)
583 for(;;) halt(); 586 for(;;) halt();
@@ -590,11 +593,16 @@ static void stop_this_cpu (void * dummy)
590 593
591void smp_send_stop(void) 594void smp_send_stop(void)
592{ 595{
593 smp_call_function(stop_this_cpu, NULL, 1, 0); 596 /* Don't deadlock on the call lock in panic */
597 int nolock = !spin_trylock(&call_lock);
598 unsigned long flags;
594 599
595 local_irq_disable(); 600 local_irq_save(flags);
601 __smp_call_function(stop_this_cpu, NULL, 0, 0);
602 if (!nolock)
603 spin_unlock(&call_lock);
596 disable_local_APIC(); 604 disable_local_APIC();
597 local_irq_enable(); 605 local_irq_restore(flags);
598} 606}
599 607
600/* 608/*