[PATCH RFC 04/10] PM / devfreq: Add new target_freq attribute flag for governors
Pragnesh Papaniya <[email protected]> Fri, 24 Jul 2026 12:48:09 +0530
| Newsgroups | org.kernel.vger.arm-scmi,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm,org.kernel.vger.linux-tegra |
|---|---|
| Message-ID | <[email protected]> |
From: Sibi Sankar <[email protected]> The target_freq sysfs attribute exposes a governor's predicted next target frequency. Not every devfreq governor has a meaningful value to report there; some merely observe an externally-driven device. Add a DEVFREQ_GOV_ATTR_TARGET_FREQ attribute flag that governors with a meaningful target frequency must opt in to. Gate the existing target_freq sysfs read on the flag and return -EINVAL when the active governor does not advertise it. Tag all in-tree governors so visible behaviour stays unchanged for in-tree users. Out-of-tree governors that drive frequency updates and want to keep target_freq readable need to set the new flag. Signed-off-by: Sibi Sankar <[email protected]> Co-developed-by: Pragnesh Papaniya <[email protected]> Signed-off-by: Pragnesh Papaniya <[email protected]> --- Documentation/ABI/testing/sysfs-class-devfreq | 8 ++++++++ drivers/devfreq/devfreq.c | 6 ++++++ drivers/devfreq/governor_passive.c | 1 + drivers/devfreq/governor_performance.c | 1 + drivers/devfreq/governor_powersave.c | 1 + drivers/devfreq/governor_simpleondemand.c | 1 + drivers/devfreq/governor_userspace.c | 1 + drivers/devfreq/hisi_uncore_freq.c | 1 + drivers/devfreq/tegra30-devfreq.c | 3 ++- include/linux/devfreq-governor.h | 3 +++ 10 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index df8ba88b9f6a..5be9940a5853 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -37,6 +37,14 @@ Description: The /sys/class/devfreq/.../target_freq shows the next governor predicted target frequency of the corresponding devfreq object. + Reading this attribute returns -EINVAL when the active + governor does not advertise DEVFREQ_GOV_ATTR_TARGET_FREQ. + All in-tree governors that drive frequency transitions tag + this attribute, so existing in-tree behaviour is unchanged. + Out-of-tree governors that previously relied on the + unconditional read of df->previous_freq must opt in by + setting DEVFREQ_GOV_ATTR_TARGET_FREQ in their attrs field. + What: /sys/class/devfreq/.../trans_stat Date: October 2012 Contact: MyungJoo Ham <[email protected]> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index f08fc6966eae..2f27a239e34a 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1530,6 +1530,12 @@ static ssize_t target_freq_show(struct device *dev, { struct devfreq *df = to_devfreq(dev); + guard(mutex)(&devfreq_list_lock); + + if (!df->profile || !df->governor || + !IS_SUPPORTED_ATTR(df->governor->attrs, TARGET_FREQ)) + return -EINVAL; + return sprintf(buf, "%lu\n", df->previous_freq); } static DEVICE_ATTR_RO(target_freq); diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c index d7feecd900f1..b75e4bbee4b1 100644 --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c @@ -448,6 +448,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_passive = { .name = DEVFREQ_GOV_PASSIVE, + .attrs = DEVFREQ_GOV_ATTR_TARGET_FREQ, .flags = DEVFREQ_GOV_FLAG_IMMUTABLE, .get_target_freq = devfreq_passive_get_target_freq, .event_handler = devfreq_passive_event_handler, diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index fdb22bf512cf..b9ec587f582c 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -37,6 +37,7 @@ static int devfreq_performance_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_performance = { .name = DEVFREQ_GOV_PERFORMANCE, + .attrs = DEVFREQ_GOV_ATTR_TARGET_FREQ, .get_target_freq = devfreq_performance_func, .event_handler = devfreq_performance_handler, }; diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index ee2d6ec8a512..69eab1d0a7fc 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -37,6 +37,7 @@ static int devfreq_powersave_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_powersave = { .name = DEVFREQ_GOV_POWERSAVE, + .attrs = DEVFREQ_GOV_ATTR_TARGET_FREQ, .get_target_freq = devfreq_powersave_func, .event_handler = devfreq_powersave_handler, }; diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index ac9c5e9e51a4..65ff9d912ef9 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -118,6 +118,7 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_simple_ondemand = { .name = DEVFREQ_GOV_SIMPLE_ONDEMAND, .attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL + | DEVFREQ_GOV_ATTR_TARGET_FREQ | DEVFREQ_GOV_ATTR_TIMER, .get_target_freq = devfreq_simple_ondemand_func, .event_handler = devfreq_simple_ondemand_handler, diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 3906ebedbae8..d1b765a7b8e5 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -135,6 +135,7 @@ static int devfreq_userspace_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_userspace = { .name = DEVFREQ_GOV_USERSPACE, + .attrs = DEVFREQ_GOV_ATTR_TARGET_FREQ, .get_target_freq = devfreq_userspace_func, .event_handler = devfreq_userspace_handler, }; diff --git a/drivers/devfreq/hisi_uncore_freq.c b/drivers/devfreq/hisi_uncore_freq.c index e1f64b723082..5a2d7e011ad1 100644 --- a/drivers/devfreq/hisi_uncore_freq.c +++ b/drivers/devfreq/hisi_uncore_freq.c @@ -398,6 +398,7 @@ static struct devfreq_governor hisi_platform_governor = { * Set interrupt_driven to skip the devfreq monitor mechanism, though * this governor is not interrupt-driven. */ + .attrs = DEVFREQ_GOV_ATTR_TARGET_FREQ, .flags = DEVFREQ_GOV_FLAG_IRQ_DRIVEN, .get_target_freq = hisi_platform_gov_func, .event_handler = hisi_platform_gov_handler, diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c index 401aac6a9f07..fcb278c4a74c 100644 --- a/drivers/devfreq/tegra30-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c @@ -776,7 +776,8 @@ static int tegra_governor_event_handler(struct devfreq *devfreq, static struct devfreq_governor tegra_devfreq_governor = { .name = "tegra_actmon", - .attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL, + .attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL + | DEVFREQ_GOV_ATTR_TARGET_FREQ, .flags = DEVFREQ_GOV_FLAG_IMMUTABLE | DEVFREQ_GOV_FLAG_IRQ_DRIVEN, .get_target_freq = tegra_governor_get_target, diff --git a/include/linux/devfreq-governor.h b/include/linux/devfreq-governor.h index dfdd0160a29f..2853f571dfdf 100644 --- a/include/linux/devfreq-governor.h +++ b/include/linux/devfreq-governor.h @@ -43,9 +43,12 @@ * : Indicate polling_interval sysfs attribute * - DEVFREQ_GOV_ATTR_TIMER * : Indicate timer sysfs attribute + * - DEVFREQ_GOV_ATTR_TARGET_FREQ + * : Indicate the target freq sysfs attribute */ #define DEVFREQ_GOV_ATTR_POLLING_INTERVAL BIT(0) #define DEVFREQ_GOV_ATTR_TIMER BIT(1) +#define DEVFREQ_GOV_ATTR_TARGET_FREQ BIT(2) /** * struct devfreq_governor - Devfreq policy governor -- 2.34.1