Skip to content

Commit a4e6512

Browse files
storulfrafaeljw
authored andcommitted
PM: QoS: Introduce a CPU system wakeup QoS limit
Some platforms supports multiple low power states for CPUs that can be used when entering system-wide suspend. Currently we are always selecting the deepest possible state for the CPUs, which can break the system wakeup latency constraint that may be required for a use case. Let's take the first step towards addressing this problem, by introducing an interface for user space, that allows us to specify the CPU system wakeup QoS limit. Subsequent changes will start taking into account the new QoS limit. Reviewed-by: Dhruva Gole <d-gole@ti.com> Reviewed-by: Kevin Hilman (TI) <khilman@baylibre.com> Tested-by: Kevin Hilman (TI) <khilman@baylibre.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Link: https://patch.msgid.link/20251125112650.329269-2-ulf.hansson@linaro.org Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent ac3fd01 commit a4e6512

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

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

kernel/power/qos.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,105 @@ static struct miscdevice cpu_latency_qos_miscdev = {
415415
.fops = &cpu_latency_qos_fops,
416416
};
417417

418+
#ifdef CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP
419+
/* The CPU system wakeup latency QoS. */
420+
static struct pm_qos_constraints cpu_wakeup_latency_constraints = {
421+
.list = PLIST_HEAD_INIT(cpu_wakeup_latency_constraints.list),
422+
.target_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT,
423+
.default_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT,
424+
.no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT,
425+
.type = PM_QOS_MIN,
426+
};
427+
428+
/**
429+
* cpu_wakeup_latency_qos_limit - Current CPU system wakeup latency QoS limit.
430+
*
431+
* Returns the current CPU system wakeup latency QoS limit that may have been
432+
* requested by user space.
433+
*/
434+
s32 cpu_wakeup_latency_qos_limit(void)
435+
{
436+
return pm_qos_read_value(&cpu_wakeup_latency_constraints);
437+
}
438+
439+
static int cpu_wakeup_latency_qos_open(struct inode *inode, struct file *filp)
440+
{
441+
struct pm_qos_request *req;
442+
443+
req = kzalloc(sizeof(*req), GFP_KERNEL);
444+
if (!req)
445+
return -ENOMEM;
446+
447+
req->qos = &cpu_wakeup_latency_constraints;
448+
pm_qos_update_target(req->qos, &req->node, PM_QOS_ADD_REQ,
449+
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
450+
filp->private_data = req;
451+
452+
return 0;
453+
}
454+
455+
static int cpu_wakeup_latency_qos_release(struct inode *inode,
456+
struct file *filp)
457+
{
458+
struct pm_qos_request *req = filp->private_data;
459+
460+
filp->private_data = NULL;
461+
pm_qos_update_target(req->qos, &req->node, PM_QOS_REMOVE_REQ,
462+
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
463+
kfree(req);
464+
465+
return 0;
466+
}
467+
468+
static ssize_t cpu_wakeup_latency_qos_read(struct file *filp, char __user *buf,
469+
size_t count, loff_t *f_pos)
470+
{
471+
s32 value = pm_qos_read_value(&cpu_wakeup_latency_constraints);
472+
473+
return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
474+
}
475+
476+
static ssize_t cpu_wakeup_latency_qos_write(struct file *filp,
477+
const char __user *buf,
478+
size_t count, loff_t *f_pos)
479+
{
480+
struct pm_qos_request *req = filp->private_data;
481+
s32 value;
482+
483+
if (count == sizeof(s32)) {
484+
if (copy_from_user(&value, buf, sizeof(s32)))
485+
return -EFAULT;
486+
} else {
487+
int ret;
488+
489+
ret = kstrtos32_from_user(buf, count, 16, &value);
490+
if (ret)
491+
return ret;
492+
}
493+
494+
if (value < 0)
495+
return -EINVAL;
496+
497+
pm_qos_update_target(req->qos, &req->node, PM_QOS_UPDATE_REQ, value);
498+
499+
return count;
500+
}
501+
502+
static const struct file_operations cpu_wakeup_latency_qos_fops = {
503+
.open = cpu_wakeup_latency_qos_open,
504+
.release = cpu_wakeup_latency_qos_release,
505+
.read = cpu_wakeup_latency_qos_read,
506+
.write = cpu_wakeup_latency_qos_write,
507+
.llseek = noop_llseek,
508+
};
509+
510+
static struct miscdevice cpu_wakeup_latency_qos_miscdev = {
511+
.minor = MISC_DYNAMIC_MINOR,
512+
.name = "cpu_wakeup_latency",
513+
.fops = &cpu_wakeup_latency_qos_fops,
514+
};
515+
#endif /* CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP */
516+
418517
static int __init cpu_latency_qos_init(void)
419518
{
420519
int ret;
@@ -424,6 +523,13 @@ static int __init cpu_latency_qos_init(void)
424523
pr_err("%s: %s setup failed\n", __func__,
425524
cpu_latency_qos_miscdev.name);
426525

526+
#ifdef CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP
527+
ret = misc_register(&cpu_wakeup_latency_qos_miscdev);
528+
if (ret < 0)
529+
pr_err("%s: %s setup failed\n", __func__,
530+
cpu_wakeup_latency_qos_miscdev.name);
531+
#endif
532+
427533
return ret;
428534
}
429535
late_initcall(cpu_latency_qos_init);

0 commit comments

Comments
 (0)