Skip to content

Commit ecabcf5

Browse files
nordic-krchkartben
authored andcommitted
pm: Use pointers for current and forced power states
Use power state pointers instead of copies which improves performance. Align power_mgmt_multicore test which was creating pm states in runtime. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
1 parent e4c2cec commit ecabcf5

File tree

4 files changed

+89
-49
lines changed

4 files changed

+89
-49
lines changed

include/zephyr/pm/state.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,16 @@ struct pm_state_constraint {
370370
*/
371371
uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states);
372372

373+
/**
374+
* Get power state structure.
375+
*
376+
* @param cpu CPU index.
377+
* @param state Power state.
378+
* @param substate_id Substate.
379+
*
380+
* @return Pointer to the power state structure or NULL if state is not found.
381+
*/
382+
const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id);
373383
/**
374384
* @}
375385
*/
@@ -384,6 +394,17 @@ static inline uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_in
384394
return 0;
385395
}
386396

397+
static inline const struct pm_state_info *pm_state_get(uint8_t cpu,
398+
enum pm_state state,
399+
uint8_t substate_id)
400+
{
401+
ARG_UNUSED(cpu);
402+
ARG_UNUSED(state);
403+
ARG_UNUSED(substate_id);
404+
405+
return NULL;
406+
}
407+
387408
#endif /* CONFIG_PM */
388409

389410
#ifdef __cplusplus

subsys/pm/pm.c

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,10 @@ static sys_slist_t pm_notifiers = SYS_SLIST_STATIC_INIT(&pm_notifiers);
3131
IS_ENABLED(CONFIG_PM_PREWAKEUP_CONV_MODE_NEAR) ? k_us_to_ticks_near32(us) : \
3232
IS_ENABLED(CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL) ? k_us_to_ticks_ceil32(us) : \
3333
k_us_to_ticks_floor32(us)
34-
/*
35-
* Properly initialize cpu power states. Do not make assumptions that
36-
* ACTIVE_STATE is 0
37-
*/
38-
#define CPU_PM_STATE_INIT(_, __) \
39-
{ .state = PM_STATE_ACTIVE }
40-
static struct pm_state_info z_cpus_pm_state[] = {
41-
LISTIFY(CONFIG_MP_MAX_NUM_CPUS, CPU_PM_STATE_INIT, (,))
42-
};
4334

44-
static struct pm_state_info z_cpus_pm_forced_state[] = {
45-
LISTIFY(CONFIG_MP_MAX_NUM_CPUS, CPU_PM_STATE_INIT, (,))
46-
};
35+
/* State pointers which are set to NULL indicate ACTIVE state. */
36+
static const struct pm_state_info *z_cpus_pm_state[CONFIG_MP_MAX_NUM_CPUS];
37+
static const struct pm_state_info *z_cpus_pm_forced_state[CONFIG_MP_MAX_NUM_CPUS];
4738

4839
static struct k_spinlock pm_forced_state_lock;
4940
static struct k_spinlock pm_notifier_lock;
@@ -67,7 +58,7 @@ static inline void pm_state_notify(bool entering_state)
6758
}
6859

6960
if (callback) {
70-
callback(z_cpus_pm_state[CPU_ID].state);
61+
callback(z_cpus_pm_state[CPU_ID]->state);
7162
}
7263
}
7364
k_spin_unlock(&pm_notifier_lock, pm_notifier_key);
@@ -115,19 +106,19 @@ void pm_system_resume(void)
115106
if (atomic_test_and_clear_bit(z_post_ops_required, id)) {
116107
#ifdef CONFIG_PM_DEVICE_SYSTEM_MANAGED
117108
if (atomic_add(&_cpus_active, 1) == 0) {
118-
if ((z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) &&
119-
!z_cpus_pm_state[id].pm_device_disabled) {
109+
if ((z_cpus_pm_state[id]->state != PM_STATE_RUNTIME_IDLE) &&
110+
!z_cpus_pm_state[id]->pm_device_disabled) {
120111
pm_resume_devices();
121112
}
122113
}
123114
#endif
124-
pm_state_exit_post_ops(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id);
115+
pm_state_exit_post_ops(z_cpus_pm_state[id]->state,
116+
z_cpus_pm_state[id]->substate_id);
125117
pm_state_notify(false);
126118
#ifdef CONFIG_SYS_CLOCK_EXISTS
127119
sys_clock_idle_exit();
128120
#endif /* CONFIG_SYS_CLOCK_EXISTS */
129-
z_cpus_pm_state[id] = (struct pm_state_info){PM_STATE_ACTIVE, 0, false,
130-
0, 0};
121+
z_cpus_pm_state[id] = NULL;
131122
}
132123
}
133124

