diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 16:47:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 16:47:05 -0700 |
commit | 59d66ce238e573fe3369427e91a8291f2cf67891 (patch) | |
tree | 2d6be8e29e7cceaaa2d1ce9a8957bda103467a7a | |
parent | 5c0d6b34d6ee11ff979cbdac9a59b47a74cb9f43 (diff) | |
parent | 89039b37be7c34194db0e72f956a5f02cfa30941 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-x86
* git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-x86:
x86: force timer broadcast on late AMD C1E detection
x86: move local APIC timer init to the end of start_secondary()
clockevents: introduce force broadcast notifier
x86: fix missing include for vsyscall
-rw-r--r-- | arch/x86/kernel/alternative.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/apic_64.c | 26 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot_64.c | 7 | ||||
-rw-r--r-- | include/linux/clockchips.h | 1 | ||||
-rw-r--r-- | kernel/time/tick-broadcast.c | 29 | ||||
-rw-r--r-- | kernel/time/tick-common.c | 1 |
6 files changed, 54 insertions, 11 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index bd72d94e713..11b03d3c6fd 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -10,6 +10,7 @@ #include <asm/pgtable.h> #include <asm/mce.h> #include <asm/nmi.h> +#include <asm/vsyscall.h> #define MAX_PATCH_LEN (255-1) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 395928de28e..09b82093bc7 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) setup_APIC_timer(); } +/* + * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the + * C1E flag only in the secondary CPU, so when we detect the wreckage + * we already have enabled the boot CPU local apic timer. Check, if + * disable_apic_timer is set and the DUMMY flag is cleared. If yes, + * set the DUMMY flag again and force the broadcast mode in the + * clockevents layer. + */ +void __cpuinit check_boot_apic_timer_broadcast(void) +{ + struct clock_event_device *levt = &per_cpu(lapic_events, boot_cpu_id); + + if (!disable_apic_timer || + (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY)) + return; + + printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n"); + lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY; + levt->features |= CLOCK_EVT_FEAT_DUMMY; + + local_irq_enable(); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, &boot_cpu_id); + local_irq_disable(); +} + void __cpuinit setup_secondary_APIC_clock(void) { + check_boot_apic_timer_broadcast(); setup_APIC_timer(); } diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c index 57ccf7cb6b9..720a7d1f886 100644 --- a/arch/x86/kernel/smpboot_64.c +++ b/arch/x86/kernel/smpboot_64.c @@ -335,11 +335,6 @@ void __cpuinit start_secondary(void) */ check_tsc_sync_target(); - Dprintk("cpu %d: setting up apic clock\n", smp_processor_id()); - setup_secondary_APIC_clock(); - - Dprintk("cpu %d: enabling apic timer\n", smp_processor_id()); - if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); enable_NMI_through_LVT0(NULL); @@ -374,6 +369,8 @@ void __cpuinit start_secondary(void) unlock_ipi_call_lock(); + setup_secondary_APIC_clock(); + cpu_idle(); } diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index d2ddea92689..c33b0dc28e4 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -31,6 +31,7 @@ enum clock_event_nofitiers { CLOCK_EVT_NOTIFY_ADD, CLOCK_EVT_NOTIFY_BROADCAST_ON, CLOCK_EVT_NOTIFY_BROADCAST_OFF, + CLOCK_EVT_NOTIFY_BROADCAST_FORCE, CLOCK_EVT_NOTIFY_BROADCAST_ENTER, CLOCK_EVT_NOTIFY_BROADCAST_EXIT, CLOCK_EVT_NOTIFY_SUSPEND, diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 298bc7c6f09..fc3fc79b3d5 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -217,26 +217,43 @@ static void tick_do_broadcast_on_off(void *why) bc = tick_broadcast_device.evtdev; /* - * Is the device in broadcast mode forever or is it not - * affected by the powerstate ? + * Is the device not affected by the powerstate ? */ - if (!dev || !tick_device_is_functional(dev) || - !(dev->features & CLOCK_EVT_FEAT_C3STOP)) + if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP)) goto out; - if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) { + /* + * Defect device ? + */ + if (!tick_device_is_functional(dev)) { + /* + * AMD C1E wreckage fixup: + * + * Device was registered functional in the first + * place. Now the secondary CPU detected the C1E + * misfeature and notifies us to fix it up + */ + if (*reason != CLOCK_EVT_NOTIFY_BROADCAST_FORCE) + goto out; + } + + switch (*reason) { + case CLOCK_EVT_NOTIFY_BROADCAST_ON: + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: if (!cpu_isset(cpu, tick_broadcast_mask)) { cpu_set(cpu, tick_broadcast_mask); if (td->mode == TICKDEV_MODE_PERIODIC) clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN); } - } else { + break; + case CLOCK_EVT_NOTIFY_BROADCAST_OFF: if (cpu_isset(cpu, tick_broadcast_mask)) { cpu_clear(cpu, tick_broadcast_mask); if (td->mode == TICKDEV_MODE_PERIODIC) tick_setup_periodic(dev, 0); } + break; } if (cpus_empty(tick_broadcast_mask)) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 3f3ae390783..1bea399a9ef 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -345,6 +345,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason, case CLOCK_EVT_NOTIFY_BROADCAST_ON: case CLOCK_EVT_NOTIFY_BROADCAST_OFF: + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: tick_broadcast_on_off(reason, dev); break; |