clockevents: introduce force broadcast notifier
authorThomas Gleixner <tglx@linutronix.de>
Sun, 14 Oct 2007 20:57:45 +0000 (22:57 +0200)
committerThomas Gleixner <tglx@inhelltoy.tec.linutronix.de>
Sun, 14 Oct 2007 20:57:45 +0000 (22:57 +0200)
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>
include/linux/clockchips.h
kernel/time/tick-broadcast.c
kernel/time/tick-common.c

index d2ddea926895378effcf67862b5a875910018c52..c33b0dc28e4db5de75df8a2419c128d22c8e29d9 100644 (file)
@@ -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,
index 298bc7c6f09f292487046a2969004ca38a0ce7d2..fc3fc79b3d593c7e4c5e170431a6204228f2e697 100644 (file)
@@ -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))
index 3f3ae39078306264182734d35df7271b1c74dc48..1bea399a9ef009293958a8b37ac90dd5869fac40 100644 (file)
@@ -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;