@@ -138,8 +129,10 @@ bool pm_state_force(uint8_t cpu, const struct pm_state_info *info)
138129
__ASSERT(info->state < PM_STATE_COUNT,
139130
"Invalid power state %d!", info->state);
140131

132+
info = pm_state_get(cpu, info->state, info->substate_id);
133+
141134
key = k_spin_lock(&pm_forced_state_lock);
142-
z_cpus_pm_forced_state[cpu] = *info;
135+
z_cpus_pm_forced_state[cpu] = info;
143136
k_spin_unlock(&pm_forced_state_lock, key);
144137

145138
return true;
@@ -162,45 +155,37 @@ bool pm_system_suspend(int32_t kernel_ticks)
162155
ticks = ticks_expiring_sooner(kernel_ticks, events_ticks);
163156

164157
key = k_spin_lock(&pm_forced_state_lock);
165-
if (z_cpus_pm_forced_state[id].state != PM_STATE_ACTIVE) {
158+
if (z_cpus_pm_forced_state[id] != NULL) {
166159
z_cpus_pm_state[id] = z_cpus_pm_forced_state[id];
167-
z_cpus_pm_forced_state[id].state = PM_STATE_ACTIVE;
160+
z_cpus_pm_forced_state[id] = NULL;
168161
} else {
169-
const struct pm_state_info *info;
170-
171-
info = pm_policy_next_state(id, ticks);
172-
if (info != NULL) {
173-
z_cpus_pm_state[id] = *info;
174-
} else {
175-
z_cpus_pm_state[id].state = PM_STATE_ACTIVE;
176-
}
162+
z_cpus_pm_state[id] = pm_policy_next_state(id, ticks);
177163
}
178164
k_spin_unlock(&pm_forced_state_lock, key);
179165

180-
if (z_cpus_pm_state[id].state == PM_STATE_ACTIVE) {
166+
if (z_cpus_pm_state[id] == NULL) {
181167
LOG_DBG("No PM operations done.");
182-
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,
183-
z_cpus_pm_state[id].state);
168+
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks, PM_STATE_ACTIVE);
184169
return false;
185170
}
186171

187172
#ifdef CONFIG_PM_DEVICE_SYSTEM_MANAGED
188173
if (atomic_sub(&_cpus_active, 1) == 1) {
189-
if ((z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) &&
190-
!z_cpus_pm_state[id].pm_device_disabled) {
174+
if ((z_cpus_pm_state[id]->state != PM_STATE_RUNTIME_IDLE) &&
175+
!z_cpus_pm_state[id]->pm_device_disabled) {
191176
if (!pm_suspend_devices()) {
192177
pm_resume_devices();
193-
z_cpus_pm_state[id].state = PM_STATE_ACTIVE;
178+
z_cpus_pm_state[id] = NULL;
194179
(void)atomic_add(&_cpus_active, 1);
195180
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,
196-
z_cpus_pm_state[id].state);
181+
PM_STATE_ACTIVE);
197182
return false;
198183
}
199184
}
200185
}
201186
#endif
202187

