diff options
Diffstat (limited to 'arch/x86/kernel/apic_32.c')
-rw-r--r-- | arch/x86/kernel/apic_32.c | 69 |
1 files changed, 39 insertions, 30 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 6cb8aaaf10f5..9e8702eebd46 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -251,6 +251,9 @@ int lapic_get_maxlvt(void) | |||
251 | * this function twice on the boot CPU, once with a bogus timeout | 251 | * this function twice on the boot CPU, once with a bogus timeout |
252 | * value, second time for real. The other (noncalibrating) CPUs | 252 | * value, second time for real. The other (noncalibrating) CPUs |
253 | * call this function only once, with the real, calibrated value. | 253 | * call this function only once, with the real, calibrated value. |
254 | * | ||
255 | * We do reads before writes even if unnecessary, to get around the | ||
256 | * P5 APIC double write bug. | ||
254 | */ | 257 | */ |
255 | static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | 258 | static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) |
256 | { | 259 | { |
@@ -280,6 +283,36 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
280 | } | 283 | } |
281 | 284 | ||
282 | /* | 285 | /* |
286 | * Setup extended LVT, AMD specific (K8, family 10h) | ||
287 | * | ||
288 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and | ||
289 | * MCE interrupts are supported. Thus MCE offset must be set to 0. | ||
290 | */ | ||
291 | |||
292 | #define APIC_EILVT_LVTOFF_MCE 0 | ||
293 | #define APIC_EILVT_LVTOFF_IBS 1 | ||
294 | |||
295 | static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask) | ||
296 | { | ||
297 | unsigned long reg = (lvt_off << 4) + APIC_EILVT0; | ||
298 | unsigned int v = (mask << 16) | (msg_type << 8) | vector; | ||
299 | |||
300 | apic_write(reg, v); | ||
301 | } | ||
302 | |||
303 | u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask) | ||
304 | { | ||
305 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask); | ||
306 | return APIC_EILVT_LVTOFF_MCE; | ||
307 | } | ||
308 | |||
309 | u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask) | ||
310 | { | ||
311 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); | ||
312 | return APIC_EILVT_LVTOFF_IBS; | ||
313 | } | ||
314 | |||
315 | /* | ||
283 | * Program the next event, relative to now | 316 | * Program the next event, relative to now |
284 | */ | 317 | */ |
285 | static int lapic_next_event(unsigned long delta, | 318 | static int lapic_next_event(unsigned long delta, |
@@ -298,7 +331,7 @@ static void lapic_timer_setup(enum clock_event_mode mode, | |||
298 | unsigned long flags; | 331 | unsigned long flags; |
299 | unsigned int v; | 332 | unsigned int v; |
300 | 333 | ||
301 | /* Lapic used for broadcast ? */ | 334 | /* Lapic used as dummy for broadcast ? */ |
302 | if (evt->features & CLOCK_EVT_FEAT_DUMMY) | 335 | if (evt->features & CLOCK_EVT_FEAT_DUMMY) |
303 | return; | 336 | return; |
304 | 337 | ||
@@ -681,35 +714,6 @@ int setup_profiling_timer(unsigned int multiplier) | |||
681 | } | 714 | } |
682 | 715 | ||
683 | /* | 716 | /* |
684 | * Setup extended LVT, AMD specific (K8, family 10h) | ||
685 | * | ||
686 | * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and | ||
687 | * MCE interrupts are supported. Thus MCE offset must be set to 0. | ||
688 | */ | ||
689 | |||
690 | #define APIC_EILVT_LVTOFF_MCE 0 | ||
691 | #define APIC_EILVT_LVTOFF_IBS 1 | ||
692 | |||
693 | static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask) | ||
694 | { | ||
695 | unsigned long reg = (lvt_off << 4) + APIC_EILVT0; | ||
696 | unsigned int v = (mask << 16) | (msg_type << 8) | vector; | ||
697 | apic_write(reg, v); | ||
698 | } | ||
699 | |||
700 | u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask) | ||
701 | { | ||
702 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask); | ||
703 | return APIC_EILVT_LVTOFF_MCE; | ||
704 | } | ||
705 | |||
706 | u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask) | ||
707 | { | ||
708 | setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); | ||
709 | return APIC_EILVT_LVTOFF_IBS; | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * Local APIC start and shutdown | 717 | * Local APIC start and shutdown |
714 | */ | 718 | */ |
715 | 719 | ||
@@ -1542,6 +1546,11 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1542 | #ifdef CONFIG_PM | 1546 | #ifdef CONFIG_PM |
1543 | 1547 | ||
1544 | static struct { | 1548 | static struct { |
1549 | /* | ||
1550 | * 'active' is true if the local APIC was enabled by us and | ||
1551 | * not the BIOS; this signifies that we are also responsible | ||
1552 | * for disabling it before entering apm/acpi suspend | ||
1553 | */ | ||
1545 | int active; | 1554 | int active; |
1546 | /* r/w apic fields */ | 1555 | /* r/w apic fields */ |
1547 | unsigned int apic_id; | 1556 | unsigned int apic_id; |