diff --git a/include/zephyr/pm/state.h b/include/zephyr/pm/state.h index 6590b90c385..a0607997137 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -370,6 +370,16 @@ struct pm_state_constraint { */ uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states); +/** + * Get power state structure. + * + * @param cpu CPU index. + * @param state Power state. + * @param substate_id Substate. + * + * @return Pointer to the power state structure or NULL if state is not found. + */ +const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id); /** * @} */ @@ -384,6 +394,17 @@ static inline uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_in return 0; } +static inline const struct pm_state_info *pm_state_get(uint8_t cpu, + enum pm_state state, + uint8_t substate_id) +{ + ARG_UNUSED(cpu); + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + return NULL; +} + #endif /* CONFIG_PM */ #ifdef __cplusplus diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index cc2eeb39b93..1baad192fbf 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -31,19 +31,10 @@ static sys_slist_t pm_notifiers = SYS_SLIST_STATIC_INIT(&pm_notifiers); IS_ENABLED(CONFIG_PM_PREWAKEUP_CONV_MODE_NEAR) ? k_us_to_ticks_near32(us) : \ IS_ENABLED(CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL) ? k_us_to_ticks_ceil32(us) : \ k_us_to_ticks_floor32(us) -/* - * Properly initialize cpu power states. Do not make assumptions that - * ACTIVE_STATE is 0 - */ -#define CPU_PM_STATE_INIT(_, __) \ - { .state = PM_STATE_ACTIVE } -static struct pm_state_info z_cpus_pm_state[] = { - LISTIFY(CONFIG_MP_MAX_NUM_CPUS, CPU_PM_STATE_INIT, (,)) -}; -static struct pm_state_info z_cpus_pm_forced_state[] = { - LISTIFY(CONFIG_MP_MAX_NUM_CPUS, CPU_PM_STATE_INIT, (,)) -}; +/* State pointers which are set to NULL indicate ACTIVE state. */ +static const struct pm_state_info *z_cpus_pm_state[CONFIG_MP_MAX_NUM_CPUS]; +static const struct pm_state_info *z_cpus_pm_forced_state[CONFIG_MP_MAX_NUM_CPUS]; static struct k_spinlock pm_forced_state_lock; static struct k_spinlock pm_notifier_lock; @@ -67,7 +58,7 @@ static inline void pm_state_notify(bool entering_state) } if (callback) { - callback(z_cpus_pm_state[CPU_ID].state); + callback(z_cpus_pm_state[CPU_ID]->state); } } k_spin_unlock(&pm_notifier_lock, pm_notifier_key); @@ -115,19 +106,19 @@ void pm_system_resume(void) if (atomic_test_and_clear_bit(z_post_ops_required, id)) { #ifdef CONFIG_PM_DEVICE_SYSTEM_MANAGED if (atomic_add(&_cpus_active, 1) == 0) { - if ((z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) && - !z_cpus_pm_state[id].pm_device_disabled) { + if ((z_cpus_pm_state[id]->state != PM_STATE_RUNTIME_IDLE) && + !z_cpus_pm_state[id]->pm_device_disabled) { pm_resume_devices(); } } #endif - pm_state_exit_post_ops(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); + pm_state_exit_post_ops(z_cpus_pm_state[id]->state, + z_cpus_pm_state[id]->substate_id); pm_state_notify(false); #ifdef CONFIG_SYS_CLOCK_EXISTS sys_clock_idle_exit(); #endif /* CONFIG_SYS_CLOCK_EXISTS */ - z_cpus_pm_state[id] = (struct pm_state_info){PM_STATE_ACTIVE, 0, false, - 0, 0}; + z_cpus_pm_state[id] = NULL; } } @@ -138,8 +129,10 @@ bool pm_state_force(uint8_t cpu, const struct pm_state_info *info) __ASSERT(info->state < PM_STATE_COUNT, "Invalid power state %d!", info->state); + info = pm_state_get(cpu, info->state, info->substate_id); + key = k_spin_lock(&pm_forced_state_lock); - z_cpus_pm_forced_state[cpu] = *info; + z_cpus_pm_forced_state[cpu] = info; k_spin_unlock(&pm_forced_state_lock, key); return true; @@ -162,45 +155,37 @@ bool pm_system_suspend(int32_t kernel_ticks) ticks = ticks_expiring_sooner(kernel_ticks, events_ticks); key = k_spin_lock(&pm_forced_state_lock); - if (z_cpus_pm_forced_state[id].state != PM_STATE_ACTIVE) { + if (z_cpus_pm_forced_state[id] != NULL) { z_cpus_pm_state[id] = z_cpus_pm_forced_state[id]; - z_cpus_pm_forced_state[id].state = PM_STATE_ACTIVE; + z_cpus_pm_forced_state[id] = NULL; } else { - const struct pm_state_info *info; - - info = pm_policy_next_state(id, ticks); - if (info != NULL) { - z_cpus_pm_state[id] = *info; - } else { - z_cpus_pm_state[id].state = PM_STATE_ACTIVE; - } + z_cpus_pm_state[id] = pm_policy_next_state(id, ticks); } k_spin_unlock(&pm_forced_state_lock, key); - if (z_cpus_pm_state[id].state == PM_STATE_ACTIVE) { + if (z_cpus_pm_state[id] == NULL) { LOG_DBG("No PM operations done."); - SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks, - z_cpus_pm_state[id].state); + SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks, PM_STATE_ACTIVE); return false; } #ifdef CONFIG_PM_DEVICE_SYSTEM_MANAGED if (atomic_sub(&_cpus_active, 1) == 1) { - if ((z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) && - !z_cpus_pm_state[id].pm_device_disabled) { + if ((z_cpus_pm_state[id]->state != PM_STATE_RUNTIME_IDLE) && + !z_cpus_pm_state[id]->pm_device_disabled) { if (!pm_suspend_devices()) { pm_resume_devices(); - z_cpus_pm_state[id].state = PM_STATE_ACTIVE; + z_cpus_pm_state[id] = NULL; (void)atomic_add(&_cpus_active, 1); SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks, - z_cpus_pm_state[id].state); + PM_STATE_ACTIVE); return false; } } } #endif - exit_latency_ticks = EXIT_LATENCY_US_TO_TICKS(z_cpus_pm_state[id].exit_latency_us); + exit_latency_ticks = EXIT_LATENCY_US_TO_TICKS(z_cpus_pm_state[id]->exit_latency_us); if ((exit_latency_ticks > 0) && (ticks != K_TICKS_FOREVER)) { /* * We need to set the timer to interrupt a little bit early to @@ -223,15 +208,16 @@ bool pm_system_suspend(int32_t kernel_ticks) /* Enter power state */ pm_state_notify(true); atomic_set_bit(z_post_ops_required, id); - pm_state_set(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); + pm_state_set(z_cpus_pm_state[id]->state, z_cpus_pm_state[id]->substate_id); pm_stats_stop(); /* Wake up sequence starts here */ - pm_stats_update(z_cpus_pm_state[id].state); + pm_stats_update(z_cpus_pm_state[id]->state); pm_system_resume(); k_sched_unlock(); SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks, - z_cpus_pm_state[id].state); + z_cpus_pm_state[id] ? + z_cpus_pm_state[id]->state : PM_STATE_ACTIVE); return true; } @@ -260,5 +246,9 @@ int pm_notifier_unregister(struct pm_notifier *notifier) const struct pm_state_info *pm_state_next_get(uint8_t cpu) { - return &z_cpus_pm_state[cpu]; + static const struct pm_state_info active = { + .state = PM_STATE_ACTIVE + }; + + return z_cpus_pm_state[cpu] ? z_cpus_pm_state[cpu] : &active; } diff --git a/subsys/pm/state.c b/subsys/pm/state.c index 297d28a3768..3cf2888d339 100644 --- a/subsys/pm/state.c +++ b/subsys/pm/state.c @@ -66,3 +66,18 @@ uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states) return states_per_cpu[cpu]; } + +const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id) +{ + __ASSERT_NO_MSG(cpu < ARRAY_SIZE(cpus_states)); + const struct pm_state_info *states = cpus_states[cpu]; + uint8_t cnt = states_per_cpu[cpu]; + + for (uint8_t i = 0; i < cnt; i++) { + if ((states[i].state == state) && (states[i].substate_id == substate_id)) { + return &states[i]; + } + } + + return NULL; +} diff --git a/tests/subsys/pm/power_mgmt_multicore/src/main.c b/tests/subsys/pm/power_mgmt_multicore/src/main.c index 6915694a6d8..e87c38ea746 100644 --- a/tests/subsys/pm/power_mgmt_multicore/src/main.c +++ b/tests/subsys/pm/power_mgmt_multicore/src/main.c @@ -63,26 +63,40 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int ticks) { - static struct pm_state_info info = {}; + static const struct pm_state_info states[] = { + { + .state = PM_STATE_ACTIVE + }, + { + .state = PM_STATE_RUNTIME_IDLE + }, + { + .state = PM_STATE_SUSPEND_TO_IDLE + }, + { + .state = PM_STATE_STANDBY + }, + }; + static const struct pm_state_info *info; int32_t msecs = k_ticks_to_ms_floor64(ticks); if (msecs < ACTIVE_MSEC) { - info.state = PM_STATE_ACTIVE; + info = NULL; } else if (msecs <= IDLE_MSEC) { - info.state = PM_STATE_RUNTIME_IDLE; + info = &states[1]; } else if (msecs <= SUSPEND_TO_IDLE_MSEC) { - info.state = PM_STATE_SUSPEND_TO_IDLE; + info = &states[2]; } else { if (cpu == 0U) { - info.state = PM_STATE_SUSPEND_TO_IDLE; + info = &states[2]; } else { - info.state = PM_STATE_STANDBY; + info = &states[3]; } } - state_testing[cpu] = info.state; + state_testing[cpu] = info ? info->state : PM_STATE_ACTIVE; - return &info; + return info; } /*