aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-14 19:47:05 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-14 19:47:05 -0400
commit59d66ce238e573fe3369427e91a8291f2cf67891 (patch)
tree2d6be8e29e7cceaaa2d1ce9a8957bda103467a7a
parent5c0d6b34d6ee11ff979cbdac9a59b47a74cb9f43 (diff)
parent89039b37be7c34194db0e72f956a5f02cfa30941 (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.c1
-rw-r--r--arch/x86/kernel/apic_64.c26
-rw-r--r--arch/x86/kernel/smpboot_64.c7
-rw-r--r--include/linux/clockchips.h1
-rw-r--r--kernel/time/tick-broadcast.c29
-rw-r--r--kernel/time/tick-common.c1
6 files changed, 54 insertions, 11 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index bd72d94e713e..11b03d3c6fda 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -10,6 +10,7 @@
10#include <asm/pgtable.h> 10#include <asm/pgtable.h>
11#include <asm/mce.h> 11#include <asm/mce.h>
12#include <asm/nmi.h> 12#include <asm/nmi.h>
13#include <asm/vsyscall.h>
13 14
14#define MAX_PATCH_LEN (255-1) 15#define MAX_PATCH_LEN (255-1)
15 16
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
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 57ccf7cb6b91..720a7d1f8862 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -335,11 +335,6 @@ void __cpuinit start_secondary(void)
335 */ 335 */
336 check_tsc_sync_target(); 336 check_tsc_sync_target();
337 337
338 Dprintk("cpu %d: setting up apic clock\n", smp_processor_id());
339 setup_secondary_APIC_clock();
340
341 Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
342
343 if (nmi_watchdog == NMI_IO_APIC) { 338 if (nmi_watchdog == NMI_IO_APIC) {
344 disable_8259A_irq(0); 339 disable_8259A_irq(0);
345 enable_NMI_through_LVT0(NULL); 340 enable_NMI_through_LVT0(NULL);
@@ -374,6 +369,8 @@ void __cpuinit start_secondary(void)
374 369
375 unlock_ipi_call_lock(); 370 unlock_ipi_call_lock();
376 371
372 setup_secondary_APIC_clock();
373
377 cpu_idle(); 374 cpu_idle();
378} 375}
379 376
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index d2ddea926895..c33b0dc28e4d 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -31,6 +31,7 @@ enum clock_event_nofitiers {
31 CLOCK_EVT_NOTIFY_ADD, 31 CLOCK_EVT_NOTIFY_ADD,
32 CLOCK_EVT_NOTIFY_BROADCAST_ON, 32 CLOCK_EVT_NOTIFY_BROADCAST_ON,
33 CLOCK_EVT_NOTIFY_BROADCAST_OFF, 33 CLOCK_EVT_NOTIFY_BROADCAST_OFF,
34 CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
34 CLOCK_EVT_NOTIFY_BROADCAST_ENTER, 35 CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
35 CLOCK_EVT_NOTIFY_BROADCAST_EXIT, 36 CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
36 CLOCK_EVT_NOTIFY_SUSPEND, 37 CLOCK_EVT_NOTIFY_SUSPEND,
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 298bc7c6f09f..fc3fc79b3d59 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)
217 bc = tick_broadcast_device.evtdev; 217 bc = tick_broadcast_device.evtdev;
218 218
219 /* 219 /*
220 * Is the device in broadcast mode forever or is it not 220 * Is the device not affected by the powerstate ?
221 * affected by the powerstate ?
222 */ 221 */
223 if (!dev || !tick_device_is_functional(dev) || 222 if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
224 !(dev->features & CLOCK_EVT_FEAT_C3STOP))
225 goto out; 223 goto out;
226 224
227 if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) { 225 /*
226 * Defect device ?
227 */
228 if (!tick_device_is_functional(dev)) {
229 /*
230 * AMD C1E wreckage fixup:
231 *
232 * Device was registered functional in the first
233 * place. Now the secondary CPU detected the C1E
234 * misfeature and notifies us to fix it up
235 */
236 if (*reason != CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
237 goto out;
238 }
239
240 switch (*reason) {
241 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
242 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
228 if (!cpu_isset(cpu, tick_broadcast_mask)) { 243 if (!cpu_isset(cpu, tick_broadcast_mask)) {
229 cpu_set(cpu, tick_broadcast_mask); 244 cpu_set(cpu, tick_broadcast_mask);
230 if (td->mode == TICKDEV_MODE_PERIODIC) 245 if (td->mode == TICKDEV_MODE_PERIODIC)
231 clockevents_set_mode(dev, 246 clockevents_set_mode(dev,
232 CLOCK_EVT_MODE_SHUTDOWN); 247 CLOCK_EVT_MODE_SHUTDOWN);
233 } 248 }
234 } else { 249 break;
250 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
235 if (cpu_isset(cpu, tick_broadcast_mask)) { 251 if (cpu_isset(cpu, tick_broadcast_mask)) {
236 cpu_clear(cpu, tick_broadcast_mask); 252 cpu_clear(cpu, tick_broadcast_mask);
237 if (td->mode == TICKDEV_MODE_PERIODIC) 253 if (td->mode == TICKDEV_MODE_PERIODIC)
238 tick_setup_periodic(dev, 0); 254 tick_setup_periodic(dev, 0);
239 } 255 }
256 break;
240 } 257 }
241 258
242 if (cpus_empty(tick_broadcast_mask)) 259 if (cpus_empty(tick_broadcast_mask))
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 3f3ae3907830..1bea399a9ef0 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,
345 345
346 case CLOCK_EVT_NOTIFY_BROADCAST_ON: 346 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
347 case CLOCK_EVT_NOTIFY_BROADCAST_OFF: 347 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
348 case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
348 tick_broadcast_on_off(reason, dev); 349 tick_broadcast_on_off(reason, dev);
349 break; 350 break;
350 351