Skip to content

Commit 7cede21

Browse files
committed
Merge branches 'pm-qos' and 'pm-tools'
Merge PM QoS updates and a cpupower utility update for 6.19-rc1: - Introduce and document a QoS limit on CPU exit latency during wakeup from suspend-to-idle (Ulf Hansson) - Add support for building libcpupower statically (Zuo An) * pm-qos: Documentation: power/cpuidle: Document the CPU system wakeup latency QoS cpuidle: Respect the CPU system wakeup QoS limit for cpuidle sched: idle: Respect the CPU system wakeup QoS limit for s2idle pmdomain: Respect the CPU system wakeup QoS limit for cpuidle pmdomain: Respect the CPU system wakeup QoS limit for s2idle PM: QoS: Introduce a CPU system wakeup QoS limit * pm-tools: tools/power/cpupower: Support building libcpupower statically
3 parents 638757c + c19dfb2 + 30a8e0a commit 7cede21

13 files changed

Lines changed: 224 additions & 30 deletions

File tree

Documentation/admin-guide/pm/cpuidle.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,15 @@ the given CPU as the upper limit for the exit latency of the idle states that
580580
they are allowed to select for that CPU. They should never select any idle
581581
states with exit latency beyond that limit.
582582

583+
While the above CPU QoS constraints apply to CPU idle time management, user
584+
space may also request a CPU system wakeup latency QoS limit, via the
585+
`cpu_wakeup_latency` file. This QoS constraint is respected when selecting a
586+
suitable idle state for the CPUs, while entering the system-wide suspend-to-idle
587+
sleep state, but also to the regular CPU idle time management.
588+
589+
Note that, the management of the `cpu_wakeup_latency` file works according to
590+
the 'cpu_dma_latency' file from user space point of view. Moreover, the unit
591+
is also microseconds.
583592

584593
Idle States Control Via Kernel Command Line
585594
===========================================

Documentation/power/pm_qos_interface.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,24 @@ int cpu_latency_qos_request_active(handle):
5555

5656
From user space:
5757

58-
The infrastructure exposes one device node, /dev/cpu_dma_latency, for the CPU
58+
The infrastructure exposes two separate device nodes, /dev/cpu_dma_latency for
59+
the CPU latency QoS and /dev/cpu_wakeup_latency for the CPU system wakeup
5960
latency QoS.
6061

6162
Only processes can register a PM QoS request. To provide for automatic
6263
cleanup of a process, the interface requires the process to register its
6364
parameter requests as follows.
6465

6566
To register the default PM QoS target for the CPU latency QoS, the process must
66-
open /dev/cpu_dma_latency.
67+
open /dev/cpu_dma_latency. To register a CPU system wakeup QoS limit, the
68+
process must open /dev/cpu_wakeup_latency.
6769

6870
As long as the device node is held open that process has a registered
6971
request on the parameter.
7072

7173
To change the requested target value, the process needs to write an s32 value to
7274
the open device node. Alternatively, it can write a hex string for the value
73-
using the 10 char long format e.g. "0x12345678". This translates to a
74-
cpu_latency_qos_update_request() call.
75+
using the 10 char long format e.g. "0x12345678".
7576

7677
To remove the user mode request for a target value simply close the device
7778
node.

drivers/cpuidle/cpuidle.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,20 +184,22 @@ static noinstr void enter_s2idle_proper(struct cpuidle_driver *drv,
184184
* cpuidle_enter_s2idle - Enter an idle state suitable for suspend-to-idle.
185185
* @drv: cpuidle driver for the given CPU.
186186
* @dev: cpuidle device for the given CPU.
187+
* @latency_limit_ns: Idle state exit latency limit
187188
*
188189
* If there are states with the ->enter_s2idle callback, find the deepest of
189190
* them and enter it with frozen tick.
190191
*/
191-
int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev)
192+
int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
193+
u64 latency_limit_ns)
192194
{
193195
int index;
194196

195197
/*
196-
* Find the deepest state with ->enter_s2idle present, which guarantees
197-
* that interrupts won't be enabled when it exits and allows the tick to
198-
* be frozen safely.
198+
* Find the deepest state with ->enter_s2idle present that meets the
199+
* specified latency limit, which guarantees that interrupts won't be
200+
* enabled when it exits and allows the tick to be frozen safely.
199201
*/
200-
index = find_deepest_state(drv, dev, U64_MAX, 0, true);
202+
index = find_deepest_state(drv, dev, latency_limit_ns, 0, true);
201203
if (index > 0) {
202204
enter_s2idle_proper(drv, dev, index);
203205
local_irq_enable();

drivers/cpuidle/governor.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ s64 cpuidle_governor_latency_req(unsigned int cpu)
111111
struct device *device = get_cpu_device(cpu);
112112
int device_req = dev_pm_qos_raw_resume_latency(device);
113113
int global_req = cpu_latency_qos_limit();
114+
int global_wake_req = cpu_wakeup_latency_qos_limit();
115+
116+
if (global_req > global_wake_req)
117+
global_req = global_wake_req;
114118

115119
if (device_req > global_req)
116120
device_req = global_req;

drivers/pmdomain/core.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,8 +1425,14 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
14251425
return;
14261426
}
14271427

1428-
/* Choose the deepest state when suspending */
1429-
genpd->state_idx = genpd->state_count - 1;
1428+
if (genpd->gov && genpd->gov->system_power_down_ok) {
1429+
if (!genpd->gov->system_power_down_ok(&genpd->domain))
1430+
return;
1431+
} else {
1432+
/* Default to the deepest state. */
1433+
genpd->state_idx = genpd->state_count - 1;
1434+
}
1435+
14301436
if (_genpd_power_off(genpd, false)) {
14311437
genpd->states[genpd->state_idx].rejected++;
14321438
return;

drivers/pmdomain/governor.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
351351
ktime_t domain_wakeup, next_hrtimer;
352352
ktime_t now = ktime_get();
353353
struct device *cpu_dev;
354-
s64 cpu_constraint, global_constraint;
354+
s64 cpu_constraint, global_constraint, wakeup_constraint;
355355
s64 idle_duration_ns;
356356
int cpu, i;
357357

@@ -362,7 +362,11 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
362362
if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN))
363363
return true;
364364

