aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/smpboot.c
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2012-11-14 07:36:53 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2012-11-14 18:28:03 -0500
commite1c467e69040c3be68959332959c07fb3d818e87 (patch)
tree8b26708bc23accd1ebfb6b7dcd08f69350f07a92 /arch/x86/kernel/smpboot.c
parent3e2a0cc3cdc19e0518ae87583add40ea1bf55b67 (diff)
x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI
Instead of waiting for STARTUP after INITs, BSP will execute the BIOS boot-strap code which is not a desired behavior for waking up BSP. To avoid the boot-strap code, wake up CPU0 by NMI instead. This works to wake up soft offlined CPU0 only. If CPU0 is hard offlined (i.e. physically hot removed and then hot added), NMI won't wake it up. We'll change this code in the future to wake up hard offlined CPU0 if real platform and request are available. AP is still waken up as before by INIT, SIPI, SIPI sequence. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Link: http://lkml.kernel.org/r/1352896613-25957-1-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r--arch/x86/kernel/smpboot.c111
1 files changed, 104 insertions, 7 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c297907f3c75..ef53e667e051 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -138,15 +138,17 @@ static void __cpuinit smp_callin(void)
138 * we may get here before an INIT-deassert IPI reaches 138 * we may get here before an INIT-deassert IPI reaches
139 * our local APIC. We have to wait for the IPI or we'll 139 * our local APIC. We have to wait for the IPI or we'll
140 * lock up on an APIC access. 140 * lock up on an APIC access.
141 *
142 * Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
141 */ 143 */
142 if (apic->wait_for_init_deassert) 144 cpuid = smp_processor_id();
145 if (apic->wait_for_init_deassert && cpuid != 0)
143 apic->wait_for_init_deassert(&init_deasserted); 146 apic->wait_for_init_deassert(&init_deasserted);
144 147
145 /* 148 /*
146 * (This works even if the APIC is not enabled.) 149 * (This works even if the APIC is not enabled.)
147 */ 150 */
148 phys_id = read_apic_id(); 151 phys_id = read_apic_id();
149 cpuid = smp_processor_id();
150 if (cpumask_test_cpu(cpuid, cpu_callin_mask)) { 152 if (cpumask_test_cpu(cpuid, cpu_callin_mask)) {
151 panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__, 153 panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
152 phys_id, cpuid); 154 phys_id, cpuid);
@@ -228,6 +230,8 @@ static void __cpuinit smp_callin(void)
228 cpumask_set_cpu(cpuid, cpu_callin_mask); 230 cpumask_set_cpu(cpuid, cpu_callin_mask);
229} 231}
230 232
233static int cpu0_logical_apicid;
234static int enable_start_cpu0;
231/* 235/*
232 * Activate a secondary processor. 236 * Activate a secondary processor.
233 */ 237 */
@@ -243,6 +247,8 @@ notrace static void __cpuinit start_secondary(void *unused)
243 preempt_disable(); 247 preempt_disable();
244 smp_callin(); 248 smp_callin();
245 249
250 enable_start_cpu0 = 0;
251
246#ifdef CONFIG_X86_32 252#ifdef CONFIG_X86_32
247 /* switch away from the initial page table */ 253 /* switch away from the initial page table */
248 load_cr3(swapper_pg_dir); 254 load_cr3(swapper_pg_dir);
@@ -492,7 +498,7 @@ void __inquire_remote_apic(int apicid)
492 * won't ... remember to clear down the APIC, etc later. 498 * won't ... remember to clear down the APIC, etc later.
493 */ 499 */
494int __cpuinit 500int __cpuinit
495wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip) 501wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
496{ 502{
497 unsigned long send_status, accept_status = 0; 503 unsigned long send_status, accept_status = 0;
498 int maxlvt; 504 int maxlvt;
@@ -500,7 +506,7 @@ wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
500 /* Target chip */ 506 /* Target chip */
501 /* Boot on the stack */ 507 /* Boot on the stack */
502 /* Kick the second */ 508 /* Kick the second */
503 apic_icr_write(APIC_DM_NMI | apic->dest_logical, logical_apicid); 509 apic_icr_write(APIC_DM_NMI | apic->dest_logical, apicid);
504 510
505 pr_debug("Waiting for send to finish...\n"); 511 pr_debug("Waiting for send to finish...\n");
506 send_status = safe_apic_wait_icr_idle(); 512 send_status = safe_apic_wait_icr_idle();
@@ -660,6 +666,63 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
660 node, cpu, apicid); 666 node, cpu, apicid);
661} 667}
662 668
669static int wakeup_cpu0_nmi(unsigned int cmd, struct pt_regs *regs)
670{
671 int cpu;
672
673 cpu = smp_processor_id();
674 if (cpu == 0 && !cpu_online(cpu) && enable_start_cpu0)
675 return NMI_HANDLED;
676
677 return NMI_DONE;
678}
679
680/*
681 * Wake up AP by INIT, INIT, STARTUP sequence.
682 *
683 * Instead of waiting for STARTUP after INITs, BSP will execute the BIOS
684 * boot-strap code which is not a desired behavior for waking up BSP. To
685 * void the boot-strap code, wake up CPU0 by NMI instead.
686 *
687 * This works to wake up soft offlined CPU0 only. If CPU0 is hard offlined
688 * (i.e. physically hot removed and then hot added), NMI won't wake it up.
689 * We'll change this code in the future to wake up hard offlined CPU0 if
690 * real platform and request are available.
691 */
692static int __cpuinit
693wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
694 int *cpu0_nmi_registered)
695{
696 int id;
697 int boot_error;
698
699 /*
700 * Wake up AP by INIT, INIT, STARTUP sequence.
701 */
702 if (cpu)
703 return wakeup_secondary_cpu_via_init(apicid, start_ip);
704
705 /*
706 * Wake up BSP by nmi.
707 *
708 * Register a NMI handler to help wake up CPU0.
709 */
710 boot_error = register_nmi_handler(NMI_LOCAL,
711 wakeup_cpu0_nmi, 0, "wake_cpu0");
712
713 if (!boot_error) {
714 enable_start_cpu0 = 1;
715 *cpu0_nmi_registered = 1;
716 if (apic->dest_logical == APIC_DEST_LOGICAL)
717 id = cpu0_logical_apicid;
718 else
719 id = apicid;
720 boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
721 }
722
723 return boot_error;
724}
725
663/* 726/*
664 * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad 727 * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
665 * (ie clustered apic addressing mode), this is a LOGICAL apic ID. 728 * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -675,6 +738,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
675 738
676 unsigned long boot_error = 0; 739 unsigned long boot_error = 0;
677 int timeout; 740 int timeout;
741 int cpu0_nmi_registered = 0;
678 742
679 /* Just in case we booted with a single CPU. */ 743 /* Just in case we booted with a single CPU. */
680 alternatives_enable_smp(); 744 alternatives_enable_smp();
@@ -722,13 +786,16 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
722 } 786 }
723 787
724 /* 788 /*
725 * Kick the secondary CPU. Use the method in the APIC driver 789 * Wake up a CPU in difference cases:
726 * if it's defined - or use an INIT boot APIC message otherwise: 790 * - Use the method in the APIC driver if it's defined
791 * Otherwise,
792 * - Use an INIT boot APIC message for APs or NMI for BSP.
727 */ 793 */
728 if (apic->wakeup_secondary_cpu) 794 if (apic->wakeup_secondary_cpu)
729 boot_error = apic->wakeup_secondary_cpu(apicid, start_ip); 795 boot_error = apic->wakeup_secondary_cpu(apicid, start_ip);
730 else 796 else
731 boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip); 797 boot_error = wakeup_cpu_via_init_nmi(cpu, start_ip, apicid,
798 &cpu0_nmi_registered);
732 799
733 if (!boot_error) { 800 if (!boot_error) {
734 /* 801 /*
@@ -793,6 +860,13 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
793 */ 860 */
794 smpboot_restore_warm_reset_vector(); 861 smpboot_restore_warm_reset_vector();
795 } 862 }
863 /*
864 * Clean up the nmi handler. Do this after the callin and callout sync
865 * to avoid impact of possible long unregister time.
866 */
867 if (cpu0_nmi_registered)
868 unregister_nmi_handler(NMI_LOCAL, "wake_cpu0");
869
796 return boot_error; 870 return boot_error;
797} 871}
798 872
@@ -1037,6 +1111,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
1037 */ 1111 */
1038 setup_local_APIC(); 1112 setup_local_APIC();
1039 1113
1114 if (x2apic_mode)
1115 cpu0_logical_apicid = apic_read(APIC_LDR);
1116 else
1117 cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
1118
1040 /* 1119 /*
1041 * Enable IO APIC before setting up error vector 1120 * Enable IO APIC before setting up error vector
1042 */ 1121 */
@@ -1264,6 +1343,14 @@ void play_dead_common(void)
1264 local_irq_disable(); 1343 local_irq_disable();
1265} 1344}
1266 1345
1346static bool wakeup_cpu0(void)
1347{
1348 if (smp_processor_id() == 0 && enable_start_cpu0)
1349 return true;
1350
1351 return false;
1352}
1353
1267/* 1354/*
1268 * We need to flush the caches before going to sleep, lest we have 1355 * We need to flush the caches before going to sleep, lest we have
1269 * dirty data in our caches when we come back up. 1356 * dirty data in our caches when we come back up.
@@ -1327,6 +1414,11 @@ static inline void mwait_play_dead(void)
1327 __monitor(mwait_ptr, 0, 0); 1414 __monitor(mwait_ptr, 0, 0);
1328 mb(); 1415 mb();
1329 __mwait(eax, 0); 1416 __mwait(eax, 0);
1417 /*
1418 * If NMI wants to wake up CPU0, start CPU0.
1419 */
1420 if (wakeup_cpu0())
1421 start_cpu0();
1330 } 1422 }
1331} 1423}
1332 1424
@@ -1337,6 +1429,11 @@ static inline void hlt_play_dead(void)
1337 1429
1338 while (1) { 1430 while (1) {
1339 native_halt(); 1431 native_halt();
1432 /*
1433 * If NMI wants to wake up CPU0, start CPU0.
1434 */
1435 if (wakeup_cpu0())
1436 start_cpu0();
1340 } 1437 }
1341} 1438}
1342 1439