From eb6eaeb5d28df03aa7a21555398f83554f587eca Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Wed, 1 Apr 2026 11:30:46 +0800 Subject: PM / devfreq: Fix possible null pointer issue in devfreq_add_governor() When a user removes a governor using devfreq_remove_governor(), if the current device is using this governor, devfreq->governor will be set to NULL. When the user registers any governor using devfreq_add_governor(), since devfreq->governor is NULL, a null pointer error occurs in strncmp(). For example: A user loads the userspace gov through a module, then a device selects userspace. When unloading the userspace module and then loading it again, the null pointer error occurs: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010 Mem abort info: ESR = 0x0000000096000004 EC = 0x25: DABT (current EL), IL = 32 bits *******************skip ********************* Call trace: __pi_strncmp+0x20/0x1b8 devfreq_userspace_init+0x1c/0xff8 [governor_userspace] do_one_initcall+0x4c/0x278 do_init_module+0x5c/0x218 load_module+0x1f1c/0x1fc8 init_module_from_file+0x8c/0xd0 __arm64_sys_finit_module+0x220/0x3d8 invoke_syscall+0x48/0x110 el0_svc_common.constprop.0+0xbc/0xe8 do_el0_svc+0x20/0x30 el0_svc+0x24/0xb8 el0t_64_sync_handler+0xb8/0xc0 el0t_64_sync+0x14c/0x150 To fix this issue, remove the list_for_each_entry() logic, as find_devfreq_governor() has already checked for the existence of governor with the same name. This makes it impossible to find a duplicate governor in the list, so the subsequent logic is unreachable and can be removed. Fixes: 1b5c1be2c88e ("PM / devfreq: map devfreq drivers to governor using name") Signed-off-by: Yaxiong Tian Co-developed-by: Jie Zhan Signed-off-by: Jie Zhan Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20260401033046.67482-1-tianyaxiong@kylinos.cn/ --- drivers/devfreq/devfreq.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'drivers') diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 82dd9a43dc62..994984f7b6e1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1261,7 +1261,6 @@ void devfreq_resume(void) int devfreq_add_governor(struct devfreq_governor *governor) { struct devfreq_governor *g; - struct devfreq *devfreq; int err = 0; if (!governor) { @@ -1280,38 +1279,6 @@ int devfreq_add_governor(struct devfreq_governor *governor) list_add(&governor->node, &devfreq_governor_list); - list_for_each_entry(devfreq, &devfreq_list, node) { - int ret = 0; - struct device *dev = devfreq->dev.parent; - - if (!strncmp(devfreq->governor->name, governor->name, - DEVFREQ_NAME_LEN)) { - /* The following should never occur */ - if (devfreq->governor) { - dev_warn(dev, - "%s: Governor %s already present\n", - __func__, devfreq->governor->name); - ret = devfreq->governor->event_handler(devfreq, - DEVFREQ_GOV_STOP, NULL); - if (ret) { - dev_warn(dev, - "%s: Governor %s stop = %d\n", - __func__, - devfreq->governor->name, ret); - } - /* Fall through */ - } - devfreq->governor = governor; - ret = devfreq->governor->event_handler(devfreq, - DEVFREQ_GOV_START, NULL); - if (ret) { - dev_warn(dev, "%s: Governor %s start=%d\n", - __func__, devfreq->governor->name, - ret); - } - } - } - err_out: mutex_unlock(&devfreq_list_lock); -- cgit v1.2.3 From a0f11920bacdd86c9d1f2509f8a2bd5617040ed2 Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Wed, 1 Apr 2026 11:30:55 +0800 Subject: PM / devfreq: Fix available_governors_show() when no governor is set Since devfreq_remove_governor() may clear the device's current governor in certain situations, while governors actually exist independently of the device, directly returning EINVAL in this case is inaccurate. To fix this issue, remove this check and use df->governor for validity verification in the following code. Fixes: 483d557ee9a3 ("PM / devfreq: Clean up the devfreq instance name in sysfs attr") Signed-off-by: Yaxiong Tian Reviewed-by: Jie Zhan Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20260401033055.67608-1-tianyaxiong@kylinos.cn/ --- drivers/devfreq/devfreq.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 994984f7b6e1..2977b07be939 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1468,16 +1468,13 @@ static ssize_t available_governors_show(struct device *d, struct devfreq *df = to_devfreq(d); ssize_t count = 0; - if (!df->governor) - return -EINVAL; - mutex_lock(&devfreq_list_lock); /* * The devfreq with immutable governor (e.g., passive) shows * only own governor. */ - if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE)) { + if (df->governor && IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE)) { count = scnprintf(&buf[count], DEVFREQ_NAME_LEN, "%s ", df->governor->name); /* -- cgit v1.2.3 From 0f02633e08f799f5829569a0f0eb42b65ddacbe0 Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Wed, 1 Apr 2026 11:31:28 +0800 Subject: PM / devfreq: Optimize error return value of governor_show() When df->governor is NULL, governor_show() returns -EINVAL, which confuses users. To fix this issue, return -ENOENT to indicate that no governor is currently set for the device. Signed-off-by: Yaxiong Tian Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20260401033128.67925-1-tianyaxiong@kylinos.cn/ --- drivers/devfreq/devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 2977b07be939..e5d3f9cf94dc 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1377,7 +1377,7 @@ static ssize_t governor_show(struct device *dev, struct devfreq *df = to_devfreq(dev); if (!df->governor) - return -EINVAL; + return -ENOENT; return sprintf(buf, "%s\n", df->governor->name); } -- cgit v1.2.3 From d0d288caaae9c4d43adb2ce00ed6f8f00b43c523 Mon Sep 17 00:00:00 2001 From: Anas Iqbal Date: Thu, 19 Mar 2026 16:30:11 +0000 Subject: PM / devfreq: event: rockchip-dfi: Fix missing clk_disable_unprepare() on error Smatch reports: drivers/devfreq/event/rockchip-dfi.c:215 rockchip_dfi_enable() warn: 'dfi->clk' from clk_prepare_enable() not released. If rockchip_dfi_ddrtype_to_ctrl() fails after clk_prepare_enable(), the clock is not disabled, leading to a resource leak. Add clk_disable_unprepare() in the error path to properly release the clock. Fixes: d724f4a4581b ("PM / devfreq: rockchip-dfi: Prepare for multiple users") Signed-off-by: Anas Iqbal Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20260319163011.18876-1-mohd.abd.6602@gmail.com/ --- drivers/devfreq/event/rockchip-dfi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 5e6e7e900bda..8db0bceeded4 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -185,8 +185,10 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi) } ret = rockchip_dfi_ddrtype_to_ctrl(dfi, &ctrl); - if (ret) + if (ret) { + clk_disable_unprepare(dfi->clk); goto out; + } for (i = 0; i < dfi->max_channels; i++) { -- cgit v1.2.3 From 9a222650d9e70d0027126e4df5b00b1b5b678a97 Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Thu, 30 Apr 2026 11:20:35 +0800 Subject: PM / devfreq: Fix governor_store() failing when device has no current governor Since devfreq_remove_governor() may clear the device's current governor in certain situations, while governors actually exist independently of the device, directly returning EINVAL in this case is inaccurate. To fix this issue, remove this check and add relevant logic for when df->governor is NULL. Fixes: 483d557ee9a3 ("PM / devfreq: Clean up the devfreq instance name in sysfs attr") Co-developed-by: Choi Chanwoo Signed-off-by: Yaxiong Tian Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/all/20260430032035.75496-1-tianyaxiong@kylinos.cn/ --- drivers/devfreq/devfreq.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index e5d3f9cf94dc..f08fc6966eae 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1390,9 +1390,6 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, char str_governor[DEVFREQ_NAME_LEN + 1]; const struct devfreq_governor *governor, *prev_governor; - if (!df->governor) - return -EINVAL; - ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor); if (ret != 1) return -EINVAL; @@ -1403,6 +1400,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, ret = PTR_ERR(governor); goto out; } + if (!df->governor) + goto start_new_governor; + if (df->governor == governor) { ret = 0; goto out; @@ -1423,6 +1423,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, goto out; } +start_new_governor: /* * Start the new governor and create the specific sysfs files * which depend on the new governor. @@ -1436,6 +1437,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, /* Restore previous governor */ df->governor = prev_governor; + if (!df->governor) + goto out; + ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL); if (ret) { dev_err(dev, -- cgit v1.2.3