diff options
Diffstat (limited to 'arch/x86/kernel/apic_32.c')
-rw-r--r-- | arch/x86/kernel/apic_32.c | 123 |
1 files changed, 63 insertions, 60 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 4b99b1bdeb6c..3e58b676d23b 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -52,30 +52,41 @@ | |||
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 | |||
85 | static struct resource lapic_resource = { | ||
86 | .name = "Local APIC", | ||
87 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, | ||
88 | }; | ||
89 | |||
79 | static unsigned int calibration_result; | 90 | static unsigned int calibration_result; |
80 | 91 | ||
81 | static int lapic_next_event(unsigned long delta, | 92 | static int lapic_next_event(unsigned long delta, |
@@ -545,7 +556,7 @@ void __init setup_boot_APIC_clock(void) | |||
545 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; | 556 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; |
546 | else | 557 | else |
547 | printk(KERN_WARNING "APIC timer registered as dummy," | 558 | printk(KERN_WARNING "APIC timer registered as dummy," |
548 | " due to nmi_watchdog=1!\n"); | 559 | " due to nmi_watchdog=%d!\n", nmi_watchdog); |
549 | } | 560 | } |
550 | 561 | ||
551 | /* Setup the lapic or request the broadcast */ | 562 | /* Setup the lapic or request the broadcast */ |
@@ -963,7 +974,7 @@ void __cpuinit setup_local_APIC(void) | |||
963 | * Double-check whether this APIC is really registered. | 974 | * Double-check whether this APIC is really registered. |
964 | */ | 975 | */ |
965 | if (!apic_id_registered()) | 976 | if (!apic_id_registered()) |
966 | BUG(); | 977 | WARN_ON_ONCE(1); |
967 | 978 | ||
968 | /* | 979 | /* |
969 | * Intel recommends to set DFR, LDR and TPR before enabling | 980 | * Intel recommends to set DFR, LDR and TPR before enabling |
@@ -1094,7 +1105,7 @@ static int __init detect_init_APIC(void) | |||
1094 | u32 h, l, features; | 1105 | u32 h, l, features; |
1095 | 1106 | ||
1096 | /* Disabled by kernel option? */ | 1107 | /* Disabled by kernel option? */ |
1097 | if (enable_local_apic < 0) | 1108 | if (disable_apic) |
1098 | return -1; | 1109 | return -1; |
1099 | 1110 | ||
1100 | switch (boot_cpu_data.x86_vendor) { | 1111 | switch (boot_cpu_data.x86_vendor) { |
@@ -1117,7 +1128,7 @@ static int __init detect_init_APIC(void) | |||
1117 | * Over-ride BIOS and try to enable the local APIC only if | 1128 | * Over-ride BIOS and try to enable the local APIC only if |
1118 | * "lapic" specified. | 1129 | * "lapic" specified. |
1119 | */ | 1130 | */ |
1120 | if (enable_local_apic <= 0) { | 1131 | if (!force_enable_local_apic) { |
1121 | printk(KERN_INFO "Local APIC disabled by BIOS -- " | 1132 | printk(KERN_INFO "Local APIC disabled by BIOS -- " |
1122 | "you can enable it with \"lapic\"\n"); | 1133 | "you can enable it with \"lapic\"\n"); |
1123 | return -1; | 1134 | return -1; |
@@ -1154,9 +1165,6 @@ static int __init detect_init_APIC(void) | |||
1154 | if (l & MSR_IA32_APICBASE_ENABLE) | 1165 | if (l & MSR_IA32_APICBASE_ENABLE) |
1155 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; | 1166 | mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; |
1156 | 1167 | ||
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"); | 1168 | printk(KERN_INFO "Found and enabled local APIC!\n"); |
1161 | 1169 | ||
1162 | apic_pm_activate(); | 1170 | apic_pm_activate(); |
@@ -1195,36 +1203,6 @@ void __init init_apic_mappings(void) | |||
1195 | if (boot_cpu_physical_apicid == -1U) | 1203 | if (boot_cpu_physical_apicid == -1U) |
1196 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1204 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); |
1197 | 1205 | ||
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 | } | 1206 | } |
1229 | 1207 | ||
1230 | /* | 1208 | /* |
@@ -1236,7 +1214,7 @@ int apic_version[MAX_APICS]; | |||
1236 | 1214 | ||
1237 | int __init APIC_init_uniprocessor(void) | 1215 | int __init APIC_init_uniprocessor(void) |
1238 | { | 1216 | { |
1239 | if (enable_local_apic < 0) | 1217 | if (disable_apic) |
1240 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); | 1218 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
1241 | 1219 | ||
1242 | if (!smp_found_config && !cpu_has_apic) | 1220 | if (!smp_found_config && !cpu_has_apic) |
@@ -1265,10 +1243,14 @@ int __init APIC_init_uniprocessor(void) | |||
1265 | #ifdef CONFIG_CRASH_DUMP | 1243 | #ifdef CONFIG_CRASH_DUMP |
1266 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1244 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); |
1267 | #endif | 1245 | #endif |
1268 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); | 1246 | physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); |
1269 | 1247 | ||
1270 | setup_local_APIC(); | 1248 | setup_local_APIC(); |
1271 | 1249 | ||
1250 | #ifdef CONFIG_X86_IO_APIC | ||
1251 | if (!smp_found_config || skip_ioapic_setup || !nr_ioapics) | ||
1252 | #endif | ||
1253 | localise_nmi_watchdog(); | ||
1272 | end_local_APIC_setup(); | 1254 | end_local_APIC_setup(); |
1273 | #ifdef CONFIG_X86_IO_APIC | 1255 | #ifdef CONFIG_X86_IO_APIC |
1274 | if (smp_found_config) | 1256 | if (smp_found_config) |
@@ -1351,13 +1333,13 @@ void __init smp_intr_init(void) | |||
1351 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | 1333 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper |
1352 | * IPI, driven by wakeup. | 1334 | * IPI, driven by wakeup. |
1353 | */ | 1335 | */ |
1354 | set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); | 1336 | alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); |
1355 | 1337 | ||
1356 | /* IPI for invalidation */ | 1338 | /* IPI for invalidation */ |
1357 | set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); | 1339 | alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); |
1358 | 1340 | ||
1359 | /* IPI for generic function call */ | 1341 | /* IPI for generic function call */ |
1360 | set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); | 1342 | alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); |
1361 | } | 1343 | } |
1362 | #endif | 1344 | #endif |
1363 | 1345 | ||
@@ -1370,15 +1352,15 @@ void __init apic_intr_init(void) | |||
1370 | smp_intr_init(); | 1352 | smp_intr_init(); |
1371 | #endif | 1353 | #endif |
1372 | /* self generated IPI for local APIC timer */ | 1354 | /* self generated IPI for local APIC timer */ |
1373 | set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); | 1355 | alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); |
1374 | 1356 | ||
1375 | /* IPI vectors for APIC spurious and error interrupts */ | 1357 | /* IPI vectors for APIC spurious and error interrupts */ |
1376 | set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | 1358 | alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); |
1377 | set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | 1359 | alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); |
1378 | 1360 | ||
1379 | /* thermal monitor LVT interrupt */ | 1361 | /* thermal monitor LVT interrupt */ |
1380 | #ifdef CONFIG_X86_MCE_P4THERMAL | 1362 | #ifdef CONFIG_X86_MCE_P4THERMAL |
1381 | set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); | 1363 | alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); |
1382 | #endif | 1364 | #endif |
1383 | } | 1365 | } |
1384 | 1366 | ||
@@ -1513,6 +1495,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1513 | */ | 1495 | */ |
1514 | cpu = 0; | 1496 | cpu = 0; |
1515 | 1497 | ||
1498 | if (apicid > max_physical_apicid) | ||
1499 | max_physical_apicid = apicid; | ||
1500 | |||
1516 | /* | 1501 | /* |
1517 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y | 1502 | * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y |
1518 | * but we need to work other dependencies like SMP_SUSPEND etc | 1503 | * but we need to work other dependencies like SMP_SUSPEND etc |
@@ -1520,7 +1505,7 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1520 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) | 1505 | * if (CPU_HOTPLUG_ENABLED || num_processors > 8) |
1521 | * - Ashok Raj <ashok.raj@intel.com> | 1506 | * - Ashok Raj <ashok.raj@intel.com> |
1522 | */ | 1507 | */ |
1523 | if (num_processors > 8) { | 1508 | if (max_physical_apicid >= 8) { |
1524 | switch (boot_cpu_data.x86_vendor) { | 1509 | switch (boot_cpu_data.x86_vendor) { |
1525 | case X86_VENDOR_INTEL: | 1510 | case X86_VENDOR_INTEL: |
1526 | if (!APIC_XAPIC(version)) { | 1511 | if (!APIC_XAPIC(version)) { |
@@ -1534,9 +1519,9 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1534 | } | 1519 | } |
1535 | #ifdef CONFIG_SMP | 1520 | #ifdef CONFIG_SMP |
1536 | /* are we being called early in kernel startup? */ | 1521 | /* are we being called early in kernel startup? */ |
1537 | if (x86_cpu_to_apicid_early_ptr) { | 1522 | if (early_per_cpu_ptr(x86_cpu_to_apicid)) { |
1538 | u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr; | 1523 | u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid); |
1539 | u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr; | 1524 | u16 *bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid); |
1540 | 1525 | ||
1541 | cpu_to_apicid[cpu] = apicid; | 1526 | cpu_to_apicid[cpu] = apicid; |
1542 | bios_cpu_apicid[cpu] = apicid; | 1527 | bios_cpu_apicid[cpu] = apicid; |
@@ -1703,14 +1688,14 @@ static void apic_pm_activate(void) { } | |||
1703 | */ | 1688 | */ |
1704 | static int __init parse_lapic(char *arg) | 1689 | static int __init parse_lapic(char *arg) |
1705 | { | 1690 | { |
1706 | enable_local_apic = 1; | 1691 | force_enable_local_apic = 1; |
1707 | return 0; | 1692 | return 0; |
1708 | } | 1693 | } |
1709 | early_param("lapic", parse_lapic); | 1694 | early_param("lapic", parse_lapic); |
1710 | 1695 | ||
1711 | static int __init parse_nolapic(char *arg) | 1696 | static int __init parse_nolapic(char *arg) |
1712 | { | 1697 | { |
1713 | enable_local_apic = -1; | 1698 | disable_apic = 1; |
1714 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); | 1699 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
1715 | return 0; | 1700 | return 0; |
1716 | } | 1701 | } |
@@ -1740,3 +1725,21 @@ static int __init apic_set_verbosity(char *str) | |||
1740 | } | 1725 | } |
1741 | __setup("apic=", apic_set_verbosity); | 1726 | __setup("apic=", apic_set_verbosity); |
1742 | 1727 | ||
1728 | static int __init lapic_insert_resource(void) | ||
1729 | { | ||
1730 | if (!apic_phys) | ||
1731 | return -1; | ||
1732 | |||
1733 | /* Put local APIC into the resource map. */ | ||
1734 | lapic_resource.start = apic_phys; | ||
1735 | lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1; | ||
1736 | insert_resource(&iomem_resource, &lapic_resource); | ||
1737 | |||
1738 | return 0; | ||
1739 | } | ||
1740 | |||
1741 | /* | ||
1742 | * need call insert after e820_reserve_resources() | ||
1743 | * that is using request_resource | ||
1744 | */ | ||
1745 | late_initcall(lapic_insert_resource); | ||