aboutsummaryrefslogtreecommitdiffstats
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
commit1595f452f3d8daa066bfd3ba4120754bed3329e1 (patch)
tree86fa49114c03e0f2dc7c7987b2a5be6adace140f
parentb097976e8d6f6e6220161fa6b72b0798ce9f4f4c (diff)
clockevents: introduce force broadcast notifier
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. Add a new notifier reason and implement the force broadcast in the clock events layer. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/clockchips.h1
-rw-r--r--kernel/time/tick-broadcast.c29
-rw-r--r--kernel/time/tick-common.c1
3 files changed, 25 insertions, 6 deletions
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