* [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX
@ 2026-04-13 14:19 Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
` (9 more replies)
0 siblings, 10 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The current ETMx configuration via sysfs can lead to the following
inconsistencies:
- If a configuration is modified via sysfs while a perf session is
active, the running configuration may differ between before
a sched-out and after a subsequent sched-in.
- If a perf session and sysfs session tries to enable concurrently,
configuration from configfs could be corrupted (etm4).
- There is chance to corrupt drvdata->config if perf session tries
to enabled among handling cscfg_csdev_disable_active_config()
in etm4_disable_sysfs() (etm4).
To resolve these inconsistencies, the configuration should be separated into:
- active_config, which is applied configuration for the current session
- config, which stores the settings configured via sysfs.
and apply configuration from configfs after taking a mode.
This patch based on v7.0
Patch History
=============
from v3 to v4:
- change etm_drvdata->spinlock type to raw_spin_lock_t
- remove redundant call etmX_enable_hw() with starting_cpu() callsback.
- fix missing trace id release.
- add missing docs.
- https://lore.kernel.org/all/20260412175506.412301-1-yeoreum.yun@arm.com/
from v2 to v3:
- fix build error for etm3x.
- fix checkpatch warning.
- https://lore.kernel.org/all/20260410074310.2693385-1-yeoreum.yun@arm.com/
from v1 to v2
- rebased to v7.0-rc7.
- introduce etmX_caps structure to save etmX's capabilities.
- remove ss_status from etmv4_config.
- modify active_config after taking a mode (perf/sysfs).
- https://lore.kernel.org/all/20260317181705.2456271-1-yeoreum.yun@arm.com/
Yeoreum Yun (9):
coresight: etm4x: introduce struct etm4_caps
coresight: etm4x: exclude ss_status from drvdata->config
coresight: etm4x: fix leaked trace id
coresight: etm4x: fix inconsistencies with sysfs configuration
coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug
coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t
coresight: etm3x: introduce struct etm_caps
coresight: etm3x: fix inconsistencies with sysfs configuration
coresight: etm3x: remove redundant call etm_enable_hw() with hotplug
drivers/hwtracing/coresight/coresight-etm.h | 46 ++-
.../coresight/coresight-etm3x-core.c | 100 ++---
.../coresight/coresight-etm3x-sysfs.c | 159 ++++----
.../hwtracing/coresight/coresight-etm4x-cfg.c | 3 +-
.../coresight/coresight-etm4x-core.c | 365 ++++++++++--------
.../coresight/coresight-etm4x-sysfs.c | 197 ++++++----
drivers/hwtracing/coresight/coresight-etm4x.h | 182 +++++----
7 files changed, 575 insertions(+), 477 deletions(-)
base-commit: 028ef9c96e96197026887c0f092424679298aae8
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-13 17:21 ` Leo Yan
2026-04-13 14:19 ` [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
` (8 subsequent siblings)
9 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
Introduce struct etm4_caps to describe ETMv4 capabilities
and move capabilities information into it.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../coresight/coresight-etm4x-core.c | 234 +++++++++---------
.../coresight/coresight-etm4x-sysfs.c | 190 ++++++++------
drivers/hwtracing/coresight/coresight-etm4x.h | 176 ++++++-------
3 files changed, 328 insertions(+), 272 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index d565a73f0042..6443f3717b37 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -88,8 +88,9 @@ static int etm4_probe_cpu(unsigned int cpu);
*/
static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
{
- return (n < drvdata->nr_ss_cmp) &&
- drvdata->nr_pe &&
+ const struct etmv4_caps *caps = &drvdata->caps;
+
+ return (n < caps->nr_ss_cmp) && caps->nr_pe &&
(drvdata->config.ss_status[n] & TRCSSCSRn_PC);
}
@@ -160,17 +161,20 @@ static void ete_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit)
static void etm_detect_os_lock(struct etmv4_drvdata *drvdata,
struct csdev_access *csa)
{
+ struct etmv4_caps *caps = &drvdata->caps;
u32 oslsr = etm4x_relaxed_read32(csa, TRCOSLSR);
- drvdata->os_lock_model = ETM_OSLSR_OSLM(oslsr);
+ caps->os_lock_model = ETM_OSLSR_OSLM(oslsr);
}
static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
struct csdev_access *csa, u32 val)
{
+ const struct etmv4_caps *caps = &drvdata->caps;
+
val = !!val;
- switch (drvdata->os_lock_model) {
+ switch (caps->os_lock_model) {
case ETM_OSLOCK_PRESENT:
etm4x_relaxed_write32(csa, val, TRCOSLAR);
break;
@@ -179,7 +183,7 @@ static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
break;
default:
pr_warn_once("CPU%d: Unsupported Trace OSLock model: %x\n",
- smp_processor_id(), drvdata->os_lock_model);
+ smp_processor_id(), caps->os_lock_model);
fallthrough;
case ETM_OSLOCK_NI:
return;
@@ -494,6 +498,7 @@ static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata)
static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
struct device *etm_dev = &csdev->dev;
@@ -525,14 +530,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
etm4x_relaxed_write32(csa, config->pe_sel, TRCPROCSELR);
etm4x_relaxed_write32(csa, config->cfg, TRCCONFIGR);
/* nothing specific implemented */
etm4x_relaxed_write32(csa, 0x0, TRCAUXCTLR);
etm4x_relaxed_write32(csa, config->eventctrl0, TRCEVENTCTL0R);
etm4x_relaxed_write32(csa, config->eventctrl1, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
etm4x_relaxed_write32(csa, config->stall_ctrl, TRCSTALLCTLR);
etm4x_relaxed_write32(csa, config->ts_ctrl, TRCTSCTLR);
etm4x_relaxed_write32(csa, config->syncfreq, TRCSYNCPR);
@@ -542,17 +547,17 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, config->vinst_ctrl, TRCVICTLR);
etm4x_relaxed_write32(csa, config->viiectlr, TRCVIIECTLR);
etm4x_relaxed_write32(csa, config->vissctlr, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR);
etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm4x_relaxed_write32(csa, config->cntrldvr[i], TRCCNTRLDVRn(i));
etm4x_relaxed_write32(csa, config->cntr_ctrl[i], TRCCNTCTLRn(i));
etm4x_relaxed_write32(csa, config->cntr_val[i], TRCCNTVRn(i));
@@ -562,10 +567,10 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
* Resource selector pair 0 is always implemented and reserved. As
* such start at 2.
*/
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
/* always clear status bit on restart if using single-shot */
if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
config->ss_status[i] &= ~TRCSSCSRn_STATUS;
@@ -574,23 +579,23 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
etm4x_relaxed_write64(csa, config->addr_val[i], TRCACVRn(i));
etm4x_relaxed_write64(csa, config->addr_acc[i], TRCACATRn(i));
}
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
etm4x_relaxed_write64(csa, config->ctxid_pid[i], TRCCIDCVRn(i));
etm4x_relaxed_write32(csa, config->ctxid_mask0, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
etm4x_relaxed_write32(csa, config->ctxid_mask1, TRCCIDCCTLR1);
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
etm4x_relaxed_write64(csa, config->vmid_val[i], TRCVMIDCVRn(i));
etm4x_relaxed_write32(csa, config->vmid_mask0, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
etm4x_relaxed_write32(csa, config->vmid_mask1, TRCVMIDCCTLR1);
- if (!drvdata->skip_power_up) {
+ if (!caps->skip_power_up) {
u32 trcpdcr = etm4x_relaxed_read32(csa, TRCPDCR);
/*
@@ -666,19 +671,20 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
{
int ctridx;
int rselector;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/* No point in trying if we don't have at least one counter */
- if (!drvdata->nr_cntr)
+ if (!caps->nr_cntr)
return -EINVAL;
/* Find a counter that hasn't been initialised */
- for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++)
+ for (ctridx = 0; ctridx < caps->nr_cntr; ctridx++)
if (config->cntr_val[ctridx] == 0)
break;
/* All the counters have been configured already, bail out */
- if (ctridx == drvdata->nr_cntr) {
+ if (ctridx == caps->nr_cntr) {
pr_debug("%s: no available counter found\n", __func__);
return -ENOSPC;
}
@@ -694,11 +700,11 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
* ETMIDR4 gives the number of resource selector _pairs_, hence multiply
* by 2.
*/
- for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++)
+ for (rselector = 2; rselector < caps->nr_resource * 2; rselector++)
if (!config->res_ctrl[rselector])
break;
- if (rselector == drvdata->nr_resource * 2) {
+ if (rselector == caps->nr_resource * 2) {
pr_debug("%s: no available resource selector found\n",
__func__);
return -ENOSPC;
@@ -749,6 +755,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
{
int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr max_timestamp = {
.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
@@ -788,8 +795,8 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
cc_threshold = ATTR_CFG_GET_FLD(attr, cc_threshold);
if (!cc_threshold)
cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
- if (cc_threshold < drvdata->ccitmin)
- cc_threshold = drvdata->ccitmin;
+ if (cc_threshold < caps->ccitmin)
+ cc_threshold = caps->ccitmin;
config->ccctlr = cc_threshold;
}
@@ -837,7 +844,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
}
/* return stack - enable if selected and supported */
- if (ATTR_CFG_GET_FLD(attr, retstack) && drvdata->retstack)
+ if (ATTR_CFG_GET_FLD(attr, retstack) && caps->retstack)
/* bit[12], Return stack enable bit */
config->cfg |= TRCCONFIGR_RS;
@@ -853,7 +860,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
/* branch broadcast - enable if selected and supported */
if (ATTR_CFG_GET_FLD(attr, branch_broadcast)) {
- if (!drvdata->trcbb) {
+ if (!caps->trcbb) {
/*
* Missing BB support could cause silent decode errors
* so fail to open if it's not supported.
@@ -1028,6 +1035,7 @@ static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata)
static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
{
u32 control;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa = &csdev->access;
@@ -1036,7 +1044,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_cs_unlock(drvdata, csa);
etm4_disable_arch_specific(drvdata);
- if (!drvdata->skip_power_up) {
+ if (!caps->skip_power_up) {
/* power can be removed from the trace unit now */
control = etm4x_relaxed_read32(csa, TRCPDCR);
control &= ~TRCPDCR_PU;
@@ -1046,13 +1054,13 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_disable_trace_unit(drvdata);
/* read the status of the single shot comparators */
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
config->ss_status[i] =
etm4x_relaxed_read32(csa, TRCSSCSRn(i));
}
/* read back the current counter values */
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
config->cntr_val[i] =
etm4x_relaxed_read32(csa, TRCCNTVRn(i));
}
@@ -1350,7 +1358,7 @@ static struct midr_range etm_wrong_ccitmin_cpus[] = {
{},
};
-static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
+static void etm4_fixup_wrong_ccitmin(struct etmv4_caps *caps)
{
/*
* Erratum affected cpus will read 256 as the minimum
@@ -1360,8 +1368,8 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
* this problem.
*/
if (is_midr_in_range_list(etm_wrong_ccitmin_cpus)) {
- if (drvdata->ccitmin == 256)
- drvdata->ccitmin = 4;
+ if (caps->ccitmin == 256)
+ caps->ccitmin = 4;
}
}
@@ -1374,11 +1382,13 @@ static void etm4_init_arch_data(void *info)
u32 etmidr5;
struct etm4_init_arg *init_arg = info;
struct etmv4_drvdata *drvdata;
+ struct etmv4_caps *caps;
struct csdev_access *csa;
struct device *dev = init_arg->dev;
int i;
drvdata = dev_get_drvdata(init_arg->dev);
+ caps = &drvdata->caps;
csa = init_arg->csa;
/*
@@ -1391,7 +1401,7 @@ static void etm4_init_arch_data(void *info)
if (!csa->io_mem ||
fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
- drvdata->skip_power_up = true;
+ caps->skip_power_up = true;
/* Detect the support for OS Lock before we actually use it */
etm_detect_os_lock(drvdata, csa);
@@ -1406,71 +1416,71 @@ static void etm4_init_arch_data(void *info)
etmidr0 = etm4x_relaxed_read32(csa, TRCIDR0);
/* INSTP0, bits[2:1] P0 tracing support field */
- drvdata->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
+ caps->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
/* TRCBB, bit[5] Branch broadcast tracing support bit */
- drvdata->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
+ caps->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
/* TRCCOND, bit[6] Conditional instruction tracing support bit */
- drvdata->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
+ caps->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
/* TRCCCI, bit[7] Cycle counting instruction bit */
- drvdata->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
+ caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
/* RETSTACK, bit[9] Return stack bit */
- drvdata->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
+ caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
/* NUMEVENT, bits[11:10] Number of events field */
- drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
+ caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
/* QSUPP, bits[16:15] Q element support field */
- drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
- if (drvdata->q_support)
- drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
+ caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
+ if (caps->q_support)
+ caps->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
/* TSSIZE, bits[28:24] Global timestamp size field */
- drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
+ caps->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
/* maximum size of resources */
etmidr2 = etm4x_relaxed_read32(csa, TRCIDR2);
/* CIDSIZE, bits[9:5] Indicates the Context ID size */
- drvdata->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
+ caps->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
/* VMIDSIZE, bits[14:10] Indicates the VMID size */
- drvdata->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
+ caps->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
- drvdata->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
+ caps->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
- drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
- etm4_fixup_wrong_ccitmin(drvdata);
+ caps->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
+ etm4_fixup_wrong_ccitmin(caps);
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
- drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
- drvdata->config.s_ex_level = drvdata->s_ex_level;
+ caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
+ drvdata->config.s_ex_level = caps->s_ex_level;
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
- drvdata->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
+ caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
/*
* TRCERR, bit[24] whether a trace unit can trace a
* system error exception.
*/
- drvdata->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
+ caps->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
- drvdata->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
+ caps->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
/* STALLCTL, bit[26] is stall control implemented? */
- drvdata->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
+ caps->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
/* SYSSTALL, bit[27] implementation can support stall control? */
- drvdata->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
+ caps->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
/*
* NUMPROC - the number of PEs available for tracing, 5bits
* = TRCIDR3.bits[13:12]bits[30:28]
* bits[4:3] = TRCIDR3.bits[13:12] (since etm-v4.2, otherwise RES0)
* bits[3:0] = TRCIDR3.bits[30:28]
*/
- drvdata->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
- FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
+ caps->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
+ FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
- drvdata->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
+ caps->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
/* number of resources trace unit supports */
etmidr4 = etm4x_relaxed_read32(csa, TRCIDR4);
/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
- drvdata->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
+ caps->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
- drvdata->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
+ caps->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
/*
* NUMRSPAIR, bits[19:16]
* The number of resource pairs conveyed by the HW starts at 0, i.e a
@@ -1481,41 +1491,41 @@ static void etm4_init_arch_data(void *info)
* the default TRUE and FALSE resource selectors are omitted.
* Otherwise for values 0x1 and above the number is N + 1 as per v4.2.
*/
- drvdata->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
- if ((drvdata->arch < ETM_ARCH_V4_3) || (drvdata->nr_resource > 0))
- drvdata->nr_resource += 1;
+ caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
+ if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
+ caps->nr_resource += 1;
/*
* NUMSSCC, bits[23:20] the number of single-shot
* comparator control for tracing. Read any status regs as these
* also contain RO capability data.
*/
- drvdata->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
drvdata->config.ss_status[i] =
etm4x_relaxed_read32(csa, TRCSSCSRn(i));
}
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
- drvdata->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
+ caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
- drvdata->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
+ caps->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
etmidr5 = etm4x_relaxed_read32(csa, TRCIDR5);
/* NUMEXTIN, bits[8:0] number of external inputs implemented */
- drvdata->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
- drvdata->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
+ caps->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
+ caps->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
- drvdata->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
+ caps->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
/* ATBTRIG, bit[22] implementation can support ATB triggers? */
- drvdata->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
+ caps->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
/*
* LPOVERRIDE, bit[23] implementation supports
* low-power state override
*/
- drvdata->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!drvdata->skip_power_up);
+ caps->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!caps->skip_power_up);
/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
- drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
+ caps->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
/* NUMCNTR, bits[30:28] number of counters available for tracing */
- drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
+ caps->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
coresight_clear_self_claim_tag_unlocked(csa);
etm4_cs_lock(drvdata, csa);
@@ -1691,7 +1701,7 @@ static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
* nr_addr_cmp holds the number of comparator _pair_, so time 2
* for the total number of comparators.
*/
- nr_comparator = drvdata->nr_addr_cmp * 2;
+ nr_comparator = drvdata->caps.nr_addr_cmp * 2;
/* Go through the tally of comparators looking for a free one. */
while (index < nr_comparator) {
@@ -1869,6 +1879,7 @@ static int etm4_dying_cpu(unsigned int cpu)
static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
{
int i, ret = 0;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_save_state *state;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa;
@@ -1905,57 +1916,57 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
state = drvdata->save_state;
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
state->trcprocselr = etm4x_read32(csa, TRCPROCSELR);
state->trcconfigr = etm4x_read32(csa, TRCCONFIGR);
state->trcauxctlr = etm4x_read32(csa, TRCAUXCTLR);
state->trceventctl0r = etm4x_read32(csa, TRCEVENTCTL0R);
state->trceventctl1r = etm4x_read32(csa, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
state->trcstallctlr = etm4x_read32(csa, TRCSTALLCTLR);
state->trctsctlr = etm4x_read32(csa, TRCTSCTLR);
state->trcsyncpr = etm4x_read32(csa, TRCSYNCPR);
state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
- if (drvdata->q_filt)
+ if (caps->q_filt)
state->trcqctlr = etm4x_read32(csa, TRCQCTLR);
state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR);
state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR);
state->trcseqstr = etm4x_read32(csa, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
state->trccntrldvr[i] = etm4x_read32(csa, TRCCNTRLDVRn(i));
state->trccntctlr[i] = etm4x_read32(csa, TRCCNTCTLRn(i));
state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
}
/* Resource selector pair 0 is reserved */
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
state->trcssccr[i] = etm4x_read32(csa, TRCSSCCRn(i));
state->trcsscsr[i] = etm4x_read32(csa, TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
state->trcsspcicr[i] = etm4x_read32(csa, TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
state->trcacvr[i] = etm4x_read64(csa, TRCACVRn(i));
state->trcacatr[i] = etm4x_read64(csa, TRCACATRn(i));
}
@@ -1967,23 +1978,23 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
* unit") of ARM IHI 0064D.
*/
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
state->trccidcvr[i] = etm4x_read64(csa, TRCCIDCVRn(i));
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
state->trcvmidcvr[i] = etm4x_read64(csa, TRCVMIDCVRn(i));
state->trccidcctlr0 = etm4x_read32(csa, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
state->trccidcctlr1 = etm4x_read32(csa, TRCCIDCCTLR1);
state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR1);
state->trcclaimset = etm4x_read32(csa, TRCCLAIMCLR);
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
state->trcpdcr = etm4x_read32(csa, TRCPDCR);
/* wait for TRCSTATR.IDLE to go up */
@@ -2000,7 +2011,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
* potentially save power on systems that respect the TRCPDCR_PU
* despite requesting software to save/restore state.
*/
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
etm4x_relaxed_write32(csa, (state->trcpdcr & ~TRCPDCR_PU),
TRCPDCR);
out:
@@ -2027,6 +2038,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
{
int i;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_save_state *state = drvdata->save_state;
struct csdev_access *csa = &drvdata->csdev->access;
@@ -2036,77 +2048,77 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
etm4_cs_unlock(drvdata, csa);
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
etm4x_relaxed_write32(csa, state->trcprocselr, TRCPROCSELR);
etm4x_relaxed_write32(csa, state->trcconfigr, TRCCONFIGR);
etm4x_relaxed_write32(csa, state->trcauxctlr, TRCAUXCTLR);
etm4x_relaxed_write32(csa, state->trceventctl0r, TRCEVENTCTL0R);
etm4x_relaxed_write32(csa, state->trceventctl1r, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
etm4x_relaxed_write32(csa, state->trcstallctlr, TRCSTALLCTLR);
etm4x_relaxed_write32(csa, state->trctsctlr, TRCTSCTLR);
etm4x_relaxed_write32(csa, state->trcsyncpr, TRCSYNCPR);
etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
- if (drvdata->q_filt)
+ if (caps->q_filt)
etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);
etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR);
etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR);
etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm4x_relaxed_write32(csa, state->trccntrldvr[i], TRCCNTRLDVRn(i));
etm4x_relaxed_write32(csa, state->trccntctlr[i], TRCCNTCTLRn(i));
etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
}
/* Resource selector pair 0 is reserved */
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
etm4x_relaxed_write32(csa, state->trcssccr[i], TRCSSCCRn(i));
etm4x_relaxed_write32(csa, state->trcsscsr[i], TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, state->trcsspcicr[i], TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
etm4x_relaxed_write64(csa, state->trcacvr[i], TRCACVRn(i));
etm4x_relaxed_write64(csa, state->trcacatr[i], TRCACATRn(i));
}
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
etm4x_relaxed_write64(csa, state->trccidcvr[i], TRCCIDCVRn(i));
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
etm4x_relaxed_write64(csa, state->trcvmidcvr[i], TRCVMIDCVRn(i));
etm4x_relaxed_write32(csa, state->trccidcctlr0, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
etm4x_relaxed_write32(csa, state->trccidcctlr1, TRCCIDCCTLR1);
etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR1);
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
etm4x_relaxed_write32(csa, state->trcpdcr, TRCPDCR);
/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index e9eeea6240d5..50408215d1ac 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -62,8 +62,9 @@ static ssize_t nr_pe_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_pe_cmp;
+ val = caps->nr_pe_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_pe_cmp);
@@ -74,8 +75,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_addr_cmp;
+ val = caps->nr_addr_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_addr_cmp);
@@ -86,8 +88,9 @@ static ssize_t nr_cntr_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_cntr;
+ val = caps->nr_cntr;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_cntr);
@@ -98,8 +101,9 @@ static ssize_t nr_ext_inp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_ext_inp;
+ val = caps->nr_ext_inp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ext_inp);
@@ -110,8 +114,9 @@ static ssize_t numcidc_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->numcidc;
+ val = caps->numcidc;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(numcidc);
@@ -122,8 +127,9 @@ static ssize_t numvmidc_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->numvmidc;
+ val = caps->numvmidc;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(numvmidc);
@@ -134,8 +140,9 @@ static ssize_t nrseqstate_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nrseqstate;
+ val = caps->nrseqstate;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nrseqstate);
@@ -146,8 +153,9 @@ static ssize_t nr_resource_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_resource;
+ val = caps->nr_resource;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_resource);
@@ -158,8 +166,9 @@ static ssize_t nr_ss_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_ss_cmp;
+ val = caps->nr_ss_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ss_cmp);
@@ -171,6 +180,7 @@ static ssize_t reset_store(struct device *dev,
int i;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -200,7 +210,7 @@ static ssize_t reset_store(struct device *dev,
config->stall_ctrl = 0x0;
/* Reset trace synchronization period to 2^8 = 256 bytes*/
- if (drvdata->syncpr == false)
+ if (!caps->syncpr)
config->syncfreq = 0x8;
/*
@@ -209,7 +219,7 @@ static ssize_t reset_store(struct device *dev,
* each trace run.
*/
config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
- if (drvdata->nr_addr_cmp > 0) {
+ if (caps->nr_addr_cmp > 0) {
config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
/* SSSTATUS, bit[9] */
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
@@ -223,7 +233,7 @@ static ssize_t reset_store(struct device *dev,
config->vipcssctlr = 0x0;
/* Disable seq events */
- for (i = 0; i < drvdata->nrseqstate-1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
config->seq_ctrl[i] = 0x0;
config->seq_rst = 0x0;
config->seq_state = 0x0;
@@ -232,38 +242,38 @@ static ssize_t reset_store(struct device *dev,
config->ext_inp = 0x0;
config->cntr_idx = 0x0;
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
config->cntrldvr[i] = 0x0;
config->cntr_ctrl[i] = 0x0;
config->cntr_val[i] = 0x0;
}
config->res_idx = 0x0;
- for (i = 2; i < 2 * drvdata->nr_resource; i++)
+ for (i = 2; i < 2 * caps->nr_resource; i++)
config->res_ctrl[i] = 0x0;
config->ss_idx = 0x0;
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
config->ss_ctrl[i] = 0x0;
config->ss_pe_cmp[i] = 0x0;
}
config->addr_idx = 0x0;
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
config->addr_val[i] = 0x0;
config->addr_acc[i] = 0x0;
config->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
config->ctxid_idx = 0x0;
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
config->ctxid_pid[i] = 0x0;
config->ctxid_mask0 = 0x0;
config->ctxid_mask1 = 0x0;
config->vmid_idx = 0x0;
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
config->vmid_val[i] = 0x0;
config->vmid_mask0 = 0x0;
config->vmid_mask1 = 0x0;
@@ -297,6 +307,7 @@ static ssize_t mode_store(struct device *dev,
{
unsigned long val, mode;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -305,7 +316,7 @@ static ssize_t mode_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
config->mode = val & ETMv4_MODE_ALL;
- if (drvdata->instrp0 == true) {
+ if (caps->instrp0) {
/* start by clearing instruction P0 field */
config->cfg &= ~TRCCONFIGR_INSTP0_LOAD_STORE;
if (config->mode & ETM_MODE_LOAD)
@@ -323,45 +334,44 @@ static ssize_t mode_store(struct device *dev,
}
/* bit[3], Branch broadcast mode */
- if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
+ if ((config->mode & ETM_MODE_BB) && (caps->trcbb))
config->cfg |= TRCCONFIGR_BB;
else
config->cfg &= ~TRCCONFIGR_BB;
/* bit[4], Cycle counting instruction trace bit */
if ((config->mode & ETMv4_MODE_CYCACC) &&
- (drvdata->trccci == true))
+ (caps->trccci == true))
config->cfg |= TRCCONFIGR_CCI;
else
config->cfg &= ~TRCCONFIGR_CCI;
/* bit[6], Context ID tracing bit */
- if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
+ if ((config->mode & ETMv4_MODE_CTXID) && (caps->ctxid_size))
config->cfg |= TRCCONFIGR_CID;
else
config->cfg &= ~TRCCONFIGR_CID;
- if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
+ if ((config->mode & ETM_MODE_VMID) && (caps->vmid_size))
config->cfg |= TRCCONFIGR_VMID;
else
config->cfg &= ~TRCCONFIGR_VMID;
/* bits[10:8], Conditional instruction tracing bit */
mode = ETM_MODE_COND(config->mode);
- if (drvdata->trccond == true) {
+ if (caps->trccond) {
config->cfg &= ~TRCCONFIGR_COND_MASK;
config->cfg |= mode << __bf_shf(TRCCONFIGR_COND_MASK);
}
/* bit[11], Global timestamp tracing bit */
- if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
+ if ((config->mode & ETMv4_MODE_TIMESTAMP) && (caps->ts_size))
config->cfg |= TRCCONFIGR_TS;
else
config->cfg &= ~TRCCONFIGR_TS;
/* bit[12], Return stack enable bit */
- if ((config->mode & ETM_MODE_RETURNSTACK) &&
- (drvdata->retstack == true))
+ if ((config->mode & ETM_MODE_RETURNSTACK) && (caps->retstack))
config->cfg |= TRCCONFIGR_RS;
else
config->cfg &= ~TRCCONFIGR_RS;
@@ -375,31 +385,29 @@ static ssize_t mode_store(struct device *dev,
* Always set the low bit for any requested mode. Valid combos are
* 0b00, 0b01 and 0b11.
*/
- if (mode && drvdata->q_support)
+ if (mode && caps->q_support)
config->cfg |= TRCCONFIGR_QE_W_COUNTS;
/*
* if supported, Q elements with and without instruction
* counts are enabled
*/
- if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
+ if ((mode & BIT(1)) && (caps->q_support & BIT(1)))
config->cfg |= TRCCONFIGR_QE_WO_COUNTS;
/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
- if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
- (drvdata->atbtrig == true))
+ if ((config->mode & ETM_MODE_ATB_TRIGGER) && (caps->atbtrig))
config->eventctrl1 |= TRCEVENTCTL1R_ATB;
else
config->eventctrl1 &= ~TRCEVENTCTL1R_ATB;
/* bit[12], Low-power state behavior override bit */
- if ((config->mode & ETM_MODE_LPOVERRIDE) &&
- (drvdata->lpoverride == true))
+ if ((config->mode & ETM_MODE_LPOVERRIDE) && (caps->lpoverride))
config->eventctrl1 |= TRCEVENTCTL1R_LPOVERRIDE;
else
config->eventctrl1 &= ~TRCEVENTCTL1R_LPOVERRIDE;
/* bit[8], Instruction stall bit */
- if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true))
+ if ((config->mode & ETM_MODE_ISTALL_EN) && (caps->stallctl))
config->stall_ctrl |= TRCSTALLCTLR_ISTALL;
else
config->stall_ctrl &= ~TRCSTALLCTLR_ISTALL;
@@ -411,8 +419,7 @@ static ssize_t mode_store(struct device *dev,
config->stall_ctrl &= ~TRCSTALLCTLR_INSTPRIORITY;
/* bit[13], Trace overflow prevention bit */
- if ((config->mode & ETM_MODE_NOOVERFLOW) &&
- (drvdata->nooverflow == true))
+ if ((config->mode & ETM_MODE_NOOVERFLOW) && (caps->nooverflow))
config->stall_ctrl |= TRCSTALLCTLR_NOOVERFLOW;
else
config->stall_ctrl &= ~TRCSTALLCTLR_NOOVERFLOW;
@@ -430,8 +437,7 @@ static ssize_t mode_store(struct device *dev,
config->vinst_ctrl &= ~TRCVICTLR_TRCRESET;
/* bit[11], Whether a trace unit must trace a system error exception */
- if ((config->mode & ETM_MODE_TRACE_ERR) &&
- (drvdata->trc_error == true))
+ if ((config->mode & ETM_MODE_TRACE_ERR) && (caps->trc_error))
config->vinst_ctrl |= TRCVICTLR_TRCERR;
else
config->vinst_ctrl &= ~TRCVICTLR_TRCERR;
@@ -463,13 +469,14 @@ static ssize_t pe_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
- if (val > drvdata->nr_pe) {
+ if (val > caps->nr_pe) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -498,13 +505,14 @@ static ssize_t event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
- switch (drvdata->nr_event) {
+ switch (caps->nr_event) {
case 0x0:
/* EVENT0, bits[7:0] */
config->eventctrl0 = val & 0xFF;
@@ -547,6 +555,7 @@ static ssize_t event_instren_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -555,7 +564,7 @@ static ssize_t event_instren_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
/* start by clearing all instruction event enable bits */
config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
- switch (drvdata->nr_event) {
+ switch (caps->nr_event) {
case 0x0:
/* generate Event element for event 1 */
config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
@@ -603,11 +612,12 @@ static ssize_t event_ts_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!drvdata->ts_size)
+ if (!caps->ts_size)
return -EINVAL;
config->ts_ctrl = val & ETMv4_EVENT_MASK;
@@ -633,11 +643,12 @@ static ssize_t syncfreq_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (drvdata->syncpr == true)
+ if (caps->syncpr)
return -EINVAL;
config->syncfreq = val & ETMv4_SYNC_MASK;
@@ -663,6 +674,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -670,7 +682,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
/* mask off max threshold before checking min value */
val &= ETM_CYC_THRESHOLD_MASK;
- if (val < drvdata->ccitmin)
+ if (val < caps->ccitmin)
return -EINVAL;
config->ccctlr = val;
@@ -696,13 +708,14 @@ static ssize_t bb_ctrl_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (drvdata->trcbb == false)
+ if (!caps->trcbb)
return -EINVAL;
- if (!drvdata->nr_addr_cmp)
+ if (!caps->nr_addr_cmp)
return -EINVAL;
/*
@@ -768,6 +781,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -777,7 +791,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
/* clear all EXLEVEL_S bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
/* enable instruction tracing for corresponding exception level */
- val &= drvdata->s_ex_level;
+ val &= caps->s_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
raw_spin_unlock(&drvdata->spinlock);
return size;
@@ -803,6 +817,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -812,7 +827,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
/* clear EXLEVEL_NS bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
/* enable instruction tracing for corresponding exception level */
- val &= drvdata->ns_ex_level;
+ val &= caps->ns_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
raw_spin_unlock(&drvdata->spinlock);
return size;
@@ -837,11 +852,12 @@ static ssize_t addr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_addr_cmp * 2)
+ if (val >= caps->nr_addr_cmp * 2)
return -EINVAL;
/*
@@ -1060,6 +1076,7 @@ static ssize_t addr_start_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1067,7 +1084,7 @@ static ssize_t addr_start_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
- if (!drvdata->nr_addr_cmp) {
+ if (!caps->nr_addr_cmp) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -1115,6 +1132,7 @@ static ssize_t addr_stop_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1122,7 +1140,7 @@ static ssize_t addr_stop_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
- if (!drvdata->nr_addr_cmp) {
+ if (!caps->nr_addr_cmp) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -1167,6 +1185,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
u8 idx;
char str[10] = "";
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (strlen(buf) >= 10)
@@ -1181,13 +1200,13 @@ static ssize_t addr_ctxtype_store(struct device *dev,
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_MASK;
else if (!strcmp(str, "ctxid")) {
/* 0b01 The trace unit performs a Context ID */
- if (drvdata->numcidc) {
+ if (caps->numcidc) {
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_VMID;
}
} else if (!strcmp(str, "vmid")) {
/* 0b10 The trace unit performs a VMID */
- if (drvdata->numvmidc) {
+ if (caps->numvmidc) {
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_CTXID;
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
}
@@ -1196,9 +1215,9 @@ static ssize_t addr_ctxtype_store(struct device *dev,
* 0b11 The trace unit performs a Context ID
* comparison and a VMID
*/
- if (drvdata->numcidc)
+ if (caps->numcidc)
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
- if (drvdata->numvmidc)
+ if (caps->numvmidc)
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
}
raw_spin_unlock(&drvdata->spinlock);
@@ -1230,14 +1249,15 @@ static ssize_t addr_context_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if ((drvdata->numcidc <= 1) && (drvdata->numvmidc <= 1))
+ if ((caps->numcidc <= 1) && (caps->numvmidc <= 1))
return -EINVAL;
- if (val >= (drvdata->numcidc >= drvdata->numvmidc ?
- drvdata->numcidc : drvdata->numvmidc))
+ if (val >= (caps->numcidc >= caps->numvmidc ?
+ caps->numcidc : caps->numvmidc))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1348,9 +1368,10 @@ static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
- if (!drvdata->nr_pe_cmp)
+ if (!caps->nr_pe_cmp)
return -EINVAL;
val = config->vipcssctlr;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
@@ -1361,11 +1382,12 @@ static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!drvdata->nr_pe_cmp)
+ if (!caps->nr_pe_cmp)
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1393,11 +1415,12 @@ static ssize_t seq_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nrseqstate - 1)
+ if (val >= caps->nrseqstate - 1)
return -EINVAL;
/*
@@ -1429,11 +1452,12 @@ static ssize_t seq_state_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nrseqstate)
+ if (val >= caps->nrseqstate)
return -EINVAL;
config->seq_state = val;
@@ -1496,11 +1520,12 @@ static ssize_t seq_reset_event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!(drvdata->nrseqstate))
+ if (!(caps->nrseqstate))
return -EINVAL;
config->seq_rst = val & ETMv4_EVENT_MASK;
@@ -1526,11 +1551,12 @@ static ssize_t cntr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_cntr)
+ if (val >= caps->nr_cntr)
return -EINVAL;
/*
@@ -1674,6 +1700,7 @@ static ssize_t res_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1682,7 +1709,7 @@ static ssize_t res_idx_store(struct device *dev,
* Resource selector pair 0 is always implemented and reserved,
* namely an idx with 0 and 1 is illegal.
*/
- if ((val < 2) || (val >= 2 * drvdata->nr_resource))
+ if ((val < 2) || (val >= 2 * caps->nr_resource))
return -EINVAL;
/*
@@ -1756,11 +1783,12 @@ static ssize_t sshot_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_ss_cmp)
+ if (val >= caps->nr_ss_cmp)
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1874,11 +1902,12 @@ static ssize_t ctxid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->numcidc)
+ if (val >= caps->numcidc)
return -EINVAL;
/*
@@ -1922,6 +1951,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
u8 idx;
unsigned long pid;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/*
@@ -1941,7 +1971,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
* ctxid comparator is implemented and ctxid is greater than 0 bits
* in length
*/
- if (!drvdata->ctxid_size || !drvdata->numcidc)
+ if (!caps->ctxid_size || !caps->numcidc)
return -EINVAL;
if (kstrtoul(buf, 16, &pid))
return -EINVAL;
@@ -1983,6 +2013,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
int nr_inputs;
@@ -1998,11 +2029,11 @@ static ssize_t ctxid_masks_store(struct device *dev,
* ctxid comparator is implemented and ctxid is greater than 0 bits
* in length
*/
- if (!drvdata->ctxid_size || !drvdata->numcidc)
+ if (!caps->ctxid_size || !caps->numcidc)
return -EINVAL;
/* one mask if <= 4 comparators, two for up to 8 */
nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
- if ((drvdata->numcidc > 4) && (nr_inputs != 2))
+ if ((caps->numcidc > 4) && (nr_inputs != 2))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -2010,7 +2041,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
* each byte[0..3] controls mask value applied to ctxid
* comparator[0..3]
*/
- switch (drvdata->numcidc) {
+ switch (caps->numcidc) {
case 0x1:
/* COMP0, bits[7:0] */
config->ctxid_mask0 = val1 & 0xFF;
@@ -2057,7 +2088,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
* of ctxid comparator0 value (corresponding to byte 0) register.
*/
mask = config->ctxid_mask0;
- for (i = 0; i < drvdata->numcidc; i++) {
+ for (i = 0; i < caps->numcidc; i++) {
/* mask value of corresponding ctxid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
/*
@@ -2100,11 +2131,12 @@ static ssize_t vmid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->numvmidc)
+ if (val >= caps->numvmidc)
return -EINVAL;
/*
@@ -2145,6 +2177,7 @@ static ssize_t vmid_val_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/*
@@ -2158,7 +2191,7 @@ static ssize_t vmid_val_store(struct device *dev,
* only implemented when vmid tracing is enabled, i.e. at least one
* vmid comparator is implemented and at least 8 bit vmid size
*/
- if (!drvdata->vmid_size || !drvdata->numvmidc)
+ if (!caps->vmid_size || !caps->numvmidc)
return -EINVAL;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -2198,6 +2231,7 @@ static ssize_t vmid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
int nr_inputs;
@@ -2212,11 +2246,11 @@ static ssize_t vmid_masks_store(struct device *dev,
* only implemented when vmid tracing is enabled, i.e. at least one
* vmid comparator is implemented and at least 8 bit vmid size
*/
- if (!drvdata->vmid_size || !drvdata->numvmidc)
+ if (!caps->vmid_size || !caps->numvmidc)
return -EINVAL;
/* one mask if <= 4 comparators, two for up to 8 */
nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
- if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
+ if ((caps->numvmidc > 4) && (nr_inputs != 2))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -2225,7 +2259,7 @@ static ssize_t vmid_masks_store(struct device *dev,
* each byte[0..3] controls mask value applied to vmid
* comparator[0..3]
*/
- switch (drvdata->numvmidc) {
+ switch (caps->numvmidc) {
case 0x1:
/* COMP0, bits[7:0] */
config->vmid_mask0 = val1 & 0xFF;
@@ -2273,7 +2307,7 @@ static ssize_t vmid_masks_store(struct device *dev,
* of vmid comparator0 value (corresponding to byte 0) register.
*/
mask = config->vmid_mask0;
- for (i = 0; i < drvdata->numvmidc; i++) {
+ for (i = 0; i < caps->numvmidc; i++) {
/* mask value of corresponding vmid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 89d81ce4e04e..8168676f2945 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -812,6 +812,95 @@ enum etm_impdef_type {
ETM4_IMPDEF_FEATURE_MAX,
};
+/**
+ * struct etmv4_caps - specifics ETM capabilities
+ * @nr_pe: The number of processing entity available for tracing.
+ * @nr_pe_cmp: The number of processing entity comparator inputs that are
+ * available for tracing.
+ * @nr_addr_cmp:Number of pairs of address comparators available
+ * as found in ETMIDR4 0-3.
+ * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
+ * @nr_ext_inp: Number of external input.
+ * @numcidc: Number of contextID comparators.
+ * @numextinsel: Number of external input selector resources.
+ * @numvmidc: Number of VMID comparators.
+ * @nrseqstate: The number of sequencer states that are implemented.
+ * @nr_event: Indicates how many events the trace unit support.
+ * @nr_resource:The number of resource selection pairs available for tracing.
+ * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * @trcid_size: Indicates the trace ID width.
+ * @ts_size: Global timestamp size field.
+ * @ctxid_size: Size of the context ID field to consider.
+ * @vmid_size: Size of the VM ID comparator to consider.
+ * @ccsize: Indicates the size of the cycle counter in bits.
+ * @ccitmin: minimum value that can be programmed in
+ * @s_ex_level: In secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @q_support: Q element support characteristics.
+ * @os_lock_model: OSLock model.
+ * @instrp0: Tracing of load and store instructions
+ * as P0 elements is supported.
+ * @q_filt: Q element filtering support, if Q elements are supported.
+ * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
+ * @trccond: If the trace unit supports conditional
+ * instruction tracing.
+ * @retstack: Indicates if the implementation supports a return stack.
+ * @trccci: Indicates if the trace unit supports cycle counting
+ * for instruction.
+ * @trc_error: Whether a trace unit can trace a system
+ * error exception.
+ * @syncpr: Indicates if an implementation has a fixed
+ * synchronization period.
+ * @stallctl: If functionality that prevents trace unit buffer overflows
+ * is available.
+ * @sysstall: Does the system support stall control of the PE?
+ * @nooverflow: Indicate if overflow prevention is supported.
+ * @atbtrig: If the implementation can support ATB triggers
+ * @lpoverride: If the implementation can support low-power state over.
+ * @skip_power_up: Indicates if an implementation can skip powering up
+ * the trace unit.
+ */
+struct etmv4_caps {
+ u8 nr_pe;
+ u8 nr_pe_cmp;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 numcidc;
+ u8 numextinsel;
+ u8 numvmidc;
+ u8 nrseqstate;
+ u8 nr_event;
+ u8 nr_resource;
+ u8 nr_ss_cmp;
+ u8 trcid_size;
+ u8 ts_size;
+ u8 ctxid_size;
+ u8 vmid_size;
+ u8 ccsize;
+ u16 ccitmin;
+ u8 s_ex_level;
+ u8 ns_ex_level;
+ u8 q_support;
+ u8 os_lock_model;
+ bool instrp0 : 1;
+ bool q_filt : 1;
+ bool trcbb : 1;
+ bool trccond : 1;
+ bool retstack : 1;
+ bool trccci : 1;
+ bool trc_error : 1;
+ bool syncpr : 1;
+ bool stallctl : 1;
+ bool sysstall : 1;
+ bool nooverflow : 1;
+ bool atbtrig : 1;
+ bool lpoverride : 1;
+ bool skip_power_up : 1;
+};
+
/**
* struct etmv4_config - configuration information related to an ETMv4
* @mode: Controls various modes supported by this ETM.
@@ -819,8 +908,8 @@ enum etm_impdef_type {
* @cfg: Controls the tracing options.
* @eventctrl0: Controls the tracing of arbitrary events.
* @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
- * @stallctl: If functionality that prevents trace unit buffer overflows
- * is available.
+ * @stall_ctrl: Enables trace unit functionality that prevents trace
+ * unit buffer overflows.
* @ts_ctrl: Controls the insertion of global timestamps in the
* trace streams.
* @syncfreq: Controls how often trace synchronization requests occur.
@@ -971,61 +1060,17 @@ struct etmv4_save_state {
* @mode: This tracer's mode, i.e sysFS, Perf or disabled.
* @cpu: The cpu this component is affined to.
* @arch: ETM architecture version.
- * @nr_pe: The number of processing entity available for tracing.
- * @nr_pe_cmp: The number of processing entity comparator inputs that are
- * available for tracing.
- * @nr_addr_cmp:Number of pairs of address comparators available
- * as found in ETMIDR4 0-3.
- * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
- * @nr_ext_inp: Number of external input.
- * @numcidc: Number of contextID comparators.
- * @numvmidc: Number of VMID comparators.
- * @nrseqstate: The number of sequencer states that are implemented.
- * @nr_event: Indicates how many events the trace unit support.
- * @nr_resource:The number of resource selection pairs available for tracing.
- * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * @caps: ETM capabilities.
* @trcid: value of the current ID for this component.
- * @trcid_size: Indicates the trace ID width.
- * @ts_size: Global timestamp size field.
- * @ctxid_size: Size of the context ID field to consider.
- * @vmid_size: Size of the VM ID comparator to consider.
- * @ccsize: Indicates the size of the cycle counter in bits.
- * @ccitmin: minimum value that can be programmed in
- * @s_ex_level: In secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
- * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:True if we should start tracing at boot time.
* @os_unlock: True if access to management registers is allowed.
- * @instrp0: Tracing of load and store instructions
- * as P0 elements is supported.
- * @q_filt: Q element filtering support, if Q elements are supported.
- * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
- * @trccond: If the trace unit supports conditional
- * instruction tracing.
- * @retstack: Indicates if the implementation supports a return stack.
- * @trccci: Indicates if the trace unit supports cycle counting
- * for instruction.
- * @q_support: Q element support characteristics.
- * @trc_error: Whether a trace unit can trace a system
- * error exception.
- * @syncpr: Indicates if an implementation has a fixed
- * synchronization period.
- * @stall_ctrl: Enables trace unit functionality that prevents trace
- * unit buffer overflows.
- * @sysstall: Does the system support stall control of the PE?
- * @nooverflow: Indicate if overflow prevention is supported.
- * @atbtrig: If the implementation can support ATB triggers
- * @lpoverride: If the implementation can support low-power state over.
* @trfcr: If the CPU supports FEAT_TRF, value of the TRFCR_ELx that
* allows tracing at all ELs. We don't want to compute this
* at runtime, due to the additional setting of TRFCR_CX when
* in EL2. Otherwise, 0.
* @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
- * @skip_power_up: Indicates if an implementation can skip powering up
- * the trace unit.
* @paused: Indicates if the trace unit is paused.
* @arch_features: Bitmap of arch features of etmv4 devices.
*/
@@ -1037,46 +1082,11 @@ struct etmv4_drvdata {
raw_spinlock_t spinlock;
int cpu;
u8 arch;
- u8 nr_pe;
- u8 nr_pe_cmp;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 numcidc;
- u8 numextinsel;
- u8 numvmidc;
- u8 nrseqstate;
- u8 nr_event;
- u8 nr_resource;
- u8 nr_ss_cmp;
+ struct etmv4_caps caps;
u8 trcid;
- u8 trcid_size;
- u8 ts_size;
- u8 ctxid_size;
- u8 vmid_size;
- u8 ccsize;
- u16 ccitmin;
- u8 s_ex_level;
- u8 ns_ex_level;
- u8 q_support;
- u8 os_lock_model;
bool sticky_enable : 1;
bool boot_enable : 1;
bool os_unlock : 1;
- bool instrp0 : 1;
- bool q_filt : 1;
- bool trcbb : 1;
- bool trccond : 1;
- bool retstack : 1;
- bool trccci : 1;
- bool trc_error : 1;
- bool syncpr : 1;
- bool stallctl : 1;
- bool sysstall : 1;
- bool nooverflow : 1;
- bool atbtrig : 1;
- bool lpoverride : 1;
- bool skip_power_up : 1;
bool paused : 1;
u64 trfcr;
struct etmv4_config config;
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-14 8:02 ` Jie Gan
2026-04-14 16:04 ` Leo Yan
2026-04-13 14:19 ` [PATCH v4 3/9] coresight: etm4x: fix leaked trace id Yeoreum Yun
` (7 subsequent siblings)
9 siblings, 2 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The purpose of TRCSSCSRn register is to show status of
the corresponding Single-shot Comparator Control and input supports.
That means writable field's purpose for reset or restore from idle status
not for configuration.
Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
This includes remove TRCSSCRn from configurable item and
remove saving in etm4_disable_hw().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
.../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
.../coresight/coresight-etm4x-sysfs.c | 7 ++-----
drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
4 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index c302072b293a..d14d7c8a23e5 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
off_mask = (offset & GENMASK(11, 5));
do {
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
- CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
} while (0);
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 6443f3717b37..8ebfd3924143 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
const struct etmv4_caps *caps = &drvdata->caps;
return (n < caps->nr_ss_cmp) && caps->nr_pe &&
- (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
+ (caps->ss_status[n] & TRCSSCSRn_PC);
}
u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
@@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
for (i = 0; i < caps->nr_ss_cmp; i++) {
- /* always clear status bit on restart if using single-shot */
- if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
- config->ss_status[i] &= ~TRCSSCSRn_STATUS;
etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
- etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
+ /* always clear status and pending bits on restart if using single-shot */
+ etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
}
@@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_disable_trace_unit(drvdata);
- /* read the status of the single shot comparators */
- for (i = 0; i < caps->nr_ss_cmp; i++) {
- config->ss_status[i] =
- etm4x_relaxed_read32(csa, TRCSSCSRn(i));
- }
-
/* read back the current counter values */
for (i = 0; i < caps->nr_cntr; i++) {
config->cntr_val[i] =
@@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
*/
caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
for (i = 0; i < caps->nr_ss_cmp; i++) {
- drvdata->config.ss_status[i] =
- etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+ caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+ caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
}
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 50408215d1ac..dd62f01674cf 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
- /* must clear bit 31 in related status register on programming */
- config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
raw_spin_lock(&drvdata->spinlock);
- val = config->ss_status[config->ss_idx];
+ val = caps->ss_status[config->ss_idx];
raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
- /* must clear bit 31 in related status register on programming */
- config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
raw_spin_unlock(&drvdata->spinlock);
return size;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 8168676f2945..8864cfb76bad 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -213,6 +213,7 @@
#define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
#define TRCSSCSRn_STATUS BIT(31)
+#define TRCSSCSRn_PENDING BIT(30)
#define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
#define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
@@ -861,6 +862,7 @@ enum etm_impdef_type {
* @lpoverride: If the implementation can support low-power state over.
* @skip_power_up: Indicates if an implementation can skip powering up
* the trace unit.
+ * @ss_status: The status of the corresponding single-shot comparator.
*/
struct etmv4_caps {
u8 nr_pe;
@@ -899,6 +901,7 @@ struct etmv4_caps {
bool atbtrig : 1;
bool lpoverride : 1;
bool skip_power_up : 1;
+ u32 ss_status[ETM_MAX_SS_CMP];
};
/**
@@ -977,7 +980,6 @@ struct etmv4_config {
u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
u8 ss_idx;
u32 ss_ctrl[ETM_MAX_SS_CMP];
- u32 ss_status[ETM_MAX_SS_CMP];
u32 ss_pe_cmp[ETM_MAX_SS_CMP];
u8 addr_idx;
u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-14 8:04 ` Jie Gan
2026-04-14 16:32 ` Leo Yan
2026-04-13 14:19 ` [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration Yeoreum Yun
` (6 subsequent siblings)
9 siblings, 2 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
the trace ID may be leaked because it is not released.
To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
fails in cscfg_csdev_enable_active_config().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 8ebfd3924143..1bc9f13e33f7 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
if (cfg_hash) {
ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
- if (ret)
+ if (ret) {
+ etm4_release_trace_id(drvdata);
return ret;
+ }
}
raw_spin_lock(&drvdata->spinlock);
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (2 preceding siblings ...)
2026-04-13 14:19 ` [PATCH v4 3/9] coresight: etm4x: fix leaked trace id Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-15 4:25 ` Jie Gan
2026-04-13 14:19 ` [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug Yeoreum Yun
` (5 subsequent siblings)
9 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The current ETM4x configuration via sysfs can lead to
several inconsistencies:
- If the configuration is modified via sysfs while a perf session is
active, the running configuration may differ before a sched-out and
after a subsequent sched-in.
- If a perf session and a sysfs session enable tracing concurrently,
the configuration from configfs may become corrupted.
- There is a risk of corrupting drvdata->config if a perf session enables
tracing while cscfg_csdev_disable_active_config() is being handled in
etm4_disable_sysfs().
To resolve these issues, separate the configuration into:
- active_config: the configuration applied to the current session
- config: the configuration set via sysfs
Additionally:
- Apply the configuration from configfs after taking the appropriate mode.
- Since active_config and related fields are accessed only by the local CPU
in etm4_enable/disable_sysfs_smp_call() (similar to perf enable/disable),
remove the lock/unlock from the sysfs enable/disable path and
startup/dying_cpu except when to access config fields.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../hwtracing/coresight/coresight-etm4x-cfg.c | 2 +-
.../coresight/coresight-etm4x-core.c | 107 ++++++++++--------
drivers/hwtracing/coresight/coresight-etm4x.h | 2 +
3 files changed, 62 insertions(+), 49 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index d14d7c8a23e5..0553771d04e7 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
struct cscfg_regval_csdev *reg_csdev, u32 offset)
{
int err = -EINVAL, idx;
- struct etmv4_config *drvcfg = &drvdata->config;
+ struct etmv4_config *drvcfg = &drvdata->active_config;
u32 off_mask;
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 1bc9f13e33f7..01099689525b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -245,6 +245,10 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
struct etm4_enable_arg {
struct etmv4_drvdata *drvdata;
+ unsigned long cfg_hash;
+ int preset;
+ u8 trace_id;
+ struct etmv4_config config;
int rc;
};
@@ -270,10 +274,11 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
{
u64 trfcr = drvdata->trfcr;
+ struct etmv4_config *config = &drvdata->active_config;
- if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
+ if (config->mode & ETM_MODE_EXCL_KERN)
trfcr &= ~TRFCR_EL1_ExTRE;
- if (drvdata->config.mode & ETM_MODE_EXCL_USER)
+ if (config->mode & ETM_MODE_EXCL_USER)
trfcr &= ~TRFCR_EL1_E0TRE;
return trfcr;
@@ -281,7 +286,7 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
/*
* etm4x_allow_trace - Allow CPU tracing in the respective ELs,
- * as configured by the drvdata->config.mode for the current
+ * as configured by the drvdata->active_config.mode for the current
* session. Even though we have TRCVICTLR bits to filter the
* trace in the ELs, it doesn't prevent the ETM from generating
* a packet (e.g, TraceInfo) that might contain the addresses from
@@ -292,12 +297,13 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
{
u64 trfcr, guest_trfcr;
+ struct etmv4_config *config = &drvdata->active_config;
/* If the CPU doesn't support FEAT_TRF, nothing to do */
if (!drvdata->trfcr)
return;
- if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
+ if (config->mode & ETM_MODE_EXCL_HOST)
trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
else
trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -305,7 +311,7 @@ static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
write_trfcr(trfcr);
/* Set filters for guests and pass to KVM */
- if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
+ if (config->mode & ETM_MODE_EXCL_GUEST)
guest_trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
else
guest_trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -499,7 +505,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
struct device *etm_dev = &csdev->dev;
struct csdev_access *csa = &csdev->access;
@@ -616,23 +622,46 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
static void etm4_enable_sysfs_smp_call(void *info)
{
struct etm4_enable_arg *arg = info;
+ struct etmv4_drvdata *drvdata;
struct coresight_device *csdev;
if (WARN_ON(!arg))
return;
- csdev = arg->drvdata->csdev;
+ drvdata = arg->drvdata;
+ csdev = drvdata->csdev;
if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
/* Someone is already using the tracer */
arg->rc = -EBUSY;
return;
}
- arg->rc = etm4_enable_hw(arg->drvdata);
+ drvdata->active_config = arg->config;
- /* The tracer didn't start */
+ if (arg->cfg_hash) {
+ arg->rc = cscfg_csdev_enable_active_config(csdev,
+ arg->cfg_hash,
+ arg->preset);
+ if (arg->rc)
+ goto err;
+ }
+
+ drvdata->trcid = arg->trace_id;
+
+ /* Tracer will never be paused in sysfs mode */
+ drvdata->paused = false;
+
+ arg->rc = etm4_enable_hw(drvdata);
if (arg->rc)
- coresight_set_mode(csdev, CS_MODE_DISABLED);
+ goto err;
+
+ drvdata->sticky_enable = true;
+
+ return;
+err:
+ /* The tracer didn't start */
+ etm4_release_trace_id(drvdata);
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
}
/*
@@ -670,7 +699,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
int ctridx;
int rselector;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
/* No point in trying if we don't have at least one counter */
if (!caps->nr_cntr)
@@ -754,7 +783,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct perf_event_attr max_timestamp = {
.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
};
@@ -916,38 +945,24 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
/* enable any config activated by configfs */
cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
- if (cfg_hash) {
- ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
- if (ret) {
- etm4_release_trace_id(drvdata);
- return ret;
- }
- }
-
- raw_spin_lock(&drvdata->spinlock);
-
- drvdata->trcid = path->trace_id;
-
- /* Tracer will never be paused in sysfs mode */
- drvdata->paused = false;
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
*/
arg.drvdata = drvdata;
+ arg.cfg_hash = cfg_hash;
+ arg.preset = preset;
+ arg.trace_id = path->trace_id;
+
+ raw_spin_lock(&drvdata->spinlock);
+ arg.config = drvdata->config;
+ raw_spin_unlock(&drvdata->spinlock);
+
ret = smp_call_function_single(drvdata->cpu,
etm4_enable_sysfs_smp_call, &arg, 1);
if (!ret)
ret = arg.rc;
- if (!ret)
- drvdata->sticky_enable = true;
-
- if (ret)
- etm4_release_trace_id(drvdata);
-
- raw_spin_unlock(&drvdata->spinlock);
-
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
return ret;
@@ -1036,7 +1051,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
{
u32 control;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa = &csdev->access;
int i;
@@ -1072,6 +1087,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
etm4_disable_hw(drvdata);
+ cscfg_csdev_disable_active_config(drvdata->csdev);
+
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
}
@@ -1122,7 +1139,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
* DYING hotplug callback is serviced by the ETM driver.
*/
cpus_read_lock();
- raw_spin_lock(&drvdata->spinlock);
/*
* Executing etm4_disable_hw on the cpu whose ETM is being disabled
@@ -1131,10 +1147,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
smp_call_function_single(drvdata->cpu, etm4_disable_sysfs_smp_call,
drvdata, 1);
- raw_spin_unlock(&drvdata->spinlock);
-
- cscfg_csdev_disable_active_config(csdev);
-
cpus_read_unlock();
/*
@@ -1377,6 +1389,7 @@ static void etm4_init_arch_data(void *info)
struct etm4_init_arg *init_arg = info;
struct etmv4_drvdata *drvdata;
struct etmv4_caps *caps;
+ struct etmv4_config *config;
struct csdev_access *csa;
struct device *dev = init_arg->dev;
int i;
@@ -1384,6 +1397,7 @@ static void etm4_init_arch_data(void *info)
drvdata = dev_get_drvdata(init_arg->dev);
caps = &drvdata->caps;
csa = init_arg->csa;
+ config = &drvdata->active_config;
/*
* If we are unable to detect the access mechanism,
@@ -1444,7 +1458,7 @@ static void etm4_init_arch_data(void *info)
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
- drvdata->config.s_ex_level = caps->s_ex_level;
+ config->s_ex_level = caps->s_ex_level;
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
/*
@@ -1689,7 +1703,7 @@ static void etm4_set_default(struct etmv4_config *config)
static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
{
int nr_comparator, index = 0;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
/*
* nr_addr_cmp holds the number of comparator _pair_, so time 2
@@ -1730,7 +1744,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
{
int i, comparator, ret = 0;
u64 address;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct etm_filters *filters = event->hw.addr_filters;
if (!filters)
@@ -1848,13 +1862,11 @@ static int etm4_starting_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock)
etm4_os_unlock(etmdrvdata[cpu]);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_enable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -1863,10 +1875,8 @@ static int etm4_dying_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_disable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -2252,7 +2262,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
if (!desc.name)
return -ENOMEM;
- etm4_set_default(&drvdata->config);
+ etm4_set_default(&drvdata->active_config);
+ drvdata->config = drvdata->active_config;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 8864cfb76bad..725e6360a8b9 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1071,6 +1071,7 @@ struct etmv4_save_state {
* allows tracing at all ELs. We don't want to compute this
* at runtime, due to the additional setting of TRFCR_CX when
* in EL2. Otherwise, 0.
+ * @active_config: structure holding current applied configuration parameters.
* @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
* @paused: Indicates if the trace unit is paused.
@@ -1091,6 +1092,7 @@ struct etmv4_drvdata {
bool os_unlock : 1;
bool paused : 1;
u64 trfcr;
+ struct etmv4_config active_config;
struct etmv4_config config;
struct etmv4_save_state *save_state;
DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (3 preceding siblings ...)
2026-04-13 14:19 ` [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-15 11:59 ` Jie Gan
2026-04-13 14:19 ` [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t Yeoreum Yun
` (4 subsequent siblings)
9 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
In other words, if etm4_enable_sysfs() is called between
CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
etm4_enable_hw() may be invoked in etm4_enable_sysfs_smp_call()
and then executed again in etm4_starting_cpu().
To remove this redundant call, take the hotplug lock before executing
etm4_enable_sysfs_smp_call().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 01099689525b..facd5a306228 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -959,8 +959,20 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
arg.config = drvdata->config;
raw_spin_unlock(&drvdata->spinlock);
+ /*
+ * Take the hotplug lock to prevent redundant calls to etm4_enable_hw().
+ *
+ * The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
+ * In other words, if etm4_enable_sysfs() is called between
+ * CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
+ * etm4_enable_hw() may be invoked in etm4_enable_sysfs_smp_call()
+ * and then executed again in etm4_starting_cpu().
+ */
+ cpus_read_lock();
ret = smp_call_function_single(drvdata->cpu,
etm4_enable_sysfs_smp_call, &arg, 1);
+ cpus_read_unlock();
+
if (!ret)
ret = arg.rc;
if (!ret)
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (4 preceding siblings ...)
2026-04-13 14:19 ` [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug Yeoreum Yun
@ 2026-04-13 14:19 ` Yeoreum Yun
2026-04-15 12:05 ` Jie Gan
2026-04-13 14:20 ` [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps Yeoreum Yun
` (3 subsequent siblings)
9 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:19 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
etm_starting_cpu()/etm_dying_cpu() are called in not sleepable context.
This poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable.
To address this, change etm3's drvdata->spinlock type to raw_spin_lock_t.
This will be good to align with etm4x.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm.h | 2 +-
.../coresight/coresight-etm3x-core.c | 18 +--
.../coresight/coresight-etm3x-sysfs.c | 130 +++++++++---------
3 files changed, 75 insertions(+), 75 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 1d753cca2943..40f20daded4f 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -232,7 +232,7 @@ struct etm_drvdata {
struct csdev_access csa;
struct clk *atclk;
struct coresight_device *csdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
int cpu;
int port_size;
u8 arch;
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index a547a6d2e0bd..4a702b515733 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -511,7 +511,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
struct etm_enable_arg arg = { };
int ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
drvdata->traceid = path->trace_id;
@@ -534,7 +534,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
if (ret)
etm_release_trace_id(drvdata);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
@@ -634,7 +634,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
* DYING hotplug callback is serviced by the ETM driver.
*/
cpus_read_lock();
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
/*
* Executing etm_disable_hw on the cpu whose ETM is being disabled
@@ -643,7 +643,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
smp_call_function_single(drvdata->cpu, etm_disable_sysfs_smp_call,
drvdata, 1);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
/*
@@ -709,7 +709,7 @@ static int etm_starting_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock) {
etm_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
@@ -717,7 +717,7 @@ static int etm_starting_cpu(unsigned int cpu)
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_enable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -726,10 +726,10 @@ static int etm_dying_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- spin_lock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_disable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
+ raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -856,7 +856,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
desc.access = drvdata->csa = CSDEV_ACCESS_IOMEM(base);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
if (IS_ERR(drvdata->atclk))
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..42b12c33516b 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -49,13 +49,13 @@ static ssize_t etmsr_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
pm_runtime_get_sync(dev->parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->csa.base);
val = etm_readl(drvdata, ETMSR);
CS_LOCK(drvdata->csa.base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
pm_runtime_put(dev->parent);
return sprintf(buf, "%#lx\n", val);
@@ -76,7 +76,7 @@ static ssize_t reset_store(struct device *dev,
return ret;
if (val) {
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
memset(config, 0, sizeof(struct etm_config));
config->mode = ETM_MODE_EXCLUDE;
config->trigger_event = ETM_DEFAULT_EVENT_VAL;
@@ -86,7 +86,7 @@ static ssize_t reset_store(struct device *dev,
etm_set_default(config);
etm_release_trace_id(drvdata);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
}
return size;
@@ -117,7 +117,7 @@ static ssize_t mode_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->mode = val & ETM_MODE_ALL;
if (config->mode & ETM_MODE_EXCLUDE)
@@ -168,12 +168,12 @@ static ssize_t mode_store(struct device *dev,
if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
etm_config_trace_mode(config);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
err_unlock:
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return ret;
}
static DEVICE_ATTR_RW(mode);
@@ -299,9 +299,9 @@ static ssize_t addr_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->addr_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -315,16 +315,16 @@ static ssize_t addr_single_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
val = config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -343,17 +343,17 @@ static ssize_t addr_single_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
config->addr_val[idx] = val;
config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -367,23 +367,23 @@ static ssize_t addr_range_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val1 = config->addr_val[idx];
val2 = config->addr_val[idx + 1];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx %#lx\n", val1, val2);
}
@@ -403,17 +403,17 @@ static ssize_t addr_range_store(struct device *dev,
if (val1 > val2)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (idx % 2 != 0) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@@ -422,7 +422,7 @@ static ssize_t addr_range_store(struct device *dev,
config->addr_val[idx + 1] = val2;
config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
config->enable_ctrl1 |= (1 << (idx/2));
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -436,16 +436,16 @@ static ssize_t addr_start_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -464,11 +464,11 @@ static ssize_t addr_start_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@@ -476,7 +476,7 @@ static ssize_t addr_start_store(struct device *dev,
config->addr_type[idx] = ETM_ADDR_TYPE_START;
config->startstop_ctrl |= (1 << idx);
config->enable_ctrl1 |= ETMTECR1_START_STOP;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -490,16 +490,16 @@ static ssize_t addr_stop_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = config->addr_val[idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -518,11 +518,11 @@ static ssize_t addr_stop_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@@ -530,7 +530,7 @@ static ssize_t addr_stop_store(struct device *dev,
config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
config->startstop_ctrl |= (1 << (idx + 16));
config->enable_ctrl1 |= ETMTECR1_START_STOP;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -543,9 +543,9 @@ static ssize_t addr_acctype_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->addr_acctype[config->addr_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -563,9 +563,9 @@ static ssize_t addr_acctype_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->addr_acctype[config->addr_idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -601,9 +601,9 @@ static ssize_t cntr_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -616,9 +616,9 @@ static ssize_t cntr_rld_val_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->cntr_rld_val[config->cntr_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -636,9 +636,9 @@ static ssize_t cntr_rld_val_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_rld_val[config->cntr_idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -651,9 +651,9 @@ static ssize_t cntr_event_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->cntr_event[config->cntr_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -671,9 +671,9 @@ static ssize_t cntr_event_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_event[config->cntr_idx] = val & ETM_EVENT_MASK;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -686,9 +686,9 @@ static ssize_t cntr_rld_event_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->cntr_rld_event[config->cntr_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -706,9 +706,9 @@ static ssize_t cntr_rld_event_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_rld_event[config->cntr_idx] = val & ETM_EVENT_MASK;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -723,11 +723,11 @@ static ssize_t cntr_val_show(struct device *dev,
struct etm_config *config = &drvdata->config;
if (!coresight_get_mode(drvdata->csdev)) {
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
for (i = 0; i < drvdata->nr_cntr; i++)
ret += sprintf(buf, "counter %d: %x\n",
i, config->cntr_val[i]);
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return ret;
}
@@ -752,9 +752,9 @@ static ssize_t cntr_val_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->cntr_val[config->cntr_idx] = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -947,13 +947,13 @@ static ssize_t seq_curr_state_show(struct device *dev,
}
pm_runtime_get_sync(dev->parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->csa.base);
val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
CS_LOCK(drvdata->csa.base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
pm_runtime_put(dev->parent);
out:
return sprintf(buf, "%#lx\n", val);
@@ -1012,9 +1012,9 @@ static ssize_t ctxid_idx_store(struct device *dev,
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->ctxid_idx = val;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1034,9 +1034,9 @@ static ssize_t ctxid_pid_show(struct device *dev,
if (task_active_pid_ns(current) != &init_pid_ns)
return -EINVAL;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
val = config->ctxid_pid[config->ctxid_idx];
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return sprintf(buf, "%#lx\n", val);
}
@@ -1066,9 +1066,9 @@ static ssize_t ctxid_pid_store(struct device *dev,
if (ret)
return ret;
- spin_lock(&drvdata->spinlock);
+ raw_spin_lock(&drvdata->spinlock);
config->ctxid_pid[config->ctxid_idx] = pid;
- spin_unlock(&drvdata->spinlock);
+ raw_spin_unlock(&drvdata->spinlock);
return size;
}
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (5 preceding siblings ...)
2026-04-13 14:19 ` [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t Yeoreum Yun
@ 2026-04-13 14:20 ` Yeoreum Yun
2026-04-15 12:17 ` Jie Gan
2026-04-13 14:20 ` [PATCH v4 8/9] coresight: etm3x: fix inconsistencies with sysfs configuration Yeoreum Yun
` (2 subsequent siblings)
9 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:20 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
Introduce struct etm_caps to describe ETMv3 capabilities
and move capabilities information into it.
Since drvdata->etmccr and drvdata->etmccer are used to check
whether it supports fifofull logic and timestamping,
remove etmccr and etmccer field from drvdata and add relevant fields
in etm_caps structure.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm.h | 42 ++++++++++++-------
.../coresight/coresight-etm3x-core.c | 39 ++++++++++-------
.../coresight/coresight-etm3x-sysfs.c | 29 ++++++++-----
3 files changed, 67 insertions(+), 43 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 40f20daded4f..8d1a1079b008 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -140,6 +140,30 @@
ETM_ADD_COMP_0 | \
ETM_EVENT_NOT_A)
+/**
+ * struct etmv_caps - specifics ETM capabilities
+ * @port_size: port size as reported by ETMCR bit 4-6 and 21.
+ * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
+ * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
+ * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
+ * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
+ * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
+ * @fifofull: FIFOFULL logic is present.
+ * @timestamp: Timestamping is implemented.
+ * @retstack: Return stack is implemented.
+ */
+struct etm_caps {
+ int port_size;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 nr_ext_out;
+ u8 nr_ctxid_cmp;
+ bool fifofull : 1;
+ bool timestamp : 1;
+ bool retstack : 1;
+};
+
/**
* struct etm_config - configuration information related to an ETM
* @mode: controls various modes supported by this ETM/PTM.
@@ -212,19 +236,12 @@ struct etm_config {
* @csdev: component vitals needed by the framework.
* @spinlock: only one at a time pls.
* @cpu: the cpu this component is affined to.
- * @port_size: port size as reported by ETMCR bit 4-6 and 21.
* @arch: ETM/PTM version number.
+ * @caps: ETM capabilities.
* @use_cpu14: true if management registers need to be accessed via CP14.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
- * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
- * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
- * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
- * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
- * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
- * @etmccr: value of register ETMCCR.
- * @etmccer: value of register ETMCCER.
* @traceid: value of the current ID for this component.
* @config: structure holding configuration parameters.
*/
@@ -234,19 +251,12 @@ struct etm_drvdata {
struct coresight_device *csdev;
raw_spinlock_t spinlock;
int cpu;
- int port_size;
u8 arch;
+ struct etm_caps caps;
bool use_cp14;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 nr_ext_out;
- u8 nr_ctxid_cmp;
- u32 etmccr;
- u32 etmccer;
u32 traceid;
struct etm_config config;
};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index 4a702b515733..e42ca346da91 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -308,6 +308,7 @@ void etm_config_trace_mode(struct etm_config *config)
static int etm_parse_event_config(struct etm_drvdata *drvdata,
struct perf_event *event)
{
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
u8 ts_level;
@@ -356,8 +357,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
* has ret stack) on the same SoC. So only enable when it can be honored
* - trace will still continue normally otherwise.
*/
- if (ATTR_CFG_GET_FLD(attr, retstack) &&
- (drvdata->etmccer & ETMCCER_RETSTACK))
+ if (ATTR_CFG_GET_FLD(attr, retstack) && (caps->retstack))
config->ctrl |= ETMCR_RETURN_STACK;
return 0;
@@ -367,6 +367,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
{
int i, rc;
u32 etmcr;
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
@@ -388,7 +389,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etmcr = etm_readl(drvdata, ETMCR);
/* Clear setting from a previous run if need be */
etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
- etmcr |= drvdata->port_size;
+ etmcr |= caps->port_size;
etmcr |= ETMCR_ETM_EN;
etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
@@ -396,11 +397,11 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etm_writel(drvdata, config->enable_event, ETMTEEVR);
etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
etm_writel(drvdata, config->fifofull_level, ETMFFLR);
- for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+ for (i = 0; i < caps->nr_addr_cmp; i++) {
etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
}
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
etm_writel(drvdata, config->cntr_rld_event[i],
@@ -414,9 +415,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
etm_writel(drvdata, config->seq_curr_state, ETMSQR);
- for (i = 0; i < drvdata->nr_ext_out; i++)
+ for (i = 0; i < caps->nr_ext_out; i++)
etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
- for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
+ for (i = 0; i < caps->nr_ctxid_cmp; i++)
etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
@@ -563,6 +564,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
static void etm_disable_hw(struct etm_drvdata *drvdata)
{
int i;
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
@@ -572,7 +574,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
/* Read back sequencer and counters for post trace analysis */
config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
- for (i = 0; i < drvdata->nr_cntr; i++)
+ for (i = 0; i < caps->nr_cntr; i++)
config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
etm_set_pwrdwn(drvdata);
@@ -754,7 +756,9 @@ static void etm_init_arch_data(void *info)
{
u32 etmidr;
u32 etmccr;
+ u32 etmccer;
struct etm_drvdata *drvdata = info;
+ struct etm_caps *caps = &drvdata->caps;
/* Make sure all registers are accessible */
etm_os_unlock(drvdata);
@@ -779,16 +783,19 @@ static void etm_init_arch_data(void *info)
/* Find all capabilities */
etmidr = etm_readl(drvdata, ETMIDR);
drvdata->arch = BMVAL(etmidr, 4, 11);
- drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+ caps->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+
+ etmccer = etm_readl(drvdata, ETMCCER);
+ caps->timestamp = !!(etmccer & ETMCCER_TIMESTAMP);
+ caps->retstack = !!(etmccer & ETMCCER_RETSTACK);
- drvdata->etmccer = etm_readl(drvdata, ETMCCER);
etmccr = etm_readl(drvdata, ETMCCR);
- drvdata->etmccr = etmccr;
- drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
- drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
- drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
- drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
- drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+ caps->fifofull = !!(etmccr & ETMCCR_FIFOFULL);
+ caps->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+ caps->nr_cntr = BMVAL(etmccr, 13, 15);
+ caps->nr_ext_inp = BMVAL(etmccr, 17, 19);
+ caps->nr_ext_out = BMVAL(etmccr, 20, 22);
+ caps->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
etm_set_pwrdwn(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 42b12c33516b..f7330d830e21 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -15,8 +15,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
{
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
- val = drvdata->nr_addr_cmp;
+ val = caps->nr_addr_cmp;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_addr_cmp);
@@ -25,8 +26,9 @@ static ssize_t nr_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
- val = drvdata->nr_cntr;
+ val = caps->nr_cntr;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_cntr);
@@ -37,7 +39,7 @@ static ssize_t nr_ctxid_cmp_show(struct device *dev,
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- val = drvdata->nr_ctxid_cmp;
+ val = drvdata->caps.nr_ctxid_cmp;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ctxid_cmp);
@@ -80,7 +82,7 @@ static ssize_t reset_store(struct device *dev,
memset(config, 0, sizeof(struct etm_config));
config->mode = ETM_MODE_EXCLUDE;
config->trigger_event = ETM_DEFAULT_EVENT_VAL;
- for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+ for (i = 0; i < drvdata->caps.nr_addr_cmp; i++) {
config->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
@@ -111,6 +113,7 @@ static ssize_t mode_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
@@ -131,7 +134,7 @@ static ssize_t mode_store(struct device *dev,
config->ctrl &= ~ETMCR_CYC_ACC;
if (config->mode & ETM_MODE_STALL) {
- if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
+ if (!caps->fifofull) {
dev_warn(dev, "stall mode not supported\n");
ret = -EINVAL;
goto err_unlock;
@@ -141,7 +144,7 @@ static ssize_t mode_store(struct device *dev,
config->ctrl &= ~ETMCR_STALL_MODE;
if (config->mode & ETM_MODE_TIMESTAMP) {
- if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
+ if (!caps->timestamp) {
dev_warn(dev, "timestamp not supported\n");
ret = -EINVAL;
goto err_unlock;
@@ -286,13 +289,14 @@ static ssize_t addr_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_addr_cmp)
+ if (val >= caps->nr_addr_cmp)
return -EINVAL;
/*
@@ -589,13 +593,14 @@ static ssize_t cntr_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_cntr)
+ if (val >= caps->nr_cntr)
return -EINVAL;
/*
* Use spinlock to ensure index doesn't change while it gets
@@ -720,18 +725,19 @@ static ssize_t cntr_val_show(struct device *dev,
int i, ret = 0;
u32 val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
if (!coresight_get_mode(drvdata->csdev)) {
raw_spin_lock(&drvdata->spinlock);
- for (i = 0; i < drvdata->nr_cntr; i++)
+ for (i = 0; i < caps->nr_cntr; i++)
ret += sprintf(buf, "counter %d: %x\n",
i, config->cntr_val[i]);
raw_spin_unlock(&drvdata->spinlock);
return ret;
}
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
val = etm_readl(drvdata, ETMCNTVRn(i));
ret += sprintf(buf, "counter %d: %x\n", i, val);
}
@@ -999,13 +1005,14 @@ static ssize_t ctxid_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_ctxid_cmp)
+ if (val >= caps->nr_ctxid_cmp)
return -EINVAL;
/*
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 8/9] coresight: etm3x: fix inconsistencies with sysfs configuration
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (6 preceding siblings ...)
2026-04-13 14:20 ` [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps Yeoreum Yun
@ 2026-04-13 14:20 ` Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm4_enable_hw with hotplug Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm_enable_hw() " Yeoreum Yun
9 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:20 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The current ETM3x configuration via sysfs can lead to the following
inconsistencies:
- If a configuration is modified via sysfs while a perf session is
active, the running configuration may differ between before
a sched-out and after a subsequent sched-in.
To resolve these issues, separate the configuration into:
- active_config: the configuration applied to the current session
- config: the configuration set via sysfs
Additionally:
- Since active_config and related fields are accessed only by the local CPU
in etm_enable/disable_sysfs_smp_call() (similar to perf enable/disable),
remove the lock/unlock from the sysfs enable/disable path and
starting/dying_cpu path except when to access config fields only.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm.h | 2 +
.../coresight/coresight-etm3x-core.c | 49 +++++++++----------
2 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 8d1a1079b008..e381acb47d20 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -243,6 +243,7 @@ struct etm_config {
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
* @traceid: value of the current ID for this component.
+ * @active_config: structure holding current running configuration parameters.
* @config: structure holding configuration parameters.
*/
struct etm_drvdata {
@@ -258,6 +259,7 @@ struct etm_drvdata {
bool boot_enable;
bool os_unlock;
u32 traceid;
+ struct etm_config active_config;
struct etm_config config;
};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index e42ca346da91..b7e3b5eea3f9 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -309,7 +309,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
struct perf_event *event)
{
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct perf_event_attr *attr = &event->attr;
u8 ts_level;
@@ -368,7 +368,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
int i, rc;
u32 etmcr;
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
CS_UNLOCK(drvdata->csa.base);
@@ -442,29 +442,39 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
struct etm_enable_arg {
struct etm_drvdata *drvdata;
+ u32 traceid;
+ struct etm_config config;
int rc;
};
static void etm_enable_sysfs_smp_call(void *info)
{
struct etm_enable_arg *arg = info;
+ struct etm_drvdata *drvdata;
struct coresight_device *csdev;
if (WARN_ON(!arg))
return;
- csdev = arg->drvdata->csdev;
+ drvdata = arg->drvdata;
+ csdev = drvdata->csdev;
if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
/* Someone is already using the tracer */
arg->rc = -EBUSY;
return;
}
+ drvdata->active_config = arg->config;
+ drvdata->traceid = arg->traceid;
+
arg->rc = etm_enable_hw(arg->drvdata);
/* The tracer didn't start */
- if (arg->rc)
+ if (arg->rc) {
+ etm_release_trace_id(drvdata);
coresight_set_mode(csdev, CS_MODE_DISABLED);
+ } else
+ drvdata->sticky_enable = true;
}
static int etm_cpu_id(struct coresight_device *csdev)
@@ -512,9 +522,6 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
struct etm_enable_arg arg = { };
int ret;
- raw_spin_lock(&drvdata->spinlock);
-
- drvdata->traceid = path->trace_id;
/*
* Configure the ETM only if the CPU is online. If it isn't online
@@ -522,21 +529,20 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
*/
if (cpu_online(drvdata->cpu)) {
arg.drvdata = drvdata;
+ arg.traceid = path->trace_id;
+
+ raw_spin_lock(&drvdata->spinlock);
+ arg.config = drvdata->config;
+ raw_spin_unlock(&drvdata->spinlock);
+
ret = smp_call_function_single(drvdata->cpu,
etm_enable_sysfs_smp_call, &arg, 1);
if (!ret)
ret = arg.rc;
- if (!ret)
- drvdata->sticky_enable = true;
} else {
ret = -ENODEV;
}
- if (ret)
- etm_release_trace_id(drvdata);
-
- raw_spin_unlock(&drvdata->spinlock);
-
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
return ret;
@@ -565,7 +571,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
{
int i;
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
CS_UNLOCK(drvdata->csa.base);
@@ -636,7 +642,6 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
* DYING hotplug callback is serviced by the ETM driver.
*/
cpus_read_lock();
- raw_spin_lock(&drvdata->spinlock);
/*
* Executing etm_disable_hw on the cpu whose ETM is being disabled
@@ -645,7 +650,6 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
smp_call_function_single(drvdata->cpu, etm_disable_sysfs_smp_call,
drvdata, 1);
- raw_spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
/*
@@ -711,15 +715,11 @@ static int etm_starting_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
- if (!etmdrvdata[cpu]->os_unlock) {
+ if (!etmdrvdata[cpu]->os_unlock)
etm_os_unlock(etmdrvdata[cpu]);
- etmdrvdata[cpu]->os_unlock = true;
- }
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_enable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -728,10 +728,8 @@ static int etm_dying_cpu(unsigned int cpu)
if (!etmdrvdata[cpu])
return 0;
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_disable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
@@ -884,7 +882,8 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
if (etm_arch_supported(drvdata->arch) == false)
return -EINVAL;
- etm_set_default(&drvdata->config);
+ etm_set_default(&drvdata->active_config);
+ drvdata->config = drvdata->active_config;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 9/9] coresight: etm3x: remove redundant call etm4_enable_hw with hotplug
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (7 preceding siblings ...)
2026-04-13 14:20 ` [PATCH v4 8/9] coresight: etm3x: fix inconsistencies with sysfs configuration Yeoreum Yun
@ 2026-04-13 14:20 ` Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm_enable_hw() " Yeoreum Yun
9 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:20 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
In other words, if etm4_enable_sysfs() is called between
CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
etm_enable_hw() may be invoked in etm_enable_sysfs_smp_call()
and then executed again in etm_starting_cpu().
To remove this redundant call, take the hotplug lock before executing
etm_enable_sysfs_smp_call().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../coresight/coresight-etm3x-core.c | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index b7e3b5eea3f9..5dc5492a1fb5 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -522,26 +522,26 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
struct etm_enable_arg arg = { };
int ret;
+ arg.drvdata = drvdata;
+ arg.traceid = path->trace_id;
+
+ raw_spin_lock(&drvdata->spinlock);
+ arg.config = drvdata->config;
+ raw_spin_unlock(&drvdata->spinlock);
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place on the local CPU during bring up.
*/
- if (cpu_online(drvdata->cpu)) {
- arg.drvdata = drvdata;
- arg.traceid = path->trace_id;
-
- raw_spin_lock(&drvdata->spinlock);
- arg.config = drvdata->config;
- raw_spin_unlock(&drvdata->spinlock);
-
+ cpus_read_lock();
ret = smp_call_function_single(drvdata->cpu,
etm_enable_sysfs_smp_call, &arg, 1);
- if (!ret)
- ret = arg.rc;
- } else {
+ cpus_read_unlock();
+
+ if (!ret)
+ ret = arg.rc;
+ else
ret = -ENODEV;
- }
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v4 9/9] coresight: etm3x: remove redundant call etm_enable_hw() with hotplug
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
` (8 preceding siblings ...)
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm4_enable_hw with hotplug Yeoreum Yun
@ 2026-04-13 14:20 ` Yeoreum Yun
9 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-13 14:20 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
In other words, if etm4_enable_sysfs() is called between
CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
etm_enable_hw() may be invoked in etm_enable_sysfs_smp_call()
and then executed again in etm_starting_cpu().
To remove this redundant call, take the hotplug lock before executing
etm_enable_sysfs_smp_call().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../coresight/coresight-etm3x-core.c | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index b7e3b5eea3f9..5dc5492a1fb5 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -522,26 +522,26 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
struct etm_enable_arg arg = { };
int ret;
+ arg.drvdata = drvdata;
+ arg.traceid = path->trace_id;
+
+ raw_spin_lock(&drvdata->spinlock);
+ arg.config = drvdata->config;
+ raw_spin_unlock(&drvdata->spinlock);
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place on the local CPU during bring up.
*/
- if (cpu_online(drvdata->cpu)) {
- arg.drvdata = drvdata;
- arg.traceid = path->trace_id;
-
- raw_spin_lock(&drvdata->spinlock);
- arg.config = drvdata->config;
- raw_spin_unlock(&drvdata->spinlock);
-
+ cpus_read_lock();
ret = smp_call_function_single(drvdata->cpu,
etm_enable_sysfs_smp_call, &arg, 1);
- if (!ret)
- ret = arg.rc;
- } else {
+ cpus_read_unlock();
+
+ if (!ret)
+ ret = arg.rc;
+ else
ret = -ENODEV;
- }
if (!ret)
dev_dbg(&csdev->dev, "ETM tracing enabled\n");
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps
2026-04-13 14:19 ` [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
@ 2026-04-13 17:21 ` Leo Yan
2026-04-14 7:55 ` Yeoreum Yun
0 siblings, 1 reply; 31+ messages in thread
From: Leo Yan @ 2026-04-13 17:21 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
On Mon, Apr 13, 2026 at 03:19:54PM +0100, Yeoreum Yun wrote:
> Introduce struct etm4_caps to describe ETMv4 capabilities
> and move capabilities information into it.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
LGTM:
Reviewed-by: Leo Yan <leo.yan@arm.com>
FWIW, two comments from Sashiko are valuable for me, please see below.
> ---
> .../coresight/coresight-etm4x-core.c | 234 +++++++++---------
> .../coresight/coresight-etm4x-sysfs.c | 190 ++++++++------
> drivers/hwtracing/coresight/coresight-etm4x.h | 176 ++++++-------
> 3 files changed, 328 insertions(+), 272 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index d565a73f0042..6443f3717b37 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -88,8 +88,9 @@ static int etm4_probe_cpu(unsigned int cpu);
> */
> static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> {
> - return (n < drvdata->nr_ss_cmp) &&
> - drvdata->nr_pe &&
> + const struct etmv4_caps *caps = &drvdata->caps;
> +
> + return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
As Sashiko suggests:
"This isn't a regression introduced by this patch, but should this be
checking caps->nr_pe_cmp instead of caps->nr_pe?"
I confirmed the ETMv4 specification (ARM IHI0064H.b), the comment
above is valid as the we should check caps->nr_pe_cmp instead.
Could you first use a patch to fix the typo and then apply
capabilities afterwards? This is helpful for porting to stable
kernels.
[...]
> @@ -525,14 +530,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
> dev_err(etm_dev,
> "timeout while waiting for Idle Trace Status\n");
> - if (drvdata->nr_pe)
> + if (caps->nr_pe)
> etm4x_relaxed_write32(csa, config->pe_sel, TRCPROCSELR);
> etm4x_relaxed_write32(csa, config->cfg, TRCCONFIGR);
> /* nothing specific implemented */
> etm4x_relaxed_write32(csa, 0x0, TRCAUXCTLR);
> etm4x_relaxed_write32(csa, config->eventctrl0, TRCEVENTCTL0R);
> etm4x_relaxed_write32(csa, config->eventctrl1, TRCEVENTCTL1R);
> - if (drvdata->stallctl)
> + if (caps->stallctl)
> etm4x_relaxed_write32(csa, config->stall_ctrl, TRCSTALLCTLR);
> etm4x_relaxed_write32(csa, config->ts_ctrl, TRCTSCTLR);
> etm4x_relaxed_write32(csa, config->syncfreq, TRCSYNCPR);
> @@ -542,17 +547,17 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> etm4x_relaxed_write32(csa, config->vinst_ctrl, TRCVICTLR);
> etm4x_relaxed_write32(csa, config->viiectlr, TRCVIIECTLR);
> etm4x_relaxed_write32(csa, config->vissctlr, TRCVISSCTLR);
> - if (drvdata->nr_pe_cmp)
> + if (caps->nr_pe_cmp)
> etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
> - for (i = 0; i < drvdata->nrseqstate - 1; i++)
> + for (i = 0; i < caps->nrseqstate - 1; i++)
> etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
Sashiko's comment:
"If the hardware does not implement a sequencer, caps->nrseqstate (a u8)
will be 0. Does 0 - 1 evaluate to -1 as an int, which then gets promoted
to ULONG_MAX against val (an unsigned long)?"
This is a good catch. The condition check should be:
for (i = 0; i < caps->nrseqstate; i++)
...;
The issue is irrelevant to your patch, but could you use a patch to fix
"nrseqstate - 1" first and then apply the cap refactoring on it? This
would be friendly for porting to stable kernel.
Thanks,
Leo
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps
2026-04-13 17:21 ` Leo Yan
@ 2026-04-14 7:55 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-14 7:55 UTC (permalink / raw)
To: Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
Hi Leo!
> On Mon, Apr 13, 2026 at 03:19:54PM +0100, Yeoreum Yun wrote:
> > Introduce struct etm4_caps to describe ETMv4 capabilities
> > and move capabilities information into it.
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
>
> LGTM:
>
> Reviewed-by: Leo Yan <leo.yan@arm.com>
Thanks.
>
> FWIW, two comments from Sashiko are valuable for me, please see below.
>
> > ---
> > .../coresight/coresight-etm4x-core.c | 234 +++++++++---------
> > .../coresight/coresight-etm4x-sysfs.c | 190 ++++++++------
> > drivers/hwtracing/coresight/coresight-etm4x.h | 176 ++++++-------
> > 3 files changed, 328 insertions(+), 272 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index d565a73f0042..6443f3717b37 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -88,8 +88,9 @@ static int etm4_probe_cpu(unsigned int cpu);
> > */
> > static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> > {
> > - return (n < drvdata->nr_ss_cmp) &&
> > - drvdata->nr_pe &&
> > + const struct etmv4_caps *caps = &drvdata->caps;
> > +
> > + return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> > (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
>
> As Sashiko suggests:
>
> "This isn't a regression introduced by this patch, but should this be
> checking caps->nr_pe_cmp instead of caps->nr_pe?"
>
> I confirmed the ETMv4 specification (ARM IHI0064H.b), the comment
> above is valid as the we should check caps->nr_pe_cmp instead.
>
> Could you first use a patch to fix the typo and then apply
> capabilities afterwards? This is helpful for porting to stable
> kernels.
Sashiko finds valid point. And I'm bit of surprised no body find it.
Okay. I'll send it next round.
>
> [...]
>
> > @@ -525,14 +530,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> > if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
> > dev_err(etm_dev,
> > "timeout while waiting for Idle Trace Status\n");
> > - if (drvdata->nr_pe)
> > + if (caps->nr_pe)
> > etm4x_relaxed_write32(csa, config->pe_sel, TRCPROCSELR);
> > etm4x_relaxed_write32(csa, config->cfg, TRCCONFIGR);
> > /* nothing specific implemented */
> > etm4x_relaxed_write32(csa, 0x0, TRCAUXCTLR);
> > etm4x_relaxed_write32(csa, config->eventctrl0, TRCEVENTCTL0R);
> > etm4x_relaxed_write32(csa, config->eventctrl1, TRCEVENTCTL1R);
> > - if (drvdata->stallctl)
> > + if (caps->stallctl)
> > etm4x_relaxed_write32(csa, config->stall_ctrl, TRCSTALLCTLR);
> > etm4x_relaxed_write32(csa, config->ts_ctrl, TRCTSCTLR);
> > etm4x_relaxed_write32(csa, config->syncfreq, TRCSYNCPR);
> > @@ -542,17 +547,17 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> > etm4x_relaxed_write32(csa, config->vinst_ctrl, TRCVICTLR);
> > etm4x_relaxed_write32(csa, config->viiectlr, TRCVIIECTLR);
> > etm4x_relaxed_write32(csa, config->vissctlr, TRCVISSCTLR);
> > - if (drvdata->nr_pe_cmp)
> > + if (caps->nr_pe_cmp)
> > etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
> > - for (i = 0; i < drvdata->nrseqstate - 1; i++)
> > + for (i = 0; i < caps->nrseqstate - 1; i++)
> > etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
>
> Sashiko's comment:
>
> "If the hardware does not implement a sequencer, caps->nrseqstate (a u8)
> will be 0. Does 0 - 1 evaluate to -1 as an int, which then gets promoted
> to ULONG_MAX against val (an unsigned long)?"
>
> This is a good catch. The condition check should be:
>
> for (i = 0; i < caps->nrseqstate; i++)
> ...;
>
> The issue is irrelevant to your patch, but could you use a patch to fix
> "nrseqstate - 1" first and then apply the cap refactoring on it? This
> would be friendly for porting to stable kernel.
Okay. I'll send it next round.
Thanks!
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
2026-04-13 14:19 ` [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
@ 2026-04-14 8:02 ` Jie Gan
2026-04-14 16:04 ` Leo Yan
1 sibling, 0 replies; 31+ messages in thread
From: Jie Gan @ 2026-04-14 8:02 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> The purpose of TRCSSCSRn register is to show status of
> the corresponding Single-shot Comparator Control and input supports.
> That means writable field's purpose for reset or restore from idle status
> not for configuration.
>
> Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
> This includes remove TRCSSCRn from configurable item and
> remove saving in etm4_disable_hw().
>
LGTM.
Reviewed-by: Jie Gan <jie.gan@oss.qualcomm.com>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
> .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
> .../coresight/coresight-etm4x-sysfs.c | 7 ++-----
> drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
> 4 files changed, 10 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index c302072b293a..d14d7c8a23e5 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> off_mask = (offset & GENMASK(11, 5));
> do {
> CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
> - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
> CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
> } while (0);
> } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 6443f3717b37..8ebfd3924143 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> const struct etmv4_caps *caps = &drvdata->caps;
>
> return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
> + (caps->ss_status[n] & TRCSSCSRn_PC);
> }
>
> u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
> @@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
>
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - /* always clear status bit on restart if using single-shot */
> - if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
> etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
> - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
> + /* always clear status and pending bits on restart if using single-shot */
> + etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
> if (etm4x_sspcicrn_present(drvdata, i))
> etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
> }
> @@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
>
> etm4_disable_trace_unit(drvdata);
>
> - /* read the status of the single shot comparators */
> - for (i = 0; i < caps->nr_ss_cmp; i++) {
> - config->ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> - }
> -
> /* read back the current counter values */
> for (i = 0; i < caps->nr_cntr; i++) {
> config->cntr_val[i] =
> @@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
> */
> caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - drvdata->config.ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
> }
> /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
> caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index 50408215d1ac..dd62f01674cf 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> @@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
> {
> unsigned long val;
> struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etmv4_caps *caps = &drvdata->caps;
> struct etmv4_config *config = &drvdata->config;
>
> raw_spin_lock(&drvdata->spinlock);
> - val = config->ss_status[config->ss_idx];
> + val = caps->ss_status[config->ss_idx];
> raw_spin_unlock(&drvdata->spinlock);
> return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> }
> @@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 8168676f2945..8864cfb76bad 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -213,6 +213,7 @@
> #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
>
> #define TRCSSCSRn_STATUS BIT(31)
> +#define TRCSSCSRn_PENDING BIT(30)
> #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
>
> #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
> @@ -861,6 +862,7 @@ enum etm_impdef_type {
> * @lpoverride: If the implementation can support low-power state over.
> * @skip_power_up: Indicates if an implementation can skip powering up
> * the trace unit.
> + * @ss_status: The status of the corresponding single-shot comparator.
> */
> struct etmv4_caps {
> u8 nr_pe;
> @@ -899,6 +901,7 @@ struct etmv4_caps {
> bool atbtrig : 1;
> bool lpoverride : 1;
> bool skip_power_up : 1;
> + u32 ss_status[ETM_MAX_SS_CMP];
> };
>
> /**
> @@ -977,7 +980,6 @@ struct etmv4_config {
> u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
> u8 ss_idx;
> u32 ss_ctrl[ETM_MAX_SS_CMP];
> - u32 ss_status[ETM_MAX_SS_CMP];
> u32 ss_pe_cmp[ETM_MAX_SS_CMP];
> u8 addr_idx;
> u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-13 14:19 ` [PATCH v4 3/9] coresight: etm4x: fix leaked trace id Yeoreum Yun
@ 2026-04-14 8:04 ` Jie Gan
2026-04-14 16:32 ` Leo Yan
1 sibling, 0 replies; 31+ messages in thread
From: Jie Gan @ 2026-04-14 8:04 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
> the trace ID may be leaked because it is not released.
>
> To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
> fails in cscfg_csdev_enable_active_config().
>
LGTM.
Reviewed-by: Jie Gan <jie.gan@oss.qualcomm.com>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 8ebfd3924143..1bc9f13e33f7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> if (cfg_hash) {
> ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> - if (ret)
> + if (ret) {
> + etm4_release_trace_id(drvdata);
> return ret;
> + }
> }
>
> raw_spin_lock(&drvdata->spinlock);
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
2026-04-13 14:19 ` [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
2026-04-14 8:02 ` Jie Gan
@ 2026-04-14 16:04 ` Leo Yan
2026-04-14 16:59 ` Yeoreum Yun
1 sibling, 1 reply; 31+ messages in thread
From: Leo Yan @ 2026-04-14 16:04 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
On Mon, Apr 13, 2026 at 03:19:55PM +0100, Yeoreum Yun wrote:
> The purpose of TRCSSCSRn register is to show status of
> the corresponding Single-shot Comparator Control and input supports.
> That means writable field's purpose for reset or restore from idle status
> not for configuration.
>
> Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
> This includes remove TRCSSCRn from configurable item and
> remove saving in etm4_disable_hw().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
> .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
> .../coresight/coresight-etm4x-sysfs.c | 7 ++-----
> drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
> 4 files changed, 10 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index c302072b293a..d14d7c8a23e5 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> off_mask = (offset & GENMASK(11, 5));
> do {
> CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
> - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
> CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
> } while (0);
> } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 6443f3717b37..8ebfd3924143 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> const struct etmv4_caps *caps = &drvdata->caps;
>
> return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
> + (caps->ss_status[n] & TRCSSCSRn_PC);
Nitpick: The naming 'ss_status' is a bit confused for capability.
Could we rename 'ss_status' to 'ss_comparator' or a simple one
'ss_cmp' ?
> }
>
> u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
> @@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
>
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - /* always clear status bit on restart if using single-shot */
> - if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
> etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
> - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
> + /* always clear status and pending bits on restart if using single-shot */
> + etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
It is a bit weird to use caps to write a register. A smooth way is to
clear STATUS and PENDING bits based on the read back value:
val = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
val &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
etm4x_relaxed_write32(csa, val, TRCSSCSRn(i));
> if (etm4x_sspcicrn_present(drvdata, i))
> etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
> }
> @@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
>
> etm4_disable_trace_unit(drvdata);
>
> - /* read the status of the single shot comparators */
> - for (i = 0; i < caps->nr_ss_cmp; i++) {
> - config->ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> - }
> -
> /* read back the current counter values */
> for (i = 0; i < caps->nr_cntr; i++) {
> config->cntr_val[i] =
> @@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
> */
> caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - drvdata->config.ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
For init cap, we can use explict way:
caps->ss_cmp &= (TRCSSCSRn_PC | TRCSSCSRn_DV |
TRCSSCSRn_DA | TRCSSCSRn_INST);
> }
> /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
> caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index 50408215d1ac..dd62f01674cf 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> @@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
> {
> unsigned long val;
> struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etmv4_caps *caps = &drvdata->caps;
> struct etmv4_config *config = &drvdata->config;
>
> raw_spin_lock(&drvdata->spinlock);
> - val = config->ss_status[config->ss_idx];
> + val = caps->ss_status[config->ss_idx];
I think cap->ss_cmp is a good refactoring, but for legacy reason, I am
just wandering if we still need config->ss_status so that it can record
the lastest status (mainly for STATUS bit and PENDING bit).
Otherwise, this Sysfs interface can only provide capability rather
than status value.
Thanks,
Leo
> raw_spin_unlock(&drvdata->spinlock);
> return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> }
> @@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 8168676f2945..8864cfb76bad 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -213,6 +213,7 @@
> #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
>
> #define TRCSSCSRn_STATUS BIT(31)
> +#define TRCSSCSRn_PENDING BIT(30)
> #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
>
> #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
> @@ -861,6 +862,7 @@ enum etm_impdef_type {
> * @lpoverride: If the implementation can support low-power state over.
> * @skip_power_up: Indicates if an implementation can skip powering up
> * the trace unit.
> + * @ss_status: The status of the corresponding single-shot comparator.
> */
> struct etmv4_caps {
> u8 nr_pe;
> @@ -899,6 +901,7 @@ struct etmv4_caps {
> bool atbtrig : 1;
> bool lpoverride : 1;
> bool skip_power_up : 1;
> + u32 ss_status[ETM_MAX_SS_CMP];
> };
>
> /**
> @@ -977,7 +980,6 @@ struct etmv4_config {
> u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
> u8 ss_idx;
> u32 ss_ctrl[ETM_MAX_SS_CMP];
> - u32 ss_status[ETM_MAX_SS_CMP];
> u32 ss_pe_cmp[ETM_MAX_SS_CMP];
> u8 addr_idx;
> u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-13 14:19 ` [PATCH v4 3/9] coresight: etm4x: fix leaked trace id Yeoreum Yun
2026-04-14 8:04 ` Jie Gan
@ 2026-04-14 16:32 ` Leo Yan
2026-04-14 16:50 ` Yeoreum Yun
1 sibling, 1 reply; 31+ messages in thread
From: Leo Yan @ 2026-04-14 16:32 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
> If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
> the trace ID may be leaked because it is not released.
>
> To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
> fails in cscfg_csdev_enable_active_config().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 8ebfd3924143..1bc9f13e33f7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> if (cfg_hash) {
> ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> - if (ret)
> + if (ret) {
> + etm4_release_trace_id(drvdata);
I am not familiar with the trace ID, seems to me, it just allocate a ID
for each tracer from the ID map and then always use this cached ID for
the tracers.
If so, even an ID is reserved for failures, and the ID map is big enough
for each CPU, we don't need to worry memory leak or ID used out issue ?
Thanks,
Leo
> return ret;
> + }
> }
>
> raw_spin_lock(&drvdata->spinlock);
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-14 16:32 ` Leo Yan
@ 2026-04-14 16:50 ` Yeoreum Yun
2026-04-15 1:21 ` Jie Gan
0 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-14 16:50 UTC (permalink / raw)
To: Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
Hi,
> On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
> > If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
> > the trace ID may be leaked because it is not released.
> >
> > To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
> > fails in cscfg_csdev_enable_active_config().
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index 8ebfd3924143..1bc9f13e33f7 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> > cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> > if (cfg_hash) {
> > ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> > - if (ret)
> > + if (ret) {
> > + etm4_release_trace_id(drvdata);
>
> I am not familiar with the trace ID, seems to me, it just allocate a ID
> for each tracer from the ID map and then always use this cached ID for
> the tracers.
>
> If so, even an ID is reserved for failures, and the ID map is big enough
> for each CPU, we don't need to worry memory leak or ID used out issue ?
>
Agree. Practically, this is not a big issue and I don't think
because of this new id couldn't be allocated in 128
although the one id is occupied by cpu while source is disabled.
However, in theory, this could lead to an ID leak,
so it would be better to release it in error cases.
[...]
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
2026-04-14 16:04 ` Leo Yan
@ 2026-04-14 16:59 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-14 16:59 UTC (permalink / raw)
To: Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
Hi Leo,
> On Mon, Apr 13, 2026 at 03:19:55PM +0100, Yeoreum Yun wrote:
> > The purpose of TRCSSCSRn register is to show status of
> > the corresponding Single-shot Comparator Control and input supports.
> > That means writable field's purpose for reset or restore from idle status
> > not for configuration.
> >
> > Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
> > This includes remove TRCSSCRn from configurable item and
> > remove saving in etm4_disable_hw().
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
> > .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
> > .../coresight/coresight-etm4x-sysfs.c | 7 ++-----
> > drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
> > 4 files changed, 10 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > index c302072b293a..d14d7c8a23e5 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> > off_mask = (offset & GENMASK(11, 5));
> > do {
> > CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
> > - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
> > CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
> > } while (0);
> > } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index 6443f3717b37..8ebfd3924143 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> > const struct etmv4_caps *caps = &drvdata->caps;
> >
> > return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> > - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
> > + (caps->ss_status[n] & TRCSSCSRn_PC);
>
> Nitpick: The naming 'ss_status' is a bit confused for capability.
> Could we rename 'ss_status' to 'ss_comparator' or a simple one
> 'ss_cmp' ?
Okay.
>
> > }
> >
> > u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
> > @@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> > etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
> >
> > for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - /* always clear status bit on restart if using single-shot */
> > - if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> > - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
> > etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
> > - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
> > + /* always clear status and pending bits on restart if using single-shot */
> > + etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
>
> It is a bit weird to use caps to write a register. A smooth way is to
> clear STATUS and PENDING bits based on the read back value:
>
> val = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> val &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
> etm4x_relaxed_write32(csa, val, TRCSSCSRn(i));
TBH, this is what I want to avoid. anyway Why do we need to
read again TRCSSCSR<n>? I think it's enough to write caps->ss_cmp
for clear purpose or
since the cap->ss_cmp will be all RO fields, It seems to better
to write "0" in here without reading TRCSSSR again.
>
> > if (etm4x_sspcicrn_present(drvdata, i))
> > etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
> > }
> > @@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
> >
> > etm4_disable_trace_unit(drvdata);
> >
> > - /* read the status of the single shot comparators */
> > - for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - config->ss_status[i] =
> > - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > - }
> > -
> > /* read back the current counter values */
> > for (i = 0; i < caps->nr_cntr; i++) {
> > config->cntr_val[i] =
> > @@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
> > */
> > caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
> > for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - drvdata->config.ss_status[i] =
> > - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > + caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > + caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
>
> For init cap, we can use explict way:
>
> caps->ss_cmp &= (TRCSSCSRn_PC | TRCSSCSRn_DV |
> TRCSSCSRn_DA | TRCSSCSRn_INST);
Okay.
>
> > }
> > /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
> > caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > index 50408215d1ac..dd62f01674cf 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > @@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
> > raw_spin_lock(&drvdata->spinlock);
> > idx = config->ss_idx;
> > config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
> > - /* must clear bit 31 in related status register on programming */
> > - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> > raw_spin_unlock(&drvdata->spinlock);
> > return size;
> > }
> > @@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
> > {
> > unsigned long val;
> > struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > + const struct etmv4_caps *caps = &drvdata->caps;
> > struct etmv4_config *config = &drvdata->config;
> >
> > raw_spin_lock(&drvdata->spinlock);
> > - val = config->ss_status[config->ss_idx];
> > + val = caps->ss_status[config->ss_idx];
>
> I think cap->ss_cmp is a good refactoring, but for legacy reason, I am
> just wandering if we still need config->ss_status so that it can record
> the lastest status (mainly for STATUS bit and PENDING bit).
>
> Otherwise, this Sysfs interface can only provide capability rather
> than status value.
The legacy *totally* isn't understandable.
Since config->ss_status is *updated* at "disable" -- end of sysfs session,
STATUS and PENDING bit doesn't have any meaning in here
and while running a session config->ss_status isn't updated all
So, I don't believe there was any user who care about this bit via
sysfs interface.
Therefore, I think we can refactor with caps->ss_cmp. let's drop the
useless and meaningless information.
>
> Thanks,
> Leo
>
> > raw_spin_unlock(&drvdata->spinlock);
> > return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > }
> > @@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
> > raw_spin_lock(&drvdata->spinlock);
> > idx = config->ss_idx;
> > config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
> > - /* must clear bit 31 in related status register on programming */
> > - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> > raw_spin_unlock(&drvdata->spinlock);
> > return size;
> > }
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> > index 8168676f2945..8864cfb76bad 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> > @@ -213,6 +213,7 @@
> > #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
> >
> > #define TRCSSCSRn_STATUS BIT(31)
> > +#define TRCSSCSRn_PENDING BIT(30)
> > #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
> >
> > #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
> > @@ -861,6 +862,7 @@ enum etm_impdef_type {
> > * @lpoverride: If the implementation can support low-power state over.
> > * @skip_power_up: Indicates if an implementation can skip powering up
> > * the trace unit.
> > + * @ss_status: The status of the corresponding single-shot comparator.
> > */
> > struct etmv4_caps {
> > u8 nr_pe;
> > @@ -899,6 +901,7 @@ struct etmv4_caps {
> > bool atbtrig : 1;
> > bool lpoverride : 1;
> > bool skip_power_up : 1;
> > + u32 ss_status[ETM_MAX_SS_CMP];
> > };
> >
> > /**
> > @@ -977,7 +980,6 @@ struct etmv4_config {
> > u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
> > u8 ss_idx;
> > u32 ss_ctrl[ETM_MAX_SS_CMP];
> > - u32 ss_status[ETM_MAX_SS_CMP];
> > u32 ss_pe_cmp[ETM_MAX_SS_CMP];
> > u8 addr_idx;
> > u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
> > --
> > LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
> >
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-14 16:50 ` Yeoreum Yun
@ 2026-04-15 1:21 ` Jie Gan
2026-04-15 7:29 ` Leo Yan
0 siblings, 1 reply; 31+ messages in thread
From: Jie Gan @ 2026-04-15 1:21 UTC (permalink / raw)
To: Yeoreum Yun, Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin
On 4/15/2026 12:50 AM, Yeoreum Yun wrote:
> Hi,
>
>> On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
>>> If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
>>> the trace ID may be leaked because it is not released.
>>>
>>> To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
>>> fails in cscfg_csdev_enable_active_config().
>>>
>>> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
>>> ---
>>> drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> index 8ebfd3924143..1bc9f13e33f7 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
>>> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
>>> if (cfg_hash) {
>>> ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
>>> - if (ret)
>>> + if (ret) {
>>> + etm4_release_trace_id(drvdata);
>>
>> I am not familiar with the trace ID, seems to me, it just allocate a ID
>> for each tracer from the ID map and then always use this cached ID for
>> the tracers.
>>
>> If so, even an ID is reserved for failures, and the ID map is big enough
>> for each CPU, we don't need to worry memory leak or ID used out issue ?
>>
>
> Agree. Practically, this is not a big issue and I don't think
> because of this new id couldn't be allocated in 128
> although the one id is occupied by cpu while source is disabled.
>
> However, in theory, this could lead to an ID leak,
> so it would be better to release it in error cases.
Actually, the 128 Trace ID is not enough for allocating. That's why the
TPDM devices share the trace ID of the connected TPDA devices.
For the QCOM platform, we may got plenty of ETM devices (SoC with more
than 20 Cores), lots of TPDM devices for each subsystem(CDSP, ADSP, GPU,
GCC, MODEM, etc ...), and lots of dummy sources...
What I am thinking is as SoCs continue to grow more complex with an
increasing number of subsystems, trace IDs may be exhausted in the near
future. (that's why we have dynamic trace ID allocation/release).
Thanks,
Jie
>
> [...]
>
> --
> Sincerely,
> Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration
2026-04-13 14:19 ` [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration Yeoreum Yun
@ 2026-04-15 4:25 ` Jie Gan
2026-04-15 5:36 ` Yeoreum Yun
0 siblings, 1 reply; 31+ messages in thread
From: Jie Gan @ 2026-04-15 4:25 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> The current ETM4x configuration via sysfs can lead to
> several inconsistencies:
>
> - If the configuration is modified via sysfs while a perf session is
> active, the running configuration may differ before a sched-out and
> after a subsequent sched-in.
>
> - If a perf session and a sysfs session enable tracing concurrently,
> the configuration from configfs may become corrupted.
>
> - There is a risk of corrupting drvdata->config if a perf session enables
> tracing while cscfg_csdev_disable_active_config() is being handled in
> etm4_disable_sysfs().
>
> To resolve these issues, separate the configuration into:
>
> - active_config: the configuration applied to the current session
> - config: the configuration set via sysfs
>
> Additionally:
>
> - Apply the configuration from configfs after taking the appropriate mode.
>
> - Since active_config and related fields are accessed only by the local CPU
> in etm4_enable/disable_sysfs_smp_call() (similar to perf enable/disable),
> remove the lock/unlock from the sysfs enable/disable path and
> startup/dying_cpu except when to access config fields.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 2 +-
> .../coresight/coresight-etm4x-core.c | 107 ++++++++++--------
> drivers/hwtracing/coresight/coresight-etm4x.h | 2 +
> 3 files changed, 62 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index d14d7c8a23e5..0553771d04e7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> struct cscfg_regval_csdev *reg_csdev, u32 offset)
> {
> int err = -EINVAL, idx;
> - struct etmv4_config *drvcfg = &drvdata->config;
> + struct etmv4_config *drvcfg = &drvdata->active_config;
> u32 off_mask;
>
> if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 1bc9f13e33f7..01099689525b 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -245,6 +245,10 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
>
> struct etm4_enable_arg {
> struct etmv4_drvdata *drvdata;
> + unsigned long cfg_hash;
> + int preset;
> + u8 trace_id;
> + struct etmv4_config config;
> int rc;
> };
>
> @@ -270,10 +274,11 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
> static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
> {
> u64 trfcr = drvdata->trfcr;
> + struct etmv4_config *config = &drvdata->active_config;
>
> - if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
> + if (config->mode & ETM_MODE_EXCL_KERN)
> trfcr &= ~TRFCR_EL1_ExTRE;
> - if (drvdata->config.mode & ETM_MODE_EXCL_USER)
> + if (config->mode & ETM_MODE_EXCL_USER)
> trfcr &= ~TRFCR_EL1_E0TRE;
>
> return trfcr;
> @@ -281,7 +286,7 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
>
> /*
> * etm4x_allow_trace - Allow CPU tracing in the respective ELs,
> - * as configured by the drvdata->config.mode for the current
> + * as configured by the drvdata->active_config.mode for the current
> * session. Even though we have TRCVICTLR bits to filter the
> * trace in the ELs, it doesn't prevent the ETM from generating
> * a packet (e.g, TraceInfo) that might contain the addresses from
> @@ -292,12 +297,13 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
> static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
> {
> u64 trfcr, guest_trfcr;
> + struct etmv4_config *config = &drvdata->active_config;
>
> /* If the CPU doesn't support FEAT_TRF, nothing to do */
> if (!drvdata->trfcr)
> return;
>
> - if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
> + if (config->mode & ETM_MODE_EXCL_HOST)
> trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
> else
> trfcr = etm4x_get_kern_user_filter(drvdata);
> @@ -305,7 +311,7 @@ static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
> write_trfcr(trfcr);
>
> /* Set filters for guests and pass to KVM */
> - if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
> + if (config->mode & ETM_MODE_EXCL_GUEST)
> guest_trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
> else
> guest_trfcr = etm4x_get_kern_user_filter(drvdata);
> @@ -499,7 +505,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> {
> int i, rc;
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct coresight_device *csdev = drvdata->csdev;
> struct device *etm_dev = &csdev->dev;
> struct csdev_access *csa = &csdev->access;
> @@ -616,23 +622,46 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> static void etm4_enable_sysfs_smp_call(void *info)
> {
> struct etm4_enable_arg *arg = info;
> + struct etmv4_drvdata *drvdata;
> struct coresight_device *csdev;
>
> if (WARN_ON(!arg))
> return;
>
> - csdev = arg->drvdata->csdev;
> + drvdata = arg->drvdata;
> + csdev = drvdata->csdev;
> if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
> /* Someone is already using the tracer */
> arg->rc = -EBUSY;
> return;
> }
>
> - arg->rc = etm4_enable_hw(arg->drvdata);
> + drvdata->active_config = arg->config;
>
> - /* The tracer didn't start */
> + if (arg->cfg_hash) {
> + arg->rc = cscfg_csdev_enable_active_config(csdev,
> + arg->cfg_hash,
> + arg->preset);
> + if (arg->rc)
> + goto err;
> + }
> +
> + drvdata->trcid = arg->trace_id;
> +
> + /* Tracer will never be paused in sysfs mode */
> + drvdata->paused = false;
> +
> + arg->rc = etm4_enable_hw(drvdata);
> if (arg->rc)
> - coresight_set_mode(csdev, CS_MODE_DISABLED);
> + goto err;
> +
> + drvdata->sticky_enable = true;
> +
> + return;
> +err:
> + /* The tracer didn't start */
> + etm4_release_trace_id(drvdata);
[NIT] better move this error handle to etm4_enable_sysfs.
smp_call_function_single possible return before call
etm4_enable_sysfs_smp_call if the cpu is offline. The error path here
cannot handle this error, breaking previous logic(handle all errors in
etm4_enable_sysfs by releasing trace id).
There is no harm in not releasing the trace id here because ETM can
re-use the allocated trace ID. But it's better to fix the inconsistent
logic.
Thanks,
Jie
> + coresight_set_mode(csdev, CS_MODE_DISABLED);
> }
>
> /*
> @@ -670,7 +699,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
> int ctridx;
> int rselector;
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
>
> /* No point in trying if we don't have at least one counter */
> if (!caps->nr_cntr)
> @@ -754,7 +783,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
> int ret = 0;
> struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct perf_event_attr max_timestamp = {
> .ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
> };
> @@ -916,38 +945,24 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
>
> /* enable any config activated by configfs */
> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> - if (cfg_hash) {
> - ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> - if (ret) {
> - etm4_release_trace_id(drvdata);
> - return ret;
> - }
> - }
> -
> - raw_spin_lock(&drvdata->spinlock);
> -
> - drvdata->trcid = path->trace_id;
> -
> - /* Tracer will never be paused in sysfs mode */
> - drvdata->paused = false;
>
> /*
> * Executing etm4_enable_hw on the cpu whose ETM is being enabled
> * ensures that register writes occur when cpu is powered.
> */
> arg.drvdata = drvdata;
> + arg.cfg_hash = cfg_hash;
> + arg.preset = preset;
> + arg.trace_id = path->trace_id;
> +
> + raw_spin_lock(&drvdata->spinlock);
> + arg.config = drvdata->config;
> + raw_spin_unlock(&drvdata->spinlock);
> +
> ret = smp_call_function_single(drvdata->cpu,
> etm4_enable_sysfs_smp_call, &arg, 1);
> if (!ret)
> ret = arg.rc;
> - if (!ret)
> - drvdata->sticky_enable = true;
> -
> - if (ret)
> - etm4_release_trace_id(drvdata);
> -
> - raw_spin_unlock(&drvdata->spinlock);
> -
> if (!ret)
> dev_dbg(&csdev->dev, "ETM tracing enabled\n");
> return ret;
> @@ -1036,7 +1051,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
> {
> u32 control;
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct coresight_device *csdev = drvdata->csdev;
> struct csdev_access *csa = &csdev->access;
> int i;
> @@ -1072,6 +1087,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
>
> etm4_disable_hw(drvdata);
>
> + cscfg_csdev_disable_active_config(drvdata->csdev);
> +
> coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
> }
>
> @@ -1122,7 +1139,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
> * DYING hotplug callback is serviced by the ETM driver.
> */
> cpus_read_lock();
> - raw_spin_lock(&drvdata->spinlock);
>
> /*
> * Executing etm4_disable_hw on the cpu whose ETM is being disabled
> @@ -1131,10 +1147,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
> smp_call_function_single(drvdata->cpu, etm4_disable_sysfs_smp_call,
> drvdata, 1);
>
> - raw_spin_unlock(&drvdata->spinlock);
> -
> - cscfg_csdev_disable_active_config(csdev);
> -
> cpus_read_unlock();
>
> /*
> @@ -1377,6 +1389,7 @@ static void etm4_init_arch_data(void *info)
> struct etm4_init_arg *init_arg = info;
> struct etmv4_drvdata *drvdata;
> struct etmv4_caps *caps;
> + struct etmv4_config *config;
> struct csdev_access *csa;
> struct device *dev = init_arg->dev;
> int i;
> @@ -1384,6 +1397,7 @@ static void etm4_init_arch_data(void *info)
> drvdata = dev_get_drvdata(init_arg->dev);
> caps = &drvdata->caps;
> csa = init_arg->csa;
> + config = &drvdata->active_config;
>
> /*
> * If we are unable to detect the access mechanism,
> @@ -1444,7 +1458,7 @@ static void etm4_init_arch_data(void *info)
>
> /* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
> caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
> - drvdata->config.s_ex_level = caps->s_ex_level;
> + config->s_ex_level = caps->s_ex_level;
> /* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
> caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
> /*
> @@ -1689,7 +1703,7 @@ static void etm4_set_default(struct etmv4_config *config)
> static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
> {
> int nr_comparator, index = 0;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
>
> /*
> * nr_addr_cmp holds the number of comparator _pair_, so time 2
> @@ -1730,7 +1744,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
> {
> int i, comparator, ret = 0;
> u64 address;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct etm_filters *filters = event->hw.addr_filters;
>
> if (!filters)
> @@ -1848,13 +1862,11 @@ static int etm4_starting_cpu(unsigned int cpu)
> if (!etmdrvdata[cpu])
> return 0;
>
> - raw_spin_lock(&etmdrvdata[cpu]->spinlock);
> if (!etmdrvdata[cpu]->os_unlock)
> etm4_os_unlock(etmdrvdata[cpu]);
>
> if (coresight_get_mode(etmdrvdata[cpu]->csdev))
> etm4_enable_hw(etmdrvdata[cpu]);
> - raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
> return 0;
> }
>
> @@ -1863,10 +1875,8 @@ static int etm4_dying_cpu(unsigned int cpu)
> if (!etmdrvdata[cpu])
> return 0;
>
> - raw_spin_lock(&etmdrvdata[cpu]->spinlock);
> if (coresight_get_mode(etmdrvdata[cpu]->csdev))
> etm4_disable_hw(etmdrvdata[cpu]);
> - raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
> return 0;
> }
>
> @@ -2252,7 +2262,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
> if (!desc.name)
> return -ENOMEM;
>
> - etm4_set_default(&drvdata->config);
> + etm4_set_default(&drvdata->active_config);
> + drvdata->config = drvdata->active_config;
>
> pdata = coresight_get_platform_data(dev);
> if (IS_ERR(pdata))
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 8864cfb76bad..725e6360a8b9 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -1071,6 +1071,7 @@ struct etmv4_save_state {
> * allows tracing at all ELs. We don't want to compute this
> * at runtime, due to the additional setting of TRFCR_CX when
> * in EL2. Otherwise, 0.
> + * @active_config: structure holding current applied configuration parameters.
> * @config: structure holding configuration parameters.
> * @save_state: State to be preserved across power loss
> * @paused: Indicates if the trace unit is paused.
> @@ -1091,6 +1092,7 @@ struct etmv4_drvdata {
> bool os_unlock : 1;
> bool paused : 1;
> u64 trfcr;
> + struct etmv4_config active_config;
> struct etmv4_config config;
> struct etmv4_save_state *save_state;
> DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration
2026-04-15 4:25 ` Jie Gan
@ 2026-04-15 5:36 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-15 5:36 UTC (permalink / raw)
To: Jie Gan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, leo.yan
[...]
> > @@ -616,23 +622,46 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> > static void etm4_enable_sysfs_smp_call(void *info)
> > {
> > struct etm4_enable_arg *arg = info;
> > + struct etmv4_drvdata *drvdata;
> > struct coresight_device *csdev;
> > if (WARN_ON(!arg))
> > return;
> > - csdev = arg->drvdata->csdev;
> > + drvdata = arg->drvdata;
> > + csdev = drvdata->csdev;
> > if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
> > /* Someone is already using the tracer */
> > arg->rc = -EBUSY;
> > return;
> > }
> > - arg->rc = etm4_enable_hw(arg->drvdata);
> > + drvdata->active_config = arg->config;
> > - /* The tracer didn't start */
> > + if (arg->cfg_hash) {
> > + arg->rc = cscfg_csdev_enable_active_config(csdev,
> > + arg->cfg_hash,
> > + arg->preset);
> > + if (arg->rc)
> > + goto err;
> > + }
> > +
> > + drvdata->trcid = arg->trace_id;
> > +
> > + /* Tracer will never be paused in sysfs mode */
> > + drvdata->paused = false;
> > +
> > + arg->rc = etm4_enable_hw(drvdata);
> > if (arg->rc)
> > - coresight_set_mode(csdev, CS_MODE_DISABLED);
> > + goto err;
> > +
> > + drvdata->sticky_enable = true;
> > +
> > + return;
> > +err:
> > + /* The tracer didn't start */
> > + etm4_release_trace_id(drvdata);
>
> [NIT] better move this error handle to etm4_enable_sysfs.
>
> smp_call_function_single possible return before call
> etm4_enable_sysfs_smp_call if the cpu is offline. The error path here cannot
> handle this error, breaking previous logic(handle all errors in
> etm4_enable_sysfs by releasing trace id).
>
> There is no harm in not releasing the trace id here because ETM can re-use
> the allocated trace ID. But it's better to fix the inconsistent logic.
Agree. I've missed this!
Thanks ;)
[...]
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-15 1:21 ` Jie Gan
@ 2026-04-15 7:29 ` Leo Yan
2026-04-15 8:01 ` Yeoreum Yun
0 siblings, 1 reply; 31+ messages in thread
From: Leo Yan @ 2026-04-15 7:29 UTC (permalink / raw)
To: Jie Gan
Cc: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel,
suzuki.poulose, mike.leach, james.clark, alexander.shishkin
On Wed, Apr 15, 2026 at 09:21:21AM +0800, Jie Gan wrote:
[...]
> > > > @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> > > > cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> > > > if (cfg_hash) {
> > > > ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> > > > - if (ret)
> > > > + if (ret) {
> > > > + etm4_release_trace_id(drvdata);
> > >
> > > If so, even an ID is reserved for failures, and the ID map is big enough
> > > for each CPU, we don't need to worry memory leak or ID used out issue ?
> >
> > However, in theory, this could lead to an ID leak,
> > so it would be better to release it in error cases.
>
> What I am thinking is as SoCs continue to grow more complex with an
> increasing number of subsystems, trace IDs may be exhausted in the near
> future. (that's why we have dynamic trace ID allocation/release).
Thanks for the input.
I am wandering if we can use "dev->devt" as the trace ID. A device's
major/minor number is unique in kernel and dev_t is defined as u32:
typedef u32 __kernel_dev_t;
And we can consolidate this for both SYSFS and PERF modes.
Thanks,
Leo
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-15 7:29 ` Leo Yan
@ 2026-04-15 8:01 ` Yeoreum Yun
2026-04-15 8:32 ` Leo Yan
0 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-15 8:01 UTC (permalink / raw)
To: Leo Yan
Cc: Jie Gan, coresight, linux-arm-kernel, linux-kernel,
suzuki.poulose, mike.leach, james.clark, alexander.shishkin
Hi Leo,
> On Wed, Apr 15, 2026 at 09:21:21AM +0800, Jie Gan wrote:
>
> [...]
>
> > > > > @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> > > > > cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> > > > > if (cfg_hash) {
> > > > > ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> > > > > - if (ret)
> > > > > + if (ret) {
> > > > > + etm4_release_trace_id(drvdata);
> > > >
> > > > If so, even an ID is reserved for failures, and the ID map is big enough
> > > > for each CPU, we don't need to worry memory leak or ID used out issue ?
> > >
> > > However, in theory, this could lead to an ID leak,
> > > so it would be better to release it in error cases.
> >
> > What I am thinking is as SoCs continue to grow more complex with an
> > increasing number of subsystems, trace IDs may be exhausted in the near
> > future. (that's why we have dynamic trace ID allocation/release).
>
> Thanks for the input.
>
> I am wandering if we can use "dev->devt" as the trace ID. A device's
> major/minor number is unique in kernel and dev_t is defined as u32:
>
> typedef u32 __kernel_dev_t;
>
> And we can consolidate this for both SYSFS and PERF modes.
>
When I see the CORESIGHT_TRACE_ID_MAX:
/* architecturally we have 128 IDs some of which are reserved */
#define CORESIGHT_TRACE_IDS_MAX 128
I think this came from the hardware restriction for number of TRACE_IDs.
In this case, clamping the device_id to trace_id seems more complex and
reduce some performance perspective.
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-15 8:01 ` Yeoreum Yun
@ 2026-04-15 8:32 ` Leo Yan
2026-04-15 8:45 ` Jie Gan
0 siblings, 1 reply; 31+ messages in thread
From: Leo Yan @ 2026-04-15 8:32 UTC (permalink / raw)
To: Yeoreum Yun
Cc: Jie Gan, coresight, linux-arm-kernel, linux-kernel,
suzuki.poulose, mike.leach, james.clark, alexander.shishkin
On Wed, Apr 15, 2026 at 09:01:09AM +0100, Yeoreum Yun wrote:
[...]
> > > What I am thinking is as SoCs continue to grow more complex with an
> > > increasing number of subsystems, trace IDs may be exhausted in the near
> > > future. (that's why we have dynamic trace ID allocation/release).
> >
> > Thanks for the input.
> >
> > I am wandering if we can use "dev->devt" as the trace ID. A device's
> > major/minor number is unique in kernel and dev_t is defined as u32:
> >
> > typedef u32 __kernel_dev_t;
> >
> > And we can consolidate this for both SYSFS and PERF modes.
> >
>
> When I see the CORESIGHT_TRACE_ID_MAX:
>
> /* architecturally we have 128 IDs some of which are reserved */
> #define CORESIGHT_TRACE_IDS_MAX 128
>
> I think this came from the hardware restriction for number of TRACE_IDs.
> In this case, clamping the device_id to trace_id seems more complex and
> reduce some performance perspective.
Sigh, my stupid. Please ignore my previous comment, let us first fix
ID leak issue.
Given Jie's comment on the use-out issue, it is valid for me especially
if a system have many dummy tracers. We can defer to refactor it
later (e.g., use separate ranges for hardware and dummy tracers).
thanks for correction!
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-15 8:32 ` Leo Yan
@ 2026-04-15 8:45 ` Jie Gan
2026-04-15 8:56 ` Suzuki K Poulose
0 siblings, 1 reply; 31+ messages in thread
From: Jie Gan @ 2026-04-15 8:45 UTC (permalink / raw)
To: Leo Yan, Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin
On 4/15/2026 4:32 PM, Leo Yan wrote:
> On Wed, Apr 15, 2026 at 09:01:09AM +0100, Yeoreum Yun wrote:
>
> [...]
>
>>>> What I am thinking is as SoCs continue to grow more complex with an
>>>> increasing number of subsystems, trace IDs may be exhausted in the near
>>>> future. (that's why we have dynamic trace ID allocation/release).
>>>
>>> Thanks for the input.
>>>
>>> I am wandering if we can use "dev->devt" as the trace ID. A device's
>>> major/minor number is unique in kernel and dev_t is defined as u32:
>>>
>>> typedef u32 __kernel_dev_t;
>>>
>>> And we can consolidate this for both SYSFS and PERF modes.
>>>
>>
>> When I see the CORESIGHT_TRACE_ID_MAX:
>>
>> /* architecturally we have 128 IDs some of which are reserved */
>> #define CORESIGHT_TRACE_IDS_MAX 128
>>
>> I think this came from the hardware restriction for number of TRACE_IDs.
>> In this case, clamping the device_id to trace_id seems more complex and
>> reduce some performance perspective.
>
> Sigh, my stupid. Please ignore my previous comment, let us first fix
> ID leak issue.
>
> Given Jie's comment on the use-out issue, it is valid for me especially
> if a system have many dummy tracers. We can defer to refactor it
> later (e.g., use separate ranges for hardware and dummy tracers).
>
> thanks for correction!
Just share some info:
With my memory, The ARM AMBA ATB Protocol Specification defined a 7-bit
width field for the trace ID, that's where the 128 comes from. (in each
frame, we also have 7-bit field for containing the trace ID)
Thanks,
Jie
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
2026-04-15 8:45 ` Jie Gan
@ 2026-04-15 8:56 ` Suzuki K Poulose
0 siblings, 0 replies; 31+ messages in thread
From: Suzuki K Poulose @ 2026-04-15 8:56 UTC (permalink / raw)
To: Jie Gan, Leo Yan, Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, mike.leach,
james.clark, alexander.shishkin
On 15/04/2026 09:45, Jie Gan wrote:
>
>
> On 4/15/2026 4:32 PM, Leo Yan wrote:
>> On Wed, Apr 15, 2026 at 09:01:09AM +0100, Yeoreum Yun wrote:
>>
>> [...]
>>
>>>>> What I am thinking is as SoCs continue to grow more complex with an
>>>>> increasing number of subsystems, trace IDs may be exhausted in the
>>>>> near
>>>>> future. (that's why we have dynamic trace ID allocation/release).
>>>>
>>>> Thanks for the input.
>>>>
>>>> I am wandering if we can use "dev->devt" as the trace ID. A device's
>>>> major/minor number is unique in kernel and dev_t is defined as u32:
>>>>
>>>> typedef u32 __kernel_dev_t;
>>>>
>>>> And we can consolidate this for both SYSFS and PERF modes.
>>>>
>>>
>>> When I see the CORESIGHT_TRACE_ID_MAX:
>>>
>>> /* architecturally we have 128 IDs some of which are reserved */
>>> #define CORESIGHT_TRACE_IDS_MAX 128
>>>
>>> I think this came from the hardware restriction for number of TRACE_IDs.
>>> In this case, clamping the device_id to trace_id seems more complex and
>>> reduce some performance perspective.
>>
>> Sigh, my stupid. Please ignore my previous comment, let us first fix
>> ID leak issue.
>>
>> Given Jie's comment on the use-out issue, it is valid for me especially
>> if a system have many dummy tracers. We can defer to refactor it
>> later (e.g., use separate ranges for hardware and dummy tracers).
>>
>> thanks for correction!
>
> Just share some info:
>
> With my memory, The ARM AMBA ATB Protocol Specification defined a 7-bit
> width field for the trace ID, that's where the 128 comes from. (in each
> frame, we also have 7-bit field for containing the trace ID)
That is true and some IDs in the range (0-128) are reserved. So we
actually have less than 128. We need the dynamic allocation, preferrably
isolated to a "pool" for the relevant session to make the full use of
the space.
Suzuki
>
> Thanks,
> Jie
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug
2026-04-13 14:19 ` [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug Yeoreum Yun
@ 2026-04-15 11:59 ` Jie Gan
0 siblings, 0 replies; 31+ messages in thread
From: Jie Gan @ 2026-04-15 11:59 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
> In other words, if etm4_enable_sysfs() is called between
> CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
> etm4_enable_hw() may be invoked in etm4_enable_sysfs_smp_call()
> and then executed again in etm4_starting_cpu().
>
> To remove this redundant call, take the hotplug lock before executing
> etm4_enable_sysfs_smp_call().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm4x-core.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 01099689525b..facd5a306228 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -959,8 +959,20 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> arg.config = drvdata->config;
> raw_spin_unlock(&drvdata->spinlock);
>
> + /*
> + * Take the hotplug lock to prevent redundant calls to etm4_enable_hw().
> + *
> + * The cpu_online_mask is set at the CPUHP_BRINGUP_CPU step.
> + * In other words, if etm4_enable_sysfs() is called between
> + * CPUHP_BRINGUP_CPU and CPUHP_AP_ARM_CORESIGHT_STARTING,
> + * etm4_enable_hw() may be invoked in etm4_enable_sysfs_smp_call()
> + * and then executed again in etm4_starting_cpu().
> + */
> + cpus_read_lock();
> ret = smp_call_function_single(drvdata->cpu,
> etm4_enable_sysfs_smp_call, &arg, 1);
> + cpus_read_unlock();
> +
> if (!ret)
> ret = arg.rc;
> if (!ret)
Reviewed-by: Jie Gan <jie.gan@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t
2026-04-13 14:19 ` [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t Yeoreum Yun
@ 2026-04-15 12:05 ` Jie Gan
0 siblings, 0 replies; 31+ messages in thread
From: Jie Gan @ 2026-04-15 12:05 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> etm_starting_cpu()/etm_dying_cpu() are called in not sleepable context.
> This poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable.
>
> To address this, change etm3's drvdata->spinlock type to raw_spin_lock_t.
> This will be good to align with etm4x.
>
LGTM
Reviewed-by: Jie Gan <jie.gan@oss.qualcomm.com>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm.h | 2 +-
> .../coresight/coresight-etm3x-core.c | 18 +--
> .../coresight/coresight-etm3x-sysfs.c | 130 +++++++++---------
> 3 files changed, 75 insertions(+), 75 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
> index 1d753cca2943..40f20daded4f 100644
> --- a/drivers/hwtracing/coresight/coresight-etm.h
> +++ b/drivers/hwtracing/coresight/coresight-etm.h
> @@ -232,7 +232,7 @@ struct etm_drvdata {
> struct csdev_access csa;
> struct clk *atclk;
> struct coresight_device *csdev;
> - spinlock_t spinlock;
> + raw_spinlock_t spinlock;
> int cpu;
> int port_size;
> u8 arch;
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> index a547a6d2e0bd..4a702b515733 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> @@ -511,7 +511,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
> struct etm_enable_arg arg = { };
> int ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
>
> drvdata->traceid = path->trace_id;
>
> @@ -534,7 +534,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
> if (ret)
> etm_release_trace_id(drvdata);
>
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> if (!ret)
> dev_dbg(&csdev->dev, "ETM tracing enabled\n");
> @@ -634,7 +634,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
> * DYING hotplug callback is serviced by the ETM driver.
> */
> cpus_read_lock();
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
>
> /*
> * Executing etm_disable_hw on the cpu whose ETM is being disabled
> @@ -643,7 +643,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
> smp_call_function_single(drvdata->cpu, etm_disable_sysfs_smp_call,
> drvdata, 1);
>
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> cpus_read_unlock();
>
> /*
> @@ -709,7 +709,7 @@ static int etm_starting_cpu(unsigned int cpu)
> if (!etmdrvdata[cpu])
> return 0;
>
> - spin_lock(&etmdrvdata[cpu]->spinlock);
> + raw_spin_lock(&etmdrvdata[cpu]->spinlock);
> if (!etmdrvdata[cpu]->os_unlock) {
> etm_os_unlock(etmdrvdata[cpu]);
> etmdrvdata[cpu]->os_unlock = true;
> @@ -717,7 +717,7 @@ static int etm_starting_cpu(unsigned int cpu)
>
> if (coresight_get_mode(etmdrvdata[cpu]->csdev))
> etm_enable_hw(etmdrvdata[cpu]);
> - spin_unlock(&etmdrvdata[cpu]->spinlock);
> + raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
> return 0;
> }
>
> @@ -726,10 +726,10 @@ static int etm_dying_cpu(unsigned int cpu)
> if (!etmdrvdata[cpu])
> return 0;
>
> - spin_lock(&etmdrvdata[cpu]->spinlock);
> + raw_spin_lock(&etmdrvdata[cpu]->spinlock);
> if (coresight_get_mode(etmdrvdata[cpu]->csdev))
> etm_disable_hw(etmdrvdata[cpu]);
> - spin_unlock(&etmdrvdata[cpu]->spinlock);
> + raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
> return 0;
> }
>
> @@ -856,7 +856,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
>
> desc.access = drvdata->csa = CSDEV_ACCESS_IOMEM(base);
>
> - spin_lock_init(&drvdata->spinlock);
> + raw_spin_lock_init(&drvdata->spinlock);
>
> drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
> if (IS_ERR(drvdata->atclk))
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> index 762109307b86..42b12c33516b 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> @@ -49,13 +49,13 @@ static ssize_t etmsr_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>
> pm_runtime_get_sync(dev->parent);
> - spin_lock_irqsave(&drvdata->spinlock, flags);
> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
> CS_UNLOCK(drvdata->csa.base);
>
> val = etm_readl(drvdata, ETMSR);
>
> CS_LOCK(drvdata->csa.base);
> - spin_unlock_irqrestore(&drvdata->spinlock, flags);
> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
> pm_runtime_put(dev->parent);
>
> return sprintf(buf, "%#lx\n", val);
> @@ -76,7 +76,7 @@ static ssize_t reset_store(struct device *dev,
> return ret;
>
> if (val) {
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> memset(config, 0, sizeof(struct etm_config));
> config->mode = ETM_MODE_EXCLUDE;
> config->trigger_event = ETM_DEFAULT_EVENT_VAL;
> @@ -86,7 +86,7 @@ static ssize_t reset_store(struct device *dev,
>
> etm_set_default(config);
> etm_release_trace_id(drvdata);
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> }
>
> return size;
> @@ -117,7 +117,7 @@ static ssize_t mode_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->mode = val & ETM_MODE_ALL;
>
> if (config->mode & ETM_MODE_EXCLUDE)
> @@ -168,12 +168,12 @@ static ssize_t mode_store(struct device *dev,
> if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
> etm_config_trace_mode(config);
>
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
>
> err_unlock:
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return ret;
> }
> static DEVICE_ATTR_RW(mode);
> @@ -299,9 +299,9 @@ static ssize_t addr_idx_store(struct device *dev,
> * Use spinlock to ensure index doesn't change while it gets
> * dereferenced multiple times within a spinlock block elsewhere.
> */
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->addr_idx = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -315,16 +315,16 @@ static ssize_t addr_single_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EINVAL;
> }
>
> val = config->addr_val[idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -343,17 +343,17 @@ static ssize_t addr_single_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EINVAL;
> }
>
> config->addr_val[idx] = val;
> config->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -367,23 +367,23 @@ static ssize_t addr_range_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (idx % 2 != 0) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
> if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
> config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
> (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
> config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> val1 = config->addr_val[idx];
> val2 = config->addr_val[idx + 1];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx %#lx\n", val1, val2);
> }
> @@ -403,17 +403,17 @@ static ssize_t addr_range_store(struct device *dev,
> if (val1 > val2)
> return -EINVAL;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (idx % 2 != 0) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
> if (!((config->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
> config->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
> (config->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
> config->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> @@ -422,7 +422,7 @@ static ssize_t addr_range_store(struct device *dev,
> config->addr_val[idx + 1] = val2;
> config->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
> config->enable_ctrl1 |= (1 << (idx/2));
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -436,16 +436,16 @@ static ssize_t addr_start_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> val = config->addr_val[idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -464,11 +464,11 @@ static ssize_t addr_start_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_START)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> @@ -476,7 +476,7 @@ static ssize_t addr_start_store(struct device *dev,
> config->addr_type[idx] = ETM_ADDR_TYPE_START;
> config->startstop_ctrl |= (1 << idx);
> config->enable_ctrl1 |= ETMTECR1_START_STOP;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -490,16 +490,16 @@ static ssize_t addr_stop_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> val = config->addr_val[idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -518,11 +518,11 @@ static ssize_t addr_stop_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> idx = config->addr_idx;
> if (!(config->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
> config->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return -EPERM;
> }
>
> @@ -530,7 +530,7 @@ static ssize_t addr_stop_store(struct device *dev,
> config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
> config->startstop_ctrl |= (1 << (idx + 16));
> config->enable_ctrl1 |= ETMTECR1_START_STOP;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -543,9 +543,9 @@ static ssize_t addr_acctype_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> val = config->addr_acctype[config->addr_idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -563,9 +563,9 @@ static ssize_t addr_acctype_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->addr_acctype[config->addr_idx] = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -601,9 +601,9 @@ static ssize_t cntr_idx_store(struct device *dev,
> * Use spinlock to ensure index doesn't change while it gets
> * dereferenced multiple times within a spinlock block elsewhere.
> */
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->cntr_idx = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -616,9 +616,9 @@ static ssize_t cntr_rld_val_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> val = config->cntr_rld_val[config->cntr_idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -636,9 +636,9 @@ static ssize_t cntr_rld_val_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->cntr_rld_val[config->cntr_idx] = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -651,9 +651,9 @@ static ssize_t cntr_event_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> val = config->cntr_event[config->cntr_idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -671,9 +671,9 @@ static ssize_t cntr_event_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->cntr_event[config->cntr_idx] = val & ETM_EVENT_MASK;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -686,9 +686,9 @@ static ssize_t cntr_rld_event_show(struct device *dev,
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> struct etm_config *config = &drvdata->config;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> val = config->cntr_rld_event[config->cntr_idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -706,9 +706,9 @@ static ssize_t cntr_rld_event_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->cntr_rld_event[config->cntr_idx] = val & ETM_EVENT_MASK;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -723,11 +723,11 @@ static ssize_t cntr_val_show(struct device *dev,
> struct etm_config *config = &drvdata->config;
>
> if (!coresight_get_mode(drvdata->csdev)) {
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> for (i = 0; i < drvdata->nr_cntr; i++)
> ret += sprintf(buf, "counter %d: %x\n",
> i, config->cntr_val[i]);
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
> return ret;
> }
>
> @@ -752,9 +752,9 @@ static ssize_t cntr_val_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->cntr_val[config->cntr_idx] = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -947,13 +947,13 @@ static ssize_t seq_curr_state_show(struct device *dev,
> }
>
> pm_runtime_get_sync(dev->parent);
> - spin_lock_irqsave(&drvdata->spinlock, flags);
> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>
> CS_UNLOCK(drvdata->csa.base);
> val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
> CS_LOCK(drvdata->csa.base);
>
> - spin_unlock_irqrestore(&drvdata->spinlock, flags);
> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
> pm_runtime_put(dev->parent);
> out:
> return sprintf(buf, "%#lx\n", val);
> @@ -1012,9 +1012,9 @@ static ssize_t ctxid_idx_store(struct device *dev,
> * Use spinlock to ensure index doesn't change while it gets
> * dereferenced multiple times within a spinlock block elsewhere.
> */
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->ctxid_idx = val;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
> @@ -1034,9 +1034,9 @@ static ssize_t ctxid_pid_show(struct device *dev,
> if (task_active_pid_ns(current) != &init_pid_ns)
> return -EINVAL;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> val = config->ctxid_pid[config->ctxid_idx];
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return sprintf(buf, "%#lx\n", val);
> }
> @@ -1066,9 +1066,9 @@ static ssize_t ctxid_pid_store(struct device *dev,
> if (ret)
> return ret;
>
> - spin_lock(&drvdata->spinlock);
> + raw_spin_lock(&drvdata->spinlock);
> config->ctxid_pid[config->ctxid_idx] = pid;
> - spin_unlock(&drvdata->spinlock);
> + raw_spin_unlock(&drvdata->spinlock);
>
> return size;
> }
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps
2026-04-13 14:20 ` [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps Yeoreum Yun
@ 2026-04-15 12:17 ` Jie Gan
2026-04-15 16:45 ` Yeoreum Yun
0 siblings, 1 reply; 31+ messages in thread
From: Jie Gan @ 2026-04-15 12:17 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
On 4/13/2026 10:20 PM, Yeoreum Yun wrote:
> Introduce struct etm_caps to describe ETMv3 capabilities
> and move capabilities information into it.
>
> Since drvdata->etmccr and drvdata->etmccer are used to check
> whether it supports fifofull logic and timestamping,
> remove etmccr and etmccer field from drvdata and add relevant fields
> in etm_caps structure.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm.h | 42 ++++++++++++-------
> .../coresight/coresight-etm3x-core.c | 39 ++++++++++-------
> .../coresight/coresight-etm3x-sysfs.c | 29 ++++++++-----
> 3 files changed, 67 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
> index 40f20daded4f..8d1a1079b008 100644
> --- a/drivers/hwtracing/coresight/coresight-etm.h
> +++ b/drivers/hwtracing/coresight/coresight-etm.h
> @@ -140,6 +140,30 @@
> ETM_ADD_COMP_0 | \
> ETM_EVENT_NOT_A)
>
> +/**
> + * struct etmv_caps - specifics ETM capabilities
s/etmv_caps/etm_caps
Thanks,
Jie
> + * @port_size: port size as reported by ETMCR bit 4-6 and 21.
> + * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
> + * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
> + * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
> + * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
> + * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
> + * @fifofull: FIFOFULL logic is present.
> + * @timestamp: Timestamping is implemented.
> + * @retstack: Return stack is implemented.
> + */
> +struct etm_caps {
> + int port_size;
> + u8 nr_addr_cmp;
> + u8 nr_cntr;
> + u8 nr_ext_inp;
> + u8 nr_ext_out;
> + u8 nr_ctxid_cmp;
> + bool fifofull : 1;
> + bool timestamp : 1;
> + bool retstack : 1;
> +};
> +
> /**
> * struct etm_config - configuration information related to an ETM
> * @mode: controls various modes supported by this ETM/PTM.
> @@ -212,19 +236,12 @@ struct etm_config {
> * @csdev: component vitals needed by the framework.
> * @spinlock: only one at a time pls.
> * @cpu: the cpu this component is affined to.
> - * @port_size: port size as reported by ETMCR bit 4-6 and 21.
> * @arch: ETM/PTM version number.
> + * @caps: ETM capabilities.
> * @use_cpu14: true if management registers need to be accessed via CP14.
> * @sticky_enable: true if ETM base configuration has been done.
> * @boot_enable:true if we should start tracing at boot time.
> * @os_unlock: true if access to management registers is allowed.
> - * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
> - * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
> - * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
> - * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
> - * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
> - * @etmccr: value of register ETMCCR.
> - * @etmccer: value of register ETMCCER.
> * @traceid: value of the current ID for this component.
> * @config: structure holding configuration parameters.
> */
> @@ -234,19 +251,12 @@ struct etm_drvdata {
> struct coresight_device *csdev;
> raw_spinlock_t spinlock;
> int cpu;
> - int port_size;
> u8 arch;
> + struct etm_caps caps;
> bool use_cp14;
> bool sticky_enable;
> bool boot_enable;
> bool os_unlock;
> - u8 nr_addr_cmp;
> - u8 nr_cntr;
> - u8 nr_ext_inp;
> - u8 nr_ext_out;
> - u8 nr_ctxid_cmp;
> - u32 etmccr;
> - u32 etmccer;
> u32 traceid;
> struct etm_config config;
> };
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> index 4a702b515733..e42ca346da91 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> @@ -308,6 +308,7 @@ void etm_config_trace_mode(struct etm_config *config)
> static int etm_parse_event_config(struct etm_drvdata *drvdata,
> struct perf_event *event)
> {
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
> struct perf_event_attr *attr = &event->attr;
> u8 ts_level;
> @@ -356,8 +357,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
> * has ret stack) on the same SoC. So only enable when it can be honored
> * - trace will still continue normally otherwise.
> */
> - if (ATTR_CFG_GET_FLD(attr, retstack) &&
> - (drvdata->etmccer & ETMCCER_RETSTACK))
> + if (ATTR_CFG_GET_FLD(attr, retstack) && (caps->retstack))
> config->ctrl |= ETMCR_RETURN_STACK;
>
> return 0;
> @@ -367,6 +367,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
> {
> int i, rc;
> u32 etmcr;
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
> struct coresight_device *csdev = drvdata->csdev;
>
> @@ -388,7 +389,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
> etmcr = etm_readl(drvdata, ETMCR);
> /* Clear setting from a previous run if need be */
> etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
> - etmcr |= drvdata->port_size;
> + etmcr |= caps->port_size;
> etmcr |= ETMCR_ETM_EN;
> etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
> etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
> @@ -396,11 +397,11 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
> etm_writel(drvdata, config->enable_event, ETMTEEVR);
> etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
> etm_writel(drvdata, config->fifofull_level, ETMFFLR);
> - for (i = 0; i < drvdata->nr_addr_cmp; i++) {
> + for (i = 0; i < caps->nr_addr_cmp; i++) {
> etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
> etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
> }
> - for (i = 0; i < drvdata->nr_cntr; i++) {
> + for (i = 0; i < caps->nr_cntr; i++) {
> etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
> etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
> etm_writel(drvdata, config->cntr_rld_event[i],
> @@ -414,9 +415,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
> etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
> etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
> etm_writel(drvdata, config->seq_curr_state, ETMSQR);
> - for (i = 0; i < drvdata->nr_ext_out; i++)
> + for (i = 0; i < caps->nr_ext_out; i++)
> etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
> - for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
> + for (i = 0; i < caps->nr_ctxid_cmp; i++)
> etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
> etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
> etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
> @@ -563,6 +564,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
> static void etm_disable_hw(struct etm_drvdata *drvdata)
> {
> int i;
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
> struct coresight_device *csdev = drvdata->csdev;
>
> @@ -572,7 +574,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
> /* Read back sequencer and counters for post trace analysis */
> config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
>
> - for (i = 0; i < drvdata->nr_cntr; i++)
> + for (i = 0; i < caps->nr_cntr; i++)
> config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
>
> etm_set_pwrdwn(drvdata);
> @@ -754,7 +756,9 @@ static void etm_init_arch_data(void *info)
> {
> u32 etmidr;
> u32 etmccr;
> + u32 etmccer;
> struct etm_drvdata *drvdata = info;
> + struct etm_caps *caps = &drvdata->caps;
>
> /* Make sure all registers are accessible */
> etm_os_unlock(drvdata);
> @@ -779,16 +783,19 @@ static void etm_init_arch_data(void *info)
> /* Find all capabilities */
> etmidr = etm_readl(drvdata, ETMIDR);
> drvdata->arch = BMVAL(etmidr, 4, 11);
> - drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
> + caps->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
> +
> + etmccer = etm_readl(drvdata, ETMCCER);
> + caps->timestamp = !!(etmccer & ETMCCER_TIMESTAMP);
> + caps->retstack = !!(etmccer & ETMCCER_RETSTACK);
>
> - drvdata->etmccer = etm_readl(drvdata, ETMCCER);
> etmccr = etm_readl(drvdata, ETMCCR);
> - drvdata->etmccr = etmccr;
> - drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
> - drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
> - drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
> - drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
> - drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
> + caps->fifofull = !!(etmccr & ETMCCR_FIFOFULL);
> + caps->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
> + caps->nr_cntr = BMVAL(etmccr, 13, 15);
> + caps->nr_ext_inp = BMVAL(etmccr, 17, 19);
> + caps->nr_ext_out = BMVAL(etmccr, 20, 22);
> + caps->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
>
> coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
> etm_set_pwrdwn(drvdata);
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> index 42b12c33516b..f7330d830e21 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> @@ -15,8 +15,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
> {
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
>
> - val = drvdata->nr_addr_cmp;
> + val = caps->nr_addr_cmp;
> return sprintf(buf, "%#lx\n", val);
> }
> static DEVICE_ATTR_RO(nr_addr_cmp);
> @@ -25,8 +26,9 @@ static ssize_t nr_cntr_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> { unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
>
> - val = drvdata->nr_cntr;
> + val = caps->nr_cntr;
> return sprintf(buf, "%#lx\n", val);
> }
> static DEVICE_ATTR_RO(nr_cntr);
> @@ -37,7 +39,7 @@ static ssize_t nr_ctxid_cmp_show(struct device *dev,
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>
> - val = drvdata->nr_ctxid_cmp;
> + val = drvdata->caps.nr_ctxid_cmp;
> return sprintf(buf, "%#lx\n", val);
> }
> static DEVICE_ATTR_RO(nr_ctxid_cmp);
> @@ -80,7 +82,7 @@ static ssize_t reset_store(struct device *dev,
> memset(config, 0, sizeof(struct etm_config));
> config->mode = ETM_MODE_EXCLUDE;
> config->trigger_event = ETM_DEFAULT_EVENT_VAL;
> - for (i = 0; i < drvdata->nr_addr_cmp; i++) {
> + for (i = 0; i < drvdata->caps.nr_addr_cmp; i++) {
> config->addr_type[i] = ETM_ADDR_TYPE_NONE;
> }
>
> @@ -111,6 +113,7 @@ static ssize_t mode_store(struct device *dev,
> int ret;
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
>
> ret = kstrtoul(buf, 16, &val);
> @@ -131,7 +134,7 @@ static ssize_t mode_store(struct device *dev,
> config->ctrl &= ~ETMCR_CYC_ACC;
>
> if (config->mode & ETM_MODE_STALL) {
> - if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
> + if (!caps->fifofull) {
> dev_warn(dev, "stall mode not supported\n");
> ret = -EINVAL;
> goto err_unlock;
> @@ -141,7 +144,7 @@ static ssize_t mode_store(struct device *dev,
> config->ctrl &= ~ETMCR_STALL_MODE;
>
> if (config->mode & ETM_MODE_TIMESTAMP) {
> - if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
> + if (!caps->timestamp) {
> dev_warn(dev, "timestamp not supported\n");
> ret = -EINVAL;
> goto err_unlock;
> @@ -286,13 +289,14 @@ static ssize_t addr_idx_store(struct device *dev,
> int ret;
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
>
> ret = kstrtoul(buf, 16, &val);
> if (ret)
> return ret;
>
> - if (val >= drvdata->nr_addr_cmp)
> + if (val >= caps->nr_addr_cmp)
> return -EINVAL;
>
> /*
> @@ -589,13 +593,14 @@ static ssize_t cntr_idx_store(struct device *dev,
> int ret;
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
>
> ret = kstrtoul(buf, 16, &val);
> if (ret)
> return ret;
>
> - if (val >= drvdata->nr_cntr)
> + if (val >= caps->nr_cntr)
> return -EINVAL;
> /*
> * Use spinlock to ensure index doesn't change while it gets
> @@ -720,18 +725,19 @@ static ssize_t cntr_val_show(struct device *dev,
> int i, ret = 0;
> u32 val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
>
> if (!coresight_get_mode(drvdata->csdev)) {
> raw_spin_lock(&drvdata->spinlock);
> - for (i = 0; i < drvdata->nr_cntr; i++)
> + for (i = 0; i < caps->nr_cntr; i++)
> ret += sprintf(buf, "counter %d: %x\n",
> i, config->cntr_val[i]);
> raw_spin_unlock(&drvdata->spinlock);
> return ret;
> }
>
> - for (i = 0; i < drvdata->nr_cntr; i++) {
> + for (i = 0; i < caps->nr_cntr; i++) {
> val = etm_readl(drvdata, ETMCNTVRn(i));
> ret += sprintf(buf, "counter %d: %x\n", i, val);
> }
> @@ -999,13 +1005,14 @@ static ssize_t ctxid_idx_store(struct device *dev,
> int ret;
> unsigned long val;
> struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etm_caps *caps = &drvdata->caps;
> struct etm_config *config = &drvdata->config;
>
> ret = kstrtoul(buf, 16, &val);
> if (ret)
> return ret;
>
> - if (val >= drvdata->nr_ctxid_cmp)
> + if (val >= caps->nr_ctxid_cmp)
> return -EINVAL;
>
> /*
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps
2026-04-15 12:17 ` Jie Gan
@ 2026-04-15 16:45 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-04-15 16:45 UTC (permalink / raw)
To: Jie Gan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, leo.yan
[...]
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > drivers/hwtracing/coresight/coresight-etm.h | 42 ++++++++++++-------
> > .../coresight/coresight-etm3x-core.c | 39 ++++++++++-------
> > .../coresight/coresight-etm3x-sysfs.c | 29 ++++++++-----
> > 3 files changed, 67 insertions(+), 43 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
> > index 40f20daded4f..8d1a1079b008 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm.h
> > +++ b/drivers/hwtracing/coresight/coresight-etm.h
> > @@ -140,6 +140,30 @@
> > ETM_ADD_COMP_0 | \
> > ETM_EVENT_NOT_A)
> > +/**
> > + * struct etmv_caps - specifics ETM capabilities
>
> s/etmv_caps/etm_caps
Sorry. I'll fix it. Thanks!
[...]
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-04-15 16:45 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-13 14:19 [PATCH v4 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 1/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
2026-04-13 17:21 ` Leo Yan
2026-04-14 7:55 ` Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
2026-04-14 8:02 ` Jie Gan
2026-04-14 16:04 ` Leo Yan
2026-04-14 16:59 ` Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 3/9] coresight: etm4x: fix leaked trace id Yeoreum Yun
2026-04-14 8:04 ` Jie Gan
2026-04-14 16:32 ` Leo Yan
2026-04-14 16:50 ` Yeoreum Yun
2026-04-15 1:21 ` Jie Gan
2026-04-15 7:29 ` Leo Yan
2026-04-15 8:01 ` Yeoreum Yun
2026-04-15 8:32 ` Leo Yan
2026-04-15 8:45 ` Jie Gan
2026-04-15 8:56 ` Suzuki K Poulose
2026-04-13 14:19 ` [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration Yeoreum Yun
2026-04-15 4:25 ` Jie Gan
2026-04-15 5:36 ` Yeoreum Yun
2026-04-13 14:19 ` [PATCH v4 5/9] coresight: etm4x: remove redundant call etm4_enable_hw() with hotplug Yeoreum Yun
2026-04-15 11:59 ` Jie Gan
2026-04-13 14:19 ` [PATCH v4 6/9] coresight: etm3x: change drvdata->spinlock type to raw_spin_lock_t Yeoreum Yun
2026-04-15 12:05 ` Jie Gan
2026-04-13 14:20 ` [PATCH v4 7/9] coresight: etm3x: introduce struct etm_caps Yeoreum Yun
2026-04-15 12:17 ` Jie Gan
2026-04-15 16:45 ` Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 8/9] coresight: etm3x: fix inconsistencies with sysfs configuration Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm4_enable_hw with hotplug Yeoreum Yun
2026-04-13 14:20 ` [PATCH v4 9/9] coresight: etm3x: remove redundant call etm_enable_hw() " Yeoreum Yun
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox