summaryrefslogtreecommitdiff
path: root/drivers/devfreq/devfreq.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-13 19:47:52 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-13 19:47:52 -0700
commitd7c8087a9cd8979d70edfe7c7feda9423feae3ab (patch)
tree09a9885768964f8e6cc8e5c07681faafd1215c05 /drivers/devfreq/devfreq.c
parent2e31b16101834bdc0b720967845d6a0a309cf27b (diff)
parentd923f70e37310fe613883a3a4c2ea2f31246253b (diff)
Merge tag 'pm-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki: "Once again, cpufreq is the most active development area, mostly because of the new feature additions and documentation updates in the amd-pstate driver, but there are also changes in the cpufreq core related to boost support and other assorted updates elsewhere. Next up are power capping changes due to the major cleanup of the Intel RAPL driver. On the cpuidle front, a new C-states table for Intel Panther Lake is added to the intel_idle driver, the stopped tick handling in the menu and teo governors is updated, and there are a couple of cleanups. Apart from the above, support for Tegra114 is added to devfreq and there are assorted cleanups of that code, there are also two updates of the operating performance points (OPP) library, two minor updates related to hibernation, and cpupower utility man pages updates and cleanups. Specifics: - Update qcom-hw DT bindings to include Eliza hardware (Abel Vesa) - Update cpufreq-dt-platdev blocklist (Faruque Ansari) - Minor updates to driver and dt-bindings for Tegra (Thierry Reding, Rosen Penev) - Add MAINTAINERS entry for CPPC driver (Viresh Kumar) - Add support for new features: CPPC performance priority, Dynamic EPP, Raw EPP, and new unit tests for them to amd-pstate (Gautham Shenoy, Mario Limonciello) - Fix sysfs files being present when HW missing and broken/outdated documentation in the amd-pstate driver (Ninad Naik, Gautham Shenoy) - Pass the policy to cpufreq_driver->adjust_perf() to avoid using cpufreq_cpu_get() in the .adjust_perf() callback in amd-pstate which leads to a scheduling-while-atomic bug (K Prateek Nayak) - Clean up dead code in Kconfig for cpufreq (Julian Braha) - Remove max_freq_req update for pre-existing cpufreq policy and add a boost_freq_req QoS request to save the boost constraint instead of overwriting the last scaling_max_freq constraint (Pierre Gondois) - Embed cpufreq QoS freq_req objects in cpufreq policy so they all are allocated in one go along with the policy to simplify lifetime rules and avoid error handling issues (Viresh Kumar) - Use DMI max speed when CPPC is unavailable in the acpi-cpufreq scaling driver (Henry Tseng) - Switch policy_is_shared() in cpufreq to using cpumask_nth() instead of cpumask_weight() because the former is more efficient (Yury Norov) - Use sysfs_emit() in sysfs show functions for cpufreq governor attributes (Thorsten Blum) - Update intel_pstate to stop returning an error when "off" is written to its status sysfs attribute while the driver is already off (Fabio De Francesco) - Include current frequency in the debug message printed by __cpufreq_driver_target() (Pengjie Zhang) - Refine stopped tick handling in the menu cpuidle governor and rearrange stopped tick handling in the teo cpuidle governor (Rafael Wysocki) - Add Panther Lake C-states table to the intel_idle driver (Artem Bityutskiy) - Clean up dead dependencies on CPU_IDLE in Kconfig (Julian Braha) - Simplify cpuidle_register_device() with guard() (Huisong Li) - Use performance level if available to distinguish between rates in OPP debugfs (Manivannan Sadhasivam) - Fix scoped_guard in dev_pm_opp_xlate_required_opp() (Viresh Kumar) - Return -ENODATA if the snapshot image is not loaded (Alberto Garcia) - Remove inclusion of crypto/hash.h from hibernate_64.c on x86 (Eric Biggers) - Clean up and rearrange the intel_rapl power capping driver to make the respective interface drivers (TPMI, MSR, and MMOI) hold their own settings and primitives and consolidate PL4 and PMU support flags into rapl_defaults (Kuppuswamy Sathyanarayanan) - Correct kernel-doc function parameter names in the power capping core code (Randy Dunlap) - Remove unneeded casting for HZ_PER_KHZ in devfreq (Andy Shevchenko) - Use _visible attribute to replace create/remove_sysfs_files() in devfreq (Pengjie Zhang) - Add Tegra114 support to activity monitor device in tegra30-devfreq as a preparation to upcoming EMC controller support (Svyatoslav Ryhel) - Fix mistakes in cpupower man pages, add the boost and epp options to the cpupower-frequency-info man page, and add the perf-bias option to the cpupower-info man page (Roberto Ricci) - Remove unnecessary extern declarations from getopt.h in arguments parsing functions in cpufreq-set, cpuidle-info, cpuidle-set, cpupower-info, and cpupower-set utilities (Kaushlendra Kumar)" * tag 'pm-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (74 commits) cpufreq/amd-pstate: Add POWER_SUPPLY select for dynamic EPP cpupower: remove extern declarations in cmd functions cpuidle: Simplify cpuidle_register_device() with guard() PM / devfreq: tegra30-devfreq: add support for Tegra114 PM / devfreq: use _visible attribute to replace create/remove_sysfs_files() PM / devfreq: Remove unneeded casting for HZ_PER_KHZ MAINTAINERS: amd-pstate: Step down as maintainer, add Prateek as reviewer cpufreq: Pass the policy to cpufreq_driver->adjust_perf() cpufreq/amd-pstate: Pass the policy to amd_pstate_update() cpufreq/amd-pstate-ut: Add a unit test for raw EPP cpufreq/amd-pstate: Add support for raw EPP writes cpufreq/amd-pstate: Add support for platform profile class cpufreq/amd-pstate: add kernel command line to override dynamic epp cpufreq/amd-pstate: Add dynamic energy performance preference Documentation: amd-pstate: fix dead links in the reference section cpufreq/amd-pstate: Cache the max frequency in cpudata Documentation/amd-pstate: Add documentation for amd_pstate_floor_{freq,count} Documentation/amd-pstate: List amd_pstate_prefcore_ranking sysfs file Documentation/amd-pstate: List amd_pstate_hw_prefcore sysfs file amd-pstate-ut: Add a testcase to validate the visibility of driver attributes ...
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r--drivers/devfreq/devfreq.c108
1 files changed, 62 insertions, 46 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index c0a74091b904..82dd9a43dc62 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -38,6 +38,7 @@
static struct class *devfreq_class;
static struct dentry *devfreq_debugfs;
+static const struct attribute_group gov_attr_group;
/*
* devfreq core provides delayed work based load monitoring helper
@@ -146,10 +147,9 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
DEV_PM_QOS_MIN_FREQUENCY);
qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
DEV_PM_QOS_MAX_FREQUENCY);
- *min_freq = max(*min_freq, (unsigned long)HZ_PER_KHZ * qos_min_freq);
+ *min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE)
- *max_freq = min(*max_freq,
- (unsigned long)HZ_PER_KHZ * qos_max_freq);
+ *max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
/* Apply constraints from OPP interface */
*max_freq = clamp(*max_freq, devfreq->scaling_min_freq, devfreq->scaling_max_freq);
@@ -785,11 +785,6 @@ static void devfreq_dev_release(struct device *dev)
kfree(devfreq);
}
-static void create_sysfs_files(struct devfreq *devfreq,
- const struct devfreq_governor *gov);
-static void remove_sysfs_files(struct devfreq *devfreq,
- const struct devfreq_governor *gov);
-
/**
* devfreq_add_device() - Add devfreq feature to the device
* @dev: the device to add devfreq feature.
@@ -956,7 +951,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
__func__);
goto err_init;
}
- create_sysfs_files(devfreq, devfreq->governor);
+
+ err = sysfs_update_group(&devfreq->dev.kobj, &gov_attr_group);
+ if (err)
+ goto err_init;
list_add(&devfreq->node, &devfreq_list);
@@ -995,12 +993,9 @@ int devfreq_remove_device(struct devfreq *devfreq)
devfreq_cooling_unregister(devfreq->cdev);
- if (devfreq->governor) {
+ if (devfreq->governor)
devfreq->governor->event_handler(devfreq,
DEVFREQ_GOV_STOP, NULL);
- remove_sysfs_files(devfreq, devfreq->governor);
- }
-
device_unregister(&devfreq->dev);
return 0;
@@ -1460,7 +1455,6 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
__func__, df->governor->name, ret);
goto out;
}
- remove_sysfs_files(df, df->governor);
/*
* Start the new governor and create the specific sysfs files
@@ -1489,7 +1483,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
* Create the sysfs files for the new governor. But if failed to start
* the new governor, restore the sysfs files of previous governor.
*/
- create_sysfs_files(df, df->governor);
+ ret = sysfs_update_group(&df->dev.kobj, &gov_attr_group);
out:
mutex_unlock(&devfreq_list_lock);
@@ -1807,14 +1801,17 @@ static struct attribute *devfreq_attrs[] = {
&dev_attr_trans_stat.attr,
NULL,
};
-ATTRIBUTE_GROUPS(devfreq);
static ssize_t polling_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *df = to_devfreq(dev);
- if (!df->profile)
+ /* Protect against race between sysfs attrs update and read/write */
+ guard(mutex)(&devfreq_list_lock);
+
+ if (!df->profile || !df->governor ||
+ !IS_SUPPORTED_ATTR(df->governor->attrs, POLLING_INTERVAL))
return -EINVAL;
return sprintf(buf, "%d\n", df->profile->polling_ms);
@@ -1828,7 +1825,10 @@ static ssize_t polling_interval_store(struct device *dev,
unsigned int value;
int ret;
- if (!df->governor)
+ guard(mutex)(&devfreq_list_lock);
+
+ if (!df->governor ||
+ !IS_SUPPORTED_ATTR(df->governor->attrs, POLLING_INTERVAL))
return -EINVAL;
ret = sscanf(buf, "%u", &value);
@@ -1847,7 +1847,10 @@ static ssize_t timer_show(struct device *dev,
{
struct devfreq *df = to_devfreq(dev);
- if (!df->profile)
+ guard(mutex)(&devfreq_list_lock);
+
+ if (!df->profile || !df->governor ||
+ !IS_SUPPORTED_ATTR(df->governor->attrs, TIMER))
return -EINVAL;
return sprintf(buf, "%s\n", timer_name[df->profile->timer]);
@@ -1861,7 +1864,10 @@ static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
int timer = -1;
int ret = 0, i;
- if (!df->governor || !df->profile)
+ guard(mutex)(&devfreq_list_lock);
+
+ if (!df->governor || !df->profile ||
+ !IS_SUPPORTED_ATTR(df->governor->attrs, TIMER))
return -EINVAL;
ret = sscanf(buf, "%16s", str_timer);
@@ -1905,37 +1911,47 @@ out:
}
static DEVICE_ATTR_RW(timer);
-#define CREATE_SYSFS_FILE(df, name) \
-{ \
- int ret; \
- ret = sysfs_create_file(&df->dev.kobj, &dev_attr_##name.attr); \
- if (ret < 0) { \
- dev_warn(&df->dev, \
- "Unable to create attr(%s)\n", "##name"); \
- } \
-} \
+static struct attribute *governor_attrs[] = {
+ &dev_attr_polling_interval.attr,
+ &dev_attr_timer.attr,
+ NULL
+};
-/* Create the specific sysfs files which depend on each governor. */
-static void create_sysfs_files(struct devfreq *devfreq,
- const struct devfreq_governor *gov)
+static umode_t gov_attr_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
{
- if (IS_SUPPORTED_ATTR(gov->attrs, POLLING_INTERVAL))
- CREATE_SYSFS_FILE(devfreq, polling_interval);
- if (IS_SUPPORTED_ATTR(gov->attrs, TIMER))
- CREATE_SYSFS_FILE(devfreq, timer);
-}
+ struct device *dev = kobj_to_dev(kobj);
+ struct devfreq *df = to_devfreq(dev);
-/* Remove the specific sysfs files which depend on each governor. */
-static void remove_sysfs_files(struct devfreq *devfreq,
- const struct devfreq_governor *gov)
-{
- if (IS_SUPPORTED_ATTR(gov->attrs, POLLING_INTERVAL))
- sysfs_remove_file(&devfreq->dev.kobj,
- &dev_attr_polling_interval.attr);
- if (IS_SUPPORTED_ATTR(gov->attrs, TIMER))
- sysfs_remove_file(&devfreq->dev.kobj, &dev_attr_timer.attr);
+ if (!df->governor || !df->governor->attrs)
+ return 0;
+
+ if (attr == &dev_attr_polling_interval.attr &&
+ IS_SUPPORTED_ATTR(df->governor->attrs, POLLING_INTERVAL))
+ return attr->mode;
+
+ if (attr == &dev_attr_timer.attr &&
+ IS_SUPPORTED_ATTR(df->governor->attrs, TIMER))
+ return attr->mode;
+
+ return 0;
}
+static const struct attribute_group devfreq_group = {
+ .attrs = devfreq_attrs,
+};
+
+static const struct attribute_group gov_attr_group = {
+ .attrs = governor_attrs,
+ .is_visible = gov_attr_visible,
+};
+
+static const struct attribute_group *devfreq_groups[] = {
+ &devfreq_group,
+ &gov_attr_group,
+ NULL
+};
+
/**
* devfreq_summary_show() - Show the summary of the devfreq devices
* @s: seq_file instance to show the summary of devfreq devices