diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index f3e9b2df4b16..46bb29958509 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
| @@ -64,6 +64,8 @@ unsigned disabled_cpus; | |||
| 64 | unsigned int boot_cpu_physical_apicid = -1U; | 64 | unsigned int boot_cpu_physical_apicid = -1U; |
| 65 | EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid); | 65 | EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid); |
| 66 | 66 | ||
| 67 | u8 boot_cpu_apic_version; | ||
| 68 | |||
| 67 | /* | 69 | /* |
| 68 | * The highest APIC ID seen during enumeration. | 70 | * The highest APIC ID seen during enumeration. |
| 69 | */ | 71 | */ |
| @@ -1374,7 +1376,6 @@ void setup_local_APIC(void) | |||
| 1374 | * Actually disabling the focus CPU check just makes the hang less | 1376 | * Actually disabling the focus CPU check just makes the hang less |
| 1375 | * frequent as it makes the interrupt distributon model be more | 1377 | * frequent as it makes the interrupt distributon model be more |
| 1376 | * like LRU than MRU (the short-term load is more even across CPUs). | 1378 | * like LRU than MRU (the short-term load is more even across CPUs). |
| 1377 | * See also the comment in end_level_ioapic_irq(). --macro | ||
| 1378 | */ | 1379 | */ |
| 1379 | 1380 | ||
| 1380 | /* | 1381 | /* |
| @@ -1816,8 +1817,7 @@ void __init init_apic_mappings(void) | |||
| 1816 | * since smp_sanity_check is prepared for such a case | 1817 | * since smp_sanity_check is prepared for such a case |
| 1817 | * and disable smp mode | 1818 | * and disable smp mode |
| 1818 | */ | 1819 | */ |
| 1819 | apic_version[new_apicid] = | 1820 | boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR)); |
| 1820 | GET_APIC_VERSION(apic_read(APIC_LVR)); | ||
| 1821 | } | 1821 | } |
| 1822 | } | 1822 | } |
| 1823 | 1823 | ||
| @@ -1828,17 +1828,14 @@ void __init register_lapic_address(unsigned long address) | |||
| 1828 | if (!x2apic_mode) { | 1828 | if (!x2apic_mode) { |
| 1829 | set_fixmap_nocache(FIX_APIC_BASE, address); | 1829 | set_fixmap_nocache(FIX_APIC_BASE, address); |
| 1830 | apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", | 1830 | apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", |
| 1831 | APIC_BASE, mp_lapic_addr); | 1831 | APIC_BASE, address); |
| 1832 | } | 1832 | } |
| 1833 | if (boot_cpu_physical_apicid == -1U) { | 1833 | if (boot_cpu_physical_apicid == -1U) { |
| 1834 | boot_cpu_physical_apicid = read_apic_id(); | 1834 | boot_cpu_physical_apicid = read_apic_id(); |
| 1835 | apic_version[boot_cpu_physical_apicid] = | 1835 | boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR)); |
| 1836 | GET_APIC_VERSION(apic_read(APIC_LVR)); | ||
| 1837 | } | 1836 | } |
| 1838 | } | 1837 | } |
| 1839 | 1838 | ||
| 1840 | int apic_version[MAX_LOCAL_APIC]; | ||
| 1841 | |||
| 1842 | /* | 1839 | /* |
| 1843 | * Local APIC interrupts | 1840 | * Local APIC interrupts |
| 1844 | */ | 1841 | */ |
| @@ -2027,7 +2024,53 @@ void disconnect_bsp_APIC(int virt_wire_setup) | |||
| 2027 | apic_write(APIC_LVT1, value); | 2024 | apic_write(APIC_LVT1, value); |
| 2028 | } | 2025 | } |
| 2029 | 2026 | ||
| 2030 | int generic_processor_info(int apicid, int version) | 2027 | /* |
| 2028 | * The number of allocated logical CPU IDs. Since logical CPU IDs are allocated | ||
| 2029 | * contiguously, it equals to current allocated max logical CPU ID plus 1. | ||
| 2030 | * All allocated CPU ID should be in [0, nr_logical_cpuidi), so the maximum of | ||
| 2031 | * nr_logical_cpuids is nr_cpu_ids. | ||
| 2032 | * | ||
| 2033 | * NOTE: Reserve 0 for BSP. | ||
| 2034 | */ | ||
| 2035 | static int nr_logical_cpuids = 1; | ||
| 2036 | |||
| 2037 | /* | ||
| 2038 | * Used to store mapping between logical CPU IDs and APIC IDs. | ||
| 2039 | */ | ||
| 2040 | static int cpuid_to_apicid[] = { | ||
| 2041 | [0 ... NR_CPUS - 1] = -1, | ||
| 2042 | }; | ||
| 2043 | |||
| 2044 | /* | ||
| 2045 | * Should use this API to allocate logical CPU IDs to keep nr_logical_cpuids | ||
| 2046 | * and cpuid_to_apicid[] synchronized. | ||
| 2047 | */ | ||
| 2048 | static int allocate_logical_cpuid(int apicid) | ||
| 2049 | { | ||
| 2050 | int i; | ||
| 2051 | |||
| 2052 | /* | ||
| 2053 | * cpuid <-> apicid mapping is persistent, so when a cpu is up, | ||
| 2054 | * check if the kernel has allocated a cpuid for it. | ||
| 2055 | */ | ||
| 2056 | for (i = 0; i < nr_logical_cpuids; i++) { | ||
| 2057 | if (cpuid_to_apicid[i] == apicid) | ||
| 2058 | return i; | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | /* Allocate a new cpuid. */ | ||
| 2062 | if (nr_logical_cpuids >= nr_cpu_ids) { | ||
| 2063 | WARN_ONCE(1, "Only %d processors supported." | ||
| 2064 | "Processor %d/0x%x and the rest are ignored.\n", | ||
| 2065 | nr_cpu_ids - 1, nr_logical_cpuids, apicid); | ||
| 2066 | return -1; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | cpuid_to_apicid[nr_logical_cpuids] = apicid; | ||
| 2070 | return nr_logical_cpuids++; | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | int __generic_processor_info(int apicid, int version, bool enabled) | ||
| 2031 | { | 2074 | { |
| 2032 | int cpu, max = nr_cpu_ids; | 2075 | int cpu, max = nr_cpu_ids; |
| 2033 | bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, | 2076 | bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, |
| @@ -2102,8 +2145,16 @@ int generic_processor_info(int apicid, int version) | |||
| 2102 | * for BSP. | 2145 | * for BSP. |
| 2103 | */ | 2146 | */ |
| 2104 | cpu = 0; | 2147 | cpu = 0; |
| 2105 | } else | 2148 | |
| 2106 | cpu = cpumask_next_zero(-1, cpu_present_mask); | 2149 | /* Logical cpuid 0 is reserved for BSP. */ |
| 2150 | cpuid_to_apicid[0] = apicid; | ||
| 2151 | } else { | ||
| 2152 | cpu = allocate_logical_cpuid(apicid); | ||
| 2153 | if (cpu < 0) { | ||
| 2154 | disabled_cpus++; | ||
| 2155 | return -EINVAL; | ||
| 2156 | } | ||
| 2157 | } | ||
| 2107 | 2158 | ||
| 2108 | /* | 2159 | /* |
| 2109 | * This can happen on physical hotplug. The sanity check at boot time | 2160 | * This can happen on physical hotplug. The sanity check at boot time |
| @@ -2130,14 +2181,12 @@ int generic_processor_info(int apicid, int version) | |||
| 2130 | cpu, apicid); | 2181 | cpu, apicid); |
| 2131 | version = 0x10; | 2182 | version = 0x10; |
| 2132 | } | 2183 | } |
| 2133 | apic_version[apicid] = version; | ||
| 2134 | 2184 | ||
| 2135 | if (version != apic_version[boot_cpu_physical_apicid]) { | 2185 | if (version != boot_cpu_apic_version) { |
| 2136 | pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", | 2186 | pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", |
| 2137 | apic_version[boot_cpu_physical_apicid], cpu, version); | 2187 | boot_cpu_apic_version, cpu, version); |
| 2138 | } | 2188 | } |
| 2139 | 2189 | ||
| 2140 | physid_set(apicid, phys_cpu_present_map); | ||
| 2141 | if (apicid > max_physical_apicid) | 2190 | if (apicid > max_physical_apicid) |
| 2142 | max_physical_apicid = apicid; | 2191 | max_physical_apicid = apicid; |
| 2143 | 2192 | ||
| @@ -2150,11 +2199,23 @@ int generic_processor_info(int apicid, int version) | |||
| 2150 | apic->x86_32_early_logical_apicid(cpu); | 2199 | apic->x86_32_early_logical_apicid(cpu); |
| 2151 | #endif | 2200 | #endif |
| 2152 | set_cpu_possible(cpu, true); | 2201 | set_cpu_possible(cpu, true); |
| 2153 | set_cpu_present(cpu, true); | 2202 | |
| 2203 | if (enabled) { | ||
| 2204 | num_processors++; | ||
| 2205 | physid_set(apicid, phys_cpu_present_map); | ||
| 2206 | set_cpu_present(cpu, true); | ||
| 2207 | } else { | ||
| 2208 | disabled_cpus++; | ||
| 2209 | } | ||
| 2154 | 2210 | ||
| 2155 | return cpu; | 2211 | return cpu; |
| 2156 | } | 2212 | } |
| 2157 | 2213 | ||
| 2214 | int generic_processor_info(int apicid, int version) | ||
| 2215 | { | ||
| 2216 | return __generic_processor_info(apicid, version, true); | ||
| 2217 | } | ||
| 2218 | |||
| 2158 | int hard_smp_processor_id(void) | 2219 | int hard_smp_processor_id(void) |
| 2159 | { | 2220 | { |
| 2160 | return read_apic_id(); | 2221 | return read_apic_id(); |
| @@ -2277,7 +2338,7 @@ int __init APIC_init_uniprocessor(void) | |||
| 2277 | * Complain if the BIOS pretends there is one. | 2338 | * Complain if the BIOS pretends there is one. |
| 2278 | */ | 2339 | */ |
| 2279 | if (!boot_cpu_has(X86_FEATURE_APIC) && | 2340 | if (!boot_cpu_has(X86_FEATURE_APIC) && |
| 2280 | APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { | 2341 | APIC_INTEGRATED(boot_cpu_apic_version)) { |
| 2281 | pr_err("BIOS bug, local APIC 0x%x not detected!...\n", | 2342 | pr_err("BIOS bug, local APIC 0x%x not detected!...\n", |
| 2282 | boot_cpu_physical_apicid); | 2343 | boot_cpu_physical_apicid); |
| 2283 | return -1; | 2344 | return -1; |
