]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
clockevents: prevent mode mismatch on cpu online
authorThomas Gleixner <tglx@linutronix.de>
Mon, 22 Sep 2008 17:04:02 +0000 (19:04 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 23 Sep 2008 09:38:53 +0000 (11:38 +0200)
Impact: timer hang on CPU online observed on AMD C1E systems

When a CPU is brought online then the broadcast machinery can
be in the one shot state already. Check this and setup the timer
device of the new CPU in one shot mode so the broadcast code
can pick up the next_event value correctly.

Another AMD C1E oddity, as we switch to broadcast immediately and
not after the full bring up via the ACPI cpu idle code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h

index e2b66d1c8ca587bb30bfb6a11e90828a6103a5e6..bd7034542399f4badf620dbc5caf94578caf16ea 100644 (file)
@@ -575,4 +575,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Check, whether the broadcast device is in one shot mode
+ */
+int tick_broadcast_oneshot_active(void)
+{
+       return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
+}
+
 #endif
index b523d095decf02a603defd2057466aa80859720a..df12434b43ca09ec5ea9b0c48d679b842feddc9e 100644 (file)
@@ -109,7 +109,8 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
        if (!tick_device_is_functional(dev))
                return;
 
-       if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
+       if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
+           !tick_broadcast_oneshot_active()) {
                clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
        } else {
                unsigned long seq;
index e18014fadf953303a0e822edff601568f4ab6faf..55c3f4be6077c4ebe8c3281c41dd97f099716610 100644 (file)
@@ -35,6 +35,7 @@ extern void tick_broadcast_oneshot_control(unsigned long reason);
 extern void tick_broadcast_switch_to_oneshot(void);
 extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
 extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
+extern int tick_broadcast_oneshot_active(void);
 # else /* BROADCAST */
 static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
@@ -43,6 +44,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
 static inline void tick_broadcast_switch_to_oneshot(void) { }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
+static inline int tick_broadcast_oneshot_active(void) { return 0; }
 # endif /* !BROADCAST */
 
 #else /* !ONESHOT */