diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-02-17 17:39:39 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-04 17:08:27 -0500 |
commit | 4782e1654bdbd30cf307da090b3c4f70157477cb (patch) | |
tree | 72305fb2e3fff719330f5302dda785c044e25575 | |
parent | da863cddd831b0f4bf2d067f8b75254f1be94590 (diff) |
PM / Sleep: Make __pm_stay_awake() delete wakeup source timers
If __pm_stay_awake() is called after __pm_wakeup_event() for the same
wakep source object before its timer expires, it won't cancel the
timer, so the wakeup source will be deactivated from the timer
function as scheduled by __pm_wakeup_event(). In that case
__pm_stay_awake() doesn't have any effect beyond incrementing
the wakeup source's event_count field, although it should cancel
the timer and make the wakeup source stay active until __pm_relax()
is called for it.
To fix this problem make __pm_stay_awake() delete the wakeup source's
timer and ensure that it won't be deactivated from the timer funtion
afterwards by clearing its timer_expires field.
Reported-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | drivers/base/power/wakeup.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index b38bb9afb719..7c5ab70b9ef3 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c | |||
@@ -344,7 +344,6 @@ static void wakeup_source_activate(struct wakeup_source *ws) | |||
344 | { | 344 | { |
345 | ws->active = true; | 345 | ws->active = true; |
346 | ws->active_count++; | 346 | ws->active_count++; |
347 | ws->timer_expires = jiffies; | ||
348 | ws->last_time = ktime_get(); | 347 | ws->last_time = ktime_get(); |
349 | 348 | ||
350 | /* Increment the counter of events in progress. */ | 349 | /* Increment the counter of events in progress. */ |
@@ -365,9 +364,14 @@ void __pm_stay_awake(struct wakeup_source *ws) | |||
365 | return; | 364 | return; |
366 | 365 | ||
367 | spin_lock_irqsave(&ws->lock, flags); | 366 | spin_lock_irqsave(&ws->lock, flags); |
367 | |||
368 | ws->event_count++; | 368 | ws->event_count++; |
369 | if (!ws->active) | 369 | if (!ws->active) |
370 | wakeup_source_activate(ws); | 370 | wakeup_source_activate(ws); |
371 | |||
372 | del_timer(&ws->timer); | ||
373 | ws->timer_expires = 0; | ||
374 | |||
371 | spin_unlock_irqrestore(&ws->lock, flags); | 375 | spin_unlock_irqrestore(&ws->lock, flags); |
372 | } | 376 | } |
373 | EXPORT_SYMBOL_GPL(__pm_stay_awake); | 377 | EXPORT_SYMBOL_GPL(__pm_stay_awake); |
@@ -541,7 +545,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) | |||
541 | if (!expires) | 545 | if (!expires) |
542 | expires = 1; | 546 | expires = 1; |
543 | 547 | ||
544 | if (time_after(expires, ws->timer_expires)) { | 548 | if (!ws->timer_expires || time_after(expires, ws->timer_expires)) { |
545 | mod_timer(&ws->timer, expires); | 549 | mod_timer(&ws->timer, expires); |
546 | ws->timer_expires = expires; | 550 | ws->timer_expires = expires; |
547 | } | 551 | } |