203-
exit_latency_ticks = EXIT_LATENCY_US_TO_TICKS(z_cpus_pm_state[id].exit_latency_us);
188+
exit_latency_ticks = EXIT_LATENCY_US_TO_TICKS(z_cpus_pm_state[id]->exit_latency_us);
204189
if ((exit_latency_ticks > 0) && (ticks != K_TICKS_FOREVER)) {
205190
/*
206191
* 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)
223208
/* Enter power state */
224209
pm_state_notify(true);
225210
atomic_set_bit(z_post_ops_required, id);
226-
pm_state_set(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id);
211+
pm_state_set(z_cpus_pm_state[id]->state, z_cpus_pm_state[id]->substate_id);
227212
pm_stats_stop();
228213

229214
/* Wake up sequence starts here */
230-
pm_stats_update(z_cpus_pm_state[id].state);
215+
pm_stats_update(z_cpus_pm_state[id]->state);
231216
pm_system_resume();
232217
k_sched_unlock();
233218
SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,
234-
z_cpus_pm_state[id].state);
219+
z_cpus_pm_state[id] ?
220+
z_cpus_pm_state[id]->state : PM_STATE_ACTIVE);
235221

236222
return true;
237223
}
@@ -260,5 +246,9 @@ int pm_notifier_unregister(struct pm_notifier *notifier)
260246

261247
const struct pm_state_info *pm_state_next_get(uint8_t cpu)
262248
{
263-
return &z_cpus_pm_state[cpu];
249+
static const struct pm_state_info active = {
250+
.state = PM_STATE_ACTIVE
251+
};
252+
253+
return z_cpus_pm_state[cpu] ? z_cpus_pm_state[cpu] : &active;
264254
}

subsys/pm/state.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,18 @@ uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
6666

6767
return states_per_cpu[cpu];
6868
}
69+
70+
const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id)
71+
{
72+
__ASSERT_NO_MSG(cpu < ARRAY_SIZE(cpus_states));
73+
const struct pm_state_info *states = cpus_states[cpu];
74+
uint8_t cnt = states_per_cpu[cpu];
75+
76+
for (uint8_t i = 0; i < cnt; i++) {
77+
if ((states[i].state == state) && (states[i].substate_id == substate_id)) {
78+
return &states[i];
79+
}
80+
}
81+
82+
return NULL;
83+
}

tests/subsys/pm/power_mgmt_multicore/src/main.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,26 +63,40 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
6363

6464
const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int ticks)
6565
{
66-
static struct pm_state_info info = {};
66+
static const struct pm_state_info states[] = {
67+
{
68+
.state = PM_STATE_ACTIVE
69+
},
70+
{
71+
.state = PM_STATE_RUNTIME_IDLE
72+
},
73+
{
74+
.state = PM_STATE_SUSPEND_TO_IDLE
75+
},
76+
{
77+
.state = PM_STATE_STANDBY
78+
},
79+
};
80+
static const struct pm_state_info *info;
6781
int32_t msecs = k_ticks_to_ms_floor64(ticks);
6882

6983
if (msecs < ACTIVE_MSEC) {
70-
info.state = PM_STATE_ACTIVE;
84+
info = NULL;
7185
} else if (msecs <= IDLE_MSEC) {
72-
info.state = PM_STATE_RUNTIME_IDLE;
86+
info = &states[1];
7387
} else if (msecs <= SUSPEND_TO_IDLE_MSEC) {
74-
info.state = PM_STATE_SUSPEND_TO_IDLE;
88+
info = &states[2];
7589
} else {
7690
if (cpu == 0U) {
77-
info.state = PM_STATE_SUSPEND_TO_IDLE;
91+
info = &states[2];
7892
} else {
79-
info.state = PM_STATE_STANDBY;
93+
info = &states[3];
8094
}
8195
}
8296

83-
state_testing[cpu] = info.state;
97+
state_testing[cpu] = info ? info->state : PM_STATE_ACTIVE;
8498

85-
return &info;
99+
return info;
86100
}
87101

88102
/*

0 commit comments

Comments
 (0)