[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251218-cpu_cluster_component_pm-v2-10-2335a6ae62a0@oss.qualcomm.com>
Date: Thu, 18 Dec 2025 00:09:50 -0800
From: Yuanfang Zhang <yuanfang.zhang@....qualcomm.com>
To: Suzuki K Poulose <suzuki.poulose@....com>,
Mike Leach <mike.leach@...aro.org>,
James Clark <james.clark@...aro.org>, Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Mathieu Poirier <mathieu.poirier@...aro.org>,
Leo Yan <leo.yan@...ux.dev>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
Bjorn Andersson <andersson@...nel.org>,
Konrad Dybcio <konradybcio@...nel.org>
Cc: kernel@....qualcomm.com, coresight@...ts.linaro.org,
linux-arm-kernel@...ts.infradead.org, devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-arm-msm@...r.kernel.org,
Yuanfang Zhang <yuanfang.zhang@....qualcomm.com>,
maulik.shah@....qualcomm.com
Subject: [PATCH v2 10/12] coresight-tmc: Defer probe when associated CPUs
are offline
On some platforms, the TMC driver may probe before the associated CPUs
are online. This prevents the driver from securely accessing the
hardware or configuring it via smp_call_function_single(), which
requires the target CPU to be available.
To address this, defer the hardware initialization if the associated
CPUs are offline:
1. Track such deferred devices in a global list.
2. Register a CPU hotplug callback (`tmc_online_cpu`) to detect when
a relevant CPU comes online.
3. Upon CPU online, retry the hardware initialization and registration
for the waiting TMC devices.
Signed-off-by: Yuanfang Zhang <yuanfang.zhang@....qualcomm.com>
---
drivers/hwtracing/coresight/coresight-tmc-core.c | 59 +++++++++++++++++++++++-
drivers/hwtracing/coresight/coresight-tmc.h | 4 ++
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 5b9f2e57c78f42f0f1460d8a8dcbac72b5f6085e..9182fa8e4074a7c9739494b2f5d59be2e96f1d3d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -36,6 +36,9 @@
DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr");
+static LIST_HEAD(tmc_delay_probe);
+static enum cpuhp_state hp_online;
+static DEFINE_SPINLOCK(delay_lock);
int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
{
@@ -1027,6 +1030,8 @@ static int __tmc_probe(struct device *dev, struct resource *res)
if (!drvdata->supported_cpus)
return -EINVAL;
+ drvdata->dev = dev;
+
cpus_read_lock();
for_each_cpu(cpu, drvdata->supported_cpus) {
ret = smp_call_function_single(cpu,
@@ -1034,11 +1039,16 @@ static int __tmc_probe(struct device *dev, struct resource *res)
if (!ret)
break;
}
- cpus_read_unlock();
+
if (ret) {
+ scoped_guard(spinlock, &delay_lock)
+ list_add(&drvdata->link, &tmc_delay_probe);
+ cpus_read_unlock();
ret = 0;
goto out;
}
+
+ cpus_read_unlock();
} else {
tmc_init_hw_config(drvdata);
}
@@ -1103,8 +1113,12 @@ static void __tmc_remove(struct device *dev)
misc_deregister(&drvdata->miscdev);
if (drvdata->crashdev.fops)
misc_deregister(&drvdata->crashdev);
- if (drvdata->csdev)
+ if (drvdata->csdev) {
coresight_unregister(drvdata->csdev);
+ } else {
+ scoped_guard(spinlock, &delay_lock)
+ list_del(&drvdata->link);
+ }
}
static void tmc_remove(struct amba_device *adev)
@@ -1215,14 +1229,55 @@ static struct platform_driver tmc_platform_driver = {
},
};
+static int tmc_online_cpu(unsigned int cpu)
+{
+ struct tmc_drvdata *drvdata, *tmp;
+ int ret;
+
+ spin_lock(&delay_lock);
+ list_for_each_entry_safe(drvdata, tmp, &tmc_delay_probe, link) {
+ if (cpumask_test_cpu(cpu, drvdata->supported_cpus)) {
+ list_del(&drvdata->link);
+
+ spin_unlock(&delay_lock);
+ ret = pm_runtime_resume_and_get(drvdata->dev);
+ if (ret < 0)
+ return 0;
+
+ tmc_init_hw_config(drvdata);
+ tmc_clear_self_claim_tag(drvdata);
+ tmc_add_coresight_dev(drvdata->dev);
+ pm_runtime_put(drvdata->dev);
+ spin_lock(&delay_lock);
+ }
+ }
+ spin_unlock(&delay_lock);
+ return 0;
+}
+
static int __init tmc_init(void)
{
+ int ret;
+
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "arm/coresight-tmc:online",
+ tmc_online_cpu, NULL);
+
+ if (ret > 0)
+ hp_online = ret;
+ else
+ return ret;
+
return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE);
}
static void __exit tmc_exit(void)
{
coresight_remove_driver(&tmc_driver, &tmc_platform_driver);
+ if (hp_online) {
+ cpuhp_remove_state_nocalls(hp_online);
+ hp_online = 0;
+ }
}
module_init(tmc_init);
module_exit(tmc_exit);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index b104b7bf82d2a7a99382636e41d3718cf258d820..2583bc4f556195cd814e674dc66f08909dea61b2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -246,6 +246,8 @@ struct tmc_resrv_buf {
* @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.
+ * @dev: pointer to the device associated with this TMC.
+ * @link: link to the delay_probed list.
*/
struct tmc_drvdata {
struct clk *atclk;
@@ -279,6 +281,8 @@ struct tmc_drvdata {
struct cpumask *supported_cpus;
u32 devid;
const char *desc_name;
+ struct device *dev;
+ struct list_head link;
};
struct etr_buf_operations {
--
2.34.1
Powered by blists - more mailing lists