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