pm: Make pm_power_state_force multicore aware
Change pm_power_state_force to receive which cpu the state should be forced. Also, it changed the API behavior to force the given state only when the idle thread for that core is executed. In a multicore environment force arbitrarily a core to suspend is not safe because the kernel cannot infer what that cpu is running and how it impacts the overall system, for example, if it is holding a lock that is required by a thread that is running in another cpu. Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
This commit is contained in:
parent
52301d97c5
commit
4998c52ba8
5 changed files with 23 additions and 33 deletions
|
@ -69,14 +69,15 @@ struct pm_notifier {
|
|||
* @brief Force usage of given power state.
|
||||
*
|
||||
* This function overrides decision made by PM policy forcing
|
||||
* usage of given power state immediately.
|
||||
* usage of given power state upon next entry of the idle thread.
|
||||
*
|
||||
* @note This function can only run in thread context
|
||||
*
|
||||
* @param cpu CPU index.
|
||||
* @param info Power state which should be used in the ongoing
|
||||
* suspend operation.
|
||||
*/
|
||||
void pm_power_state_force(struct pm_state_info info);
|
||||
bool pm_power_state_force(uint8_t cpu, struct pm_state_info info);
|
||||
|
||||
/**
|
||||
* @brief Register a power management notifier
|
||||
|
|
|
@ -90,7 +90,7 @@ void main(void)
|
|||
* controlled delay. Here we need to override that, then
|
||||
* force entry to deep sleep on any delay.
|
||||
*/
|
||||
pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
pm_power_state_force(0u, (struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
|
||||
printk("ERROR: System off failed\n");
|
||||
while (true) {
|
||||
|
|
|
@ -118,5 +118,5 @@ void main(void)
|
|||
|
||||
printk("Device shutdown\n");
|
||||
|
||||
pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
pm_power_state_force(0u, (struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ void main(void)
|
|||
/*
|
||||
* Force the SOFT_OFF state.
|
||||
*/
|
||||
pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
pm_power_state_force(0u, (struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
|
||||
printk("ERROR: System off failed\n");
|
||||
while (true) {
|
||||
|
|
|
@ -24,6 +24,8 @@ LOG_MODULE_REGISTER(pm, CONFIG_PM_LOG_LEVEL);
|
|||
static bool post_ops_done = true;
|
||||
static sys_slist_t pm_notifiers = SYS_SLIST_STATIC_INIT(&pm_notifiers);
|
||||
static struct pm_state_info z_power_states[CONFIG_MP_NUM_CPUS];
|
||||
/* bitmask to check if a power state was forced. */
|
||||
static ATOMIC_DEFINE(z_power_states_forced, CONFIG_MP_NUM_CPUS);
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
static atomic_t z_cpus_active = ATOMIC_INIT(CONFIG_MP_NUM_CPUS);
|
||||
#endif
|
||||
|
@ -239,43 +241,24 @@ void pm_system_resume(void)
|
|||
pm_state_notify(false);
|
||||
z_power_states[id] = (struct pm_state_info){PM_STATE_ACTIVE,
|
||||
0, 0};
|
||||
atomic_clear_bit(z_power_states_forced, id);
|
||||
}
|
||||
}
|
||||
|
||||
void pm_power_state_force(struct pm_state_info info)
|
||||
bool pm_power_state_force(uint8_t cpu, struct pm_state_info info)
|
||||
{
|
||||
uint8_t id = _current_cpu->id;
|
||||
bool ret = false;
|
||||
|
||||
__ASSERT(info.state < PM_STATES_LEN,
|
||||
"Invalid power state %d!", info.state);
|
||||
|
||||
if (info.state == PM_STATE_ACTIVE) {
|
||||
return;
|
||||
|
||||
if (!atomic_test_and_set_bit(z_power_states_forced, cpu)) {
|
||||
z_power_states[cpu] = info;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
(void)arch_irq_lock();
|
||||
z_power_states[id] = info;
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
if (z_power_states[id].state != PM_STATE_RUNTIME_IDLE) {
|
||||
(void)atomic_sub(&z_cpus_active, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
post_ops_done = false;
|
||||
pm_state_notify(true);
|
||||
|
||||
k_sched_lock();
|
||||
pm_start_timer();
|
||||
/* Enter power state */
|
||||
pm_state_set(info);
|
||||
pm_stop_timer();
|
||||
|
||||
pm_system_resume();
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
(void)atomic_add(&z_cpus_active, 1);
|
||||
#endif
|
||||
k_sched_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pm_system_suspend(int32_t ticks)
|
||||
|
@ -283,11 +266,16 @@ bool pm_system_suspend(int32_t ticks)
|
|||
uint8_t id = _current_cpu->id;
|
||||
|
||||
SYS_PORT_TRACING_FUNC_ENTER(pm, system_suspend, ticks);
|
||||
|
||||
if (!atomic_test_and_set_bit(z_power_states_forced, id)) {
|
||||
z_power_states[id] = pm_policy_next_state(id, ticks);
|
||||
}
|
||||
|
||||
if (z_power_states[id].state == PM_STATE_ACTIVE) {
|
||||
LOG_DBG("No PM operations done.");
|
||||
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,
|
||||
z_power_states[id].state);
|
||||
atomic_clear_bit(z_power_states_forced, id);
|
||||
return false;
|
||||
}
|
||||
post_ops_done = false;
|
||||
|
@ -320,6 +308,7 @@ bool pm_system_suspend(int32_t ticks)
|
|||
(void)atomic_add(&z_cpus_active, 1);
|
||||
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,
|
||||
_handle_device_abort(z_power_states[id]));
|
||||
atomic_clear_bit(z_power_states_forced, id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue