This series focuses on CoreSight path power management. The changes can
be divided into four parts for review:
Patches 01~06: Refactor the CPU idle flow with moving common code into
the CoreSight core layer.
Patches 07~14: Add link control during CPU idle.
Patches 15~16: Support the sink (TRBE) control during CPU idle.
Patches 17~19: Move the CPU hotplug flow into the coresight core layer
and simplify the code.
This series is rebased on the coresight-next branch and has been verified
on Juno-r2 and FVP RevC.
---
Changes in v6:
- Rebase on the latest coresight-next branch.
- Always save and restore TRBE context during idle (Will).
- Use get_cpu() / put_cpu() when set the per CPU source pointer.
- Link to v5: https://lore.kernel.org/r/20251119-arm_coresight_path_power_management_impr…
Changes in v5:
- Set the per-CPU source pointer on target CPU (Suzuki).
- Reused existed enable/disable buffer functions in TRBE callbacks
(James).
- Refactored refcount for source devices in SysFS mode.
- Released path in cpu-hotplug off flow to avoid memory leak.
- Updated ETMv3 driver when move common code into core layer.
- Rebased on the latest coresight-next branch.
- Link to v4: https://lore.kernel.org/r/20251104-arm_coresight_path_power_management_impr…
Changes in v4:
- Changed to store path pointer in coresight_device, this is easier for
fetching path pointer based on source device (Mike).
- Dropped changes in CTI driver.
- Only disabled path for CPU hot-plugged off but not enable path for
hot-plugged in.
- Removed James' test tags for modified patches.
- Link to v3: https://lore.kernel.org/r/20250915-arm_coresight_power_management_fix-v3-0-…
Signed-off-by: Leo Yan <leo.yan(a)arm.com>
---
Leo Yan (18):
coresight: sysfs: Validate CPU online status for per-CPU sources
coresight: Set per-CPU source pointer
coresight: Register CPU PM notifier in core layer
coresight: etm4x: Hook CPU PM callbacks
coresight: Add callback to determine if PM is needed
coresight: etm4x: Remove redundant condition checks in save and restore
coresight: syscfg: Use spinlock to protect active variables
coresight: Introduce coresight_enable_source() helper
coresight: Save active path for system tracers
coresight: etm4x: Set active path on target CPU
coresight: etm3x: Set active path on target CPU
coresight: sysfs: Use source's path pointer for path control
coresight: Add 'in_idle' argument to path
coresight: Control path during CPU idle
coresight: Add PM callbacks for sink device
coresight: sysfs: Increment refcount only for system tracers
coresight: Take hotplug lock in enable_source_store() for Sysfs mode
coresight: Move CPU hotplug callbacks to core layer
Yabin Cui (1):
coresight: trbe: Save and restore state across CPU low power state
drivers/hwtracing/coresight/coresight-catu.c | 1 +
drivers/hwtracing/coresight/coresight-core.c | 273 ++++++++++++++++++++-
drivers/hwtracing/coresight/coresight-ctcu-core.c | 1 +
drivers/hwtracing/coresight/coresight-cti-core.c | 1 +
drivers/hwtracing/coresight/coresight-dummy.c | 1 +
drivers/hwtracing/coresight/coresight-etb10.c | 1 +
drivers/hwtracing/coresight/coresight-etm-perf.c | 2 +-
drivers/hwtracing/coresight/coresight-etm3x-core.c | 65 ++---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 153 +++---------
drivers/hwtracing/coresight/coresight-funnel.c | 1 +
drivers/hwtracing/coresight/coresight-priv.h | 3 +
drivers/hwtracing/coresight/coresight-replicator.c | 1 +
drivers/hwtracing/coresight/coresight-stm.c | 1 +
drivers/hwtracing/coresight/coresight-syscfg.c | 22 +-
drivers/hwtracing/coresight/coresight-syscfg.h | 2 +
drivers/hwtracing/coresight/coresight-sysfs.c | 126 +++-------
drivers/hwtracing/coresight/coresight-tmc-core.c | 1 +
drivers/hwtracing/coresight/coresight-tnoc.c | 2 +
drivers/hwtracing/coresight/coresight-tpda.c | 1 +
drivers/hwtracing/coresight/coresight-tpdm.c | 1 +
drivers/hwtracing/coresight/coresight-tpiu.c | 1 +
drivers/hwtracing/coresight/coresight-trbe.c | 60 ++++-
drivers/hwtracing/coresight/ultrasoc-smb.c | 1 +
include/linux/coresight.h | 11 +
24 files changed, 458 insertions(+), 274 deletions(-)
---
base-commit: 9c5ef7a30d9044f8706bd02bfdc4eff7266f3e25
change-id: 20251104-arm_coresight_path_power_management_improvement-dab4966f8280
Best regards,
--
Leo Yan <leo.yan(a)arm.com>
On 16/03/2026 10:29, Jie Gan wrote:
>
> Hi Suzuki,
>
> On 3/16/2026 5:32 PM, Suzuki K Poulose wrote:
>> On 16/03/2026 07:23, Jie Gan wrote:
>>> Save the trace ID in drvdata during TPDM enablement and expose it
>>> to userspace to support trace data parsing.
>>>
>>> The TPDM device’s trace ID corresponds to the trace ID allocated
>>> to the connected TPDA device.
>>>
>>> Signed-off-by: Jie Gan <jie.gan(a)oss.qualcomm.com>
>>> ---
>>> Changes in V2:
>>> 1. Use sysfs_emit instead of sprintf.
>>> Link to V1 - https://lore.kernel.org/all/20260306-add-traceid-show-
>>> for-tpdm-v1-1-0658a8edb972(a)oss.qualcomm.com/
>>
>> Why is this patch required even ? For each TPDM there is a single
>
> It's taking effort to retrieve the trace ID of the TPDA device because
> it's not a source device. The trace ID is required to identify the
> origin of the trace data and is essential for parsing the received data.
>
>> port in a single TPDA in the system where it can reach and that is
>> fixed for a platform. Can we not get this from there ? Also, there
>> is not TraceID technically for a TPDM, right ? It is all a property
>
> Yes, we dont allocate trace ID for a TPDM device. The TraceID is
> allocated to the TPDA device.
Now if you combine both your responses, don't you think they contradict
each other ?
Also, the TraceID we show is *not valid* if the TPDM was never enabled.
So this is inconsistent, isn't it ? Unless we return an error in this case
Suzuki
>
> Thanks,
> Jie
>
>> of the TPDA ?
>>
>
>
>> Suzuki
>>
>>
>>> ---
>>> drivers/hwtracing/coresight/coresight-tpdm.c | 31 +++++++++++++++++
>>> + +++++++++-
>>> drivers/hwtracing/coresight/coresight-tpdm.h | 2 ++
>>> 2 files changed, 32 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/
>>> hwtracing/coresight/coresight-tpdm.c
>>> index da77bdaad0a4..774a63def817 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpdm.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tpdm.c
>>> @@ -481,7 +481,7 @@ static void __tpdm_enable(struct tpdm_drvdata
>>> *drvdata)
>>> static int tpdm_enable(struct coresight_device *csdev, struct
>>> perf_event *event,
>>> enum cs_mode mode,
>>> - __maybe_unused struct coresight_path *path)
>>> + struct coresight_path *path)
>>> {
>>> struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>> @@ -497,6 +497,7 @@ static int tpdm_enable(struct coresight_device
>>> *csdev, struct perf_event *event,
>>> }
>>> __tpdm_enable(drvdata);
>>> + drvdata->traceid = path->trace_id;
>>> drvdata->enable = true;
>>> spin_unlock(&drvdata->spinlock);
>>> @@ -693,6 +694,26 @@ static struct attribute_group tpdm_attr_grp = {
>>> .attrs = tpdm_attrs,
>>> };
>>> +static ssize_t traceid_show(struct device *dev,
>>> + struct device_attribute *attr, char *buf)
>>> +{
>>> + unsigned long val;
>>> + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>>> +
>>> + val = drvdata->traceid;
>>> + return sysfs_emit(buf, "%#lx\n", val);
>>> +}
>>> +static DEVICE_ATTR_RO(traceid);
>>> +
>>> +static struct attribute *traceid_attrs[] = {
>>> + &dev_attr_traceid.attr,
>>> + NULL,
>>> +};
>>> +
>>> +static struct attribute_group traceid_attr_grp = {
>>> + .attrs = traceid_attrs,
>>> +};
>>> +
>>> static ssize_t dsb_mode_show(struct device *dev,
>>> struct device_attribute *attr,
>>> char *buf)
>>> @@ -1367,6 +1388,12 @@ static const struct attribute_group
>>> *tpdm_attr_grps[] = {
>>> &tpdm_cmb_patt_grp,
>>> &tpdm_cmb_msr_grp,
>>> &tpdm_mcmb_attr_grp,
>>> + &traceid_attr_grp,
>>> + NULL,
>>> +};
>>> +
>>> +static const struct attribute_group *static_tpdm_attr_grps[] = {
>>> + &traceid_attr_grp,
>>> NULL,
>>> };
>>> @@ -1425,6 +1452,8 @@ static int tpdm_probe(struct device *dev,
>>> struct resource *res)
>>> desc.access = CSDEV_ACCESS_IOMEM(base);
>>> if (res)
>>> desc.groups = tpdm_attr_grps;
>>> + else
>>> + desc.groups = static_tpdm_attr_grps;
>>
>> > drvdata->csdev = coresight_register(&desc);> if
>> (IS_ERR(drvdata->csdev))
>>> return PTR_ERR(drvdata->csdev);
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/
>>> hwtracing/coresight/coresight-tpdm.h
>>> index 2867f3ab8186..befecbb896f4 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpdm.h
>>> +++ b/drivers/hwtracing/coresight/coresight-tpdm.h
>>> @@ -300,6 +300,7 @@ struct cmb_dataset {
>>> * @cmb Specifics associated to TPDM CMB.
>>> * @dsb_msr_num Number of MSR supported by DSB TPDM
>>> * @cmb_msr_num Number of MSR supported by CMB TPDM
>>> + * @traceid trace ID of the path.
>>> */
>>> struct tpdm_drvdata {
>>> @@ -313,6 +314,7 @@ struct tpdm_drvdata {
>>> struct cmb_dataset *cmb;
>>> u32 dsb_msr_num;
>>> u32 cmb_msr_num;
>>> + u8 traceid;
>>> };
>>> /* Enumerate members of various datasets */
>>>
>>> ---
>>> base-commit: b84a0ebe421ca56995ff78b66307667b62b3a900
>>> change-id: 20260316-add-traceid-show-for-tpdm-88d040651f00
>>>
>>> Best regards,
>>
>>
>
Leo has been an active contributor and reviewer for CoreSight subsystem for
years. Add him as a Reviewer for CORESIGHT.
Cc: Leo Yan <leo.yan(a)arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose(a)arm.com>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c5491001908..eaf928246aaf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2710,6 +2710,7 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS
M: Suzuki K Poulose <suzuki.poulose(a)arm.com>
R: Mike Leach <mike.leach(a)arm.com>
R: James Clark <james.clark(a)linaro.org>
+R: Leo Yan <leo.yan(a)arm.com>
L: coresight(a)lists.linaro.org (moderated for non-subscribers)
L: linux-arm-kernel(a)lists.infradead.org (moderated for non-subscribers)
S: Maintained
--
2.43.0
On 10/03/2026 03:01, Jie Gan wrote:
>
>
> On 3/9/2026 8:43 PM, Suzuki K Poulose wrote:
>> On 09/03/2026 09:47, Jie Gan wrote:
>>> The byte-cntr function provided by the CTCU device is used to
>>> transfer data
>>> from the ETR buffer to the userspace. An interrupt is triggered if
>>> the data
>>> size exceeds the threshold set in the BYTECNTRVAL register. The
>>> interrupt
>>> handler counts the number of triggered interruptions and the read
>>> function
>>> will read the data from the synced ETR buffer.
>>>
>>> Switching the sysfs_buf when current buffer is full or the timeout is
>>> triggered and resets rrp and rwp registers after switched the buffer.
>>> The synced buffer will become available for reading after the switch.
>>>
>>> Signed-off-by: Jie Gan <jie.gan(a)oss.qualcomm.com>
>>> ---
>>> .../ABI/testing/sysfs-bus-coresight-devices-ctcu | 8 +
>>> drivers/hwtracing/coresight/Makefile | 2 +-
>>> .../hwtracing/coresight/coresight-ctcu-byte-cntr.c | 351 ++++++++++
>>> + ++++++++++
>>> drivers/hwtracing/coresight/coresight-ctcu-core.c | 103 +++++-
>>> drivers/hwtracing/coresight/coresight-ctcu.h | 76 ++++-
>>> drivers/hwtracing/coresight/coresight-tmc-core.c | 8 +-
>>> drivers/hwtracing/coresight/coresight-tmc-etr.c | 18 ++
>>> drivers/hwtracing/coresight/coresight-tmc.h | 4 +
>>> 8 files changed, 555 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-
>>> ctcu b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
>>> new file mode 100644
>>> index 000000000000..6ff1708fb944
>>> --- /dev/null
>>> +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-ctcu
>>> @@ -0,0 +1,8 @@
>>> +What: /sys/bus/coresight/devices/<ctcu-name>/
>>> irq_threshold[0:1]
>>> +Date: March 2026
>>> +KernelVersion: 7.1
>>> +Contact: Tingwei Zhang <tingwei.zhang(a)oss.qualcomm.com>;
>>> Jinlong Mao <jinlong.mao(a)oss.qualcomm.com>; Jie Gan
>>> <jie.gan(a)oss.qualcomm.com>
>>> +Description:
>>> + (RW) Configure the byte-cntr IRQ register for the specified
>>> ETR device
>>> + based on its port number. An interrupt is generated when the
>>> data size
>>> + exceeds the value set in the IRQ register.
>>> diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/
>>> hwtracing/ coresight/Makefile
>>> index ab16d06783a5..821a1b06b20c 100644
>>> --- a/drivers/hwtracing/coresight/Makefile
>>> +++ b/drivers/hwtracing/coresight/Makefile
>>> @@ -55,5 +55,5 @@ coresight-cti-y := coresight-cti-core.o coresight-
>>> cti-platform.o \
>>> obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
>>> obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
>>> obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
>>> -coresight-ctcu-y := coresight-ctcu-core.o
>>> +coresight-ctcu-y := coresight-ctcu-core.o coresight-ctcu-byte-cntr.o
>>> obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
>>> diff --git a/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
>>> b/ drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
>>> new file mode 100644
>>> index 000000000000..0bf738d6c283
>>> --- /dev/null
>>> +++ b/drivers/hwtracing/coresight/coresight-ctcu-byte-cntr.c
>>> @@ -0,0 +1,351 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>>> + */
>>> +
>>> +#include <linux/coresight.h>
>>> +#include <linux/device.h>
>>> +#include <linux/fs.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/uaccess.h>
>>> +
>>> +#include "coresight-ctcu.h"
>>> +#include "coresight-priv.h"
>>> +#include "coresight-tmc.h"
>>> +
>>> +static irqreturn_t byte_cntr_handler(int irq, void *data)
>>> +{
>>> + struct ctcu_byte_cntr *byte_cntr_data = (struct ctcu_byte_cntr
>>> *)data;
>>> +
>>> + atomic_inc(&byte_cntr_data->irq_cnt);
>>> + wake_up(&byte_cntr_data->wq);
>>> +
>>> + return IRQ_HANDLED;
>>> +}
>>> +
>>> +static void ctcu_reset_sysfs_buf(struct tmc_drvdata *drvdata)
>>
>> minor nit: This has nothing to do with the CTCU. For what it is worth,
>> it must be called, tmc_etr_reset_sysf_buf(). But more on this below,
>> and even do we need it, further below.
>>
>>> +{
>>> + u32 sts;
>>> +
>>> + CS_UNLOCK(drvdata->base);
>>> + tmc_write_rrp(drvdata, drvdata->sysfs_buf->hwaddr);
>>> + tmc_write_rwp(drvdata, drvdata->sysfs_buf->hwaddr);
>>> + sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL;
>>> + writel_relaxed(sts, drvdata->base + TMC_STS);
>>> + CS_LOCK(drvdata->base);
>>
>> Could we not keep this function in the tmc-etr.c and invoke from here ?
>>
>
> Sure, will move the function tmc-etr.c
>
>>> +}
>>> +
>>> +static void ctcu_cfg_byte_cntr_reg(struct tmc_drvdata *drvdata, u32
>>> val, u32 offset)
>>> +{
>>> + struct ctcu_drvdata *ctcu_drvdata;
>>> + struct coresight_device *helper;
>>> +
>>> + helper = tmc_etr_get_ctcu_device(drvdata);
>>> + if (!helper)
>>> + return;
>>> +
>>> + ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
>>> + /* A one value for IRQCTRL register represents 8 bytes */
>>> + ctcu_program_register(ctcu_drvdata, val / 8, offset);
>>> +}
>>> +
>>> +static struct ctcu_byte_cntr *ctcu_get_byte_cntr_data(struct
>>> tmc_drvdata *drvdata)
>>> +{
>>> + struct ctcu_byte_cntr *byte_cntr_data;
>>> + struct ctcu_drvdata *ctcu_drvdata;
>>> + struct coresight_device *helper;
>>> + int port;
>>> +
>>> + helper = tmc_etr_get_ctcu_device(drvdata);
>>> + if (!helper)
>>> + return NULL;
>>> +
>>
>>
>>
>>> + port = coresight_get_in_port(drvdata->csdev, helper);
>>> + if (port < 0)
>>> + return NULL;
>>> +
>>
>> Please validate that the port_num you get is valid for the CTCU ? That
>> applies to all uses of this construct.
>>
>
> Will validate it before using.
>
>>> + ctcu_drvdata = dev_get_drvdata(helper->dev.parent);
>>> + byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port];
>>> + return byte_cntr_data;
>>
>>
>>
>> nit:
>> return &ctcu_drvdata->byte_cntr_data[port]; ?
>>
>> Also, why not make this into a helper, as we seem to use this other
>> places too ?
>>
>
> Didnt get the point here. We may run more than one ETR devices
> concurrently. So we should get the proper byte_cntr_data according to
> the port number at runtime.
>
static struct ctcu_byte_cntr *ctcu_byte_cntr(struct coresight_device
*cctcu_dev, struct coresight_device *tmc_etr, ) {
port = coresight_get_in_port()..
// Verify the port in this helper and everyone uses this.
if (//!validate_port//)
return NULL
return ...
}
Suzuki
Finish removal of ETM_OPT_* defines so the coresight-pmu.h header can
by synced from the kernel.
Signed-off-by: James Clark <james.clark(a)linaro.org>
---
Changes in v2:
- Access metadata through existing etm pointer (Leo)
- Link to v1: https://lore.kernel.org/r/20260306-james-perf-remove-etm_opt-v1-0-03c662380…
---
James Clark (2):
perf cs-etm: Finish removal of ETM_OPT_*
tools: Sync coresight-pmu.h header
tools/include/linux/coresight-pmu.h | 24 -----------------
tools/perf/arch/arm/util/cs-etm.c | 14 ----------
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 2 +-
tools/perf/util/cs-etm.c | 36 +++++++++----------------
tools/perf/util/cs-etm.h | 15 +++++++++++
5 files changed, 29 insertions(+), 62 deletions(-)
---
base-commit: b1718b0367ba31e8db273e3896ebd1707bcbe59e
change-id: 20260306-james-perf-remove-etm_opt-c0e9a768dce8
Best regards,
--
James Clark <james.clark(a)linaro.org>