Merge branch 'x86/urgent' into x86/apic
[cascardo/linux.git] / arch / x86 / kernel / apic / apic.c
index f3e9b2d..46bb299 100644 (file)
@@ -64,6 +64,8 @@ unsigned disabled_cpus;
 unsigned int boot_cpu_physical_apicid = -1U;
 EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid);
 
+u8 boot_cpu_apic_version;
+
 /*
  * The highest APIC ID seen during enumeration.
  */
@@ -1374,7 +1376,6 @@ void setup_local_APIC(void)
         * Actually disabling the focus CPU check just makes the hang less
         * frequent as it makes the interrupt distributon model be more
         * like LRU than MRU (the short-term load is more even across CPUs).
-        * See also the comment in end_level_ioapic_irq().  --macro
         */
 
        /*
@@ -1816,8 +1817,7 @@ void __init init_apic_mappings(void)
                 * since smp_sanity_check is prepared for such a case
                 * and disable smp mode
                 */
-               apic_version[new_apicid] =
-                        GET_APIC_VERSION(apic_read(APIC_LVR));
+               boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
        }
 }
 
@@ -1828,17 +1828,14 @@ void __init register_lapic_address(unsigned long address)
        if (!x2apic_mode) {
                set_fixmap_nocache(FIX_APIC_BASE, address);
                apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
-                           APIC_BASE, mp_lapic_addr);
+                           APIC_BASE, address);
        }
        if (boot_cpu_physical_apicid == -1U) {
                boot_cpu_physical_apicid  = read_apic_id();
-               apic_version[boot_cpu_physical_apicid] =
-                        GET_APIC_VERSION(apic_read(APIC_LVR));
+               boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
        }
 }
 
-int apic_version[MAX_LOCAL_APIC];
-
 /*
  * Local APIC interrupts
  */
@@ -2027,7 +2024,53 @@ void disconnect_bsp_APIC(int virt_wire_setup)
        apic_write(APIC_LVT1, value);
 }
 
-int generic_processor_info(int apicid, int version)
+/*
+ * The number of allocated logical CPU IDs. Since logical CPU IDs are allocated
+ * contiguously, it equals to current allocated max logical CPU ID plus 1.
+ * All allocated CPU ID should be in [0, nr_logical_cpuidi), so the maximum of
+ * nr_logical_cpuids is nr_cpu_ids.
+ *
+ * NOTE: Reserve 0 for BSP.
+ */
+static int nr_logical_cpuids = 1;
+
+/*
+ * Used to store mapping between logical CPU IDs and APIC IDs.
+ */
+static int cpuid_to_apicid[] = {
+       [0 ... NR_CPUS - 1] = -1,
+};
+
+/*
+ * Should use this API to allocate logical CPU IDs to keep nr_logical_cpuids
+ * and cpuid_to_apicid[] synchronized.
+ */
+static int allocate_logical_cpuid(int apicid)
+{
+       int i;
+
+       /*
+        * cpuid <-> apicid mapping is persistent, so when a cpu is up,
+        * check if the kernel has allocated a cpuid for it.
+        */
+       for (i = 0; i < nr_logical_cpuids; i++) {
+               if (cpuid_to_apicid[i] == apicid)
+                       return i;
+       }
+
+       /* Allocate a new cpuid. */
+       if (nr_logical_cpuids >= nr_cpu_ids) {
+               WARN_ONCE(1, "Only %d processors supported."
+                            "Processor %d/0x%x and the rest are ignored.\n",
+                            nr_cpu_ids - 1, nr_logical_cpuids, apicid);
+               return -1;
+       }
+
+       cpuid_to_apicid[nr_logical_cpuids] = apicid;
+       return nr_logical_cpuids++;
+}
+
+int __generic_processor_info(int apicid, int version, bool enabled)
 {
        int cpu, max = nr_cpu_ids;
        bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
@@ -2102,8 +2145,16 @@ int generic_processor_info(int apicid, int version)
                 * for BSP.
                 */
                cpu = 0;
-       } else
-               cpu = cpumask_next_zero(-1, cpu_present_mask);
+
+               /* Logical cpuid 0 is reserved for BSP. */
+               cpuid_to_apicid[0] = apicid;
+       } else {
+               cpu = allocate_logical_cpuid(apicid);
+               if (cpu < 0) {
+                       disabled_cpus++;
+                       return -EINVAL;
+               }
+       }
 
        /*
         * This can happen on physical hotplug. The sanity check at boot time
@@ -2130,14 +2181,12 @@ int generic_processor_info(int apicid, int version)
                           cpu, apicid);
                version = 0x10;
        }
-       apic_version[apicid] = version;
 
-       if (version != apic_version[boot_cpu_physical_apicid]) {
+       if (version != boot_cpu_apic_version) {
                pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n",
-                       apic_version[boot_cpu_physical_apicid], cpu, version);
+                       boot_cpu_apic_version, cpu, version);
        }
 
-       physid_set(apicid, phys_cpu_present_map);
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
@@ -2150,11 +2199,23 @@ int generic_processor_info(int apicid, int version)
                apic->x86_32_early_logical_apicid(cpu);
 #endif
        set_cpu_possible(cpu, true);
-       set_cpu_present(cpu, true);
+
+       if (enabled) {
+               num_processors++;
+               physid_set(apicid, phys_cpu_present_map);
+               set_cpu_present(cpu, true);
+       } else {
+               disabled_cpus++;
+       }
 
        return cpu;
 }
 
+int generic_processor_info(int apicid, int version)
+{
+       return __generic_processor_info(apicid, version, true);
+}
+
 int hard_smp_processor_id(void)
 {
        return read_apic_id();
@@ -2277,7 +2338,7 @@ int __init APIC_init_uniprocessor(void)
         * Complain if the BIOS pretends there is one.
         */
        if (!boot_cpu_has(X86_FEATURE_APIC) &&
-           APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
+           APIC_INTEGRATED(boot_cpu_apic_version)) {
                pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
                        boot_cpu_physical_apicid);
                return -1;