diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-09-16 11:32:50 -0700 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-09-16 13:47:02 -0700 |
commit | 2344abbcbdb82140050e8be29d3d55e4f6fe860b (patch) | |
tree | 46c1842fc2a47aa4d7ee0c2c558f54bc50772b69 /kernel/time/clockevents.c | |
parent | f1926ce63b996b42772b39e4b47bb4ef4ba748b4 (diff) | |
download | lwn-2344abbcbdb82140050e8be29d3d55e4f6fe860b.tar.gz lwn-2344abbcbdb82140050e8be29d3d55e4f6fe860b.zip |
clockevents: make device shutdown robust
The device shut down does not cleanup the next_event variable of the
clock event device. So when the device is reactivated the possible
stale next_event value can prevent the device to be reprogrammed as it
claims to wait on a event already.
This is the root cause of the resurfacing suspend/resume problem,
where systems need key press to come back to life.
Fix this by setting next_event to KTIME_MAX when the device is shut
down. Use a separate function for shutdown which takes care of that
and only keep the direct set mode call in the broadcast code, where we
can not touch the next_event value.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/clockevents.c')
-rw-r--r-- | kernel/time/clockevents.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 1876b526c778..f8d968063cea 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -72,6 +72,16 @@ void clockevents_set_mode(struct clock_event_device *dev, } /** + * clockevents_shutdown - shutdown the device and clear next_event + * @dev: device to shutdown + */ +void clockevents_shutdown(struct clock_event_device *dev) +{ + clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN); + dev->next_event.tv64 = KTIME_MAX; +} + +/** * clockevents_program_event - Reprogram the clock event device. * @expires: absolute expiry time (monotonic clock) * @@ -206,7 +216,7 @@ void clockevents_exchange_device(struct clock_event_device *old, if (new) { BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED); - clockevents_set_mode(new, CLOCK_EVT_MODE_SHUTDOWN); + clockevents_shutdown(new); } local_irq_restore(flags); } |