Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

coresight: Appropriately disable programming clocks

Some CoreSight components have programming clocks (pclk) and are enabled
using clk_get() and clk_prepare_enable(). However, in many cases, these
clocks are not disabled when modules exit and only released by clk_put().

To fix the issue, this commit refactors programming clock by replacing
clk_get() and clk_prepare_enable() with devm_clk_get_optional_enabled()
for enabling APB clock. If the "apb_pclk" clock is not found, a NULL
pointer is returned, and the function proceeds to attempt enabling the
"apb" clock.

Since ACPI platforms rely on firmware to manage clocks, returning a NULL
pointer in this case leaves clock management to the firmware rather than
the driver. This effectively avoids a clock imbalance issue during
module removal - where the clock could be disabled twice: once during
the ACPI runtime suspend and again during the devm resource release.

Callers are updated to reuse the returned error value.

With the change, programming clocks are managed as resources in driver
model layer, allowing clock cleanup to be handled automatically. As a
result, manual cleanup operations are no longer needed and are removed
from the Coresight drivers.

Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices")
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-4-1dfe10bb3f6f@arm.com

authored by

Leo Yan and committed by
Suzuki K Poulose
1abc1b21 40c0cdc9

+21 -59
+2 -7
drivers/hwtracing/coresight/coresight-catu.c
··· 636 636 637 637 drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); 638 638 if (IS_ERR(drvdata->pclk)) 639 - return -ENODEV; 639 + return PTR_ERR(drvdata->pclk); 640 640 641 641 pm_runtime_get_noresume(&pdev->dev); 642 642 pm_runtime_set_active(&pdev->dev); ··· 645 645 dev_set_drvdata(&pdev->dev, drvdata); 646 646 ret = __catu_probe(&pdev->dev, res); 647 647 pm_runtime_put(&pdev->dev); 648 - if (ret) { 648 + if (ret) 649 649 pm_runtime_disable(&pdev->dev); 650 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 651 - clk_put(drvdata->pclk); 652 - } 653 650 654 651 return ret; 655 652 } ··· 660 663 661 664 __catu_remove(&pdev->dev); 662 665 pm_runtime_disable(&pdev->dev); 663 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 664 - clk_put(drvdata->pclk); 665 666 } 666 667 667 668 #ifdef CONFIG_PM
+1 -5
drivers/hwtracing/coresight/coresight-cpu-debug.c
··· 699 699 700 700 drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); 701 701 if (IS_ERR(drvdata->pclk)) 702 - return -ENODEV; 702 + return PTR_ERR(drvdata->pclk); 703 703 704 704 dev_set_drvdata(&pdev->dev, drvdata); 705 705 pm_runtime_get_noresume(&pdev->dev); ··· 710 710 if (ret) { 711 711 pm_runtime_put_noidle(&pdev->dev); 712 712 pm_runtime_disable(&pdev->dev); 713 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 714 - clk_put(drvdata->pclk); 715 713 } 716 714 return ret; 717 715 } ··· 723 725 724 726 __debug_remove(&pdev->dev); 725 727 pm_runtime_disable(&pdev->dev); 726 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 727 - clk_put(drvdata->pclk); 728 728 } 729 729 730 730 #ifdef CONFIG_ACPI
+2 -8
drivers/hwtracing/coresight/coresight-ctcu-core.c
··· 209 209 210 210 drvdata->apb_clk = coresight_get_enable_apb_pclk(dev); 211 211 if (IS_ERR(drvdata->apb_clk)) 212 - return -ENODEV; 212 + return PTR_ERR(drvdata->apb_clk); 213 213 214 214 cfgs = of_device_get_match_data(dev); 215 215 if (cfgs) { ··· 233 233 desc.access = CSDEV_ACCESS_IOMEM(base); 234 234 235 235 drvdata->csdev = coresight_register(&desc); 236 - if (IS_ERR(drvdata->csdev)) { 237 - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) 238 - clk_put(drvdata->apb_clk); 239 - 236 + if (IS_ERR(drvdata->csdev)) 240 237 return PTR_ERR(drvdata->csdev); 241 - } 242 238 243 239 return 0; 244 240 } ··· 271 275 272 276 ctcu_remove(pdev); 273 277 pm_runtime_disable(&pdev->dev); 274 - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) 275 - clk_put(drvdata->apb_clk); 276 278 } 277 279 278 280 #ifdef CONFIG_PM
+2 -7
drivers/hwtracing/coresight/coresight-etm4x-core.c
··· 2309 2309 2310 2310 drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); 2311 2311 if (IS_ERR(drvdata->pclk)) 2312 - return -ENODEV; 2312 + return PTR_ERR(drvdata->pclk); 2313 2313 2314 2314 if (res) { 2315 2315 drvdata->base = devm_ioremap_resource(&pdev->dev, res); 2316 - if (IS_ERR(drvdata->base)) { 2317 - clk_put(drvdata->pclk); 2316 + if (IS_ERR(drvdata->base)) 2318 2317 return PTR_ERR(drvdata->base); 2319 - } 2320 2318 } 2321 2319 2322 2320 dev_set_drvdata(&pdev->dev, drvdata); ··· 2421 2423 if (drvdata) 2422 2424 etm4_remove_dev(drvdata); 2423 2425 pm_runtime_disable(&pdev->dev); 2424 - 2425 - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) 2426 - clk_put(drvdata->pclk); 2427 2426 } 2428 2427 2429 2428 static const struct amba_id etm4_ids[] = {
+1 -5
drivers/hwtracing/coresight/coresight-funnel.c
··· 240 240 241 241 drvdata->pclk = coresight_get_enable_apb_pclk(dev); 242 242 if (IS_ERR(drvdata->pclk)) 243 - return -ENODEV; 243 + return PTR_ERR(drvdata->pclk); 244 244 245 245 /* 246 246 * Map the device base for dynamic-funnel, which has been ··· 284 284 out_disable_clk: 285 285 if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) 286 286 clk_disable_unprepare(drvdata->atclk); 287 - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) 288 - clk_disable_unprepare(drvdata->pclk); 289 287 return ret; 290 288 } 291 289 ··· 353 355 354 356 funnel_remove(&pdev->dev); 355 357 pm_runtime_disable(&pdev->dev); 356 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 357 - clk_put(drvdata->pclk); 358 358 } 359 359 360 360 static const struct of_device_id funnel_match[] = {
+1 -5
drivers/hwtracing/coresight/coresight-replicator.c
··· 247 247 248 248 drvdata->pclk = coresight_get_enable_apb_pclk(dev); 249 249 if (IS_ERR(drvdata->pclk)) 250 - return -ENODEV; 250 + return PTR_ERR(drvdata->pclk); 251 251 252 252 /* 253 253 * Map the device base for dynamic-replicator, which has been ··· 296 296 out_disable_clk: 297 297 if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) 298 298 clk_disable_unprepare(drvdata->atclk); 299 - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) 300 - clk_disable_unprepare(drvdata->pclk); 301 299 return ret; 302 300 } 303 301 ··· 333 335 334 336 replicator_remove(&pdev->dev); 335 337 pm_runtime_disable(&pdev->dev); 336 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 337 - clk_put(drvdata->pclk); 338 338 } 339 339 340 340 #ifdef CONFIG_PM
+1 -3
drivers/hwtracing/coresight/coresight-stm.c
··· 851 851 852 852 drvdata->pclk = coresight_get_enable_apb_pclk(dev); 853 853 if (IS_ERR(drvdata->pclk)) 854 - return -ENODEV; 854 + return PTR_ERR(drvdata->pclk); 855 855 dev_set_drvdata(dev, drvdata); 856 856 857 857 base = devm_ioremap_resource(dev, res); ··· 1033 1033 1034 1034 __stm_remove(&pdev->dev); 1035 1035 pm_runtime_disable(&pdev->dev); 1036 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 1037 - clk_put(drvdata->pclk); 1038 1036 } 1039 1037 1040 1038 #ifdef CONFIG_ACPI
+1 -3
drivers/hwtracing/coresight/coresight-tmc-core.c
··· 981 981 982 982 drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); 983 983 if (IS_ERR(drvdata->pclk)) 984 - return -ENODEV; 984 + return PTR_ERR(drvdata->pclk); 985 985 986 986 dev_set_drvdata(&pdev->dev, drvdata); 987 987 pm_runtime_get_noresume(&pdev->dev); ··· 1005 1005 1006 1006 __tmc_remove(&pdev->dev); 1007 1007 pm_runtime_disable(&pdev->dev); 1008 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 1009 - clk_put(drvdata->pclk); 1010 1008 } 1011 1009 1012 1010 #ifdef CONFIG_PM
+1 -3
drivers/hwtracing/coresight/coresight-tpiu.c
··· 153 153 154 154 drvdata->pclk = coresight_get_enable_apb_pclk(dev); 155 155 if (IS_ERR(drvdata->pclk)) 156 - return -ENODEV; 156 + return PTR_ERR(drvdata->pclk); 157 157 dev_set_drvdata(dev, drvdata); 158 158 159 159 /* Validity for the resource is already checked by the AMBA core */ ··· 293 293 294 294 __tpiu_remove(&pdev->dev); 295 295 pm_runtime_disable(&pdev->dev); 296 - if (!IS_ERR_OR_NULL(drvdata->pclk)) 297 - clk_put(drvdata->pclk); 298 296 } 299 297 300 298 #ifdef CONFIG_ACPI
+9 -13
include/linux/coresight.h
··· 6 6 #ifndef _LINUX_CORESIGHT_H 7 7 #define _LINUX_CORESIGHT_H 8 8 9 + #include <linux/acpi.h> 9 10 #include <linux/amba/bus.h> 10 11 #include <linux/clk.h> 11 12 #include <linux/device.h> ··· 481 480 * Returns: 482 481 * 483 482 * clk - Clock is found and enabled 484 - * NULL - clock is not found 483 + * NULL - Clock is controlled by firmware (ACPI device only) 485 484 * ERROR - Clock is found but failed to enable 486 485 */ 487 486 static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) 488 487 { 489 488 struct clk *pclk; 490 - int ret; 491 489 492 - pclk = clk_get(dev, "apb_pclk"); 493 - if (IS_ERR(pclk)) { 494 - pclk = clk_get(dev, "apb"); 495 - if (IS_ERR(pclk)) 496 - return NULL; 497 - } 490 + /* Firmware controls clocks for an ACPI device. */ 491 + if (has_acpi_companion(dev)) 492 + return NULL; 498 493 499 - ret = clk_prepare_enable(pclk); 500 - if (ret) { 501 - clk_put(pclk); 502 - return ERR_PTR(ret); 503 - } 494 + pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); 495 + if (!pclk) 496 + pclk = devm_clk_get_optional_enabled(dev, "apb"); 497 + 504 498 return pclk; 505 499 } 506 500