diff options
Diffstat (limited to 'arch/x86/kernel/apic_32.c')
| -rw-r--r-- | arch/x86/kernel/apic_32.c | 98 |
1 files changed, 39 insertions, 59 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 4b99b1bdeb6..6dea8306d8c 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
| @@ -52,30 +52,36 @@ | |||
| 52 | 52 | ||
| 53 | unsigned long mp_lapic_addr; | 53 | unsigned long mp_lapic_addr; |
| 54 | 54 | ||
| 55 | DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID; | ||
| 56 | EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid); | ||
| 57 | |||
| 58 | /* | 55 | /* |
| 59 | * Knob to control our willingness to enable the local APIC. | 56 | * Knob to control our willingness to enable the local APIC. |
| 60 | * | 57 | * |
| 61 | * -1=force-disable, +1=force-enable | 58 | * +1=force-enable |
| 62 | */ | 59 | */ |
| 63 | static int enable_local_apic __initdata; | 60 | static int force_enable_local_apic; |
| 61 | int disable_apic; | ||
| 64 | 62 | ||
| 65 | /* Local APIC timer verification ok */ | 63 | /* Local APIC timer verification ok */ |
| 66 | static int local_apic_timer_verify_ok; | 64 | static int local_apic_timer_verify_ok; |
| 67 | /* Disable local APIC timer from the kernel commandline or via dmi quirk | 65 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ |
| 68 | or using CPU MSR check */ | 66 | static int local_apic_timer_disabled; |
| 69 | int local_apic_timer_disabled; | ||
| 70 | /* Local APIC timer works in C2 */ | 67 | /* Local APIC timer works in C2 */ |
| 71 | int local_apic_timer_c2_ok; | 68 | int local_apic_timer_c2_ok; |
| 72 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); | 69 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); |
| 73 | 70 | ||
| 71 | int first_system_vector = 0xfe; | ||
| 72 | |||
| 73 | char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE}; | ||
| 74 | |||
| 74 | /* | 75 | /* |
| 75 | * Debug level, exported for io_apic.c | 76 | * Debug level, exported for io_apic.c |
| 76 | */ | 77 | */ |
| 77 | int apic_verbosity; | 78 | int apic_verbosity; |
| 78 | 79 | ||
| 80 | int pic_mode; | ||
| 81 | |||
| 82 | /* Have we found an MP table */ | ||
| 83 | int smp_found_config; | ||
| 84 | |||
| 79 | static unsigned int calibration_result; | 85 | static unsigned int calibration_result; |
| 80 | 86 | ||
| 81 | static int lapic_next_event(unsigned long delta, | 87 | static int lapic_next_event(unsigned long delta, |
| @@ -545,7 +551,7 @@ void __init setup_boot_APIC_clock(void) | |||
| 545 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; | 551 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; |
| 546 | else | 552 | else |
| 547 | printk(KERN_WARNING "APIC timer registered as dummy," | 553 | printk(KERN_WARNING "APIC timer registered as dummy," |
| 548 | " due to nmi_watchdog=1!\n"); | 554 | " due to nmi_watchdog=%d!\n", nmi_watchdog); |
| 549 | } | 555 | } |
| 550 | 556 | ||
| 551 | /* Setup the lapic or request the broadcast */ | 557 | /* Setup the lapic or request the broadcast */ |
| @@ -1094,7 +1100,7 @@ static int __init detect_init_APIC(void) | |||
| 1094 | u32 h, l, features; | 1100 | u32 h, l, features; |
| 1095 | 1101 | ||
| 1096 | /* Disabled by kernel option? */ | 1102 | /* Disabled by kernel option? */ |
| 1097 | if (enable_local_apic < 0) | 1103 | if (disable_apic) |
| 1098 | return -1; | 1104 | return -1; |
| 1099 | 1105 | ||
| 1100 | switch (boot_cpu_data.x86_vendor) { | 1106 | switch (boot_cpu_data.x86_vendor) { |
| @@ -1117,7 +1123,7 @@ static int __init detect_init_APIC(void) | |||
| 1117 | * Over-ride BIOS and try to enable the local APIC only if | 1123 | * Over-ride BIOS and try to enable the local APIC only if |
| 1118 | * "lapic" specified. | 1124 | * "lapic" specified. |
| 1119 | */ | 1125 | */ |
| 1120 | if (enable_local_apic <= 0) { | 1126 | if (!force_enable_local_apic) { |
| 1121 | printk(KERN_INFO "Local APIC disabled by BIOS -- " | 1127 | printk(KERN_INFO "Local APIC disabled by BIOS -- " |
| 1122 | "you can enable it with \"lapic\"\n"); | 1128 | "you can enable it with \"lapic\"\n"); |
| 1123 | return -1; | 1129 | return -1; |
| @@ -1154,9 +1160,6 @@ static int __init detect_init_APIC(void) | |||
| 1154 | if (l & MSR_IA32_APICBASE_ENABLE) | 1160 | if (l & MSR_IA32_APICBASE_ENABLE) |
| 1155 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; | 1161 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; |
| 1156 | 1162 | ||
| 1157 | if (nmi_watchdog != NMI_NONE && nmi_watchdog != NMI_DISABLED) | ||
| 1158 | nmi_watchdog = NMI_LOCAL_APIC; | ||
| 1159 | |||
| 1160 | printk(KERN_INFO "Found and enabled local APIC!\n"); | 1163 | printk(KERN_INFO "Found and enabled local APIC!\n"); |
| 1161 | 1164 | ||
| 1162 | apic_pm_activate(); | 1165 | apic_pm_activate(); |
| @@ -1195,36 +1198,6 @@ void __init init_apic_mappings(void) | |||
| 1195 | if (boot_cpu_physical_apicid == -1U) | 1198 | if (boot_cpu_physical_apicid == -1U) |
| 1196 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1199 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); |
| 1197 | 1200 | ||
| 1198 | #ifdef CONFIG_X86_IO_APIC | ||
| 1199 | { | ||
| 1200 | unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; | ||
| 1201 | int i; | ||
| 1202 | |||
| 1203 | for (i = 0; i < nr_ioapics; i++) { | ||
| 1204 | if (smp_found_config) { | ||
| 1205 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; | ||
| 1206 | if (!ioapic_phys) { | ||
| 1207 | printk(KERN_ERR | ||
| 1208 | "WARNING: bogus zero IO-APIC " | ||
| 1209 | "address found in MPTABLE, " | ||
| 1210 | "disabling IO/APIC support!\n"); | ||
| 1211 | smp_found_config = 0; | ||
| 1212 | skip_ioapic_setup = 1; | ||
| 1213 | goto fake_ioapic_page; | ||
| 1214 | } | ||
| 1215 | } else { | ||
| 1216 | fake_ioapic_page: | ||
| 1217 | ioapic_phys = (unsigned long) | ||
| 1218 | alloc_bootmem_pages(PAGE_SIZE); | ||
| 1219 | ioapic_phys = __pa(ioapic_phys); | ||
| 1220 | } | ||
| 1221 | set_fixmap_nocache(idx, ioapic_phys); | ||
| 1222 | printk(KERN_DEBUG "mapped IOAPIC to %08lx (%08lx)\n", | ||
| 1223 | __fix_to_virt(idx), ioapic_phys); | ||
| 1224 | idx++; | ||
| 1225 | } | ||
| 1226 | } | ||
| 1227 | #endif | ||
| 1228 | } | 1201 | } |
| 1229 | 1202 | ||
| 1230 | /* | 1203 | /* |
| @@ -1236,7 +1209,7 @@ int apic_version[MAX_APICS]; | |||
| 1236 | 1209 | ||
| 1237 | int __init APIC_init_uniprocessor(void) | 1210 | int __init APIC_init_uniprocessor(void) |
| 1238 | { | 1211 | { |
| 1239 | if (enable_local_apic < 0) | 1212 | if (disable_apic) |
| 1240 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); | 1213 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
| 1241 | 1214 | ||
| 1242 | if (!smp_found_config && !cpu_has_apic) | 1215 | if (!smp_found_config && !cpu_has_apic) |
| @@ -1265,10 +1238,14 @@ int __init APIC_init_uniprocessor(void) | |||
| 1265 | #ifdef CONFIG_CRASH_DUMP | 1238 | #ifdef CONFIG_CRASH_DUMP |
| 1266 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1239 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); |
| 1267 | #endif | 1240 | #endif |
| 1268 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); | 1241 | physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); |
| 1269 | 1242 | ||
| 1270 | setup_local_APIC(); | 1243 | setup_local_APIC(); |
| 1271 | 1244 | ||
| 1245 | #ifdef CONFIG_X86_IO_APIC | ||
| 1246 | if (!smp_found_config || skip_ioapic_setup || !nr_ioapics) | ||
| 1247 | #endif | ||
| 1248 | localise_nmi_watchdog(); | ||
| 1272 | end_local_APIC_setup(); | 1249 | end_local_APIC_setup(); |
| 1273 | #ifdef CONFIG_X86_IO_APIC | 1250 | #ifdef CONFIG_X86_IO_APIC |
| 1274 | if (smp_found_config) | 1251 | if (smp_found_config) |
| @@ -1351,13 +1328,13 @@ void __init smp_intr_init(void) | |||
| 1351 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | 1328 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper |
| 1352 | * IPI, driven by wakeup. | 1329 | * IPI, driven by wakeup. |
| 1353 | */ | 1330 | */ |
| 1354 | set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | 1331 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); |
| 1355 | 1332 | ||
| 1356 | /* IPI for invalidation */ | 1333 | /* IPI for invalidation */ |
| 1357 | set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); | 1334 | alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); |
| 1358 | 1335 | ||
| 1359 | /* IPI for generic function call */ | 1336 | /* IPI for generic function call */ |
| 1360 | set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | 1337 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); |
| 1361 | } | 1338 | } |
| 1362 | #endif | 1339 | #endif |
| 1363 | 1340 | ||
| @@ -1370,15 +1347,15 @@ void __init apic_intr_init(void) | |||
| 1370 | smp_intr_init(); | 1347 | smp_intr_init(); |
| 1371 | #endif | 1348 | #endif |
| 1372 | /* self generated IPI for local APIC timer */ | 1349 | /* self generated IPI for local APIC timer */ |
| 1373 | set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | 1350 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); |
| 1374 | 1351 | ||
| 1375 | /* IPI vectors for APIC spurious and error interrupts */ | 1352 | /* IPI vectors for APIC spurious and error interrupts */ |
| 1376 | set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | 1353 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); |
| 1377 | set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | 1354 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); |
| 1378 | 1355 | ||
| 1379 | /* thermal monitor LVT interrupt */ | 1356 | /* thermal monitor LVT interrupt */ |
| 1380 | #ifdef CONFIG_X86_MCE_P4THERMAL | 1357 | #ifdef CONFIG_X86_MCE_P4THERMAL |
| 1381 | set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); | 1358 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
| 1382 | #endif | 1359 | #endif |
| 1383 | } | 1360 | } |
| 1384 | 1361 | ||
| @@ -1513,6 +1490,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1513 | */ | 1490 | */ |
| 1514 | cpu = 0; | 1491 | cpu = 0; |
| 1515 | 1492 | ||
| 1493 | if (apicid > max_physical_apicid) | ||
| 1494 | max_physical_apicid = apicid; | ||
| 1495 | |||
| 1516 | /* | 1496 | /* |
| 1517 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y | 1497 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y |
| 1518 | * but we need to work other dependencies like SMP_SUSPEND etc | 1498 | * but we need to work other dependencies like SMP_SUSPEND etc |
| @@ -1520,7 +1500,7 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1520 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) | 1500 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) |
| 1521 | * - Ashok Raj <ashok.raj@intel.com> | 1501 | * - Ashok Raj <ashok.raj@intel.com> |
| 1522 | */ | 1502 | */ |
| 1523 | if (num_processors > 8) { | 1503 | if (max_physical_apicid >= 8) { |
| 1524 | switch (boot_cpu_data.x86_vendor) { | 1504 | switch (boot_cpu_data.x86_vendor) { |
| 1525 | case X86_VENDOR_INTEL: | 1505 | case X86_VENDOR_INTEL: |
| 1526 | if (!APIC_XAPIC(version)) { | 1506 | if (!APIC_XAPIC(version)) { |
| @@ -1534,9 +1514,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
| 1534 | } | 1514 | } |
| 1535 | #ifdef CONFIG_SMP | 1515 | #ifdef CONFIG_SMP |
| 1536 | /* are we being called early in kernel startup? */ | 1516 | /* are we being called early in kernel startup? */ |
| 1537 | if (x86_cpu_to_apicid_early_ptr) { | 1517 | if (early_per_cpu_ptr(x86_cpu_to_apicid)) { |
| 1538 | u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr; | 1518 | u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid); |
| 1539 | u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr; | 1519 | u16 *bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid); |
| 1540 | 1520 | ||
| 1541 | cpu_to_apicid[cpu] = apicid; | 1521 | cpu_to_apicid[cpu] = apicid; |
| 1542 | bios_cpu_apicid[cpu] = apicid; | 1522 | bios_cpu_apicid[cpu] = apicid; |
| @@ -1703,14 +1683,14 @@ static void apic_pm_activate(void) { } | |||
| 1703 | */ | 1683 | */ |
| 1704 | static int __init parse_lapic(char *arg) | 1684 | static int __init parse_lapic(char *arg) |
| 1705 | { | 1685 | { |
| 1706 | enable_local_apic = 1; | 1686 | force_enable_local_apic = 1; |
| 1707 | return 0; | 1687 | return 0; |
| 1708 | } | 1688 | } |
| 1709 | early_param("lapic", parse_lapic); | 1689 | early_param("lapic", parse_lapic); |
| 1710 | 1690 | ||
| 1711 | static int __init parse_nolapic(char *arg) | 1691 | static int __init parse_nolapic(char *arg) |
| 1712 | { | 1692 | { |
| 1713 | enable_local_apic = -1; | 1693 | disable_apic = 1; |
| 1714 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); | 1694 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
| 1715 | return 0; | 1695 | return 0; |
| 1716 | } | 1696 | } |
