From: Yuanfang Zhang <yuanfang.zhang@oss.qualcomm.com>
To: Suzuki K Poulose <suzuki.poulose@arm.com>,
Mike Leach <mike.leach@linaro.org>,
James Clark <james.clark@linaro.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Mathieu Poirier <mathieu.poirier@linaro.org>,
Leo Yan <leo.yan@linux.dev>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>
Cc: kernel@oss.qualcomm.com, coresight@lists.linaro.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
Yuanfang Zhang <yuanfang.zhang@oss.qualcomm.com>,
maulik.shah@oss.qualcomm.com
Subject: [PATCH v2 07/12] coresight-tmc: Support probe and initialization for CPU cluster TMCs
Date: Thu, 18 Dec 2025 00:09:47 -0800 [thread overview]
Message-ID: <20251218-cpu_cluster_component_pm-v2-7-2335a6ae62a0@oss.qualcomm.com> (raw)
In-Reply-To: <20251218-cpu_cluster_component_pm-v2-0-2335a6ae62a0@oss.qualcomm.com>
TMC instances associated with CPU clusters reside in the cluster's power
domain. Unlike system-level TMCs, their registers are only accessible
when the cluster is powered on. Standard runtime PM may not suffice to
wake up a cluster from low-power states during probe, making direct
register access unreliable.
Refactor the probe sequence to handle these per-cluster devices safely:
1. Identify per-cluster TMCs using the "qcom,cpu-bound-components"
property.
2. For such devices, use `smp_call_function_single()` to perform
hardware initialization (`tmc_init_hw_config`) on a CPU within the
cluster. This ensures the domain is powered during access.
3. Factor out the device registration logic into `tmc_add_coresight_dev()`.
This allows common registration code to be shared between the standard
probe path and the deferred probe path (used when the associated CPUs
are initially offline).
This change ensures reliable initialization for per-cluster TMCs while
maintaining backward compatibility for standard system-level TMCs.
Signed-off-by: Yuanfang Zhang <yuanfang.zhang@oss.qualcomm.com>
---
drivers/hwtracing/coresight/coresight-tmc-core.c | 195 +++++++++++++++--------
drivers/hwtracing/coresight/coresight-tmc.h | 6 +
2 files changed, 132 insertions(+), 69 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 36599c431be6203e871fdcb8de569cc6701c52bb..0e1b5956398d3cefdd938a8a8404076eb4850b44 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -769,56 +770,14 @@ static void register_crash_dev_interface(struct tmc_drvdata *drvdata,
"Valid crash tracedata found\n");
}
-static int __tmc_probe(struct device *dev, struct resource *res)
+static int tmc_add_coresight_dev(struct device *dev)
{
- int ret = 0;
- u32 devid;
- void __iomem *base;
- struct coresight_platform_data *pdata = NULL;
- struct tmc_drvdata *drvdata;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
struct coresight_desc desc = { 0 };
struct coresight_dev_list *dev_list = NULL;
+ int ret = 0;
- 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;
-
- /* Validity for the resource is already checked by the AMBA core */
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base)) {
- ret = PTR_ERR(base);
- goto out;
- }
-
- drvdata->base = base;
- desc.access = CSDEV_ACCESS_IOMEM(base);
-
- raw_spin_lock_init(&drvdata->spinlock);
-
- devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
- drvdata->config_type = BMVAL(devid, 6, 7);
- drvdata->memwidth = tmc_get_memwidth(devid);
- /* This device is not associated with a session */
- drvdata->pid = -1;
- drvdata->etr_mode = ETR_MODE_AUTO;
-
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- drvdata->size = tmc_etr_get_default_buffer_size(dev);
- drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev);
- } else {
- drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
- }
-
- tmc_get_reserved_region(dev);
-
+ desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
desc.dev = dev;
switch (drvdata->config_type) {
@@ -834,9 +793,9 @@ static int __tmc_probe(struct device *dev, struct resource *res)
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
desc.ops = &tmc_etr_cs_ops;
- ret = tmc_etr_setup_caps(dev, devid, &desc.access);
+ ret = tmc_etr_setup_caps(dev, drvdata->devid, &desc.access);
if (ret)
- goto out;
+ return ret;
idr_init(&drvdata->idr);
mutex_init(&drvdata->idr_mutex);
dev_list = &etr_devs;
@@ -851,44 +810,141 @@ static int __tmc_probe(struct device *dev, struct resource *res)
break;
default:
pr_err("%s: Unsupported TMC config\n", desc.name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
desc.name = coresight_alloc_device_name(dev_list, dev);
- if (!desc.name) {
- ret = -ENOMEM;
+ if (!desc.name)
+ return -ENOMEM;
+
+ drvdata->desc_name = desc.name;
+
+ desc.pdata = dev->platform_data;
+
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ drvdata->miscdev.name = desc.name;
+ drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+ drvdata->miscdev.fops = &tmc_fops;
+ ret = misc_register(&drvdata->miscdev);
+ if (ret)
+ coresight_unregister(drvdata->csdev);
+
+ return ret;
+}
+
+static void tmc_clear_self_claim_tag(struct tmc_drvdata *drvdata)
+{
+ struct csdev_access access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+ coresight_clear_self_claim_tag(&access);
+}
+
+static void tmc_init_hw_config(struct tmc_drvdata *drvdata)
+{
+ u32 devid;
+
+ devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
+ drvdata->config_type = BMVAL(devid, 6, 7);
+ drvdata->memwidth = tmc_get_memwidth(devid);
+ drvdata->devid = devid;
+ drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
+ tmc_clear_self_claim_tag(drvdata);
+}
+
+static void tmc_init_on_cpu(void *info)
+{
+ struct tmc_drvdata *drvdata = info;
+
+ tmc_init_hw_config(drvdata);
+}
+
+static struct cpumask *tmc_get_supported_cpus(struct device *dev)
+{
+ struct generic_pm_domain *pd;
+
+ pd = pd_to_genpd(dev->pm_domain);
+ if (pd)
+ return pd->cpus;
+
+ return NULL;
+}
+
+static int __tmc_probe(struct device *dev, struct resource *res)
+{
+ int cpu, ret = 0;
+ void __iomem *base;
+ struct coresight_platform_data *pdata = NULL;
+ struct tmc_drvdata *drvdata;
+
+ 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;
+
+ /* Validity for the resource is already checked by the AMBA core */
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
goto out;
}
+ drvdata->base = base;
+
+ raw_spin_lock_init(&drvdata->spinlock);
+ /* This device is not associated with a session */
+ drvdata->pid = -1;
+ drvdata->etr_mode = ETR_MODE_AUTO;
+ tmc_get_reserved_region(dev);
+
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto out;
}
dev->platform_data = pdata;
- desc.pdata = pdata;
- coresight_clear_self_claim_tag(&desc.access);
- drvdata->csdev = coresight_register(&desc);
- if (IS_ERR(drvdata->csdev)) {
- ret = PTR_ERR(drvdata->csdev);
- goto out;
+ if (fwnode_property_present(dev_fwnode(dev), "qcom,cpu-bound-components")) {
+ drvdata->supported_cpus = tmc_get_supported_cpus(dev);
+ if (!drvdata->supported_cpus)
+ return -EINVAL;
+
+ cpus_read_lock();
+ for_each_cpu(cpu, drvdata->supported_cpus) {
+ ret = smp_call_function_single(cpu,
+ tmc_init_on_cpu, drvdata, 1);
+ if (!ret)
+ break;
+ }
+ cpus_read_unlock();
+ if (ret) {
+ ret = 0;
+ goto out;
+ }
+ } else {
+ tmc_init_hw_config(drvdata);
}
- drvdata->miscdev.name = desc.name;
- drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
- drvdata->miscdev.fops = &tmc_fops;
- ret = misc_register(&drvdata->miscdev);
- if (ret) {
- coresight_unregister(drvdata->csdev);
- goto out;
+ if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+ drvdata->size = tmc_etr_get_default_buffer_size(dev);
+ drvdata->max_burst_size = tmc_etr_get_max_burst_size(dev);
}
+ ret = tmc_add_coresight_dev(dev);
+
out:
if (is_tmc_crashdata_valid(drvdata) &&
!tmc_prepare_crashdata(drvdata))
- register_crash_dev_interface(drvdata, desc.name);
+ register_crash_dev_interface(drvdata, drvdata->desc_name);
return ret;
}
@@ -934,10 +990,12 @@ static void __tmc_remove(struct device *dev)
* etb fops in this case, device is there until last file
* handler to this device is closed.
*/
- misc_deregister(&drvdata->miscdev);
+ if (!drvdata->supported_cpus)
+ misc_deregister(&drvdata->miscdev);
if (drvdata->crashdev.fops)
misc_deregister(&drvdata->crashdev);
- coresight_unregister(drvdata->csdev);
+ if (drvdata->csdev)
+ coresight_unregister(drvdata->csdev);
}
static void tmc_remove(struct amba_device *adev)
@@ -992,7 +1050,6 @@ static void tmc_platform_remove(struct platform_device *pdev)
if (WARN_ON(!drvdata))
return;
-
__tmc_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 95473d1310323425b7d136cbd46f118faa7256be..b104b7bf82d2a7a99382636e41d3718cf258d820 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -243,6 +243,9 @@ struct tmc_resrv_buf {
* (after crash) by default.
* @crash_mdata: Reserved memory for storing tmc crash metadata.
* Used by ETR/ETF.
+ * @supported_cpus: Represent the CPUs related to this TMC.
+ * @devid: TMC variant ID inferred from the device configuration register.
+ * @desc_name: Name to be used while creating crash interface.
*/
struct tmc_drvdata {
struct clk *atclk;
@@ -273,6 +276,9 @@ struct tmc_drvdata {
struct etr_buf *perf_buf;
struct tmc_resrv_buf resrv_buf;
struct tmc_resrv_buf crash_mdata;
+ struct cpumask *supported_cpus;
+ u32 devid;
+ const char *desc_name;
};
struct etr_buf_operations {
--
2.34.1
next prev parent reply other threads:[~2025-12-18 8:10 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-18 8:09 [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc support Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 01/12] dt-bindings: arm: coresight: Add 'qcom,cpu-bound-components' property Yuanfang Zhang
2025-12-18 11:37 ` Sudeep Holla
2025-12-18 8:09 ` [PATCH v2 02/12] coresight-funnel: Support CPU cluster funnel initialization Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 03/12] coresight-funnel: Defer probe when associated CPUs are offline Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 04/12] coresight-replicator: Support CPU cluster replicator initialization Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 05/12] coresight-replicator: Defer probe when associated CPUs are offline Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 06/12] coresight-replicator: Update management interface for CPU-bound devices Yuanfang Zhang
2025-12-18 8:09 ` Yuanfang Zhang [this message]
2025-12-18 8:09 ` [PATCH v2 08/12] coresight-tmc-etf: Refactor enable function for CPU cluster ETF support Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 09/12] coresight-tmc: Update management interface for CPU-bound TMCs Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 10/12] coresight-tmc: Defer probe when associated CPUs are offline Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 11/12] coresight: Pass trace mode to link enable callback Yuanfang Zhang
2025-12-18 8:09 ` [PATCH v2 12/12] arm64: dts: qcom: hamoa: Add CoreSight nodes for APSS debug block yuanfang Zhang
2025-12-18 9:32 ` [PATCH v2 00/12] coresight: Add CPU cluster funnel/replicator/tmc support Suzuki K Poulose
2025-12-18 16:18 ` yuanfang zhang
2025-12-18 17:04 ` Suzuki K Poulose
2025-12-19 10:06 ` Sudeep Holla
2025-12-18 10:40 ` Leo Yan
2025-12-19 1:50 ` yuanfang zhang
2025-12-19 10:42 ` Leo Yan
2025-12-18 11:33 ` Sudeep Holla
2025-12-19 2:13 ` yuanfang zhang
2025-12-19 10:21 ` Sudeep Holla
2025-12-19 10:28 ` Suzuki K Poulose
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251218-cpu_cluster_component_pm-v2-7-2335a6ae62a0@oss.qualcomm.com \
--to=yuanfang.zhang@oss.qualcomm.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=andersson@kernel.org \
--cc=conor+dt@kernel.org \
--cc=coresight@lists.linaro.org \
--cc=devicetree@vger.kernel.org \
--cc=james.clark@linaro.org \
--cc=kernel@oss.qualcomm.com \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=leo.yan@linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.poirier@linaro.org \
--cc=maulik.shah@oss.qualcomm.com \
--cc=mike.leach@linaro.org \
--cc=robh@kernel.org \
--cc=suzuki.poulose@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox