Commit 1595f452f3d8daa066bfd3ba4120754bed3329e1

Authored by Thomas Gleixner
Committed by Thomas Gleixner
1 parent b097976e8d

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>

Showing 3 changed files with 25 additions and 6 deletions Side-by-side Diff

include/linux/clockchips.h
... ... @@ -31,6 +31,7 @@
31 31 CLOCK_EVT_NOTIFY_ADD,
32 32 CLOCK_EVT_NOTIFY_BROADCAST_ON,
33 33 CLOCK_EVT_NOTIFY_BROADCAST_OFF,
  34 + CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
34 35 CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
35 36 CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
36 37 CLOCK_EVT_NOTIFY_SUSPEND,
kernel/time/tick-broadcast.c
... ... @@ -217,26 +217,43 @@
217 217 bc = tick_broadcast_device.evtdev;
218 218  
219 219 /*
220   - * Is the device in broadcast mode forever or is it not
221   - * affected by the powerstate ?
  220 + * Is the device not affected by the powerstate ?
222 221 */
223   - if (!dev || !tick_device_is_functional(dev) ||
224   - !(dev->features & CLOCK_EVT_FEAT_C3STOP))
  222 + if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
225 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 243 if (!cpu_isset(cpu, tick_broadcast_mask)) {
229 244 cpu_set(cpu, tick_broadcast_mask);
230 245 if (td->mode == TICKDEV_MODE_PERIODIC)
231 246 clockevents_set_mode(dev,
232 247 CLOCK_EVT_MODE_SHUTDOWN);
233 248 }
234   - } else {
  249 + break;
  250 + case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
235 251 if (cpu_isset(cpu, tick_broadcast_mask)) {
236 252 cpu_clear(cpu, tick_broadcast_mask);
237 253 if (td->mode == TICKDEV_MODE_PERIODIC)
238 254 tick_setup_periodic(dev, 0);
239 255 }
  256 + break;
240 257 }
241 258  
242 259 if (cpus_empty(tick_broadcast_mask))
kernel/time/tick-common.c
... ... @@ -345,6 +345,7 @@
345 345  
346 346 case CLOCK_EVT_NOTIFY_BROADCAST_ON:
347 347 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
  348 + case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
348 349 tick_broadcast_on_off(reason, dev);
349 350 break;
350 351