Merge branch 'master' into gfs2
[pandora-kernel.git] / arch / i386 / kernel / smpboot.c
index 6f5fea0..020d873 100644 (file)
@@ -177,6 +177,9 @@ static void __devinit smp_store_cpu_info(int id)
         */
        if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
 
+               if (num_possible_cpus() == 1)
+                       goto valid_k7;
+
                /* Athlon 660/661 is valid. */  
                if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1)))
                        goto valid_k7;
@@ -212,14 +215,20 @@ valid_k7:
  * then we print a warning if not, and always resync.
  */
 
-static atomic_t tsc_start_flag = ATOMIC_INIT(0);
-static atomic_t tsc_count_start = ATOMIC_INIT(0);
-static atomic_t tsc_count_stop = ATOMIC_INIT(0);
-static unsigned long long tsc_values[NR_CPUS];
+static struct {
+       atomic_t start_flag;
+       atomic_t count_start;
+       atomic_t count_stop;
+       unsigned long long values[NR_CPUS];
+} tsc __initdata = {
+       .start_flag = ATOMIC_INIT(0),
+       .count_start = ATOMIC_INIT(0),
+       .count_stop = ATOMIC_INIT(0),
+};
 
 #define NR_LOOPS 5
 
-static void __init synchronize_tsc_bp (void)
+static void __init synchronize_tsc_bp(void)
 {
        int i;
        unsigned long long t0;
@@ -233,7 +242,7 @@ static void __init synchronize_tsc_bp (void)
        /* convert from kcyc/sec to cyc/usec */
        one_usec = cpu_khz / 1000;
 
-       atomic_set(&tsc_start_flag, 1);
+       atomic_set(&tsc.start_flag, 1);
        wmb();
 
        /*
@@ -250,16 +259,16 @@ static void __init synchronize_tsc_bp (void)
                /*
                 * all APs synchronize but they loop on '== num_cpus'
                 */
-               while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
+               while (atomic_read(&tsc.count_start) != num_booting_cpus()-1)
                        cpu_relax();
-               atomic_set(&tsc_count_stop, 0);
+               atomic_set(&tsc.count_stop, 0);
                wmb();
                /*
                 * this lets the APs save their current TSC:
                 */
-               atomic_inc(&tsc_count_start);
+               atomic_inc(&tsc.count_start);
 
-               rdtscll(tsc_values[smp_processor_id()]);
+               rdtscll(tsc.values[smp_processor_id()]);
                /*
                 * We clear the TSC in the last loop:
                 */
@@ -269,56 +278,54 @@ static void __init synchronize_tsc_bp (void)
                /*
                 * Wait for all APs to leave the synchronization point:
                 */
-               while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
+               while (atomic_read(&tsc.count_stop) != num_booting_cpus()-1)
                        cpu_relax();
-               atomic_set(&tsc_count_start, 0);
+               atomic_set(&tsc.count_start, 0);
                wmb();
-               atomic_inc(&tsc_count_stop);
+               atomic_inc(&tsc.count_stop);
        }
 
        sum = 0;
        for (i = 0; i < NR_CPUS; i++) {
                if (cpu_isset(i, cpu_callout_map)) {
-                       t0 = tsc_values[i];
+                       t0 = tsc.values[i];
                        sum += t0;
                }
        }
        avg = sum;
        do_div(avg, num_booting_cpus());
 
-       sum = 0;
        for (i = 0; i < NR_CPUS; i++) {
                if (!cpu_isset(i, cpu_callout_map))
                        continue;
-               delta = tsc_values[i] - avg;
+               delta = tsc.values[i] - avg;
                if (delta < 0)
                        delta = -delta;
                /*
                 * We report bigger than 2 microseconds clock differences.
                 */
                if (delta > 2*one_usec) {
-                       long realdelta;
+                       long long realdelta;
+
                        if (!buggy) {
                                buggy = 1;
                                printk("\n");
                        }
                        realdelta = delta;
                        do_div(realdelta, one_usec);
-                       if (tsc_values[i] < avg)
+                       if (tsc.values[i] < avg)
                                realdelta = -realdelta;
 
-                       if (realdelta > 0)
-                               printk(KERN_INFO "CPU#%d had %ld usecs TSC "
+                       if (realdelta)
+                               printk(KERN_INFO "CPU#%d had %Ld usecs TSC "
                                        "skew, fixed it up.\n", i, realdelta);
                }
-
-               sum += delta;
        }
        if (!buggy)
                printk("passed.\n");
 }
 
-static void __init synchronize_tsc_ap (void)
+static void __init synchronize_tsc_ap(void)
 {
        int i;
 
@@ -327,20 +334,20 @@ static void __init synchronize_tsc_ap (void)
         * this gets called, so we first wait for the BP to
         * finish SMP initialization:
         */
-       while (!atomic_read(&tsc_start_flag))
+       while (!atomic_read(&tsc.start_flag))
                cpu_relax();
 
        for (i = 0; i < NR_LOOPS; i++) {
-               atomic_inc(&tsc_count_start);
-               while (atomic_read(&tsc_count_start) != num_booting_cpus())
+               atomic_inc(&tsc.count_start);
+               while (atomic_read(&tsc.count_start) != num_booting_cpus())
                        cpu_relax();
 
-               rdtscll(tsc_values[smp_processor_id()]);
+               rdtscll(tsc.values[smp_processor_id()]);
                if (i == NR_LOOPS-1)
                        write_tsc(0, 0);
 
-               atomic_inc(&tsc_count_stop);
-               while (atomic_read(&tsc_count_stop) != num_booting_cpus())
+               atomic_inc(&tsc.count_stop);
+               while (atomic_read(&tsc.count_stop) != num_booting_cpus())
                        cpu_relax();
        }
 }
@@ -638,9 +645,13 @@ static void map_cpu_to_logical_apicid(void)
 {
        int cpu = smp_processor_id();
        int apicid = logical_smp_processor_id();
+       int node = apicid_to_node(apicid);
+
+       if (!node_online(node))
+               node = first_online_node;
 
        cpu_2_logical_apicid[cpu] = apicid;
-       map_cpu_to_node(cpu, apicid_to_node(apicid));
+       map_cpu_to_node(cpu, node);
 }
 
 static void unmap_cpu_to_logical_apicid(int cpu)
@@ -1368,7 +1379,8 @@ int __cpu_disable(void)
         */
        if (cpu == 0)
                return -EBUSY;
-
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               stop_apic_nmi_watchdog(NULL);
        clear_local_APIC();
        /* Allow any queued timer interrupts to get serviced */
        local_irq_enable();
@@ -1482,3 +1494,16 @@ void __init smp_intr_init(void)
        /* IPI for generic function call */
        set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 }
+
+/*
+ * If the BIOS enumerates physical processors before logical,
+ * maxcpus=N at enumeration-time can be used to disable HT.
+ */
+static int __init parse_maxcpus(char *arg)
+{
+       extern unsigned int maxcpus;
+
+       maxcpus = simple_strtoul(arg, NULL, 0);
+       return 0;
+}
+early_param("maxcpus", parse_maxcpus);