diff options
author | Arnd Bergmann <arnd@arndb.de> | 2009-06-12 03:53:47 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2009-06-12 05:32:58 -0400 |
commit | 5b02ee3d219f9e01b6e9146e25613822cfc2e5ce (patch) | |
tree | 7ce9126738c3cf4b37d67170d0e4b34818c057a9 /arch/x86/kernel/apic/apic.c | |
parent | 26a28fa4fea5b8c65713aa50c124f76a88c7924d (diff) | |
parent | 8ebf975608aaebd7feb33d77f07ba21a6380e086 (diff) |
asm-generic: merge branch 'master' of torvalds/linux-2.6
Fixes a merge conflict against the x86 tree caused by a fix to
atomic.h which I renamed to atomic_long.h.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 314 |
1 files changed, 194 insertions, 120 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index f2870920f246..076d3881f3da 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * Mikael Pettersson : PM converted to driver model. | 14 | * Mikael Pettersson : PM converted to driver model. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/perf_counter.h> | ||
17 | #include <linux/kernel_stat.h> | 18 | #include <linux/kernel_stat.h> |
18 | #include <linux/mc146818rtc.h> | 19 | #include <linux/mc146818rtc.h> |
19 | #include <linux/acpi_pmtmr.h> | 20 | #include <linux/acpi_pmtmr.h> |
@@ -34,6 +35,7 @@ | |||
34 | #include <linux/smp.h> | 35 | #include <linux/smp.h> |
35 | #include <linux/mm.h> | 36 | #include <linux/mm.h> |
36 | 37 | ||
38 | #include <asm/perf_counter.h> | ||
37 | #include <asm/pgalloc.h> | 39 | #include <asm/pgalloc.h> |
38 | #include <asm/atomic.h> | 40 | #include <asm/atomic.h> |
39 | #include <asm/mpspec.h> | 41 | #include <asm/mpspec.h> |
@@ -98,6 +100,29 @@ early_param("lapic", parse_lapic); | |||
98 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ | 100 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ |
99 | static int enabled_via_apicbase; | 101 | static int enabled_via_apicbase; |
100 | 102 | ||
103 | /* | ||
104 | * Handle interrupt mode configuration register (IMCR). | ||
105 | * This register controls whether the interrupt signals | ||
106 | * that reach the BSP come from the master PIC or from the | ||
107 | * local APIC. Before entering Symmetric I/O Mode, either | ||
108 | * the BIOS or the operating system must switch out of | ||
109 | * PIC Mode by changing the IMCR. | ||
110 | */ | ||
111 | static inline void imcr_pic_to_apic(void) | ||
112 | { | ||
113 | /* select IMCR register */ | ||
114 | outb(0x70, 0x22); | ||
115 | /* NMI and 8259 INTR go through APIC */ | ||
116 | outb(0x01, 0x23); | ||
117 | } | ||
118 | |||
119 | static inline void imcr_apic_to_pic(void) | ||
120 | { | ||
121 | /* select IMCR register */ | ||
122 | outb(0x70, 0x22); | ||
123 | /* NMI and 8259 INTR go directly to BSP */ | ||
124 | outb(0x00, 0x23); | ||
125 | } | ||
101 | #endif | 126 | #endif |
102 | 127 | ||
103 | #ifdef CONFIG_X86_64 | 128 | #ifdef CONFIG_X86_64 |
@@ -111,13 +136,19 @@ static __init int setup_apicpmtimer(char *s) | |||
111 | __setup("apicpmtimer", setup_apicpmtimer); | 136 | __setup("apicpmtimer", setup_apicpmtimer); |
112 | #endif | 137 | #endif |
113 | 138 | ||
139 | int x2apic_mode; | ||
114 | #ifdef CONFIG_X86_X2APIC | 140 | #ifdef CONFIG_X86_X2APIC |
115 | int x2apic; | ||
116 | /* x2apic enabled before OS handover */ | 141 | /* x2apic enabled before OS handover */ |
117 | static int x2apic_preenabled; | 142 | static int x2apic_preenabled; |
118 | static int disable_x2apic; | 143 | static int disable_x2apic; |
119 | static __init int setup_nox2apic(char *str) | 144 | static __init int setup_nox2apic(char *str) |
120 | { | 145 | { |
146 | if (x2apic_enabled()) { | ||
147 | pr_warning("Bios already enabled x2apic, " | ||
148 | "can't enforce nox2apic"); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
121 | disable_x2apic = 1; | 152 | disable_x2apic = 1; |
122 | setup_clear_cpu_cap(X86_FEATURE_X2APIC); | 153 | setup_clear_cpu_cap(X86_FEATURE_X2APIC); |
123 | return 0; | 154 | return 0; |
@@ -209,6 +240,31 @@ static int modern_apic(void) | |||
209 | return lapic_get_version() >= 0x14; | 240 | return lapic_get_version() >= 0x14; |
210 | } | 241 | } |
211 | 242 | ||
243 | /* | ||
244 | * bare function to substitute write operation | ||
245 | * and it's _that_ fast :) | ||
246 | */ | ||
247 | static void native_apic_write_dummy(u32 reg, u32 v) | ||
248 | { | ||
249 | WARN_ON_ONCE((cpu_has_apic || !disable_apic)); | ||
250 | } | ||
251 | |||
252 | static u32 native_apic_read_dummy(u32 reg) | ||
253 | { | ||
254 | WARN_ON_ONCE((cpu_has_apic && !disable_apic)); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * right after this call apic->write/read doesn't do anything | ||
260 | * note that there is no restore operation it works one way | ||
261 | */ | ||
262 | void apic_disable(void) | ||
263 | { | ||
264 | apic->read = native_apic_read_dummy; | ||
265 | apic->write = native_apic_write_dummy; | ||
266 | } | ||
267 | |||
212 | void native_apic_wait_icr_idle(void) | 268 | void native_apic_wait_icr_idle(void) |
213 | { | 269 | { |
214 | while (apic_read(APIC_ICR) & APIC_ICR_BUSY) | 270 | while (apic_read(APIC_ICR) & APIC_ICR_BUSY) |
@@ -348,7 +404,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
348 | 404 | ||
349 | static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask) | 405 | static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask) |
350 | { | 406 | { |
351 | unsigned long reg = (lvt_off << 4) + APIC_EILVT0; | 407 | unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0); |
352 | unsigned int v = (mask << 16) | (msg_type << 8) | vector; | 408 | unsigned int v = (mask << 16) | (msg_type << 8) | vector; |
353 | 409 | ||
354 | apic_write(reg, v); | 410 | apic_write(reg, v); |
@@ -815,7 +871,7 @@ void clear_local_APIC(void) | |||
815 | u32 v; | 871 | u32 v; |
816 | 872 | ||
817 | /* APIC hasn't been mapped yet */ | 873 | /* APIC hasn't been mapped yet */ |
818 | if (!x2apic && !apic_phys) | 874 | if (!x2apic_mode && !apic_phys) |
819 | return; | 875 | return; |
820 | 876 | ||
821 | maxlvt = lapic_get_maxlvt(); | 877 | maxlvt = lapic_get_maxlvt(); |
@@ -1133,6 +1189,7 @@ void __cpuinit setup_local_APIC(void) | |||
1133 | apic_write(APIC_ESR, 0); | 1189 | apic_write(APIC_ESR, 0); |
1134 | } | 1190 | } |
1135 | #endif | 1191 | #endif |
1192 | perf_counters_lapic_init(); | ||
1136 | 1193 | ||
1137 | preempt_disable(); | 1194 | preempt_disable(); |
1138 | 1195 | ||
@@ -1287,7 +1344,7 @@ void check_x2apic(void) | |||
1287 | { | 1344 | { |
1288 | if (x2apic_enabled()) { | 1345 | if (x2apic_enabled()) { |
1289 | pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); | 1346 | pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); |
1290 | x2apic_preenabled = x2apic = 1; | 1347 | x2apic_preenabled = x2apic_mode = 1; |
1291 | } | 1348 | } |
1292 | } | 1349 | } |
1293 | 1350 | ||
@@ -1295,7 +1352,7 @@ void enable_x2apic(void) | |||
1295 | { | 1352 | { |
1296 | int msr, msr2; | 1353 | int msr, msr2; |
1297 | 1354 | ||
1298 | if (!x2apic) | 1355 | if (!x2apic_mode) |
1299 | return; | 1356 | return; |
1300 | 1357 | ||
1301 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | 1358 | rdmsr(MSR_IA32_APICBASE, msr, msr2); |
@@ -1304,6 +1361,7 @@ void enable_x2apic(void) | |||
1304 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); | 1361 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); |
1305 | } | 1362 | } |
1306 | } | 1363 | } |
1364 | #endif /* CONFIG_X86_X2APIC */ | ||
1307 | 1365 | ||
1308 | void __init enable_IR_x2apic(void) | 1366 | void __init enable_IR_x2apic(void) |
1309 | { | 1367 | { |
@@ -1312,32 +1370,21 @@ void __init enable_IR_x2apic(void) | |||
1312 | unsigned long flags; | 1370 | unsigned long flags; |
1313 | struct IO_APIC_route_entry **ioapic_entries = NULL; | 1371 | struct IO_APIC_route_entry **ioapic_entries = NULL; |
1314 | 1372 | ||
1315 | if (!cpu_has_x2apic) | 1373 | ret = dmar_table_init(); |
1316 | return; | 1374 | if (ret) { |
1317 | 1375 | pr_debug("dmar_table_init() failed with %d:\n", ret); | |
1318 | if (!x2apic_preenabled && disable_x2apic) { | 1376 | goto ir_failed; |
1319 | pr_info("Skipped enabling x2apic and Interrupt-remapping " | ||
1320 | "because of nox2apic\n"); | ||
1321 | return; | ||
1322 | } | 1377 | } |
1323 | 1378 | ||
1324 | if (x2apic_preenabled && disable_x2apic) | 1379 | if (!intr_remapping_supported()) { |
1325 | panic("Bios already enabled x2apic, can't enforce nox2apic"); | 1380 | pr_debug("intr-remapping not supported\n"); |
1326 | 1381 | goto ir_failed; | |
1327 | if (!x2apic_preenabled && skip_ioapic_setup) { | ||
1328 | pr_info("Skipped enabling x2apic and Interrupt-remapping " | ||
1329 | "because of skipping io-apic setup\n"); | ||
1330 | return; | ||
1331 | } | 1382 | } |
1332 | 1383 | ||
1333 | ret = dmar_table_init(); | ||
1334 | if (ret) { | ||
1335 | pr_info("dmar_table_init() failed with %d:\n", ret); | ||
1336 | 1384 | ||
1337 | if (x2apic_preenabled) | 1385 | if (!x2apic_preenabled && skip_ioapic_setup) { |
1338 | panic("x2apic enabled by bios. But IR enabling failed"); | 1386 | pr_info("Skipped enabling intr-remap because of skipping " |
1339 | else | 1387 | "io-apic setup\n"); |
1340 | pr_info("Not enabling x2apic,Intr-remapping\n"); | ||
1341 | return; | 1388 | return; |
1342 | } | 1389 | } |
1343 | 1390 | ||
@@ -1357,19 +1404,16 @@ void __init enable_IR_x2apic(void) | |||
1357 | mask_IO_APIC_setup(ioapic_entries); | 1404 | mask_IO_APIC_setup(ioapic_entries); |
1358 | mask_8259A(); | 1405 | mask_8259A(); |
1359 | 1406 | ||
1360 | ret = enable_intr_remapping(EIM_32BIT_APIC_ID); | 1407 | ret = enable_intr_remapping(x2apic_supported()); |
1361 | |||
1362 | if (ret && x2apic_preenabled) { | ||
1363 | local_irq_restore(flags); | ||
1364 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
1365 | } | ||
1366 | |||
1367 | if (ret) | 1408 | if (ret) |
1368 | goto end_restore; | 1409 | goto end_restore; |
1369 | 1410 | ||
1370 | if (!x2apic) { | 1411 | pr_info("Enabled Interrupt-remapping\n"); |
1371 | x2apic = 1; | 1412 | |
1413 | if (x2apic_supported() && !x2apic_mode) { | ||
1414 | x2apic_mode = 1; | ||
1372 | enable_x2apic(); | 1415 | enable_x2apic(); |
1416 | pr_info("Enabled x2apic\n"); | ||
1373 | } | 1417 | } |
1374 | 1418 | ||
1375 | end_restore: | 1419 | end_restore: |
@@ -1378,37 +1422,34 @@ end_restore: | |||
1378 | * IR enabling failed | 1422 | * IR enabling failed |
1379 | */ | 1423 | */ |
1380 | restore_IO_APIC_setup(ioapic_entries); | 1424 | restore_IO_APIC_setup(ioapic_entries); |
1381 | else | ||
1382 | reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries); | ||
1383 | 1425 | ||
1384 | unmask_8259A(); | 1426 | unmask_8259A(); |
1385 | local_irq_restore(flags); | 1427 | local_irq_restore(flags); |
1386 | 1428 | ||
1387 | end: | 1429 | end: |
1388 | if (!ret) { | ||
1389 | if (!x2apic_preenabled) | ||
1390 | pr_info("Enabled x2apic and interrupt-remapping\n"); | ||
1391 | else | ||
1392 | pr_info("Enabled Interrupt-remapping\n"); | ||
1393 | } else | ||
1394 | pr_err("Failed to enable Interrupt-remapping and x2apic\n"); | ||
1395 | if (ioapic_entries) | 1430 | if (ioapic_entries) |
1396 | free_ioapic_entries(ioapic_entries); | 1431 | free_ioapic_entries(ioapic_entries); |
1432 | |||
1433 | if (!ret) | ||
1434 | return; | ||
1435 | |||
1436 | ir_failed: | ||
1437 | if (x2apic_preenabled) | ||
1438 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
1439 | else if (cpu_has_x2apic) | ||
1440 | pr_info("Not enabling x2apic,Intr-remapping\n"); | ||
1397 | #else | 1441 | #else |
1398 | if (!cpu_has_x2apic) | 1442 | if (!cpu_has_x2apic) |
1399 | return; | 1443 | return; |
1400 | 1444 | ||
1401 | if (x2apic_preenabled) | 1445 | if (x2apic_preenabled) |
1402 | panic("x2apic enabled prior OS handover," | 1446 | panic("x2apic enabled prior OS handover," |
1403 | " enable CONFIG_INTR_REMAP"); | 1447 | " enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP"); |
1404 | |||
1405 | pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping " | ||
1406 | " and x2apic\n"); | ||
1407 | #endif | 1448 | #endif |
1408 | 1449 | ||
1409 | return; | 1450 | return; |
1410 | } | 1451 | } |
1411 | #endif /* CONFIG_X86_X2APIC */ | 1452 | |
1412 | 1453 | ||
1413 | #ifdef CONFIG_X86_64 | 1454 | #ifdef CONFIG_X86_64 |
1414 | /* | 1455 | /* |
@@ -1425,7 +1466,6 @@ static int __init detect_init_APIC(void) | |||
1425 | } | 1466 | } |
1426 | 1467 | ||
1427 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; | 1468 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; |
1428 | boot_cpu_physical_apicid = 0; | ||
1429 | return 0; | 1469 | return 0; |
1430 | } | 1470 | } |
1431 | #else | 1471 | #else |
@@ -1539,32 +1579,49 @@ void __init early_init_lapic_mapping(void) | |||
1539 | */ | 1579 | */ |
1540 | void __init init_apic_mappings(void) | 1580 | void __init init_apic_mappings(void) |
1541 | { | 1581 | { |
1542 | if (x2apic) { | 1582 | unsigned int new_apicid; |
1583 | |||
1584 | if (x2apic_mode) { | ||
1543 | boot_cpu_physical_apicid = read_apic_id(); | 1585 | boot_cpu_physical_apicid = read_apic_id(); |
1544 | return; | 1586 | return; |
1545 | } | 1587 | } |
1546 | 1588 | ||
1547 | /* | 1589 | /* If no local APIC can be found return early */ |
1548 | * If no local APIC can be found then set up a fake all | ||
1549 | * zeroes page to simulate the local APIC and another | ||
1550 | * one for the IO-APIC. | ||
1551 | */ | ||
1552 | if (!smp_found_config && detect_init_APIC()) { | 1590 | if (!smp_found_config && detect_init_APIC()) { |
1553 | apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); | 1591 | /* lets NOP'ify apic operations */ |
1554 | apic_phys = __pa(apic_phys); | 1592 | pr_info("APIC: disable apic facility\n"); |
1555 | } else | 1593 | apic_disable(); |
1594 | } else { | ||
1556 | apic_phys = mp_lapic_addr; | 1595 | apic_phys = mp_lapic_addr; |
1557 | 1596 | ||
1558 | set_fixmap_nocache(FIX_APIC_BASE, apic_phys); | 1597 | /* |
1559 | apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n", | 1598 | * acpi lapic path already maps that address in |
1560 | APIC_BASE, apic_phys); | 1599 | * acpi_register_lapic_address() |
1600 | */ | ||
1601 | if (!acpi_lapic) | ||
1602 | set_fixmap_nocache(FIX_APIC_BASE, apic_phys); | ||
1603 | |||
1604 | apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n", | ||
1605 | APIC_BASE, apic_phys); | ||
1606 | } | ||
1561 | 1607 | ||
1562 | /* | 1608 | /* |
1563 | * Fetch the APIC ID of the BSP in case we have a | 1609 | * Fetch the APIC ID of the BSP in case we have a |
1564 | * default configuration (or the MP table is broken). | 1610 | * default configuration (or the MP table is broken). |
1565 | */ | 1611 | */ |
1566 | if (boot_cpu_physical_apicid == -1U) | 1612 | new_apicid = read_apic_id(); |
1567 | boot_cpu_physical_apicid = read_apic_id(); | 1613 | if (boot_cpu_physical_apicid != new_apicid) { |
1614 | boot_cpu_physical_apicid = new_apicid; | ||
1615 | /* | ||
1616 | * yeah -- we lie about apic_version | ||
1617 | * in case if apic was disabled via boot option | ||
1618 | * but it's not a problem for SMP compiled kernel | ||
1619 | * since smp_sanity_check is prepared for such a case | ||
1620 | * and disable smp mode | ||
1621 | */ | ||
1622 | apic_version[new_apicid] = | ||
1623 | GET_APIC_VERSION(apic_read(APIC_LVR)); | ||
1624 | } | ||
1568 | } | 1625 | } |
1569 | 1626 | ||
1570 | /* | 1627 | /* |
@@ -1733,8 +1790,7 @@ void __init connect_bsp_APIC(void) | |||
1733 | */ | 1790 | */ |
1734 | apic_printk(APIC_VERBOSE, "leaving PIC mode, " | 1791 | apic_printk(APIC_VERBOSE, "leaving PIC mode, " |
1735 | "enabling APIC mode.\n"); | 1792 | "enabling APIC mode.\n"); |
1736 | outb(0x70, 0x22); | 1793 | imcr_pic_to_apic(); |
1737 | outb(0x01, 0x23); | ||
1738 | } | 1794 | } |
1739 | #endif | 1795 | #endif |
1740 | if (apic->enable_apic_mode) | 1796 | if (apic->enable_apic_mode) |
@@ -1762,8 +1818,7 @@ void disconnect_bsp_APIC(int virt_wire_setup) | |||
1762 | */ | 1818 | */ |
1763 | apic_printk(APIC_VERBOSE, "disabling APIC mode, " | 1819 | apic_printk(APIC_VERBOSE, "disabling APIC mode, " |
1764 | "entering PIC mode.\n"); | 1820 | "entering PIC mode.\n"); |
1765 | outb(0x70, 0x22); | 1821 | imcr_apic_to_pic(); |
1766 | outb(0x00, 0x23); | ||
1767 | return; | 1822 | return; |
1768 | } | 1823 | } |
1769 | #endif | 1824 | #endif |
@@ -1969,10 +2024,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
1969 | 2024 | ||
1970 | local_irq_save(flags); | 2025 | local_irq_save(flags); |
1971 | disable_local_APIC(); | 2026 | disable_local_APIC(); |
1972 | #ifdef CONFIG_INTR_REMAP | 2027 | |
1973 | if (intr_remapping_enabled) | 2028 | if (intr_remapping_enabled) |
1974 | disable_intr_remapping(); | 2029 | disable_intr_remapping(); |
1975 | #endif | 2030 | |
1976 | local_irq_restore(flags); | 2031 | local_irq_restore(flags); |
1977 | return 0; | 2032 | return 0; |
1978 | } | 2033 | } |
@@ -1982,42 +2037,34 @@ static int lapic_resume(struct sys_device *dev) | |||
1982 | unsigned int l, h; | 2037 | unsigned int l, h; |
1983 | unsigned long flags; | 2038 | unsigned long flags; |
1984 | int maxlvt; | 2039 | int maxlvt; |
1985 | 2040 | int ret = 0; | |
1986 | #ifdef CONFIG_INTR_REMAP | ||
1987 | int ret; | ||
1988 | struct IO_APIC_route_entry **ioapic_entries = NULL; | 2041 | struct IO_APIC_route_entry **ioapic_entries = NULL; |
1989 | 2042 | ||
1990 | if (!apic_pm_state.active) | 2043 | if (!apic_pm_state.active) |
1991 | return 0; | 2044 | return 0; |
1992 | 2045 | ||
1993 | local_irq_save(flags); | 2046 | local_irq_save(flags); |
1994 | if (x2apic) { | 2047 | if (intr_remapping_enabled) { |
1995 | ioapic_entries = alloc_ioapic_entries(); | 2048 | ioapic_entries = alloc_ioapic_entries(); |
1996 | if (!ioapic_entries) { | 2049 | if (!ioapic_entries) { |
1997 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); | 2050 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); |
1998 | return -ENOMEM; | 2051 | ret = -ENOMEM; |
2052 | goto restore; | ||
1999 | } | 2053 | } |
2000 | 2054 | ||
2001 | ret = save_IO_APIC_setup(ioapic_entries); | 2055 | ret = save_IO_APIC_setup(ioapic_entries); |
2002 | if (ret) { | 2056 | if (ret) { |
2003 | WARN(1, "Saving IO-APIC state failed: %d\n", ret); | 2057 | WARN(1, "Saving IO-APIC state failed: %d\n", ret); |
2004 | free_ioapic_entries(ioapic_entries); | 2058 | free_ioapic_entries(ioapic_entries); |
2005 | return ret; | 2059 | goto restore; |
2006 | } | 2060 | } |
2007 | 2061 | ||
2008 | mask_IO_APIC_setup(ioapic_entries); | 2062 | mask_IO_APIC_setup(ioapic_entries); |
2009 | mask_8259A(); | 2063 | mask_8259A(); |
2010 | enable_x2apic(); | ||
2011 | } | 2064 | } |
2012 | #else | ||
2013 | if (!apic_pm_state.active) | ||
2014 | return 0; | ||
2015 | 2065 | ||
2016 | local_irq_save(flags); | 2066 | if (x2apic_mode) |
2017 | if (x2apic) | ||
2018 | enable_x2apic(); | 2067 | enable_x2apic(); |
2019 | #endif | ||
2020 | |||
2021 | else { | 2068 | else { |
2022 | /* | 2069 | /* |
2023 | * Make sure the APICBASE points to the right address | 2070 | * Make sure the APICBASE points to the right address |
@@ -2055,21 +2102,16 @@ static int lapic_resume(struct sys_device *dev) | |||
2055 | apic_write(APIC_ESR, 0); | 2102 | apic_write(APIC_ESR, 0); |
2056 | apic_read(APIC_ESR); | 2103 | apic_read(APIC_ESR); |
2057 | 2104 | ||
2058 | #ifdef CONFIG_INTR_REMAP | 2105 | if (intr_remapping_enabled) { |
2059 | if (intr_remapping_enabled) | 2106 | reenable_intr_remapping(x2apic_mode); |
2060 | reenable_intr_remapping(EIM_32BIT_APIC_ID); | ||
2061 | |||
2062 | if (x2apic) { | ||
2063 | unmask_8259A(); | 2107 | unmask_8259A(); |
2064 | restore_IO_APIC_setup(ioapic_entries); | 2108 | restore_IO_APIC_setup(ioapic_entries); |
2065 | free_ioapic_entries(ioapic_entries); | 2109 | free_ioapic_entries(ioapic_entries); |
2066 | } | 2110 | } |
2067 | #endif | 2111 | restore: |
2068 | |||
2069 | local_irq_restore(flags); | 2112 | local_irq_restore(flags); |
2070 | 2113 | ||
2071 | 2114 | return ret; | |
2072 | return 0; | ||
2073 | } | 2115 | } |
2074 | 2116 | ||
2075 | /* | 2117 | /* |
@@ -2117,31 +2159,14 @@ static void apic_pm_activate(void) { } | |||
2117 | #endif /* CONFIG_PM */ | 2159 | #endif /* CONFIG_PM */ |
2118 | 2160 | ||
2119 | #ifdef CONFIG_X86_64 | 2161 | #ifdef CONFIG_X86_64 |
2120 | /* | 2162 | |
2121 | * apic_is_clustered_box() -- Check if we can expect good TSC | 2163 | static int __cpuinit apic_cluster_num(void) |
2122 | * | ||
2123 | * Thus far, the major user of this is IBM's Summit2 series: | ||
2124 | * | ||
2125 | * Clustered boxes may have unsynced TSC problems if they are | ||
2126 | * multi-chassis. Use available data to take a good guess. | ||
2127 | * If in doubt, go HPET. | ||
2128 | */ | ||
2129 | __cpuinit int apic_is_clustered_box(void) | ||
2130 | { | 2164 | { |
2131 | int i, clusters, zeros; | 2165 | int i, clusters, zeros; |
2132 | unsigned id; | 2166 | unsigned id; |
2133 | u16 *bios_cpu_apicid; | 2167 | u16 *bios_cpu_apicid; |
2134 | DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS); | 2168 | DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS); |
2135 | 2169 | ||
2136 | /* | ||
2137 | * there is not this kind of box with AMD CPU yet. | ||
2138 | * Some AMD box with quadcore cpu and 8 sockets apicid | ||
2139 | * will be [4, 0x23] or [8, 0x27] could be thought to | ||
2140 | * vsmp box still need checking... | ||
2141 | */ | ||
2142 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && !is_vsmp_box()) | ||
2143 | return 0; | ||
2144 | |||
2145 | bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid); | 2170 | bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid); |
2146 | bitmap_zero(clustermap, NUM_APIC_CLUSTERS); | 2171 | bitmap_zero(clustermap, NUM_APIC_CLUSTERS); |
2147 | 2172 | ||
@@ -2177,18 +2202,67 @@ __cpuinit int apic_is_clustered_box(void) | |||
2177 | ++zeros; | 2202 | ++zeros; |
2178 | } | 2203 | } |
2179 | 2204 | ||
2180 | /* ScaleMP vSMPowered boxes have one cluster per board and TSCs are | 2205 | return clusters; |
2181 | * not guaranteed to be synced between boards | 2206 | } |
2182 | */ | 2207 | |
2183 | if (is_vsmp_box() && clusters > 1) | 2208 | static int __cpuinitdata multi_checked; |
2209 | static int __cpuinitdata multi; | ||
2210 | |||
2211 | static int __cpuinit set_multi(const struct dmi_system_id *d) | ||
2212 | { | ||
2213 | if (multi) | ||
2214 | return 0; | ||
2215 | pr_info("APIC: %s detected, Multi Chassis\n", d->ident); | ||
2216 | multi = 1; | ||
2217 | return 0; | ||
2218 | } | ||
2219 | |||
2220 | static const __cpuinitconst struct dmi_system_id multi_dmi_table[] = { | ||
2221 | { | ||
2222 | .callback = set_multi, | ||
2223 | .ident = "IBM System Summit2", | ||
2224 | .matches = { | ||
2225 | DMI_MATCH(DMI_SYS_VENDOR, "IBM"), | ||
2226 | DMI_MATCH(DMI_PRODUCT_NAME, "Summit2"), | ||
2227 | }, | ||
2228 | }, | ||
2229 | {} | ||
2230 | }; | ||
2231 | |||
2232 | static void __cpuinit dmi_check_multi(void) | ||
2233 | { | ||
2234 | if (multi_checked) | ||
2235 | return; | ||
2236 | |||
2237 | dmi_check_system(multi_dmi_table); | ||
2238 | multi_checked = 1; | ||
2239 | } | ||
2240 | |||
2241 | /* | ||
2242 | * apic_is_clustered_box() -- Check if we can expect good TSC | ||
2243 | * | ||
2244 | * Thus far, the major user of this is IBM's Summit2 series: | ||
2245 | * Clustered boxes may have unsynced TSC problems if they are | ||
2246 | * multi-chassis. | ||
2247 | * Use DMI to check them | ||
2248 | */ | ||
2249 | __cpuinit int apic_is_clustered_box(void) | ||
2250 | { | ||
2251 | dmi_check_multi(); | ||
2252 | if (multi) | ||
2184 | return 1; | 2253 | return 1; |
2185 | 2254 | ||
2255 | if (!is_vsmp_box()) | ||
2256 | return 0; | ||
2257 | |||
2186 | /* | 2258 | /* |
2187 | * If clusters > 2, then should be multi-chassis. | 2259 | * ScaleMP vSMPowered boxes have one cluster per board and TSCs are |
2188 | * May have to revisit this when multi-core + hyperthreaded CPUs come | 2260 | * not guaranteed to be synced between boards |
2189 | * out, but AFAIK this will work even for them. | ||
2190 | */ | 2261 | */ |
2191 | return (clusters > 2); | 2262 | if (apic_cluster_num() > 1) |
2263 | return 1; | ||
2264 | |||
2265 | return 0; | ||
2192 | } | 2266 | } |
2193 | #endif | 2267 | #endif |
2194 | 2268 | ||