summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/smpboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r--arch/x86/kernel/smpboot.c99
1 files changed, 68 insertions, 31 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index bc52fac39dd3..ae2fd975b782 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -111,6 +111,7 @@ atomic_t init_deasserted;
static void smp_callin(void)
{
int cpuid, phys_id;
+ unsigned long timeout;
/*
* If waken up by an INIT in an 82489DX configuration
@@ -129,6 +130,37 @@ static void smp_callin(void)
* (This works even if the APIC is not enabled.)
*/
phys_id = read_apic_id();
+ if (cpumask_test_cpu(cpuid, cpu_callin_mask)) {
+ panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
+ phys_id, cpuid);
+ }
+ pr_debug("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
+
+ /*
+ * STARTUP IPIs are fragile beasts as they might sometimes
+ * trigger some glue motherboard logic. Complete APIC bus
+ * silence for 1 second, this overestimates the time the
+ * boot CPU is spending to send the up to 2 STARTUP IPIs
+ * by a factor of two. This should be enough.
+ */
+
+ /*
+ * Waiting 2s total for startup (udelay is not yet working)
+ */
+ timeout = jiffies + 2*HZ;
+ while (time_before(jiffies, timeout)) {
+ /*
+ * Has the boot CPU finished it's STARTUP sequence?
+ */
+ if (cpumask_test_cpu(cpuid, cpu_callout_mask))
+ break;
+ cpu_relax();
+ }
+
+ if (!time_before(jiffies, timeout)) {
+ panic("%s: CPU%d started up but did not get a callout!\n",
+ __func__, cpuid);
+ }
/*
* the boot CPU has finished the init stage and is spinning
@@ -718,8 +750,8 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
unsigned long start_ip = real_mode_header->trampoline_start;
unsigned long boot_error = 0;
+ int timeout;
int cpu0_nmi_registered = 0;
- unsigned long timeout;
/* Just in case we booted with a single CPU. */
alternatives_enable_smp();
@@ -767,15 +799,6 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
}
/*
- * AP might wait on cpu_callout_mask in cpu_init() with
- * cpu_initialized_mask set if previous attempt to online
- * it timed-out. Clear cpu_initialized_mask so that after
- * INIT/SIPI it could start with a clean state.
- */
- cpumask_clear_cpu(cpu, cpu_initialized_mask);
- smp_mb();
-
- /*
* Wake up a CPU in difference cases:
* - Use the method in the APIC driver if it's defined
* Otherwise,
@@ -787,41 +810,55 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
boot_error = wakeup_cpu_via_init_nmi(cpu, start_ip, apicid,
&cpu0_nmi_registered);
-
if (!boot_error) {
/*
- * Wait 10s total for a response from AP
+ * allow APs to start initializing.
*/
- boot_error = -1;
- timeout = jiffies + 10*HZ;
- while (time_before(jiffies, timeout)) {
- if (cpumask_test_cpu(cpu, cpu_initialized_mask)) {
- /*
- * Tell AP to proceed with initialization
- */
- cpumask_set_cpu(cpu, cpu_callout_mask);
- boot_error = 0;
- break;
- }
- udelay(100);
- schedule();
- }
- }
+ pr_debug("Before Callout %d\n", cpu);
+ cpumask_set_cpu(cpu, cpu_callout_mask);
+ pr_debug("After Callout %d\n", cpu);
- if (!boot_error) {
/*
- * Wait till AP completes initial initialization
+ * Wait 5s total for a response
*/
- while (!cpumask_test_cpu(cpu, cpu_callin_mask)) {
+ for (timeout = 0; timeout < 50000; timeout++) {
+ if (cpumask_test_cpu(cpu, cpu_callin_mask))
+ break; /* It has booted */
+ udelay(100);
/*
* Allow other tasks to run while we wait for the
* AP to come online. This also gives a chance
* for the MTRR work(triggered by the AP coming online)
* to be completed in the stop machine context.
*/
- udelay(100);
schedule();
}
+
+ if (cpumask_test_cpu(cpu, cpu_callin_mask)) {
+ print_cpu_msr(&cpu_data(cpu));
+ pr_debug("CPU%d: has booted.\n", cpu);
+ } else {
+ boot_error = 1;
+ if (*trampoline_status == 0xA5A5A5A5)
+ /* trampoline started but...? */
+ pr_err("CPU%d: Stuck ??\n", cpu);
+ else
+ /* trampoline code not run */
+ pr_err("CPU%d: Not responding\n", cpu);
+ if (apic->inquire_remote_apic)
+ apic->inquire_remote_apic(apicid);
+ }
+ }
+
+ if (boot_error) {
+ /* Try to put things back the way they were before ... */
+ numa_remove_cpu(cpu); /* was set by numa_add_cpu */
+
+ /* was set by do_boot_cpu() */
+ cpumask_clear_cpu(cpu, cpu_callout_mask);
+
+ /* was set by cpu_init() */
+ cpumask_clear_cpu(cpu, cpu_initialized_mask);
}
/* mark "stuck" area as not stuck */