mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
Merge tag 'pm-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki:
"These fix an idle loop issue exposed by recent changes and a race
condition related to device removal in the runtime PM core code:
- Consolidate the handling of two special cases in the idle loop that
occur when only one CPU idle state is present (Rafael Wysocki)
- Fix a race condition related to device removal in the runtime PM
core code that may cause a stale device object pointer to be
dereferenced (Bart Van Assche)"
* tag 'pm-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PM: runtime: Fix a race condition related to device removal
sched: idle: Consolidate the handling of two special cases
This commit is contained in:
@@ -1895,6 +1895,7 @@ void pm_runtime_reinit(struct device *dev)
|
|||||||
void pm_runtime_remove(struct device *dev)
|
void pm_runtime_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
__pm_runtime_disable(dev, false);
|
__pm_runtime_disable(dev, false);
|
||||||
|
flush_work(&dev->power.work);
|
||||||
pm_runtime_reinit(dev);
|
pm_runtime_reinit(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,14 @@ static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|||||||
return cpuidle_enter(drv, dev, next_state);
|
return cpuidle_enter(drv, dev, next_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void idle_call_stop_or_retain_tick(bool stop_tick)
|
||||||
|
{
|
||||||
|
if (stop_tick || tick_nohz_tick_stopped())
|
||||||
|
tick_nohz_idle_stop_tick();
|
||||||
|
else
|
||||||
|
tick_nohz_idle_retain_tick();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpuidle_idle_call - the main idle function
|
* cpuidle_idle_call - the main idle function
|
||||||
*
|
*
|
||||||
@@ -170,7 +178,7 @@ static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|||||||
* set, and it returns with polling set. If it ever stops polling, it
|
* set, and it returns with polling set. If it ever stops polling, it
|
||||||
* must clear the polling bit.
|
* must clear the polling bit.
|
||||||
*/
|
*/
|
||||||
static void cpuidle_idle_call(void)
|
static void cpuidle_idle_call(bool stop_tick)
|
||||||
{
|
{
|
||||||
struct cpuidle_device *dev = cpuidle_get_device();
|
struct cpuidle_device *dev = cpuidle_get_device();
|
||||||
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
|
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
|
||||||
@@ -186,7 +194,7 @@ static void cpuidle_idle_call(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpuidle_not_available(drv, dev)) {
|
if (cpuidle_not_available(drv, dev)) {
|
||||||
tick_nohz_idle_stop_tick();
|
idle_call_stop_or_retain_tick(stop_tick);
|
||||||
|
|
||||||
default_idle_call();
|
default_idle_call();
|
||||||
goto exit_idle;
|
goto exit_idle;
|
||||||
@@ -222,17 +230,19 @@ static void cpuidle_idle_call(void)
|
|||||||
next_state = cpuidle_find_deepest_state(drv, dev, max_latency_ns);
|
next_state = cpuidle_find_deepest_state(drv, dev, max_latency_ns);
|
||||||
call_cpuidle(drv, dev, next_state);
|
call_cpuidle(drv, dev, next_state);
|
||||||
} else if (drv->state_count > 1) {
|
} else if (drv->state_count > 1) {
|
||||||
bool stop_tick = true;
|
/*
|
||||||
|
* stop_tick is expected to be true by default by cpuidle
|
||||||
|
* governors, which allows them to select idle states with
|
||||||
|
* target residency above the tick period length.
|
||||||
|
*/
|
||||||
|
stop_tick = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ask the cpuidle framework to choose a convenient idle state.
|
* Ask the cpuidle framework to choose a convenient idle state.
|
||||||
*/
|
*/
|
||||||
next_state = cpuidle_select(drv, dev, &stop_tick);
|
next_state = cpuidle_select(drv, dev, &stop_tick);
|
||||||
|
|
||||||
if (stop_tick || tick_nohz_tick_stopped())
|
idle_call_stop_or_retain_tick(stop_tick);
|
||||||
tick_nohz_idle_stop_tick();
|
|
||||||
else
|
|
||||||
tick_nohz_idle_retain_tick();
|
|
||||||
|
|
||||||
entered_state = call_cpuidle(drv, dev, next_state);
|
entered_state = call_cpuidle(drv, dev, next_state);
|
||||||
/*
|
/*
|
||||||
@@ -240,7 +250,7 @@ static void cpuidle_idle_call(void)
|
|||||||
*/
|
*/
|
||||||
cpuidle_reflect(dev, entered_state);
|
cpuidle_reflect(dev, entered_state);
|
||||||
} else {
|
} else {
|
||||||
tick_nohz_idle_retain_tick();
|
idle_call_stop_or_retain_tick(stop_tick);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is only a single idle state (or none), there is
|
* If there is only a single idle state (or none), there is
|
||||||
@@ -268,6 +278,7 @@ exit_idle:
|
|||||||
static void do_idle(void)
|
static void do_idle(void)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
bool got_tick = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we need to update blocked load
|
* Check if we need to update blocked load
|
||||||
@@ -338,8 +349,9 @@ static void do_idle(void)
|
|||||||
tick_nohz_idle_restart_tick();
|
tick_nohz_idle_restart_tick();
|
||||||
cpu_idle_poll();
|
cpu_idle_poll();
|
||||||
} else {
|
} else {
|
||||||
cpuidle_idle_call();
|
cpuidle_idle_call(got_tick);
|
||||||
}
|
}
|
||||||
|
got_tick = tick_nohz_idle_got_tick();
|
||||||
arch_cpu_idle_exit();
|
arch_cpu_idle_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user