mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 22:23:14 -04:00
cpuidle / sleep: Use broadcast timer for states that stop local timer
Commit3810631332(PM / sleep: Re-implement suspend-to-idle handling) overlooked the fact that entering some sufficiently deep idle states by CPUs may cause their local timers to stop and in those cases it is necessary to switch over to a broadcast timer prior to entering the idle state. If the cpuidle driver in use does not provide the new ->enter_freeze callback for any of the idle states, that problem affects suspend-to-idle too, but it is not taken into account after the changes made by commit3810631332. Fix that by changing the definition of cpuidle_enter_freeze() and re-arranging of the code in cpuidle_idle_call(), so the former does not call cpuidle_enter() any more and the fallback case is handled by cpuidle_idle_call() directly. Fixes:3810631332(PM / sleep: Re-implement suspend-to-idle handling) Reported-and-tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
This commit is contained in:
parent
dfcacc154f
commit
ef2b22ac54
3 changed files with 58 additions and 51 deletions
|
|
@ -82,6 +82,7 @@ static void cpuidle_idle_call(void)
|
|||
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
|
||||
int next_state, entered_state;
|
||||
unsigned int broadcast;
|
||||
bool reflect;
|
||||
|
||||
/*
|
||||
* Check if the idle task must be rescheduled. If it is the
|
||||
|
|
@ -105,6 +106,9 @@ static void cpuidle_idle_call(void)
|
|||
*/
|
||||
rcu_idle_enter();
|
||||
|
||||
if (cpuidle_not_available(drv, dev))
|
||||
goto use_default;
|
||||
|
||||
/*
|
||||
* Suspend-to-idle ("freeze") is a system state in which all user space
|
||||
* has been frozen, all I/O devices have been suspended and the only
|
||||
|
|
@ -115,15 +119,22 @@ static void cpuidle_idle_call(void)
|
|||
* until a proper wakeup interrupt happens.
|
||||
*/
|
||||
if (idle_should_freeze()) {
|
||||
cpuidle_enter_freeze();
|
||||
goto exit_idle;
|
||||
}
|
||||
entered_state = cpuidle_enter_freeze(drv, dev);
|
||||
if (entered_state >= 0) {
|
||||
local_irq_enable();
|
||||
goto exit_idle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the cpuidle framework to choose a convenient idle state.
|
||||
* Fall back to the default arch idle method on errors.
|
||||
*/
|
||||
next_state = cpuidle_select(drv, dev);
|
||||
reflect = false;
|
||||
next_state = cpuidle_find_deepest_state(drv, dev);
|
||||
} else {
|
||||
reflect = true;
|
||||
/*
|
||||
* Ask the cpuidle framework to choose a convenient idle state.
|
||||
*/
|
||||
next_state = cpuidle_select(drv, dev);
|
||||
}
|
||||
/* Fall back to the default arch idle method on errors. */
|
||||
if (next_state < 0)
|
||||
goto use_default;
|
||||
|
||||
|
|
@ -170,7 +181,8 @@ static void cpuidle_idle_call(void)
|
|||
/*
|
||||
* Give the governor an opportunity to reflect on the outcome
|
||||
*/
|
||||
cpuidle_reflect(dev, entered_state);
|
||||
if (reflect)
|
||||
cpuidle_reflect(dev, entered_state);
|
||||
|
||||
exit_idle:
|
||||
__current_set_polling();
|
||||
|
|
|
|||
Loading…
Reference in a new issue