aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-10-14 16:57:45 -0400
committerThomas Gleixner <tglx@inhelltoy.tec.linutronix.de>2007-10-14 16:57:45 -0400
commit89039b37be7c34194db0e72f956a5f02cfa30941 (patch)
treec3ac037a5be066b16d4c44efd432caee60b1540c /arch
parent3ac508be76bf4ef5861365d9f337f990d523be8f (diff)
x86: force timer broadcast on late AMD C1E detection
The 64bit SMP bootup is slightly different to the 32bit one. It enables the boot CPU local APIC timer before all CPUs are brought up. Some AMD C1E systems have the C1E feature flag only set in the secondary CPU. Due to the early enable of the boot CPU local APIC timer the APIC timer is registered as a fully functional device. When we detect the wreckage during the bringup of the secondary CPU, we need to force the boot CPU into broadcast mode. Check the C1E caused APIC timer disable, when the secondary APIC timer is initialized. If the boot CPU APIC timer was registered as a functional clock event device, then fix this up and utilize the CLOCK_EVT_NOTIFY_BROADCAST_FORCE mechanism to force the already registered boot CPU APIC timer into broadcast mode. Tested by force injecting the failure mode. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/apic_64.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 395928de28ea..09b82093bc75 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -964,8 +964,34 @@ void __init setup_boot_APIC_clock (void)
964 setup_APIC_timer(); 964 setup_APIC_timer();
965} 965}
966 966
967/*
968 * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
969 * C1E flag only in the secondary CPU, so when we detect the wreckage
970 * we already have enabled the boot CPU local apic timer. Check, if
971 * disable_apic_timer is set and the DUMMY flag is cleared. If yes,
972 * set the DUMMY flag again and force the broadcast mode in the
973 * clockevents layer.
974 */
975void __cpuinit check_boot_apic_timer_broadcast(void)
976{
977 struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id);
978
979 if (!disable_apic_timer ||
980 (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
981 return;
982
983 printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
984 lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
985 levt->features |= CLOCK_EVT_FEAT_DUMMY;
986
987 local_irq_enable();
988 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id);
989 local_irq_disable();
990}
991
967void __cpuinit setup_secondary_APIC_clock(void) 992void __cpuinit setup_secondary_APIC_clock(void)
968{ 993{
994 check_boot_apic_timer_broadcast();
969 setup_APIC_timer(); 995 setup_APIC_timer();
970} 996}
971 997