Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / arch / x86 / kernel / smpboot.c
index fdbc5fce8b979d65ddaa78a9d298774feed521af..2d5200e56357d49f3466ce55e8ab2b3273306f68 100644 (file)
@@ -113,7 +113,6 @@ 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
@@ -132,37 +131,6 @@ 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
@@ -297,12 +265,20 @@ void smp_store_cpu_info(int id)
        identify_secondary_cpu(c);
 }
 
+static bool
+topology_same_node(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+       int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+       return (cpu_to_node(cpu1) == cpu_to_node(cpu2));
+}
+
 static bool
 topology_sane(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o, const char *name)
 {
        int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
-       return !WARN_ONCE(cpu_to_node(cpu1) != cpu_to_node(cpu2),
+       return !WARN_ONCE(!topology_same_node(c, o),
                "sched: CPU #%d's %s-sibling CPU #%d is not on the same node! "
                "[node: %d != %d]. Ignoring dependency.\n",
                cpu1, name, cpu2, cpu_to_node(cpu1), cpu_to_node(cpu2));
@@ -343,17 +319,44 @@ static bool match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
        return false;
 }
 
-static bool match_mc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+/*
+ * Unlike the other levels, we do not enforce keeping a
+ * multicore group inside a NUMA node.  If this happens, we will
+ * discard the MC level of the topology later.
+ */
+static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
-       if (c->phys_proc_id == o->phys_proc_id) {
-               if (cpu_has(c, X86_FEATURE_AMD_DCM))
-                       return true;
-
-               return topology_sane(c, o, "mc");
-       }
+       if (c->phys_proc_id == o->phys_proc_id)
+               return true;
        return false;
 }
 
+static struct sched_domain_topology_level numa_inside_package_topology[] = {
+#ifdef CONFIG_SCHED_SMT
+       { cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
+#endif
+#ifdef CONFIG_SCHED_MC
+       { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
+#endif
+       { NULL, },
+};
+/*
+ * set_sched_topology() sets the topology internal to a CPU.  The
+ * NUMA topologies are layered on top of it to build the full
+ * system topology.
+ *
+ * If NUMA nodes are observed to occur within a CPU package, this
+ * function should be called.  It forces the sched domain code to
+ * only use the SMT level for the CPU portion of the topology.
+ * This essentially falls back to relying on NUMA information
+ * from the SRAT table to describe the entire system topology
+ * (except for hyperthreads).
+ */
+static void primarily_use_numa_for_topology(void)
+{
+       set_sched_topology(numa_inside_package_topology);
+}
+
 void set_cpu_sibling_map(int cpu)
 {
        bool has_smt = smp_num_siblings > 1;
@@ -390,7 +393,7 @@ void set_cpu_sibling_map(int cpu)
        for_each_cpu(i, cpu_sibling_setup_mask) {
                o = &cpu_data(i);
 
-               if ((i == cpu) || (has_mp && match_mc(c, o))) {
+               if ((i == cpu) || (has_mp && match_die(c, o))) {
                        link_mask(core, cpu, i);
 
                        /*
@@ -412,6 +415,8 @@ void set_cpu_sibling_map(int cpu)
                        } else if (i != cpu && !c->booted_cores)
                                c->booted_cores = cpu_data(i).booted_cores;
                }
+               if (match_die(c, o) && !topology_same_node(c, o))
+                       primarily_use_numa_for_topology();
        }
 }
 
@@ -755,8 +760,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();
@@ -803,6 +808,15 @@ 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
@@ -817,53 +831,38 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 
        if (!boot_error) {
                /*
-                * allow APs to start initializing.
+                * Wait 10s total for a response from AP
                 */
-               pr_debug("Before Callout %d\n", cpu);
-               cpumask_set_cpu(cpu, cpu_callout_mask);
-               pr_debug("After Callout %d\n", cpu);
+               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();
+               }
+       }
 
+       if (!boot_error) {
                /*
-                * Wait 5s total for a response
+                * Wait till AP completes initial initialization
                 */
-               for (timeout = 0; timeout < 50000; timeout++) {
-                       if (cpumask_test_cpu(cpu, cpu_callin_mask))
-                               break;  /* It has booted */
-                       udelay(100);
+               while (!cpumask_test_cpu(cpu, cpu_callin_mask)) {
                        /*
                         * 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 */
@@ -1286,6 +1285,9 @@ static void remove_siblinginfo(int cpu)
 
        for_each_cpu(sibling, cpu_sibling_mask(cpu))
                cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling));
+       for_each_cpu(sibling, cpu_llc_shared_mask(cpu))
+               cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling));
+       cpumask_clear(cpu_llc_shared_mask(cpu));
        cpumask_clear(cpu_sibling_mask(cpu));
        cpumask_clear(cpu_core_mask(cpu));
        c->phys_proc_id = 0;