When a CoreSight component's parent power domain, such as a CPU cluster genpd, fails to power on, runtime resume returns a negative error. Several call sites ignored that error and continued to access registers on an unpowered device, risking an external abort.
Replace the remaining pm_runtime_get_sync() calls with pm_runtime_resume_and_get(), which restores the runtime PM usage count when resume fails. Abort before accessing hardware and propagate the error to the caller.
In coresight_get_ref(), unwind the module and device references. In debug_enable_func(), roll back the CPUs that resumed successfully before the failure. Finally, release the mode acquired by stm_enable() if its runtime resume fails.
Signed-off-by: Yuanfang Zhang yuanfang.zhang@oss.qualcomm.com --- This patch converts the remaining CoreSight pm_runtime_get_sync() users to pm_runtime_resume_and_get(), propagates resume failures before hardware access, and completes the related module, device, CPU and mode unwind paths. --- drivers/hwtracing/coresight/coresight-core.c | 13 ++++++++++--- drivers/hwtracing/coresight/coresight-cpu-debug.c | 10 +++++----- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 10 ++++++++-- drivers/hwtracing/coresight/coresight-etm3x-sysfs.c | 10 ++++++++-- drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 5 ++++- drivers/hwtracing/coresight/coresight-funnel.c | 5 ++++- drivers/hwtracing/coresight/coresight-stm.c | 7 ++++++- drivers/hwtracing/coresight/coresight-sysfs.c | 11 +++++++++-- 8 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 928488a216d4eafa3cdb5f882ae5f44ddaff0448..ff93a017dbe22b01236ac2e5021da9b82890e72c 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -822,14 +822,16 @@ struct coresight_device *coresight_get_sink_by_id(u32 id) * * @csdev: The coresight device to get a reference on. * - * Return true in successful case and power up the device. - * Return false when failed to get reference of module. + * Return true on success and power up the device. + * Return false if a reference cannot be obtained or the device cannot be + * powered up. */ static bool coresight_get_ref(struct coresight_device *csdev) { struct device *dev = &csdev->dev; struct device *parent = csdev->dev.parent; struct device_driver *drv; + int ret;
/* Make sure csdev can't go away */ get_device(dev); @@ -843,9 +845,14 @@ static bool coresight_get_ref(struct coresight_device *csdev) goto err_module;
/* Make sure the device is powered on */ - pm_runtime_get_sync(parent); + ret = pm_runtime_resume_and_get(parent); + if (ret < 0) + goto err_pm; + return true;
+err_pm: + module_put(drv->owner); err_module: put_device(parent); put_device(dev); diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 3a806c1d50eafb4249ab516ef846e437831b9681..39602d610e5b22ec4f165dbb126a7c06aea08eb0 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -429,19 +429,19 @@ static int debug_enable_func(void) if (!drvdata) continue;
- ret = pm_runtime_get_sync(drvdata->dev); + ret = pm_runtime_resume_and_get(drvdata->dev); if (ret < 0) goto err; - else - cpumask_set_cpu(cpu, &mask); + + cpumask_set_cpu(cpu, &mask); }
return 0;
err: /* - * If pm_runtime_get_sync() has failed, need rollback on - * all the other CPUs that have been enabled before that. + * If runtime resume has failed, roll back all the other CPUs + * that have been enabled before that. */ for_each_cpu(cpu, &mask) { drvdata = per_cpu(debug_drvdata, cpu); diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 3fe2c916d228808233ef19e9213a0cc0ce3cf297..6886b8713368058b9cf33ab7fafb5f87e23c1ec9 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -167,8 +167,11 @@ static ssize_t coresight_cti_reg_show(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr); u32 val = 0; + int ret;
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret;
scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) val = cti_read_single_reg(drvdata, cti_attr->off); @@ -185,11 +188,14 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr); unsigned long val = 0; + int ret;
if (kstrtoul(buf, 0, &val)) return -EINVAL;
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret;
scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) cti_write_single_reg(drvdata, cti_attr->off, val); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index b3c67e96a82a4995515457d1ac0a5b183b162f0f..b34e282ec4a5f37f7de1d2ff118042b47368acd7 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c @@ -47,8 +47,11 @@ static ssize_t etmsr_show(struct device *dev, { unsigned long flags, val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); + int ret;
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret; spin_lock_irqsave(&drvdata->spinlock, flags); CS_UNLOCK(drvdata->csa.base);
@@ -933,13 +936,16 @@ static ssize_t seq_curr_state_show(struct device *dev, unsigned long val, flags; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; + int ret;
if (!coresight_get_mode(drvdata->csdev)) { val = config->seq_curr_state; goto out; }
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret; spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->csa.base); diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index cc6cdd3ae29d502a2e67f07400de957b6dc71af6..55e05c20b302d4bf55c4df30c9ee6d6a1b5f1031 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -2457,10 +2457,13 @@ static ssize_t coresight_etm4x_reg_show(struct device *dev, { u32 val, offset; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); + int ret;
offset = coresight_etm4x_attr_to_offset(d_attr);
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret; val = etmv4_cross_read(drvdata, offset); pm_runtime_put_sync(dev->parent);
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 0abc11f0690c5272ebd55df9e98544e3b401cfe6..5824a1e4d046a3caf5b32ed1d8526b8bd7e9ca76 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -190,9 +190,12 @@ static ssize_t funnel_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 val; + int ret; struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
- pm_runtime_get_sync(dev->parent); + ret = pm_runtime_resume_and_get(dev->parent); + if (ret < 0) + return ret;
val = get_funnel_ctrl_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 4e860519a73f6fff640090cf58298b89a31e6359..b9f15990ed994ea827c8e237d764e74d8d231ddd 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -196,6 +196,7 @@ static int stm_enable(struct coresight_device *csdev, struct perf_event *event, __maybe_unused struct coresight_path *path) { struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int ret;
if (mode != CS_MODE_SYSFS) return -EINVAL; @@ -205,7 +206,11 @@ static int stm_enable(struct coresight_device *csdev, struct perf_event *event, return -EBUSY; }
- pm_runtime_get_sync(csdev->dev.parent); + ret = pm_runtime_resume_and_get(csdev->dev.parent); + if (ret < 0) { + coresight_set_mode(csdev, CS_MODE_DISABLED); + return ret; + }
spin_lock(&drvdata->spinlock); stm_enable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index 4b010f8bc4c08da31b3d295be6c37b6d941629d2..5849dfbd9d0bd3ad10734919f78bc39cc968539c 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -17,8 +17,12 @@ ssize_t coresight_simple_show_pair(struct device *_dev, struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); u64 val; + int ret; + + ret = pm_runtime_resume_and_get(_dev->parent); + if (ret < 0) + return ret;
- pm_runtime_get_sync(_dev->parent); val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); pm_runtime_put_sync(_dev->parent); return sysfs_emit(buf, "0x%llx\n", val); @@ -31,8 +35,11 @@ ssize_t coresight_simple_show32(struct device *_dev, struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); u64 val; + int ret;
- pm_runtime_get_sync(_dev->parent); + ret = pm_runtime_resume_and_get(_dev->parent); + if (ret < 0) + return ret; val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); pm_runtime_put_sync(_dev->parent); return sysfs_emit(buf, "0x%llx\n", val);
--- base-commit: 08df884136f1c1197bab2a27814404fd329d9aac change-id: 20260911-b4-coresight-runtime-pm-failures-70f250927aeb
Best regards,
On Fri, Sep 11, 2026 at 03:28:52AM -0700, Yuanfang Zhang wrote:
[...]
Replace the remaining pm_runtime_get_sync() calls with pm_runtime_resume_and_get(), which restores the runtime PM usage count when resume fails. Abort before accessing hardware and propagate the error to the caller.
The change makes sense to me.
In coresight_get_ref(), unwind the module and device references.
Sashiko reported a pre-existing issue where the callers don't handle errors returned by coresight_get_ref() [1]. In this case, we need to remove nodes from path->path_list and release them. However, this should be done in a separate patch.
[1] https://sashiko.dev/#/patchset/20260911-b4-coresight-runtime-pm-failures-v1-...
Signed-off-by: Yuanfang Zhang yuanfang.zhang@oss.qualcomm.com
Thanks for the fix! Feel free to add:
Reviewed-by: Leo Yan leo.yan@arm.com
Hi
On 11/09/2026 11:28, Yuanfang Zhang wrote:
When a CoreSight component's parent power domain, such as a CPU cluster genpd, fails to power on, runtime resume returns a negative error. Several call sites ignored that error and continued to access registers on an unpowered device, risking an external abort.
Replace the remaining pm_runtime_get_sync() calls with pm_runtime_resume_and_get(), which restores the runtime PM usage count when resume fails. Abort before accessing hardware and propagate the error to the caller.
In coresight_get_ref(), unwind the module and device references. In debug_enable_func(), roll back the CPUs that resumed successfully before the failure. Finally, release the mode acquired by stm_enable() if its runtime resume fails.
Signed-off-by: Yuanfang Zhang yuanfang.zhang@oss.qualcomm.com
This patch converts the remaining CoreSight pm_runtime_get_sync() users to pm_runtime_resume_and_get(), propagates resume failures before hardware access, and completes the related module, device, CPU and mode unwind paths.
The patch looks good to me. Please could you rebase this on the coresight/next branch ? (to address the conflicts)
Cheers Suzuki