365+
wakeup_constraint = cpu_wakeup_latency_qos_limit();
365366
global_constraint = cpu_latency_qos_limit();
367+
if (global_constraint > wakeup_constraint)
368+
global_constraint = wakeup_constraint;
369+
366370
/*
367371
* Find the next wakeup for any of the online CPUs within the PM domain
368372
* and its subdomains. Note, we only need the genpd->cpus, as it already
@@ -415,9 +419,36 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
415419
return false;
416420
}
417421

422+
static bool cpu_system_power_down_ok(struct dev_pm_domain *pd)
423+
{
424+
s64 constraint_ns = cpu_wakeup_latency_qos_limit() * NSEC_PER_USEC;
425+
struct generic_pm_domain *genpd = pd_to_genpd(pd);
426+
int state_idx = genpd->state_count - 1;
427+
428+
if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) {
429+
genpd->state_idx = state_idx;
430+
return true;
431+
}
432+
433+
/* Find the deepest state for the latency constraint. */
434+
while (state_idx >= 0) {
435+
s64 latency_ns = genpd->states[state_idx].power_off_latency_ns +
436+
genpd->states[state_idx].power_on_latency_ns;
437+
438+
if (latency_ns <= constraint_ns) {
439+
genpd->state_idx = state_idx;
440+
return true;
441+
}
442+
state_idx--;
443+
}
444+
445+
return false;
446+
}
447+
418448
struct dev_power_governor pm_domain_cpu_gov = {
419449
.suspend_ok = default_suspend_ok,
420450
.power_down_ok = cpu_power_down_ok,
451+
.system_power_down_ok = cpu_system_power_down_ok,
421452
};
422453
#endif
423454

include/linux/cpuidle.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,17 @@ extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
248248
struct cpuidle_device *dev,
249249
u64 latency_limit_ns);
250250
extern int cpuidle_enter_s2idle(struct cpuidle_driver *drv,
251-
struct cpuidle_device *dev);
251+
struct cpuidle_device *dev,
252+
u64 latency_limit_ns);
252253
extern void cpuidle_use_deepest_state(u64 latency_limit_ns);
253254
#else
254255
static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
255256
struct cpuidle_device *dev,
256257
u64 latency_limit_ns)
257258
{return -ENODEV; }
258259
static inline int cpuidle_enter_s2idle(struct cpuidle_driver *drv,
259-
struct cpuidle_device *dev)
260+
struct cpuidle_device *dev,
261+
u64 latency_limit_ns)
260262
{return -ENODEV; }
261263
static inline void cpuidle_use_deepest_state(u64 latency_limit_ns)
262264
{

include/linux/pm_domain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ enum genpd_sync_state {
153153
};
154154

155155
struct dev_power_governor {
156+
bool (*system_power_down_ok)(struct dev_pm_domain *domain);
156157
bool (*power_down_ok)(struct dev_pm_domain *domain);
157158
bool (*suspend_ok)(struct device *dev);
158159
};

include/linux/pm_qos.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ static inline void cpu_latency_qos_update_request(struct pm_qos_request *req,
162162
static inline void cpu_latency_qos_remove_request(struct pm_qos_request *req) {}
163163
#endif
164164

165+
#ifdef CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP
166+
s32 cpu_wakeup_latency_qos_limit(void);
167+
#else
168+
static inline s32 cpu_wakeup_latency_qos_limit(void)
169+
{
170+
return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
171+
}
172+
#endif
173+
165174
#ifdef CONFIG_PM
166175
enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
167176
enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask);

kernel/power/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,17 @@ config PM_WAKELOCKS_GC
202202
depends on PM_WAKELOCKS
203203
default y
204204

205+
config PM_QOS_CPU_SYSTEM_WAKEUP
206+
bool "User space interface for CPU system wakeup QoS"
207+
depends on CPU_IDLE
208+
help
209+
Enable this to allow user space via the cpu_wakeup_latency file to
210+
specify a CPU system wakeup latency limit.
211+
212+
This may be particularly useful for platforms supporting multiple low
213+
power states for CPUs during system-wide suspend and s2idle in
214+
particular.
215+
205216
config PM
206217
bool "Device power management core functionality"
207218
help

0 commit comments

Comments
 (0)