[PATCH v2 11/12] coresight: Pass trace mode to link enable callback

Yuanfang Zhang
2025-12-18T08:10:57Z

Currently, the link enable callback does not receive the CoreSight mode
(enum cs_mode). This prevents link drivers from knowing whether they are
being enabled for SysFS or Perf.

This distinction is crucial because Perf mode runs in atomic context,
where certain operations (like smp_call_function_single()) are unsafe.
Without knowing the mode, drivers cannot conditionally avoid these
unsafe calls.

Update the `enable` callback in `struct coresight_ops_link` to accept
`enum cs_mode`. This allows drivers to implement mode-specific logic,
such as using atomic-safe enablement sequences when running in Perf
mode. Update all call sites and driver implementations accordingly.

Signed-off-by: Yuanfang Zhang <yuanfang.zhang@oss.qualcomm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 7 ++++---
drivers/hwtracing/coresight/coresight-funnel.c | 21 +++++++++++++++++++-
drivers/hwtracing/coresight/coresight-replicator.c | 23 +++++++++++++++++++++-
drivers/hwtracing/coresight/coresight-tmc-etf.c | 19 +++++++++++++++++-
drivers/hwtracing/coresight/coresight-tnoc.c | 3 ++-
drivers/hwtracing/coresight/coresight-tpda.c | 3 ++-
include/linux/coresight.h | 3 ++-
7 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c660cf8adb1c7cafff8f85e501f056e4e151e372..1863bdb57281b4fd405cf966d565c581506ea270 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -314,7 +314,8 @@ static void coresight_disable_sink(struct coresight_device *csdev)
static int coresight_enable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child,
- struct coresight_device *source)
+ struct coresight_device *source,
+ enum cs_mode mode)
{
int link_subtype;
struct coresight_connection *inconn, *outconn;
@@ -331,7 +332,7 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
return PTR_ERR(outconn);

- return link_ops(csdev)->enable(csdev, inconn, outconn);
+ return link_ops(csdev)->enable(csdev, inconn, outconn, mode);
}

static void coresight_disable_link(struct coresight_device *csdev,
@@ -550,7 +551,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
child = list_next_entry(nd, link)->csdev;
- ret = coresight_enable_link(csdev, parent, child, source);
+ ret = coresight_enable_link(csdev, parent, child, source, mode);
if (ret)
goto err_disable_helpers;
break;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 5d114ce1109f4f9a8b108110bdae258f216881d8..c50522c2854c7193a8c30b1a603abe566a1c1ccf 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -121,7 +121,8 @@ static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)

static int funnel_enable(struct coresight_device *csdev,
struct coresight_connection *in,
- struct coresight_connection *out)
+ struct coresight_connection *out,
+ enum cs_mode mode)
{
int rc = 0;
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -135,6 +136,23 @@ static int funnel_enable(struct coresight_device *csdev,
else
in->dest_refcnt++;

+ if (mode == CS_MODE_PERF) {
+ if (first_enable) {
+ if (drvdata->supported_cpus &&
+ !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return -EINVAL;
+ }
+
+ if (drvdata->base)
+ rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
+ if (!rc)
+ in->dest_refcnt++;
+ }
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return rc;
+ }
+
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (first_enable) {
@@ -183,6 +201,7 @@ static void funnel_disable(struct coresight_device *csdev,
dynamic_funnel_disable_hw(drvdata, in->dest_port);
last_disable = true;
}
+
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (last_disable)
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index a9f22d0e15de21aa06c8d1e193e5db06091efd75..cc7d3916b8b9d5d342d6cde0487722eeb8dee78b 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -199,7 +199,8 @@ static int replicator_enable_hw(struct replicator_drvdata *drvdata,

static int replicator_enable(struct coresight_device *csdev,
struct coresight_connection *in,
- struct coresight_connection *out)
+ struct coresight_connection *out,
+ enum cs_mode mode)
{
int rc = 0;
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -212,6 +213,25 @@ static int replicator_enable(struct coresight_device *csdev,
first_enable = true;
else
out->src_refcnt++;
+
+ if (mode == CS_MODE_PERF) {
+ if (first_enable) {
+ if (drvdata->supported_cpus &&
+ !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return -EINVAL;
+ }
+
+ if (drvdata->base)
+ rc = dynamic_replicator_enable(drvdata, in->dest_port,
+ out->src_port);
+ if (!rc)
+ out->src_refcnt++;
+ }
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return rc;
+ }
+
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (first_enable) {
@@ -272,6 +292,7 @@ static void replicator_disable(struct coresight_device *csdev,
out->src_port);
last_disable = true;
}
+
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (last_disable)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 11357788e9d93c53980e99e0ef78450e393f4059..f1b8264b4e5c8a8d38778c25515cbf557c0993b7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -427,7 +427,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)

static int tmc_enable_etf_link(struct coresight_device *csdev,
struct coresight_connection *in,
- struct coresight_connection *out)
+ struct coresight_connection *out,
+ enum cs_mode mode)
{
int ret = 0;
unsigned long flags;
@@ -446,6 +447,22 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
if (!first_enable)
csdev->refcnt++;

+ if (mode == CS_MODE_PERF) {
+ if (first_enable) {
+ if (drvdata->supported_cpus &&
+ !cpumask_test_cpu(smp_processor_id(), drvdata->supported_cpus)) {
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return -EINVAL;
+ }
+
+ ret = tmc_etf_enable_hw_local(drvdata);
+ if (!ret)
+ csdev->refcnt++;
+ }
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return ret;
+ }
+
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable) {
ret = tmc_etf_enable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c
index ff9a0a9cfe96e5f5e3077c750ea2f890cdd50d94..48e9e685b9439d92bdaae9e40d3b3bc2d1ac1cd2 100644
--- a/drivers/hwtracing/coresight/coresight-tnoc.c
+++ b/drivers/hwtracing/coresight/coresight-tnoc.c
@@ -73,7 +73,8 @@ static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata)
}

static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport,
- struct coresight_connection *outport)
+ struct coresight_connection *outport,
+ enum cs_mode mode)
{
struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 3a3825d27f861585ca1d847929747f8096004089..e6f52abc5b023a997c36d74c0e3b1a3de8236ba2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -190,7 +190,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)

static int tpda_enable(struct coresight_device *csdev,
struct coresight_connection *in,
- struct coresight_connection *out)
+ struct coresight_connection *out,
+ enum cs_mode mode)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 2b48be97fcd0d7ea2692206692bd33f35ba4ec79..218eb1d1dcef61f5d98ebbfff38370192b8a6e45 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -383,7 +383,8 @@ struct coresight_ops_sink {
struct coresight_ops_link {
int (*enable)(struct coresight_device *csdev,
struct coresight_connection *in,
- struct coresight_connection *out);
+ struct coresight_connection *out,
+ enum cs_mode mode);
void (*disable)(struct coresight_device *csdev,
struct coresight_connection *in,
struct coresight_connection *out);

--
2.34.1