]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/x86/kernel/smpboot.c
x86/smp/boot: Add cmdline "cpu_init_udelay=N" to specify cpu_up() delay
[mirror_ubuntu-artful-kernel.git] / arch / x86 / kernel / smpboot.c
index 50e547eac8cd4b64e9e6892410366ec3a64a7a13..0629a8e513af48008d925e60d4d7d56f408f694e 100644 (file)
@@ -513,6 +513,27 @@ void __inquire_remote_apic(int apicid)
        }
 }
 
+/*
+ * The Multiprocessor Specification 1.4 (1997) example code suggests
+ * that there should be a 10ms delay between the BSP asserting INIT
+ * and de-asserting INIT, when starting a remote processor.
+ * But that slows boot and resume on modern processors, which include
+ * many cores and don't require that delay.
+ *
+ * Cmdline "init_cpu_udelay=" is available to over-ride this delay.
+ */
+#define UDELAY_10MS_DEFAULT 10000
+
+static unsigned int init_udelay = UDELAY_10MS_DEFAULT;
+
+static int __init cpu_init_udelay(char *str)
+{
+       get_option(&str, &init_udelay);
+
+       return 0;
+}
+early_param("cpu_init_udelay", cpu_init_udelay);
+
 /*
  * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
  * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
@@ -555,7 +576,7 @@ wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
 static int
 wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 {
-       unsigned long send_status, accept_status = 0;
+       unsigned long send_status = 0, accept_status = 0;
        int maxlvt, num_starts, j;
 
        maxlvt = lapic_get_maxlvt();
@@ -580,22 +601,34 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
        apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
                       phys_apicid);
 
-       pr_debug("Waiting for send to finish...\n");
-       send_status = safe_apic_wait_icr_idle();
+       if (!cpu_has_x2apic) {
+               pr_debug("Waiting for send to finish...\n");
+               send_status = safe_apic_wait_icr_idle();
 
-       mdelay(10);
+               mdelay(init_udelay);
 
-       pr_debug("Deasserting INIT\n");
+               pr_debug("Deasserting INIT\n");
 
-       /* Target chip */
-       /* Send IPI */
-       apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
+               /* Target chip */
+               /* Send IPI */
+               apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
 
-       pr_debug("Waiting for send to finish...\n");
-       send_status = safe_apic_wait_icr_idle();
+               pr_debug("Waiting for send to finish...\n");
+               send_status = safe_apic_wait_icr_idle();
 
-       mb();
-       atomic_set(&init_deasserted, 1);
+               mb();
+               atomic_set(&init_deasserted, 1);
+       } else if (tboot_enabled()) {
+               /*
+                * With tboot AP is actually spinning in a mini-guest before
+                * receiving INIT. Upon receiving INIT ipi, AP need time to
+                * VMExit, update VMCS to tracking SIPIs and VMResume.
+                *
+                * While AP is in root mode handling the INIT the CPU will drop
+                * any SIPIs
+                */
+               udelay(10);
+       }
 
        /*
         * Should we send STARTUP IPIs ?
@@ -637,20 +670,23 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
                apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
                               phys_apicid);
 
-               /*
-                * Give the other CPU some time to accept the IPI.
-                */
-               udelay(300);
+               if (!cpu_has_x2apic) {
+                       /*
+                        * Give the other CPU some time to accept the IPI.
+                        */
+                       udelay(300);
 
-               pr_debug("Startup point 1\n");
+                       pr_debug("Startup point 1\n");
 
-               pr_debug("Waiting for send to finish...\n");
-               send_status = safe_apic_wait_icr_idle();
+                       pr_debug("Waiting for send to finish...\n");
+                       send_status = safe_apic_wait_icr_idle();
+
+                       /*
+                        * Give the other CPU some time to accept the IPI.
+                        */
+                       udelay(200);
+               }
 
-               /*
-                * Give the other CPU some time to accept the IPI.
-                */
-               udelay(200);
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP.  */
                        apic_write(APIC_ESR, 0);
                accept_status = (apic_read(APIC_ESR) & 0xEF);
@@ -792,8 +828,6 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
        clear_tsk_thread_flag(idle, TIF_FORK);
        initial_gs = per_cpu_offset(cpu);
 #endif
-       per_cpu(kernel_stack, cpu) =
-               (unsigned long)task_stack_page(idle) + THREAD_SIZE;
 }
 
 /*