diff options
-rw-r--r-- | arch/x86/kernel/apic_32.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 05498c37f8d9..0b11d6e3f091 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -90,6 +90,24 @@ static __init int setup_apicpmtimer(char *s) | |||
90 | __setup("apicpmtimer", setup_apicpmtimer); | 90 | __setup("apicpmtimer", setup_apicpmtimer); |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | #ifdef CONFIG_X86_64 | ||
94 | #define HAVE_X2APIC | ||
95 | #endif | ||
96 | |||
97 | #ifdef HAVE_X2APIC | ||
98 | int x2apic; | ||
99 | /* x2apic enabled before OS handover */ | ||
100 | int x2apic_preenabled; | ||
101 | int disable_x2apic; | ||
102 | static __init int setup_nox2apic(char *str) | ||
103 | { | ||
104 | disable_x2apic = 1; | ||
105 | setup_clear_cpu_cap(X86_FEATURE_X2APIC); | ||
106 | return 0; | ||
107 | } | ||
108 | early_param("nox2apic", setup_nox2apic); | ||
109 | #endif | ||
110 | |||
93 | unsigned long mp_lapic_addr; | 111 | unsigned long mp_lapic_addr; |
94 | int disable_apic; | 112 | int disable_apic; |
95 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ | 113 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ |
@@ -231,6 +249,42 @@ static struct apic_ops xapic_ops = { | |||
231 | struct apic_ops __read_mostly *apic_ops = &xapic_ops; | 249 | struct apic_ops __read_mostly *apic_ops = &xapic_ops; |
232 | EXPORT_SYMBOL_GPL(apic_ops); | 250 | EXPORT_SYMBOL_GPL(apic_ops); |
233 | 251 | ||
252 | #ifdef HAVE_X2APIC | ||
253 | static void x2apic_wait_icr_idle(void) | ||
254 | { | ||
255 | /* no need to wait for icr idle in x2apic */ | ||
256 | return; | ||
257 | } | ||
258 | |||
259 | static u32 safe_x2apic_wait_icr_idle(void) | ||
260 | { | ||
261 | /* no need to wait for icr idle in x2apic */ | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | void x2apic_icr_write(u32 low, u32 id) | ||
266 | { | ||
267 | wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low); | ||
268 | } | ||
269 | |||
270 | u64 x2apic_icr_read(void) | ||
271 | { | ||
272 | unsigned long val; | ||
273 | |||
274 | rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val); | ||
275 | return val; | ||
276 | } | ||
277 | |||
278 | static struct apic_ops x2apic_ops = { | ||
279 | .read = native_apic_msr_read, | ||
280 | .write = native_apic_msr_write, | ||
281 | .icr_read = x2apic_icr_read, | ||
282 | .icr_write = x2apic_icr_write, | ||
283 | .wait_icr_idle = x2apic_wait_icr_idle, | ||
284 | .safe_wait_icr_idle = safe_x2apic_wait_icr_idle, | ||
285 | }; | ||
286 | #endif | ||
287 | |||
234 | /** | 288 | /** |
235 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 | 289 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 |
236 | */ | 290 | */ |
@@ -1308,6 +1362,127 @@ void __cpuinit end_local_APIC_setup(void) | |||
1308 | apic_pm_activate(); | 1362 | apic_pm_activate(); |
1309 | } | 1363 | } |
1310 | 1364 | ||
1365 | #ifdef HAVE_X2APIC | ||
1366 | void check_x2apic(void) | ||
1367 | { | ||
1368 | int msr, msr2; | ||
1369 | |||
1370 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
1371 | |||
1372 | if (msr & X2APIC_ENABLE) { | ||
1373 | printk("x2apic enabled by BIOS, switching to x2apic ops\n"); | ||
1374 | x2apic_preenabled = x2apic = 1; | ||
1375 | apic_ops = &x2apic_ops; | ||
1376 | } | ||
1377 | } | ||
1378 | |||
1379 | void enable_x2apic(void) | ||
1380 | { | ||
1381 | int msr, msr2; | ||
1382 | |||
1383 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
1384 | if (!(msr & X2APIC_ENABLE)) { | ||
1385 | printk("Enabling x2apic\n"); | ||
1386 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); | ||
1387 | } | ||
1388 | } | ||
1389 | |||
1390 | void enable_IR_x2apic(void) | ||
1391 | { | ||
1392 | #ifdef CONFIG_INTR_REMAP | ||
1393 | int ret; | ||
1394 | unsigned long flags; | ||
1395 | |||
1396 | if (!cpu_has_x2apic) | ||
1397 | return; | ||
1398 | |||
1399 | if (!x2apic_preenabled && disable_x2apic) { | ||
1400 | printk(KERN_INFO | ||
1401 | "Skipped enabling x2apic and Interrupt-remapping " | ||
1402 | "because of nox2apic\n"); | ||
1403 | return; | ||
1404 | } | ||
1405 | |||
1406 | if (x2apic_preenabled && disable_x2apic) | ||
1407 | panic("Bios already enabled x2apic, can't enforce nox2apic"); | ||
1408 | |||
1409 | if (!x2apic_preenabled && skip_ioapic_setup) { | ||
1410 | printk(KERN_INFO | ||
1411 | "Skipped enabling x2apic and Interrupt-remapping " | ||
1412 | "because of skipping io-apic setup\n"); | ||
1413 | return; | ||
1414 | } | ||
1415 | |||
1416 | ret = dmar_table_init(); | ||
1417 | if (ret) { | ||
1418 | printk(KERN_INFO | ||
1419 | "dmar_table_init() failed with %d:\n", ret); | ||
1420 | |||
1421 | if (x2apic_preenabled) | ||
1422 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
1423 | else | ||
1424 | printk(KERN_INFO | ||
1425 | "Not enabling x2apic,Intr-remapping\n"); | ||
1426 | return; | ||
1427 | } | ||
1428 | |||
1429 | local_irq_save(flags); | ||
1430 | mask_8259A(); | ||
1431 | save_mask_IO_APIC_setup(); | ||
1432 | |||
1433 | ret = enable_intr_remapping(1); | ||
1434 | |||
1435 | if (ret && x2apic_preenabled) { | ||
1436 | local_irq_restore(flags); | ||
1437 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
1438 | } | ||
1439 | |||
1440 | if (ret) | ||
1441 | goto end; | ||
1442 | |||
1443 | if (!x2apic) { | ||
1444 | x2apic = 1; | ||
1445 | apic_ops = &x2apic_ops; | ||
1446 | enable_x2apic(); | ||
1447 | } | ||
1448 | end: | ||
1449 | if (ret) | ||
1450 | /* | ||
1451 | * IR enabling failed | ||
1452 | */ | ||
1453 | restore_IO_APIC_setup(); | ||
1454 | else | ||
1455 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | ||
1456 | |||
1457 | unmask_8259A(); | ||
1458 | local_irq_restore(flags); | ||
1459 | |||
1460 | if (!ret) { | ||
1461 | if (!x2apic_preenabled) | ||
1462 | printk(KERN_INFO | ||
1463 | "Enabled x2apic and interrupt-remapping\n"); | ||
1464 | else | ||
1465 | printk(KERN_INFO | ||
1466 | "Enabled Interrupt-remapping\n"); | ||
1467 | } else | ||
1468 | printk(KERN_ERR | ||
1469 | "Failed to enable Interrupt-remapping and x2apic\n"); | ||
1470 | #else | ||
1471 | if (!cpu_has_x2apic) | ||
1472 | return; | ||
1473 | |||
1474 | if (x2apic_preenabled) | ||
1475 | panic("x2apic enabled prior OS handover," | ||
1476 | " enable CONFIG_INTR_REMAP"); | ||
1477 | |||
1478 | printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " | ||
1479 | " and x2apic\n"); | ||
1480 | #endif | ||
1481 | |||
1482 | return; | ||
1483 | } | ||
1484 | #endif /* HAVE_X2APIC */ | ||
1485 | |||
1311 | #ifdef CONFIG_X86_64 | 1486 | #ifdef CONFIG_X86_64 |
1312 | /* | 1487 | /* |
1313 | * Detect and enable local APICs on non-SMP boards. | 1488 | * Detect and enable local APICs on non-SMP boards. |
@@ -1438,6 +1613,13 @@ void __init early_init_lapic_mapping(void) | |||
1438 | */ | 1613 | */ |
1439 | void __init init_apic_mappings(void) | 1614 | void __init init_apic_mappings(void) |
1440 | { | 1615 | { |
1616 | #ifdef HAVE_X2APIC | ||
1617 | if (x2apic) { | ||
1618 | boot_cpu_physical_apicid = read_apic_id(); | ||
1619 | return; | ||
1620 | } | ||
1621 | #endif | ||
1622 | |||
1441 | /* | 1623 | /* |
1442 | * If no local APIC can be found then set up a fake all | 1624 | * If no local APIC can be found then set up a fake all |
1443 | * zeroes page to simulate the local APIC and another | 1625 | * zeroes page to simulate the local APIC and another |
@@ -1501,6 +1683,7 @@ int __init APIC_init_uniprocessor(void) | |||
1501 | #ifdef CONFIG_X86_64 | 1683 | #ifdef CONFIG_X86_64 |
1502 | setup_apic_routing(); | 1684 | setup_apic_routing(); |
1503 | #endif | 1685 | #endif |
1686 | |||
1504 | verify_local_APIC(); | 1687 | verify_local_APIC(); |
1505 | connect_bsp_APIC(); | 1688 | connect_bsp_APIC(); |
1506 | 1689 | ||
@@ -1879,6 +2062,11 @@ static int lapic_resume(struct sys_device *dev) | |||
1879 | 2062 | ||
1880 | local_irq_save(flags); | 2063 | local_irq_save(flags); |
1881 | 2064 | ||
2065 | #ifdef HAVE_X2APIC | ||
2066 | if (x2apic) | ||
2067 | enable_x2apic(); | ||
2068 | else | ||
2069 | #endif | ||
1882 | { | 2070 | { |
1883 | /* | 2071 | /* |
1884 | * Make sure the APICBASE points to the right address | 2072 | * Make sure the APICBASE points to the right address |