This series fixes and improves clock usage in the Arm CoreSight drivers.
Based on the DT binding documents, the trace clock (atclk) is defined in some CoreSight modules, but the corresponding drivers to support it are absent. In most cases, the issue is hidden because atclk is shared by multiple CoreSight modules and is enabled anyway by other drivers. The first three patches address this issue.
The programming clock (pclk) management in CoreSight drivers does not use the devm_XXX() variant APIs, so the drivers needs to manually disable and release clocks for errors and for normal module exit. However, the drivers miss to disable clocks during module exit.
Another issue is pclk might be enabled twice in init phase - once by AMBA bus driver, and again by CoreSight drivers.
Patches 04 and 05 fix pclk issues.
The atclk may also not be disabled in CoreSight drivers during module exit. This is fixed in patch 06.
Patches 07 to 09 refactor the clock related code. Patch 07 makes the clock enabling sequence consistent. Patch 08 removes redundant condition checks and adds error handling in runtime PM. Patch 09 consolidats the clock initialization into a central place.
This series is verified on Arm64 Hikey960 platform.
Leo Yan (9): coresight: tmc: Support atclk coresight: catu: Support atclk coresight: etm4x: Support atclk coresight: Disable programming clock properly coresight: Avoid enable programming clock duplicately coresight: Disable trace bus clock properly coresight: Make clock sequence consistent coresight: Refactor runtime PM coresight: Consolidate clock enabling
drivers/hwtracing/coresight/coresight-catu.c | 53 ++++++++++++++++----------------- drivers/hwtracing/coresight/coresight-catu.h | 1 + drivers/hwtracing/coresight/coresight-cpu-debug.c | 41 +++++++++----------------- drivers/hwtracing/coresight/coresight-ctcu-core.c | 24 +++++---------- drivers/hwtracing/coresight/coresight-etb10.c | 18 ++++-------- drivers/hwtracing/coresight/coresight-etm3x-core.c | 17 ++++------- drivers/hwtracing/coresight/coresight-etm4x-core.c | 32 ++++++++++---------- drivers/hwtracing/coresight/coresight-etm4x.h | 4 ++- drivers/hwtracing/coresight/coresight-funnel.c | 66 +++++++++++++++--------------------------- drivers/hwtracing/coresight/coresight-replicator.c | 63 ++++++++++++++-------------------------- drivers/hwtracing/coresight/coresight-stm.c | 34 +++++++++------------- drivers/hwtracing/coresight/coresight-tmc-core.c | 48 +++++++++++++++--------------- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ drivers/hwtracing/coresight/coresight-tpiu.c | 36 ++++++++++------------- include/linux/coresight.h | 47 ++++++++++++++++++------------ 15 files changed, 206 insertions(+), 280 deletions(-)
The atclk is an optional clock for the CoreSight TMC, but the driver misses to initialize it. In most cases, the TMC shares the same atclk with other CoreSight components. Since these components enable the clock before the TMC device is initialized, the TMC continues properly, which is why we don’t observe any lockup issues.
This change enables atclk in probe of the TMC driver. Given the clock is optional, it is possible to return NULL if the clock does not exist. IS_ERR() is tolerant for this case.
Dynamically disable and enable atclk during suspend and resume. The clock pointers will never be error values if the driver has successfully probed, and the case of a NULL pointer case will be handled by the clock core layer. The driver data is always valid after probe. Therefore, remove the related checks. Also in the resume flow adds error handling.
Fixes: bc4bf7fe98da ("coresight-tmc: add CoreSight TMC driver") Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-tmc-core.c | 22 +++++++++++++++++----- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 5978bcda2556..6aad2acd0378 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -789,6 +789,10 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL;
+ drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + ret = -ENOMEM;
/* Validity for the resource is already checked by the AMBA core */ @@ -1019,18 +1023,26 @@ static int tmc_runtime_suspend(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); + return 0; }
static int tmc_runtime_resume(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 6541a27a018e..cbb4ba439158 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -210,6 +210,7 @@ struct tmc_resrv_buf {
/** * struct tmc_drvdata - specifics associated to an TMC component + * @atclk: optional clock for the core parts of the TMC. * @pclk: APB clock if present, otherwise NULL * @base: memory mapped base address for this component. * @csdev: component vitals needed by the framework. @@ -244,6 +245,7 @@ struct tmc_resrv_buf { * Used by ETR/ETF. */ struct tmc_drvdata { + struct clk *atclk; struct clk *pclk; void __iomem *base; struct coresight_device *csdev;
On 3/27/25 17:07, Leo Yan wrote:
The atclk is an optional clock for the CoreSight TMC, but the driver misses to initialize it. In most cases, the TMC shares the same atclk
TMC shares the atclk or pclk clock with other coresight components ?
with other CoreSight components. Since these components enable the clock before the TMC device is initialized, the TMC continues properly, which is why we don’t observe any lockup issues.
This change enables atclk in probe of the TMC driver. Given the clock is optional, it is possible to return NULL if the clock does not exist. IS_ERR() is tolerant for this case.
Makes sense.
Dynamically disable and enable atclk during suspend and resume. The clock pointers will never be error values if the driver has successfully probed, and the case of a NULL pointer case will be handled by the clock core layer. The driver data is always valid after probe. Therefore, remove the related checks. Also in the resume flow adds error handling.
Probably a good clean up.
Fixes: bc4bf7fe98da ("coresight-tmc: add CoreSight TMC driver")
Right commit to attribute.
Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-tmc-core.c | 22 +++++++++++++++++----- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 5978bcda2556..6aad2acd0378 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -789,6 +789,10 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
Adding this check here in __tmc_probe() ensures that it gets called both during AMBA and platform probe methods.
ret = -ENOMEM; /* Validity for the resource is already checked by the AMBA core */ @@ -1019,18 +1023,26 @@ static int tmc_runtime_suspend(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_disable_unprepare(drvdata->pclk);
- clk_disable_unprepare(drvdata->atclk);
- clk_disable_unprepare(drvdata->pclk);
- return 0;
} static int tmc_runtime_resume(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
- int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_prepare_enable(drvdata->pclk);
- return 0;
- ret = clk_prepare_enable(drvdata->pclk);
- if (ret)
return ret;
- ret = clk_prepare_enable(drvdata->atclk);
- if (ret)
clk_disable_unprepare(drvdata->pclk);
- return ret;
} #endif diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 6541a27a018e..cbb4ba439158 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -210,6 +210,7 @@ struct tmc_resrv_buf { /**
- struct tmc_drvdata - specifics associated to an TMC component
- @atclk: optional clock for the core parts of the TMC.
- @pclk: APB clock if present, otherwise NULL
- @base: memory mapped base address for this component.
- @csdev: component vitals needed by the framework.
@@ -244,6 +245,7 @@ struct tmc_resrv_buf {
Used by ETR/ETF.
*/ struct tmc_drvdata {
- struct clk *atclk; struct clk *pclk; void __iomem *base; struct coresight_device *csdev;
Otherwise, LGTM.
Reviewed-by: Anshuman Khandual anshuman.khandual@arm.com
On Thu, Apr 03, 2025 at 11:20:38AM +0530, Anshuman Khandual wrote:
On 3/27/25 17:07, Leo Yan wrote:
The atclk is an optional clock for the CoreSight TMC, but the driver misses to initialize it. In most cases, the TMC shares the same atclk
TMC shares the atclk or pclk clock with other coresight components ?
I will refine the commit log for this.
[...]
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -789,6 +789,10 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
Adding this check here in __tmc_probe() ensures that it gets called both during AMBA and platform probe methods.
Yes.
/**
- struct tmc_drvdata - specifics associated to an TMC component
- @atclk: optional clock for the core parts of the TMC.
- @pclk: APB clock if present, otherwise NULL
- @base: memory mapped base address for this component.
- @csdev: component vitals needed by the framework.
@@ -244,6 +245,7 @@ struct tmc_resrv_buf {
Used by ETR/ETF.
*/ struct tmc_drvdata {
- struct clk *atclk; struct clk *pclk; void __iomem *base; struct coresight_device *csdev;
Otherwise, LGTM.
Reviewed-by: Anshuman Khandual anshuman.khandual@arm.com
Thanks for reviewing!
Leo
The atclk is an optional clock for the CoreSight CATU, but the driver misses to initialize it.
This change enables atclk in probe of the CATU driver, and dynamically control the clock during suspend and resume.
The checks for driver data and clocks in suspend and resume are not needed, remove them. Add error handling in the resume function.
Fixes: fcacb5c154ba ("coresight: Introduce support for Coresight Address Translation Unit") Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 22 +++++++++++++++++----- drivers/hwtracing/coresight/coresight-catu.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index fa170c966bc3..9fcda5e49253 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -513,6 +513,10 @@ static int __catu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; void __iomem *base;
+ drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) return -ENOMEM; @@ -659,18 +663,26 @@ static int catu_runtime_suspend(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); + return 0; }
static int catu_runtime_resume(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev); + int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 141feac1c14b..2fe31fed6cf1 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -62,6 +62,7 @@
struct catu_drvdata { struct clk *pclk; + struct clk *atclk; void __iomem *base; struct coresight_device *csdev; int irq;
On 3/27/25 17:07, Leo Yan wrote:
The atclk is an optional clock for the CoreSight CATU, but the driver misses to initialize it.
This change enables atclk in probe of the CATU driver, and dynamically control the clock during suspend and resume.
The checks for driver data and clocks in suspend and resume are not needed, remove them. Add error handling in the resume function.
Fixes: fcacb5c154ba ("coresight: Introduce support for Coresight Address Translation Unit") Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-catu.c | 22 +++++++++++++++++----- drivers/hwtracing/coresight/coresight-catu.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index fa170c966bc3..9fcda5e49253 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -513,6 +513,10 @@ static int __catu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; void __iomem *base;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
- catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) return -ENOMEM;
@@ -659,18 +663,26 @@ static int catu_runtime_suspend(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_disable_unprepare(drvdata->pclk);
- clk_disable_unprepare(drvdata->atclk);
- clk_disable_unprepare(drvdata->pclk);
- return 0;
} static int catu_runtime_resume(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev);
- int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_prepare_enable(drvdata->pclk);
- return 0;
- ret = clk_prepare_enable(drvdata->pclk);
- if (ret)
return ret;
- ret = clk_prepare_enable(drvdata->atclk);
- if (ret)
clk_disable_unprepare(drvdata->pclk);
- return ret;
} #endif diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 141feac1c14b..2fe31fed6cf1 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -62,6 +62,7 @@ struct catu_drvdata { struct clk *pclk;
- struct clk *atclk; void __iomem *base; struct coresight_device *csdev; int irq;
Reviewed-by: Anshuman Khandual anshuman.khandual@arm.com
The atclk is an optional clock for the CoreSight ETMv4, but the driver misses to initialize it.
This change enables atclk in probe of the ETMv4 driver, and dynamically control the clock during suspend and resume.
No need to check the driver data and clock pointer in the runtime suspend and resume, so remove checks. And add error handling in the resume function.
Add a minor fix to the comment format when adding the atclk field.
Fixes: 2e1cdfe184b5 ("coresight-etm4x: Adding CoreSight ETM4x driver") Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 20 +++++++++++++++----- drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++- 2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index e5972f16abff..537d57006a25 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2149,6 +2149,10 @@ static int etm4_probe(struct device *dev) if (WARN_ON(!drvdata)) return -ENOMEM;
+ drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) pm_save_enable = coresight_loses_context_with_cpu(dev) ? PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER; @@ -2397,8 +2401,8 @@ static int etm4_runtime_suspend(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata->pclk && !IS_ERR(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk);
return 0; } @@ -2406,11 +2410,17 @@ static int etm4_runtime_suspend(struct device *dev) static int etm4_runtime_resume(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret;
- if (drvdata->pclk && !IS_ERR(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk);
- return 0; + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index bd7db36ba197..0c21832b5d69 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -919,7 +919,8 @@ struct etmv4_save_state {
/** * struct etm4_drvdata - specifics associated to an ETM component - * @pclk APB clock if present, otherwise NULL + * @pclk: APB clock if present, otherwise NULL + * @atclk: Optional clock for the core parts of the ETMv4. * @base: Memory mapped base address for this component. * @csdev: Component vitals needed by the framework. * @spinlock: Only one at a time pls. @@ -987,6 +988,7 @@ struct etmv4_save_state { */ struct etmv4_drvdata { struct clk *pclk; + struct clk *atclk; void __iomem *base; struct coresight_device *csdev; raw_spinlock_t spinlock;
On 3/27/25 17:07, Leo Yan wrote:
The atclk is an optional clock for the CoreSight ETMv4, but the driver misses to initialize it.
This change enables atclk in probe of the ETMv4 driver, and dynamically control the clock during suspend and resume.
No need to check the driver data and clock pointer in the runtime suspend and resume, so remove checks. And add error handling in the resume function.
Add a minor fix to the comment format when adding the atclk field.
Fixes: 2e1cdfe184b5 ("coresight-etm4x: Adding CoreSight ETM4x driver") Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-etm4x-core.c | 20 +++++++++++++++----- drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++- 2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index e5972f16abff..537d57006a25 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2149,6 +2149,10 @@ static int etm4_probe(struct device *dev) if (WARN_ON(!drvdata)) return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
- if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) pm_save_enable = coresight_loses_context_with_cpu(dev) ? PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
@@ -2397,8 +2401,8 @@ static int etm4_runtime_suspend(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata->pclk && !IS_ERR(drvdata->pclk))
clk_disable_unprepare(drvdata->pclk);
- clk_disable_unprepare(drvdata->atclk);
- clk_disable_unprepare(drvdata->pclk);
return 0; } @@ -2406,11 +2410,17 @@ static int etm4_runtime_suspend(struct device *dev) static int etm4_runtime_resume(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(drvdata->pclk);
- if (ret)
return ret;
- if (drvdata->pclk && !IS_ERR(drvdata->pclk))
clk_prepare_enable(drvdata->pclk);
- ret = clk_prepare_enable(drvdata->atclk);
- if (ret)
clk_disable_unprepare(drvdata->pclk);
- return 0;
- return ret;
} #endif diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index bd7db36ba197..0c21832b5d69 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -919,7 +919,8 @@ struct etmv4_save_state { /**
- struct etm4_drvdata - specifics associated to an ETM component
- @pclk APB clock if present, otherwise NULL
- @pclk: APB clock if present, otherwise NULL
- @atclk: Optional clock for the core parts of the ETMv4.
- @base: Memory mapped base address for this component.
- @csdev: Component vitals needed by the framework.
- @spinlock: Only one at a time pls.
@@ -987,6 +988,7 @@ struct etmv4_save_state { */ struct etmv4_drvdata { struct clk *pclk;
- struct clk *atclk; void __iomem *base; struct coresight_device *csdev; raw_spinlock_t spinlock;
Reviewed-by: Anshuman Khandual anshuman.khandual@arm.com
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 coresight_get_enable_apb_pclk() by replacing clk_get() and clk_prepare_enable() with devm_clk_get_enabled() for enabling APB clock. 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") Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 9 ++------- drivers/hwtracing/coresight/coresight-cpu-debug.c | 6 +----- drivers/hwtracing/coresight/coresight-ctcu-core.c | 10 ++-------- drivers/hwtracing/coresight/coresight-etm4x-core.c | 9 ++------- drivers/hwtracing/coresight/coresight-funnel.c | 6 +----- drivers/hwtracing/coresight/coresight-replicator.c | 6 +----- drivers/hwtracing/coresight/coresight-stm.c | 4 +--- drivers/hwtracing/coresight/coresight-tmc-core.c | 4 +--- drivers/hwtracing/coresight/coresight-tpiu.c | 4 +--- include/linux/coresight.h | 16 +++------------- 10 files changed, 15 insertions(+), 59 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 9fcda5e49253..c0a51ab0312c 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -627,7 +627,7 @@ static int catu_platform_probe(struct platform_device *pdev)
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -636,11 +636,8 @@ static int catu_platform_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, drvdata); ret = __catu_probe(&pdev->dev, res); pm_runtime_put(&pdev->dev); - if (ret) { + if (ret) pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); - }
return ret; } @@ -654,8 +651,6 @@ static void catu_platform_remove(struct platform_device *pdev)
__catu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 342c3aaf414d..744b6f9b065e 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -699,7 +699,7 @@ static int debug_platform_probe(struct platform_device *pdev)
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); @@ -710,8 +710,6 @@ static int debug_platform_probe(struct platform_device *pdev) if (ret) { pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } return ret; } @@ -725,8 +723,6 @@ static void debug_platform_remove(struct platform_device *pdev)
__debug_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_ACPI diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index c6bafc96db96..de279efe3405 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -209,7 +209,7 @@ static int ctcu_probe(struct platform_device *pdev)
drvdata->apb_clk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->apb_clk)) - return -ENODEV; + return PTR_ERR(drvdata->apb_clk);
cfgs = of_device_get_match_data(dev); if (cfgs) { @@ -233,12 +233,8 @@ static int ctcu_probe(struct platform_device *pdev) desc.access = CSDEV_ACCESS_IOMEM(base);
drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_put(drvdata->apb_clk); - + if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); - }
return 0; } @@ -275,8 +271,6 @@ static void ctcu_platform_remove(struct platform_device *pdev)
ctcu_remove(pdev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_put(drvdata->apb_clk); }
#ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 537d57006a25..ff4ac4b686c4 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2237,14 +2237,12 @@ static int etm4_probe_platform_dev(struct platform_device *pdev)
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
if (res) { drvdata->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drvdata->base)) { - clk_put(drvdata->pclk); + if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - } }
dev_set_drvdata(&pdev->dev, drvdata); @@ -2351,9 +2349,6 @@ static void etm4_remove_platform_dev(struct platform_device *pdev) if (drvdata) etm4_remove_dev(drvdata); pm_runtime_disable(&pdev->dev); - - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
static const struct amba_id etm4_ids[] = { diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 0541712b2bcb..3fb9d0a37d55 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -240,7 +240,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
/* * Map the device base for dynamic-funnel, which has been @@ -283,8 +283,6 @@ static int funnel_probe(struct device *dev, struct resource *res) out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return ret; }
@@ -354,8 +352,6 @@ static void funnel_platform_remove(struct platform_device *pdev)
funnel_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
static const struct of_device_id funnel_match[] = { diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index ee7ee79f6cf7..87346617b852 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -247,7 +247,7 @@ static int replicator_probe(struct device *dev, struct resource *res)
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
/* * Map the device base for dynamic-replicator, which has been @@ -295,8 +295,6 @@ static int replicator_probe(struct device *dev, struct resource *res) out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return ret; }
@@ -334,8 +332,6 @@ static void replicator_platform_remove(struct platform_device *pdev)
replicator_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 26f9339f38b9..c32d0bd92f30 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -851,7 +851,7 @@ static int __stm_probe(struct device *dev, struct resource *res)
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata);
base = devm_ioremap_resource(dev, res); @@ -1033,8 +1033,6 @@ static void stm_platform_remove(struct platform_device *pdev)
__stm_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_ACPI diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 6aad2acd0378..86ea3fea7abb 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -990,7 +990,7 @@ static int tmc_platform_probe(struct platform_device *pdev)
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk);
dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); @@ -1014,8 +1014,6 @@ static void tmc_platform_remove(struct platform_device *pdev)
__tmc_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 97ef36f03ec2..4b9634941752 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -153,7 +153,7 @@ static int __tpiu_probe(struct device *dev, struct resource *res)
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */ @@ -293,8 +293,6 @@ static void tpiu_platform_remove(struct platform_device *pdev)
__tpiu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); }
#ifdef CONFIG_ACPI diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d79a242b271d..b888f6ed59b2 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -476,26 +476,16 @@ static inline bool is_coresight_device(void __iomem *base) * Returns: * * clk - Clock is found and enabled - * NULL - clock is not found * ERROR - Clock is found but failed to enable */ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) { struct clk *pclk; - int ret;
- pclk = clk_get(dev, "apb_pclk"); - if (IS_ERR(pclk)) { - pclk = clk_get(dev, "apb"); - if (IS_ERR(pclk)) - return NULL; - } + pclk = devm_clk_get_enabled(dev, "apb_pclk"); + if (IS_ERR(pclk)) + pclk = devm_clk_get_enabled(dev, "apb");
- ret = clk_prepare_enable(pclk); - if (ret) { - clk_put(pclk); - return ERR_PTR(ret); - } return pclk; }
The programming clock is enabled by AMBA bus driver before a dynamic probe. As a result, a CoreSight driver may redundantly enable the same clock.
To avoid this, add a check for device type and skip enabling the programming clock for AMBA devices. The returned NULL pointer will be tolerated by the drivers.
Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices") Signed-off-by: Leo Yan leo.yan@arm.com --- include/linux/coresight.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index b888f6ed59b2..26eb4a61b992 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -476,15 +476,18 @@ static inline bool is_coresight_device(void __iomem *base) * Returns: * * clk - Clock is found and enabled + * NULL - Clock is not needed as it is managed by the AMBA bus driver * ERROR - Clock is found but failed to enable */ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) { - struct clk *pclk; + struct clk *pclk = NULL;
- pclk = devm_clk_get_enabled(dev, "apb_pclk"); - if (IS_ERR(pclk)) - pclk = devm_clk_get_enabled(dev, "apb"); + if (!dev_is_amba(dev)) { + pclk = devm_clk_get_enabled(dev, "apb_pclk"); + if (IS_ERR(pclk)) + pclk = devm_clk_get_enabled(dev, "apb"); + }
return pclk; }
On 3/27/25 17:07, Leo Yan wrote:
The programming clock is enabled by AMBA bus driver before a dynamic probe. As a result, a CoreSight driver may redundantly enable the same clock.
To avoid this, add a check for device type and skip enabling the programming clock for AMBA devices. The returned NULL pointer will be tolerated by the drivers.
Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices") Signed-off-by: Leo Yan leo.yan@arm.com
include/linux/coresight.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index b888f6ed59b2..26eb4a61b992 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -476,15 +476,18 @@ static inline bool is_coresight_device(void __iomem *base)
- Returns:
- clk - Clock is found and enabled
*/
- NULL - Clock is not needed as it is managed by the AMBA bus driver
- ERROR - Clock is found but failed to enable
static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) {
- struct clk *pclk;
- struct clk *pclk = NULL;
- pclk = devm_clk_get_enabled(dev, "apb_pclk");
- if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
- if (!dev_is_amba(dev)) {
pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
- }
return pclk; }
coresight_get_enable_apb_pclk() mostly gets called in the platform driver probe paths but they are also present in some AMBA probe paths. Hence why cannot the callers in AMBA probe paths get fixed instead ? Besides return value never gets checked for NULL, which would have to be changed as well if coresight_get_enable_apb_pclk() starts returning NULL values for AMBA devices.
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) return -ENODEV;
I guess this redundancy should be fixed at the AMBA probe callers.
On Thu, Apr 03, 2025 at 12:18:56PM +0530, Anshuman Khandual wrote:
On 3/27/25 17:07, Leo Yan wrote:
The programming clock is enabled by AMBA bus driver before a dynamic probe. As a result, a CoreSight driver may redundantly enable the same clock.
To avoid this, add a check for device type and skip enabling the programming clock for AMBA devices. The returned NULL pointer will be tolerated by the drivers.
Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices") Signed-off-by: Leo Yan leo.yan@arm.com
include/linux/coresight.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index b888f6ed59b2..26eb4a61b992 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -476,15 +476,18 @@ static inline bool is_coresight_device(void __iomem *base)
- Returns:
- clk - Clock is found and enabled
*/
- NULL - Clock is not needed as it is managed by the AMBA bus driver
- ERROR - Clock is found but failed to enable
static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) {
- struct clk *pclk;
- struct clk *pclk = NULL;
- pclk = devm_clk_get_enabled(dev, "apb_pclk");
- if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
- if (!dev_is_amba(dev)) {
pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
- }
return pclk; }
coresight_get_enable_apb_pclk() mostly gets called in the platform driver probe paths but they are also present in some AMBA probe paths. Hence why cannot the callers in AMBA probe paths get fixed instead ?
With this approach, clocking operations are different in static probe and dynamic probe. This causes complexity for CoreSight drivers.
After consideration, we decided to use a central place for clock initialization. Patch 09 follows the idea to encapsulate pclk and atclk operations in the coresight_get_enable_clocks() function.
Besides return value never gets checked for NULL, which would have to be changed as well if coresight_get_enable_apb_pclk() starts returning NULL values for AMBA devices.
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) return -ENODEV;
I confirmed CoreSight drivers have used this condition, so it is safe to return NULL pointer from coresight_get_enable_apb_pclk().
Thanks, Leo
Some CoreSight components have trace bus clocks 'atclk' and are enabled using clk_prepare_enable(). These clocks are not disabled when modules exit.
As atclk is optional, use devm_clk_get_optional_enabled() to manage it. The benefit is the driver model layer can automatically disable and release clocks.
Check the returned value with IS_ERR() to detect errors but leave the NULL pointer case if the clock is not found. And remove the error handling codes which are no longer needed.
Fixes: d1839e687773 ("coresight: etm: retrieve and handle atclk") Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-etb10.c | 10 ++++------ drivers/hwtracing/coresight/coresight-etm3x-core.c | 9 +++------ drivers/hwtracing/coresight/coresight-funnel.c | 36 +++++++++++------------------------- drivers/hwtracing/coresight/coresight-replicator.c | 34 ++++++++++------------------------ drivers/hwtracing/coresight/coresight-stm.c | 9 +++------ drivers/hwtracing/coresight/coresight-tpiu.c | 10 +++------- 6 files changed, 34 insertions(+), 74 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 7948597d483d..45c2f8f50a3f 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -730,12 +730,10 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + dev_set_drvdata(dev, drvdata);
/* validity for the resource is already checked by the AMBA core */ diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 8927bfaf3af2..adbb134f80e6 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -832,12 +832,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk);
drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 3fb9d0a37d55..ec6d3e656548 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -213,7 +213,6 @@ ATTRIBUTE_GROUPS(coresight_funnel);
static int funnel_probe(struct device *dev, struct resource *res) { - int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata; @@ -231,12 +230,9 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -248,10 +244,8 @@ static int funnel_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_disable_clk; - } + if (IS_ERR(base)) + return PTR_ERR(base); drvdata->base = base; desc.groups = coresight_funnel_groups; desc.access = CSDEV_ACCESS_IOMEM(base); @@ -260,10 +254,9 @@ static int funnel_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata);
pdata = coresight_get_platform_data(dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto out_disable_clk; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + dev->platform_data = pdata;
raw_spin_lock_init(&drvdata->spinlock); @@ -273,17 +266,10 @@ static int funnel_probe(struct device *dev, struct resource *res) desc.pdata = pdata; desc.dev = dev; drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto out_disable_clk; - } + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev);
- ret = 0; - -out_disable_clk: - if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - return ret; + return 0; }
static int funnel_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 87346617b852..460af0f7b537 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -219,7 +219,6 @@ static const struct attribute_group *replicator_groups[] = {
static int replicator_probe(struct device *dev, struct resource *res) { - int ret = 0; struct coresight_platform_data *pdata = NULL; struct replicator_drvdata *drvdata; struct coresight_desc desc = { 0 }; @@ -238,12 +237,9 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -255,10 +251,8 @@ static int replicator_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_disable_clk; - } + if (IS_ERR(base)) + return PTR_ERR(base); drvdata->base = base; desc.groups = replicator_groups; desc.access = CSDEV_ACCESS_IOMEM(base); @@ -271,10 +265,8 @@ static int replicator_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata);
pdata = coresight_get_platform_data(dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto out_disable_clk; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); dev->platform_data = pdata;
raw_spin_lock_init(&drvdata->spinlock); @@ -285,17 +277,11 @@ static int replicator_probe(struct device *dev, struct resource *res) desc.dev = dev;
drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto out_disable_clk; - } + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev);
replicator_reset(drvdata); - -out_disable_clk: - if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - return ret; + return 0; }
static int replicator_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index c32d0bd92f30..f13fbab4d7a2 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -842,12 +842,9 @@ static int __stm_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 4b9634941752..cac1b5bba086 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -128,7 +128,6 @@ static const struct coresight_ops tpiu_cs_ops = {
static int __tpiu_probe(struct device *dev, struct resource *res) { - int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata; @@ -144,12 +143,9 @@ static int __tpiu_probe(struct device *dev, struct resource *res)
spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk))
On 3/27/25 17:08, Leo Yan wrote:
Some CoreSight components have trace bus clocks 'atclk' and are enabled using clk_prepare_enable(). These clocks are not disabled when modules exit.
As atclk is optional, use devm_clk_get_optional_enabled() to manage it. The benefit is the driver model layer can automatically disable and release clocks.
Check the returned value with IS_ERR() to detect errors but leave the NULL pointer case if the clock is not found. And remove the error handling codes which are no longer needed.
Fixes: d1839e687773 ("coresight: etm: retrieve and handle atclk") Signed-off-by: Leo Yan leo.yan@arm.com
This patch probably should be positioned right after [PATCH 4/9] which replaces pclk clock init with devm_clk_get_enabled().
drivers/hwtracing/coresight/coresight-etb10.c | 10 ++++------ drivers/hwtracing/coresight/coresight-etm3x-core.c | 9 +++------ drivers/hwtracing/coresight/coresight-funnel.c | 36 +++++++++++------------------------- drivers/hwtracing/coresight/coresight-replicator.c | 34 ++++++++++------------------------ drivers/hwtracing/coresight/coresight-stm.c | 9 +++------ drivers/hwtracing/coresight/coresight-tpiu.c | 10 +++------- 6 files changed, 34 insertions(+), 74 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 7948597d483d..45c2f8f50a3f 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -730,12 +730,10 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
- dev_set_drvdata(dev, drvdata);
/* validity for the resource is already checked by the AMBA core */ diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 8927bfaf3af2..adbb134f80e6 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -832,12 +832,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 3fb9d0a37d55..ec6d3e656548 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -213,7 +213,6 @@ ATTRIBUTE_GROUPS(coresight_funnel); static int funnel_probe(struct device *dev, struct resource *res) {
- int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata;
@@ -231,12 +230,9 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -248,10 +244,8 @@ static int funnel_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto out_disable_clk;
}
if (IS_ERR(base))
drvdata->base = base; desc.groups = coresight_funnel_groups; desc.access = CSDEV_ACCESS_IOMEM(base);return PTR_ERR(base);
@@ -260,10 +254,9 @@ static int funnel_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata); pdata = coresight_get_platform_data(dev);
- if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto out_disable_clk;
- }
- if (IS_ERR(pdata))
return PTR_ERR(pdata);
- dev->platform_data = pdata;
raw_spin_lock_init(&drvdata->spinlock); @@ -273,17 +266,10 @@ static int funnel_probe(struct device *dev, struct resource *res) desc.pdata = pdata; desc.dev = dev; drvdata->csdev = coresight_register(&desc);
- if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto out_disable_clk;
- }
- if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
- ret = 0;
-out_disable_clk:
- if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
clk_disable_unprepare(drvdata->atclk);
- return ret;
- return 0;
} static int funnel_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 87346617b852..460af0f7b537 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -219,7 +219,6 @@ static const struct attribute_group *replicator_groups[] = { static int replicator_probe(struct device *dev, struct resource *res) {
- int ret = 0; struct coresight_platform_data *pdata = NULL; struct replicator_drvdata *drvdata; struct coresight_desc desc = { 0 };
@@ -238,12 +237,9 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -255,10 +251,8 @@ static int replicator_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto out_disable_clk;
}
if (IS_ERR(base))
drvdata->base = base; desc.groups = replicator_groups; desc.access = CSDEV_ACCESS_IOMEM(base);return PTR_ERR(base);
@@ -271,10 +265,8 @@ static int replicator_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata); pdata = coresight_get_platform_data(dev);
- if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto out_disable_clk;
- }
- if (IS_ERR(pdata))
dev->platform_data = pdata;return PTR_ERR(pdata);
raw_spin_lock_init(&drvdata->spinlock); @@ -285,17 +277,11 @@ static int replicator_probe(struct device *dev, struct resource *res) desc.dev = dev; drvdata->csdev = coresight_register(&desc);
- if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto out_disable_clk;
- }
- if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
replicator_reset(drvdata);
-out_disable_clk:
- if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
clk_disable_unprepare(drvdata->atclk);
- return ret;
- return 0;
} static int replicator_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index c32d0bd92f30..f13fbab4d7a2 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -842,12 +842,9 @@ static int __stm_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 4b9634941752..cac1b5bba086 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -128,7 +128,6 @@ static const struct coresight_ops tpiu_cs_ops = { static int __tpiu_probe(struct device *dev, struct resource *res) {
- int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata;
@@ -144,12 +143,9 @@ static int __tpiu_probe(struct device *dev, struct resource *res) spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
- if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
- }
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk))
On Thu, Apr 03, 2025 at 12:55:46PM +0530, Anshuman Khandual wrote:
On 3/27/25 17:08, Leo Yan wrote:
Some CoreSight components have trace bus clocks 'atclk' and are enabled using clk_prepare_enable(). These clocks are not disabled when modules exit.
As atclk is optional, use devm_clk_get_optional_enabled() to manage it. The benefit is the driver model layer can automatically disable and release clocks.
Check the returned value with IS_ERR() to detect errors but leave the NULL pointer case if the clock is not found. And remove the error handling codes which are no longer needed.
Fixes: d1839e687773 ("coresight: etm: retrieve and handle atclk") Signed-off-by: Leo Yan leo.yan@arm.com
This patch probably should be positioned right after [PATCH 4/9] which replaces pclk clock init with devm_clk_get_enabled().
Sure. Will reorder patches for this.
Thanks, Leo
Since atclk is enabled after pclk during the probe phase, this commit maintains the same sequence for the runtime resume flow.
Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-funnel.c | 6 +++--- drivers/hwtracing/coresight/coresight-replicator.c | 6 +++--- drivers/hwtracing/coresight/coresight-stm.c | 6 +++--- drivers/hwtracing/coresight/coresight-tpiu.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ec6d3e656548..e378c2fffca9 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -299,11 +299,11 @@ static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 460af0f7b537..78854f586e89 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -337,11 +337,11 @@ static int replicator_runtime_resume(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index f13fbab4d7a2..ddb4f6678efd 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -972,11 +972,11 @@ static int stm_runtime_resume(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index cac1b5bba086..8212959f60d4 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -220,11 +220,11 @@ static int tpiu_runtime_resume(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif
On 3/27/25 17:08, Leo Yan wrote:
Since atclk is enabled after pclk during the probe phase, this commit maintains the same sequence for the runtime resume flow.
Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-funnel.c | 6 +++--- drivers/hwtracing/coresight/coresight-replicator.c | 6 +++--- drivers/hwtracing/coresight/coresight-stm.c | 6 +++--- drivers/hwtracing/coresight/coresight-tpiu.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ec6d3e656548..e378c2fffca9 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -299,11 +299,11 @@ static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk))
return 0;clk_prepare_enable(drvdata->atclk);
}
funnel_probe() enables pclk after atclk though - which needs to be reversed as well ?
static int funnel_probe(struct device *dev, struct resource *res) { .................. drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); if (IS_ERR(drvdata->atclk)) return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) return PTR_ERR(drvdata->pclk);
#endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 460af0f7b537..78854f586e89 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -337,11 +337,11 @@ static int replicator_runtime_resume(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk))
return 0;clk_prepare_enable(drvdata->atclk);
}
replicator_probe() enables pclk after atclk though - which needs to be reversed as well ?
static int replicator_probe(struct device *dev, struct resource *res) { .................. drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); if (IS_ERR(drvdata->atclk)) return PTR_ERR(drvdata->atclk);
drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) return PTR_ERR(drvdata->pclk);
#endif diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index f13fbab4d7a2..ddb4f6678efd 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -972,11 +972,11 @@ static int stm_runtime_resume(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk))
return 0;clk_prepare_enable(drvdata->atclk);
} #endif
same here as well.
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index cac1b5bba086..8212959f60d4 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -220,11 +220,11 @@ static int tpiu_runtime_resume(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk))
return 0;clk_prepare_enable(drvdata->atclk);
} #endif
same here as well.
I assume this patch is trying to have the same clock sequence enablement during original probe and resume path and then just the reverse sequence during suspend path.
On Thu, Apr 03, 2025 at 12:40:39PM +0530, Anshuman Khandual wrote:
On 3/27/25 17:08, Leo Yan wrote:
Since atclk is enabled after pclk during the probe phase, this commit maintains the same sequence for the runtime resume flow.
Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-funnel.c | 6 +++--- drivers/hwtracing/coresight/coresight-replicator.c | 6 +++--- drivers/hwtracing/coresight/coresight-stm.c | 6 +++--- drivers/hwtracing/coresight/coresight-tpiu.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ec6d3e656548..e378c2fffca9 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -299,11 +299,11 @@ static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk))
return 0;clk_prepare_enable(drvdata->atclk);
}
funnel_probe() enables pclk after atclk though - which needs to be reversed as well ?
Good point!
The key point is a dynamic probe enables pclk clock in AMBA bus driver, which is anyway prior to enable atclk.
We need to keep consistent flow for all flows (static probe, dynamic probe, runtime PM resume). The patch 09 consolidates clock enabling for static and dynamic probe, and this patch is for runtime PM.
For a better organization, I will place this patch after the patch 09 in the next spin.
[...]
I assume this patch is trying to have the same clock sequence enablement during original probe and resume path and then just the reverse sequence during suspend path.
Correct. As said, the patch 09 is for clock enabling sequence in probe, and this patch is for the resume path.
Thanks, Leo
The validation for driver data pointers and clock pointers are redundant in the runtime PM callbacks. After a driver's probing, its driver data and clocks have been initialized successfully, this ensures it is safe to access driver data and clocks in the runtime PM callbacks. A corner case is a clock pointer is NULL, in this case, the clock core layer can handle it properly. So remove these redundant checking.
In runtime resume, respect values returned from clock function and add error handling.
Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-cpu-debug.c | 8 +++----- drivers/hwtracing/coresight/coresight-ctcu-core.c | 8 ++------ drivers/hwtracing/coresight/coresight-etb10.c | 8 ++------ drivers/hwtracing/coresight/coresight-etm3x-core.c | 8 ++------ drivers/hwtracing/coresight/coresight-funnel.c | 21 +++++++++++---------- drivers/hwtracing/coresight/coresight-replicator.c | 20 +++++++++++--------- drivers/hwtracing/coresight/coresight-stm.c | 20 +++++++++++--------- drivers/hwtracing/coresight/coresight-tpiu.c | 20 +++++++++++--------- 8 files changed, 53 insertions(+), 60 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 744b6f9b065e..5f90351778ee 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -738,8 +738,8 @@ static int debug_runtime_suspend(struct device *dev) { struct debug_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->pclk); + return 0; }
@@ -747,9 +747,7 @@ static int debug_runtime_resume(struct device *dev) { struct debug_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + return clk_prepare_enable(drvdata->pclk); } #endif
diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index de279efe3405..edd93ff2d3c5 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -278,8 +278,7 @@ static int ctcu_runtime_suspend(struct device *dev) { struct ctcu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_disable_unprepare(drvdata->apb_clk); + clk_disable_unprepare(drvdata->apb_clk);
return 0; } @@ -288,10 +287,7 @@ static int ctcu_runtime_resume(struct device *dev) { struct ctcu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_prepare_enable(drvdata->apb_clk); - - return 0; + return clk_prepare_enable(drvdata->apb_clk); } #endif
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 45c2f8f50a3f..3f3b0eb48fdb 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -807,8 +807,7 @@ static int etb_runtime_suspend(struct device *dev) { struct etb_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk);
return 0; } @@ -817,10 +816,7 @@ static int etb_runtime_resume(struct device *dev) { struct etb_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - - return 0; + return clk_prepare_enable(drvdata->atclk); } #endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index adbb134f80e6..615ff743eef0 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -925,8 +925,7 @@ static int etm_runtime_suspend(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk);
return 0; } @@ -935,10 +934,7 @@ static int etm_runtime_resume(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - - return 0; + return clk_prepare_enable(drvdata->atclk); } #endif
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index e378c2fffca9..fd60491c9a19 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -286,11 +286,8 @@ static int funnel_runtime_suspend(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk);
return 0; } @@ -298,13 +295,17 @@ static int funnel_runtime_suspend(struct device *dev) static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 78854f586e89..aeb2b3d8e210 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -325,24 +325,26 @@ static int replicator_runtime_suspend(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; }
static int replicator_runtime_resume(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); + int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret;
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index ddb4f6678efd..d589fc61a00e 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -960,24 +960,26 @@ static int stm_runtime_suspend(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; }
static int stm_runtime_resume(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev); + int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret;
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 8212959f60d4..5821ae73a34a 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -208,24 +208,26 @@ static int tpiu_runtime_suspend(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk);
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; }
static int tpiu_runtime_resume(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev); + int ret;
- if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret;
- if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif
CoreSight drivers enable pclk and atclk conditionally. For example, pclk is only enabled in the static probe, while atclk is an optional clock that it is enabled for both dynamic and static probes, if it is present. In the current CoreSight drivers, these two clocks are initialized separately. This causes complex and duplicate codes.
This patch consolidates clock enabling into a central place. It renames coresight_get_enable_apb_pclk() to coresight_get_enable_clocks() and encapsulates clock initialization logic:
- If a clock is initialized successfully, its clock pointer is assigned to the double pointer passed as an argument. - If pclk is skipped for an AMBA device, or if atclk is not found, the corresponding double pointer is set to NULL. The function returns Success (0) to guide callers can proceed with no error. - Otherwise, an error number is returned for failures.
CoreSight drivers are refined so that clocks are initialized in one go. As a result, driver data no longer needs to be allocated separately in the static and dynamic probes. Moved the allocation into a low-level function to avoid code duplication.
Suggested-by: Suzuki K Poulose suzuki.poulose@arm.com Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 30 ++++++++++-------------------- drivers/hwtracing/coresight/coresight-cpu-debug.c | 29 +++++++++++------------------ drivers/hwtracing/coresight/coresight-ctcu-core.c | 8 ++++---- drivers/hwtracing/coresight/coresight-etm4x-core.c | 11 ++++------- drivers/hwtracing/coresight/coresight-funnel.c | 11 ++++------- drivers/hwtracing/coresight/coresight-replicator.c | 11 ++++------- drivers/hwtracing/coresight/coresight-stm.c | 9 +++------ drivers/hwtracing/coresight/coresight-tmc-core.c | 30 ++++++++++-------------------- drivers/hwtracing/coresight/coresight-tpiu.c | 10 ++++------ include/linux/coresight.h | 38 +++++++++++++++++++++++++++----------- 10 files changed, 81 insertions(+), 106 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index c0a51ab0312c..c63dee1ac997 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -508,14 +508,20 @@ static int __catu_probe(struct device *dev, struct resource *res) { int ret = 0; u32 dma_mask; - struct catu_drvdata *drvdata = dev_get_drvdata(dev); + struct catu_drvdata *drvdata; struct coresight_desc catu_desc; struct coresight_platform_data *pdata = NULL; void __iomem *base;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) @@ -571,14 +577,8 @@ static int __catu_probe(struct device *dev, struct resource *res)
static int catu_probe(struct amba_device *adev, const struct amba_id *id) { - struct catu_drvdata *drvdata; int ret;
- drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); ret = __catu_probe(&adev->dev, &adev->res); if (!ret) pm_runtime_put(&adev->dev); @@ -618,22 +618,12 @@ static struct amba_driver catu_driver = { static int catu_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct catu_drvdata *drvdata; int ret = 0;
- drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev);
- dev_set_drvdata(&pdev->dev, drvdata); ret = __catu_probe(&pdev->dev, res); pm_runtime_put(&pdev->dev); if (ret) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 5f90351778ee..dff663ac7805 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -562,10 +562,20 @@ static void debug_func_exit(void)
static int __debug_probe(struct device *dev, struct resource *res) { - struct debug_drvdata *drvdata = dev_get_drvdata(dev); + struct debug_drvdata *drvdata; void __iomem *base; int ret;
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL); + if (ret) + return ret; + drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) return drvdata->cpu; @@ -625,13 +635,6 @@ static int __debug_probe(struct device *dev, struct resource *res)
static int debug_probe(struct amba_device *adev, const struct amba_id *id) { - struct debug_drvdata *drvdata; - - drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); return __debug_probe(&adev->dev, &adev->res); }
@@ -690,18 +693,8 @@ static struct amba_driver debug_driver = { static int debug_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct debug_drvdata *drvdata; int ret = 0;
- drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index edd93ff2d3c5..c586495e9a08 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -188,7 +188,7 @@ static int ctcu_probe(struct platform_device *pdev) const struct ctcu_config *cfgs; struct ctcu_drvdata *drvdata; void __iomem *base; - int i; + int i, ret;
desc.name = coresight_alloc_device_name(&ctcu_devs, dev); if (!desc.name) @@ -207,9 +207,9 @@ static int ctcu_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base);
- drvdata->apb_clk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->apb_clk)) - return PTR_ERR(drvdata->apb_clk); + ret = coresight_get_enable_clocks(dev, &drvdata->apb_clk, NULL); + if (ret) + return ret;
cfgs = of_device_get_match_data(dev); if (cfgs) { diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index ff4ac4b686c4..ba5d1a015140 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2145,13 +2145,14 @@ static int etm4_probe(struct device *dev) struct csdev_access access = { 0 }; struct etm4_init_arg init_arg = { 0 }; struct etm4_init_arg *delayed; + int ret;
if (WARN_ON(!drvdata)) return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) pm_save_enable = coresight_loses_context_with_cpu(dev) ? @@ -2235,10 +2236,6 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) if (!drvdata) return -ENOMEM;
- drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - if (res) { drvdata->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(drvdata->base)) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index fd60491c9a19..6494a3b5d18e 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -217,6 +217,7 @@ static int funnel_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata; struct coresight_desc desc = { 0 }; + int ret;
if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) @@ -230,13 +231,9 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); - - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
/* * Map the device base for dynamic-funnel, which has been diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index aeb2b3d8e210..8595dc104795 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -223,6 +223,7 @@ static int replicator_probe(struct device *dev, struct resource *res) struct replicator_drvdata *drvdata; struct coresight_desc desc = { 0 }; void __iomem *base; + int ret;
if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-replicator")) @@ -237,13 +238,9 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); - - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
/* * Map the device base for dynamic-replicator, which has been diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index d589fc61a00e..f859ab932d22 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -842,13 +842,10 @@ static int __stm_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
- drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata);
base = devm_ioremap_resource(dev, res); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 86ea3fea7abb..745d33d0646f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -785,13 +785,19 @@ static int __tmc_probe(struct device *dev, struct resource *res) u32 devid; void __iomem *base; struct coresight_platform_data *pdata = NULL; - struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + struct tmc_drvdata *drvdata; struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
ret = -ENOMEM;
@@ -897,14 +903,8 @@ static int __tmc_probe(struct device *dev, struct resource *res)
static int tmc_probe(struct amba_device *adev, const struct amba_id *id) { - struct tmc_drvdata *drvdata; int ret;
- drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); ret = __tmc_probe(&adev->dev, &adev->res); if (!ret) pm_runtime_put(&adev->dev); @@ -981,18 +981,8 @@ static struct amba_driver tmc_driver = { static int tmc_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct tmc_drvdata *drvdata; int ret = 0;
- drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 5821ae73a34a..a68ed6b97bf7 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -132,6 +132,7 @@ static int __tpiu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata; struct coresight_desc desc = { 0 }; + int ret;
desc.name = coresight_alloc_device_name(&tpiu_devs, dev); if (!desc.name) @@ -143,13 +144,10 @@ static int __tpiu_probe(struct device *dev, struct resource *res)
spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret;
- drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 26eb4a61b992..cf3fbbc0076a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -471,25 +471,41 @@ static inline bool is_coresight_device(void __iomem *base) }
/* - * Attempt to find and enable "APB clock" for the given device + * Attempt to find and enable programming clock (pclk) and trace clock (atclk) + * for the given device. * - * Returns: + * The AMBA bus driver will cover the pclk, to avoid duplicate operations, + * skip to get and enable the pclk for an AMBA device. * - * clk - Clock is found and enabled - * NULL - Clock is not needed as it is managed by the AMBA bus driver - * ERROR - Clock is found but failed to enable + * atclk is an optional clock, it will be only enabled when it is existed. + * Otherwise, a NULL pointer will be returned to caller. + * + * Returns: '0' on Success; Error code otherwise. */ -static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) +static inline int coresight_get_enable_clocks(struct device *dev, + struct clk **pclk, + struct clk **atclk) { - struct clk *pclk = NULL; + WARN_ON(!pclk);
if (!dev_is_amba(dev)) { - pclk = devm_clk_get_enabled(dev, "apb_pclk"); - if (IS_ERR(pclk)) - pclk = devm_clk_get_enabled(dev, "apb"); + *pclk = devm_clk_get_enabled(dev, "apb_pclk"); + if (IS_ERR(*pclk)) + *pclk = devm_clk_get_enabled(dev, "apb"); + if (IS_ERR(*pclk)) + return PTR_ERR(*pclk); + } else { + /* Don't enable pclk for an AMBA device */ + *pclk = NULL; }
- return pclk; + if (atclk) { + *atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(*atclk)) + return PTR_ERR(*atclk); + } + + return 0; }
#define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4))
On 27/03/2025 11:38 am, Leo Yan wrote:
CoreSight drivers enable pclk and atclk conditionally. For example, pclk is only enabled in the static probe, while atclk is an optional clock that it is enabled for both dynamic and static probes, if it is present. In the current CoreSight drivers, these two clocks are initialized separately. This causes complex and duplicate codes.
This patch consolidates clock enabling into a central place. It renames coresight_get_enable_apb_pclk() to coresight_get_enable_clocks() and encapsulates clock initialization logic:
- If a clock is initialized successfully, its clock pointer is assigned to the double pointer passed as an argument.
- If pclk is skipped for an AMBA device, or if atclk is not found, the corresponding double pointer is set to NULL. The function returns Success (0) to guide callers can proceed with no error.
- Otherwise, an error number is returned for failures.
CoreSight drivers are refined so that clocks are initialized in one go. As a result, driver data no longer needs to be allocated separately in the static and dynamic probes. Moved the allocation into a low-level function to avoid code duplication.
Suggested-by: Suzuki K Poulose suzuki.poulose@arm.com Signed-off-by: Leo Yan leo.yan@arm.com
drivers/hwtracing/coresight/coresight-catu.c | 30 ++++++++++-------------------- drivers/hwtracing/coresight/coresight-cpu-debug.c | 29 +++++++++++------------------ drivers/hwtracing/coresight/coresight-ctcu-core.c | 8 ++++---- drivers/hwtracing/coresight/coresight-etm4x-core.c | 11 ++++------- drivers/hwtracing/coresight/coresight-funnel.c | 11 ++++------- drivers/hwtracing/coresight/coresight-replicator.c | 11 ++++------- drivers/hwtracing/coresight/coresight-stm.c | 9 +++------ drivers/hwtracing/coresight/coresight-tmc-core.c | 30 ++++++++++-------------------- drivers/hwtracing/coresight/coresight-tpiu.c | 10 ++++------ include/linux/coresight.h | 38 +++++++++++++++++++++++++++----------- 10 files changed, 81 insertions(+), 106 deletions(-)
[...]
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 26eb4a61b992..cf3fbbc0076a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -471,25 +471,41 @@ static inline bool is_coresight_device(void __iomem *base) } /*
- Attempt to find and enable "APB clock" for the given device
- Attempt to find and enable programming clock (pclk) and trace clock (atclk)
- for the given device.
- Returns:
- The AMBA bus driver will cover the pclk, to avoid duplicate operations,
- skip to get and enable the pclk for an AMBA device.
- clk - Clock is found and enabled
- NULL - Clock is not needed as it is managed by the AMBA bus driver
- ERROR - Clock is found but failed to enable
- atclk is an optional clock, it will be only enabled when it is existed.
- Otherwise, a NULL pointer will be returned to caller.
*/
- Returns: '0' on Success; Error code otherwise.
-static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) +static inline int coresight_get_enable_clocks(struct device *dev,
struct clk **pclk,
struct clk **atclk)
This function has grown a bit now, probably best to remove it from the header and export it instead.
{
- struct clk *pclk = NULL;
- WARN_ON(!pclk);
if (!dev_is_amba(dev)) {
pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
*pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(*pclk))
*pclk = devm_clk_get_enabled(dev, "apb");
if (IS_ERR(*pclk))
return PTR_ERR(*pclk);
- } else {
/* Don't enable pclk for an AMBA device */
*pclk = NULL;
Now the "apb" clock won't be enabled for amba devices. I'm assuming that's fine if the clock was always called "apb_pclk" for them, but the commit that added the new clock name didn't specify any special casing either.
Can we have a comment that says it's deliberate? But the more I think about it the more I'm confused why CTCU needed a different clock name to be defined, when all the other Coresight devices use "apb_pclk".
}
- return pclk;
- if (atclk) {
*atclk = devm_clk_get_optional_enabled(dev, "atclk");
if (IS_ERR(*atclk))
return PTR_ERR(*atclk);
- }
- return 0; }
#define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4))
On Tue, Apr 01, 2025 at 03:58:42PM +0100, James Clark wrote:
[...]
/*
- Attempt to find and enable "APB clock" for the given device
- Attempt to find and enable programming clock (pclk) and trace clock (atclk)
- for the given device.
- Returns:
- The AMBA bus driver will cover the pclk, to avoid duplicate operations,
- skip to get and enable the pclk for an AMBA device.
- clk - Clock is found and enabled
- NULL - Clock is not needed as it is managed by the AMBA bus driver
- ERROR - Clock is found but failed to enable
- atclk is an optional clock, it will be only enabled when it is existed.
- Otherwise, a NULL pointer will be returned to caller.
*/
- Returns: '0' on Success; Error code otherwise.
-static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) +static inline int coresight_get_enable_clocks(struct device *dev,
struct clk **pclk,
struct clk **atclk)
This function has grown a bit now, probably best to remove it from the header and export it instead.
Sure. I can move this function into coresight-core.c file.
{
- struct clk *pclk = NULL;
- WARN_ON(!pclk); if (!dev_is_amba(dev)) {
pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(pclk))
pclk = devm_clk_get_enabled(dev, "apb");
*pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(*pclk))
*pclk = devm_clk_get_enabled(dev, "apb");
if (IS_ERR(*pclk))
return PTR_ERR(*pclk);
- } else {
/* Don't enable pclk for an AMBA device */
*pclk = NULL;
Now the "apb" clock won't be enabled for amba devices. I'm assuming that's fine if the clock was always called "apb_pclk" for them, but the commit that added the new clock name didn't specify any special casing either.
Can we have a comment that says it's deliberate? But the more I think about it the more I'm confused why CTCU needed a different clock name to be defined, when all the other Coresight devices use "apb_pclk".
Yes, seems to me, "apb" clock is the same thing with "apb_pclk". As CTCU DT binding has been merged, for backward compatible, we cannot remove it now.
CTCU driver only supports static probe, it is never probed by AMBA bus driver. I think this is another reason that "apb_pclk" is not used in CTCU driver. I can add a comment like:
"apb_pclk" is the default clock name used by the AMBA bus driver, while "apb" is used only by the CTCU driver. A CoreSight driver should use "apb_pclk" as its programming clock name.
Thanks, Leo
}
- return pclk;
- if (atclk) {
*atclk = devm_clk_get_optional_enabled(dev, "atclk");
if (IS_ERR(*atclk))
return PTR_ERR(*atclk);
- }
- return 0; } #define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4))