diff options
Diffstat (limited to 'arch/x86/kernel/apic_32.c')
-rw-r--r-- | arch/x86/kernel/apic_32.c | 156 |
1 files changed, 88 insertions, 68 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index a56c782653be..35a568ea8400 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -43,12 +43,10 @@ | |||
43 | #include <mach_apicdef.h> | 43 | #include <mach_apicdef.h> |
44 | #include <mach_ipi.h> | 44 | #include <mach_ipi.h> |
45 | 45 | ||
46 | #include "io_ports.h" | ||
47 | |||
48 | /* | 46 | /* |
49 | * Sanity check | 47 | * Sanity check |
50 | */ | 48 | */ |
51 | #if (SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F | 49 | #if ((SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F) |
52 | # error SPURIOUS_APIC_VECTOR definition error | 50 | # error SPURIOUS_APIC_VECTOR definition error |
53 | #endif | 51 | #endif |
54 | 52 | ||
@@ -57,7 +55,7 @@ | |||
57 | * | 55 | * |
58 | * -1=force-disable, +1=force-enable | 56 | * -1=force-disable, +1=force-enable |
59 | */ | 57 | */ |
60 | static int enable_local_apic __initdata = 0; | 58 | static int enable_local_apic __initdata; |
61 | 59 | ||
62 | /* Local APIC timer verification ok */ | 60 | /* Local APIC timer verification ok */ |
63 | static int local_apic_timer_verify_ok; | 61 | static int local_apic_timer_verify_ok; |
@@ -101,6 +99,8 @@ static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | |||
101 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ | 99 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ |
102 | static int enabled_via_apicbase; | 100 | static int enabled_via_apicbase; |
103 | 101 | ||
102 | static unsigned long apic_phys; | ||
103 | |||
104 | /* | 104 | /* |
105 | * Get the LAPIC version | 105 | * Get the LAPIC version |
106 | */ | 106 | */ |
@@ -110,7 +110,7 @@ static inline int lapic_get_version(void) | |||
110 | } | 110 | } |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * Check, if the APIC is integrated or a seperate chip | 113 | * Check, if the APIC is integrated or a separate chip |
114 | */ | 114 | */ |
115 | static inline int lapic_is_integrated(void) | 115 | static inline int lapic_is_integrated(void) |
116 | { | 116 | { |
@@ -135,9 +135,9 @@ void apic_wait_icr_idle(void) | |||
135 | cpu_relax(); | 135 | cpu_relax(); |
136 | } | 136 | } |
137 | 137 | ||
138 | unsigned long safe_apic_wait_icr_idle(void) | 138 | u32 safe_apic_wait_icr_idle(void) |
139 | { | 139 | { |
140 | unsigned long send_status; | 140 | u32 send_status; |
141 | int timeout; | 141 | int timeout; |
142 | 142 | ||
143 | timeout = 0; | 143 | timeout = 0; |
@@ -154,7 +154,7 @@ unsigned long safe_apic_wait_icr_idle(void) | |||
154 | /** | 154 | /** |
155 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 | 155 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 |
156 | */ | 156 | */ |
157 | void enable_NMI_through_LVT0 (void * dummy) | 157 | void __cpuinit enable_NMI_through_LVT0(void) |
158 | { | 158 | { |
159 | unsigned int v = APIC_DM_NMI; | 159 | unsigned int v = APIC_DM_NMI; |
160 | 160 | ||
@@ -379,8 +379,10 @@ void __init setup_boot_APIC_clock(void) | |||
379 | */ | 379 | */ |
380 | if (local_apic_timer_disabled) { | 380 | if (local_apic_timer_disabled) { |
381 | /* No broadcast on UP ! */ | 381 | /* No broadcast on UP ! */ |
382 | if (num_possible_cpus() > 1) | 382 | if (num_possible_cpus() > 1) { |
383 | lapic_clockevent.mult = 1; | ||
383 | setup_APIC_timer(); | 384 | setup_APIC_timer(); |
385 | } | ||
384 | return; | 386 | return; |
385 | } | 387 | } |
386 | 388 | ||
@@ -434,7 +436,7 @@ void __init setup_boot_APIC_clock(void) | |||
434 | "with PM Timer: %ldms instead of 100ms\n", | 436 | "with PM Timer: %ldms instead of 100ms\n", |
435 | (long)res); | 437 | (long)res); |
436 | /* Correct the lapic counter value */ | 438 | /* Correct the lapic counter value */ |
437 | res = (((u64) delta ) * pm_100ms); | 439 | res = (((u64) delta) * pm_100ms); |
438 | do_div(res, deltapm); | 440 | do_div(res, deltapm); |
439 | printk(KERN_INFO "APIC delta adjusted to PM-Timer: " | 441 | printk(KERN_INFO "APIC delta adjusted to PM-Timer: " |
440 | "%lu (%ld)\n", (unsigned long) res, delta); | 442 | "%lu (%ld)\n", (unsigned long) res, delta); |
@@ -472,6 +474,19 @@ void __init setup_boot_APIC_clock(void) | |||
472 | 474 | ||
473 | local_apic_timer_verify_ok = 1; | 475 | local_apic_timer_verify_ok = 1; |
474 | 476 | ||
477 | /* | ||
478 | * Do a sanity check on the APIC calibration result | ||
479 | */ | ||
480 | if (calibration_result < (1000000 / HZ)) { | ||
481 | local_irq_enable(); | ||
482 | printk(KERN_WARNING | ||
483 | "APIC frequency too slow, disabling apic timer\n"); | ||
484 | /* No broadcast on UP ! */ | ||
485 | if (num_possible_cpus() > 1) | ||
486 | setup_APIC_timer(); | ||
487 | return; | ||
488 | } | ||
489 | |||
475 | /* We trust the pm timer based calibration */ | 490 | /* We trust the pm timer based calibration */ |
476 | if (!pm_referenced) { | 491 | if (!pm_referenced) { |
477 | apic_printk(APIC_VERBOSE, "... verify APIC timer\n"); | 492 | apic_printk(APIC_VERBOSE, "... verify APIC timer\n"); |
@@ -563,6 +578,9 @@ static void local_apic_timer_interrupt(void) | |||
563 | return; | 578 | return; |
564 | } | 579 | } |
565 | 580 | ||
581 | /* | ||
582 | * the NMI deadlock-detector uses this. | ||
583 | */ | ||
566 | per_cpu(irq_stat, cpu).apic_timer_irqs++; | 584 | per_cpu(irq_stat, cpu).apic_timer_irqs++; |
567 | 585 | ||
568 | evt->event_handler(evt); | 586 | evt->event_handler(evt); |
@@ -576,8 +594,7 @@ static void local_apic_timer_interrupt(void) | |||
576 | * [ if a single-CPU system runs an SMP kernel then we call the local | 594 | * [ if a single-CPU system runs an SMP kernel then we call the local |
577 | * interrupt as well. Thus we cannot inline the local irq ... ] | 595 | * interrupt as well. Thus we cannot inline the local irq ... ] |
578 | */ | 596 | */ |
579 | 597 | void smp_apic_timer_interrupt(struct pt_regs *regs) | |
580 | void fastcall smp_apic_timer_interrupt(struct pt_regs *regs) | ||
581 | { | 598 | { |
582 | struct pt_regs *old_regs = set_irq_regs(regs); | 599 | struct pt_regs *old_regs = set_irq_regs(regs); |
583 | 600 | ||
@@ -616,9 +633,14 @@ int setup_profiling_timer(unsigned int multiplier) | |||
616 | */ | 633 | */ |
617 | void clear_local_APIC(void) | 634 | void clear_local_APIC(void) |
618 | { | 635 | { |
619 | int maxlvt = lapic_get_maxlvt(); | 636 | int maxlvt; |
620 | unsigned long v; | 637 | u32 v; |
638 | |||
639 | /* APIC hasn't been mapped yet */ | ||
640 | if (!apic_phys) | ||
641 | return; | ||
621 | 642 | ||
643 | maxlvt = lapic_get_maxlvt(); | ||
622 | /* | 644 | /* |
623 | * Masking an LVT entry can trigger a local APIC error | 645 | * Masking an LVT entry can trigger a local APIC error |
624 | * if the vector is zero. Mask LVTERR first to prevent this. | 646 | * if the vector is zero. Mask LVTERR first to prevent this. |
@@ -976,7 +998,8 @@ void __cpuinit setup_local_APIC(void) | |||
976 | value |= APIC_LVT_LEVEL_TRIGGER; | 998 | value |= APIC_LVT_LEVEL_TRIGGER; |
977 | apic_write_around(APIC_LVT1, value); | 999 | apic_write_around(APIC_LVT1, value); |
978 | 1000 | ||
979 | if (integrated && !esr_disable) { /* !82489DX */ | 1001 | if (integrated && !esr_disable) { |
1002 | /* !82489DX */ | ||
980 | maxlvt = lapic_get_maxlvt(); | 1003 | maxlvt = lapic_get_maxlvt(); |
981 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ | 1004 | if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ |
982 | apic_write(APIC_ESR, 0); | 1005 | apic_write(APIC_ESR, 0); |
@@ -1020,7 +1043,7 @@ void __cpuinit setup_local_APIC(void) | |||
1020 | /* | 1043 | /* |
1021 | * Detect and initialize APIC | 1044 | * Detect and initialize APIC |
1022 | */ | 1045 | */ |
1023 | static int __init detect_init_APIC (void) | 1046 | static int __init detect_init_APIC(void) |
1024 | { | 1047 | { |
1025 | u32 h, l, features; | 1048 | u32 h, l, features; |
1026 | 1049 | ||
@@ -1077,7 +1100,7 @@ static int __init detect_init_APIC (void) | |||
1077 | printk(KERN_WARNING "Could not enable APIC!\n"); | 1100 | printk(KERN_WARNING "Could not enable APIC!\n"); |
1078 | return -1; | 1101 | return -1; |
1079 | } | 1102 | } |
1080 | set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); | 1103 | set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
1081 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; | 1104 | mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; |
1082 | 1105 | ||
1083 | /* The BIOS may have set up the APIC at some other address */ | 1106 | /* The BIOS may have set up the APIC at some other address */ |
@@ -1104,8 +1127,6 @@ no_apic: | |||
1104 | */ | 1127 | */ |
1105 | void __init init_apic_mappings(void) | 1128 | void __init init_apic_mappings(void) |
1106 | { | 1129 | { |
1107 | unsigned long apic_phys; | ||
1108 | |||
1109 | /* | 1130 | /* |
1110 | * If no local APIC can be found then set up a fake all | 1131 | * If no local APIC can be found then set up a fake all |
1111 | * zeroes page to simulate the local APIC and another | 1132 | * zeroes page to simulate the local APIC and another |
@@ -1164,10 +1185,10 @@ fake_ioapic_page: | |||
1164 | * This initializes the IO-APIC and APIC hardware if this is | 1185 | * This initializes the IO-APIC and APIC hardware if this is |
1165 | * a UP kernel. | 1186 | * a UP kernel. |
1166 | */ | 1187 | */ |
1167 | int __init APIC_init_uniprocessor (void) | 1188 | int __init APIC_init_uniprocessor(void) |
1168 | { | 1189 | { |
1169 | if (enable_local_apic < 0) | 1190 | if (enable_local_apic < 0) |
1170 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); | 1191 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
1171 | 1192 | ||
1172 | if (!smp_found_config && !cpu_has_apic) | 1193 | if (!smp_found_config && !cpu_has_apic) |
1173 | return -1; | 1194 | return -1; |
@@ -1179,7 +1200,7 @@ int __init APIC_init_uniprocessor (void) | |||
1179 | APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { | 1200 | APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { |
1180 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | 1201 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", |
1181 | boot_cpu_physical_apicid); | 1202 | boot_cpu_physical_apicid); |
1182 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); | 1203 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
1183 | return -1; | 1204 | return -1; |
1184 | } | 1205 | } |
1185 | 1206 | ||
@@ -1210,50 +1231,6 @@ int __init APIC_init_uniprocessor (void) | |||
1210 | } | 1231 | } |
1211 | 1232 | ||
1212 | /* | 1233 | /* |
1213 | * APIC command line parameters | ||
1214 | */ | ||
1215 | static int __init parse_lapic(char *arg) | ||
1216 | { | ||
1217 | enable_local_apic = 1; | ||
1218 | return 0; | ||
1219 | } | ||
1220 | early_param("lapic", parse_lapic); | ||
1221 | |||
1222 | static int __init parse_nolapic(char *arg) | ||
1223 | { | ||
1224 | enable_local_apic = -1; | ||
1225 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); | ||
1226 | return 0; | ||
1227 | } | ||
1228 | early_param("nolapic", parse_nolapic); | ||
1229 | |||
1230 | static int __init parse_disable_lapic_timer(char *arg) | ||
1231 | { | ||
1232 | local_apic_timer_disabled = 1; | ||
1233 | return 0; | ||
1234 | } | ||
1235 | early_param("nolapic_timer", parse_disable_lapic_timer); | ||
1236 | |||
1237 | static int __init parse_lapic_timer_c2_ok(char *arg) | ||
1238 | { | ||
1239 | local_apic_timer_c2_ok = 1; | ||
1240 | return 0; | ||
1241 | } | ||
1242 | early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok); | ||
1243 | |||
1244 | static int __init apic_set_verbosity(char *str) | ||
1245 | { | ||
1246 | if (strcmp("debug", str) == 0) | ||
1247 | apic_verbosity = APIC_DEBUG; | ||
1248 | else if (strcmp("verbose", str) == 0) | ||
1249 | apic_verbosity = APIC_VERBOSE; | ||
1250 | return 1; | ||
1251 | } | ||
1252 | |||
1253 | __setup("apic=", apic_set_verbosity); | ||
1254 | |||
1255 | |||
1256 | /* | ||
1257 | * Local APIC interrupts | 1234 | * Local APIC interrupts |
1258 | */ | 1235 | */ |
1259 | 1236 | ||
@@ -1306,7 +1283,7 @@ void smp_error_interrupt(struct pt_regs *regs) | |||
1306 | 6: Received illegal vector | 1283 | 6: Received illegal vector |
1307 | 7: Illegal register address | 1284 | 7: Illegal register address |
1308 | */ | 1285 | */ |
1309 | printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", | 1286 | printk(KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", |
1310 | smp_processor_id(), v , v1); | 1287 | smp_processor_id(), v , v1); |
1311 | irq_exit(); | 1288 | irq_exit(); |
1312 | } | 1289 | } |
@@ -1393,7 +1370,7 @@ void disconnect_bsp_APIC(int virt_wire_setup) | |||
1393 | value = apic_read(APIC_LVT0); | 1370 | value = apic_read(APIC_LVT0); |
1394 | value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | | 1371 | value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | |
1395 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | | 1372 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | |
1396 | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); | 1373 | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); |
1397 | value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; | 1374 | value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; |
1398 | value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); | 1375 | value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); |
1399 | apic_write_around(APIC_LVT0, value); | 1376 | apic_write_around(APIC_LVT0, value); |
@@ -1565,3 +1542,46 @@ device_initcall(init_lapic_sysfs); | |||
1565 | static void apic_pm_activate(void) { } | 1542 | static void apic_pm_activate(void) { } |
1566 | 1543 | ||
1567 | #endif /* CONFIG_PM */ | 1544 | #endif /* CONFIG_PM */ |
1545 | |||
1546 | /* | ||
1547 | * APIC command line parameters | ||
1548 | */ | ||
1549 | static int __init parse_lapic(char *arg) | ||
1550 | { | ||
1551 | enable_local_apic = 1; | ||
1552 | return 0; | ||
1553 | } | ||
1554 | early_param("lapic", parse_lapic); | ||
1555 | |||
1556 | static int __init parse_nolapic(char *arg) | ||
1557 | { | ||
1558 | enable_local_apic = -1; | ||
1559 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); | ||
1560 | return 0; | ||
1561 | } | ||
1562 | early_param("nolapic", parse_nolapic); | ||
1563 | |||
1564 | static int __init parse_disable_lapic_timer(char *arg) | ||
1565 | { | ||
1566 | local_apic_timer_disabled = 1; | ||
1567 | return 0; | ||
1568 | } | ||
1569 | early_param("nolapic_timer", parse_disable_lapic_timer); | ||
1570 | |||
1571 | static int __init parse_lapic_timer_c2_ok(char *arg) | ||
1572 | { | ||
1573 | local_apic_timer_c2_ok = 1; | ||
1574 | return 0; | ||
1575 | } | ||
1576 | early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok); | ||
1577 | |||
1578 | static int __init apic_set_verbosity(char *str) | ||
1579 | { | ||
1580 | if (strcmp("debug", str) == 0) | ||
1581 | apic_verbosity = APIC_DEBUG; | ||
1582 | else if (strcmp("verbose", str) == 0) | ||
1583 | apic_verbosity = APIC_VERBOSE; | ||
1584 | return 1; | ||
1585 | } | ||
1586 | __setup("apic=", apic_set_verbosity); | ||
1587 | |||