power: Effectively allow forcing a state

pm_power_state_force had two different behavior, if
CONFIG_PM_DIRECT_FORCE_MODE was enabled this function immediately
calls pm_system_suspend() without wait the idle thread. Without this
option enabled, this function will wait for the idle thread run but
will use the given power state instead of asking the policy manager.

The problem in both cases is that the process involves handling
devices and the way that was implemented if at least one device failed
to go to low power or suspended the system power state would not
change / be forced.

This commit simplifies this API removing the conditional behavior
since it is not clear the need for that and effectively, and
immediately, forces the system to go to the given state without
bother with devices.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
This commit is contained in:
Flavio Ceolin 2021-02-23 10:31:35 -08:00 committed by Anas Nashif
commit 5c5172ddae
3 changed files with 29 additions and 36 deletions

View file

@ -127,12 +127,9 @@ static inline void pm_idle_exit_notification_disable(void)
* @brief Force usage of given power state.
*
* This function overrides decision made by PM policy forcing
* usage of given power state in the ongoing suspend operation.
* And before the end of suspend, the state of forced_pm_state
* is cleared with interrupt disabled.
* usage of given power state immediately.
*
* If enabled PM_DIRECT_FORCE_MODE, this function can only
* run in thread context.
* @note This function can only run in thread context
*
* @param info Power state which should be used in the ongoing
* suspend operation.

View file

@ -22,14 +22,6 @@ menuconfig PM
if PM
config PM_DIRECT_FORCE_MODE
bool "System power management direct force trigger mode"
help
Enable system power management direct force trigger mode. In
this mode application thread can directly put system in sleep
or deep sleep mode instead of waiting for idle thread to do
it, so that it can reduce latency to enter low power mode.
config PM_DEBUG
bool "System Power Management debug hooks"
help

View file

@ -18,7 +18,6 @@
LOG_MODULE_REGISTER(power);
static int post_ops_done = 1;
static bool z_forced_power_state;
static struct pm_state_info z_power_state;
static sys_slist_t pm_notifiers = SYS_SLIST_STATIC_INIT(&pm_notifiers);
static struct k_spinlock pm_notifier_lock;
@ -84,22 +83,6 @@ __weak void pm_power_state_set(struct pm_state_info info)
*/
}
void pm_power_state_force(struct pm_state_info info)
{
__ASSERT(info.state < PM_STATES_LEN,
"Invalid power state %d!", info.state);
#ifdef CONFIG_PM_DIRECT_FORCE_MODE
(void)arch_irq_lock();
z_forced_power_state = true;
z_power_state = info;
pm_system_suspend(K_TICKS_FOREVER);
#else
z_power_state = info;
z_forced_power_state = true;
#endif
}
/*
* Function called to notify when the system is entering / exiting a
* power state
@ -125,6 +108,32 @@ static inline void pm_state_notify(bool entering_state)
k_spin_unlock(&pm_notifier_lock, pm_notifier_key);
}
void pm_power_state_force(struct pm_state_info info)
{
__ASSERT(info.state < PM_STATES_LEN,
"Invalid power state %d!", info.state);
if (info.state == PM_STATE_ACTIVE) {
return;
}
(void)arch_irq_lock();
z_power_state = info;
post_ops_done = 0;
pm_state_notify(true);
pm_debug_start_timer();
/* Enter power state */
pm_power_state_set(z_power_state);
pm_debug_stop_timer();
if (!post_ops_done) {
post_ops_done = 1;
pm_state_notify(false);
pm_power_state_exit_post_ops(z_power_state);
}
}
static enum pm_state _handle_device_abort(struct pm_state_info info)
{
LOG_DBG("Some devices didn't enter suspend state!");
@ -142,10 +151,7 @@ static enum pm_state pm_policy_mgr(int32_t ticks)
bool low_power = false;
#endif
if (z_forced_power_state == false) {
z_power_state = pm_policy_next_state(ticks);
}
z_power_state = pm_policy_next_state(ticks);
if (z_power_state.state == PM_STATE_ACTIVE) {
LOG_DBG("No PM operations done.");
return z_power_state.state;
@ -195,8 +201,6 @@ static enum pm_state pm_policy_mgr(int32_t ticks)
if (!post_ops_done) {
post_ops_done = 1;
/* clear z_forced_power_state */
z_forced_power_state = false;
pm_state_notify(false);
pm_power_state_exit_post_ops(z_power_state);
}