On 24/01/2025 7:25 am, Jie Gan wrote:
> Add 'struct coresight_path' to store the data that is needed by
> coresight_enable_path/coresight_disable_path. The structure
> will be transmitted to the helper and sink device to enable
> related funcationalities.
>
> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
> ---
[...]
> /*
> * If we still have access to the event_data via handle,
> @@ -595,11 +599,11 @@ static void etm_event_stop(struct perf_event *event, int mode)
> if (!csdev)
> return;
>
> - path = etm_event_cpu_path(event_data, cpu);
> - if (!path)
> + cs_path = etm_event_cpu_path(event_data, cpu);
> + if (!cs_path)
I don't think renaming 'path' to 'cs_path' is worth the churn. It's in a
lot of places in this change, but I think path is already good enough.
> return;
>
> - sink = coresight_get_sink(path);
> + sink = coresight_get_sink(cs_path->path);
coresight_get_sink() is always called with cs_path->path, so we might as
well make it take a whole path struct. The same with any of the other
functions that operate on path like coresight_get_source().
Proof of concept to support CTCU device. Applies to Jie's patchset in
the parent email. I think this would be a good simplification, it
removes some code and makes things a bit clearer, and works for both the
old and new CTCU requirements. It will require merging into the parent
patchset somehow as it undoes some of those changes.
James Clark (3):
coresight: Don't save handle in path
coresight: Export coresight_get_sink()
coresight: Alloc trace ID after building the path
drivers/hwtracing/coresight/coresight-core.c | 107 +++++++++++++-----
drivers/hwtracing/coresight/coresight-dummy.c | 9 +-
drivers/hwtracing/coresight/coresight-etb10.c | 8 +-
.../hwtracing/coresight/coresight-etm-perf.c | 20 ++--
drivers/hwtracing/coresight/coresight-etm.h | 1 -
.../coresight/coresight-etm3x-core.c | 84 ++------------
.../coresight/coresight-etm3x-sysfs.c | 3 +-
.../coresight/coresight-etm4x-core.c | 83 ++------------
.../coresight/coresight-etm4x-sysfs.c | 4 +-
drivers/hwtracing/coresight/coresight-etm4x.h | 1 -
drivers/hwtracing/coresight/coresight-priv.h | 17 +--
drivers/hwtracing/coresight/coresight-stm.c | 5 +-
drivers/hwtracing/coresight/coresight-sysfs.c | 6 +-
.../hwtracing/coresight/coresight-tmc-etf.c | 9 +-
.../hwtracing/coresight/coresight-tmc-etr.c | 13 +--
drivers/hwtracing/coresight/coresight-tmc.h | 2 +-
drivers/hwtracing/coresight/coresight-tpda.c | 3 +-
drivers/hwtracing/coresight/coresight-tpdm.c | 3 +-
drivers/hwtracing/coresight/coresight-tpiu.c | 2 +-
drivers/hwtracing/coresight/coresight-trbe.c | 4 +-
drivers/hwtracing/coresight/ultrasoc-smb.c | 8 +-
include/linux/coresight.h | 25 +++-
22 files changed, 159 insertions(+), 258 deletions(-)
--
2.34.1
On 29/01/2025 1:02 pm, Jie Gan wrote:
>
>
> On 1/29/2025 6:35 PM, James Clark wrote:
>>
>>
>> On 29/01/2025 12:46 am, Jie Gan wrote:
>>>
>>>
>>> On 1/28/2025 7:55 PM, James Clark wrote:
>>>>
>>>>
>>>> On 24/01/2025 7:25 am, Jie Gan wrote:
>>>>> The Coresight TMC Control Unit hosts miscellaneous configuration
>>>>> registers
>>>>> which control various features related to TMC ETR sink.
>>>>>
>>>>> Based on the trace ID, which is programmed in the related CTCU ATID
>>>>> register of a specific ETR, trace data with that trace ID gets into
>>>>> the ETR buffer, while other trace data gets dropped.
>>>>>
>>>>> Enabling source device sets one bit of the ATID register based on
>>>>> source device's trace ID.
>>>>> Disabling source device resets the bit according to the source
>>>>> device's trace ID.
>>>>>
>>>>> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
>>>>> ---
>>>>> drivers/hwtracing/coresight/Kconfig | 12 +
>>>>> drivers/hwtracing/coresight/Makefile | 1 +
>>>>> drivers/hwtracing/coresight/coresight-ctcu.c | 276 ++++++++++++++
>>>>> + ++++
>>>>> drivers/hwtracing/coresight/coresight-ctcu.h | 30 ++
>>>>> include/linux/coresight.h | 3 +-
>>>>> 5 files changed, 321 insertions(+), 1 deletion(-)
>>>>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
>>>>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>>>> >
>>>>
>>>> [...]
>>>>
>>>>> +/*
>>>>> + * ctcu_set_etr_traceid: Retrieve the ATID offset and trace ID.
>>>>> + *
>>>>> + * Returns 0 indicates success. None-zero result means failure.
>>>>> + */
>>>>> +static int ctcu_set_etr_traceid(struct coresight_device *csdev,
>>>>> struct coresight_path *cs_path,
>>>>> + bool enable)
>>>>> +{
>>>>> + struct coresight_device *sink = coresight_get_sink(cs_path-
>>>>> >path);
>>>>> + struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev-
>>>>> >dev.parent);
>>>>> + u8 trace_id = cs_path->trace_id;
>>>>> + int port_num;
>>>>> +
>>>>> + if ((sink == NULL) || !IS_VALID_CS_TRACE_ID(trace_id) ||
>>>>> IS_ERR_OR_NULL(drvdata)) {
>>>>> + dev_err(&csdev->dev, "Invalid parameters\n");
>>>>> + return -EINVAL;
>>>>> + }
>>>>> +
>>>>> + port_num = ctcu_get_active_port(sink, csdev);
>>>>> + if (port_num < 0)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + /*
>>>>> + * Skip the disable session if more than one TPDM device that
>>>>> + * connected to the same TPDA device has been enabled.
>>>>> + */
>>>>> + if (enable)
>>>>> + atomic_inc(&drvdata->traceid_refcnt[port_num][trace_id]);
>>>>> + else {
>>>>> + if (atomic_dec_return(&drvdata->traceid_refcnt[port_num]
>>>>> [trace_id]) > 0) {
>>>>> + dev_dbg(&csdev->dev, "Skip the disable session\n");
>>>>> + return 0;
>>>>> + }
>>>>> + }
>>>>> +
>>>>> + dev_dbg(&csdev->dev, "traceid is %d\n", cs_path->trace_id);
>>>>> +
>>>>> + return __ctcu_set_etr_traceid(csdev, trace_id, port_num, enable);
>>>>
>>>> Hi Jie,
>>>>
>>>> Using atomic_dec_return() here doesn't prevent
>>>> __ctcu_set_etr_traceid() from running concurrent enable and
>>>> disables. Once you pass the atomic_dec_return() a second call to
>>>> enable it will mess it up.
>>>>
>>>> I think you need a spinlock around the whole thing and then the
>>>> refcounts don't need to be atomics.
>>>>
>>> Hi, James
>>> Thanks for comment. I may not fully tested my codes here. What I was
>>> thinking is there's no way the refcnt could become a negative number
>>> under current framework. So I just added spinlock in
>>> __ctcu_set_etr_traceid() to ensure concurrent sessions correctly
>>> manipulate the register.
>>>
>>> As the trace_id related to the bit of the ATID register, I think the
>>> concurrent processes are working fine with spinlock around read/write
>>> register.
>>>
>>> I may not fully got your point here. Please help me to correct it.
>>>
>>> Thanks,
>>> Jie
>>>
>>>
>>
>> No it can't become negative, but the refcount can be a different state
>> to the one that was actually written:
>>
>>
>> CPU0 CPU1
>> ---- ----
>> ctcu_set_etr_traceid(enable)
>> ctcu_set_etr_traceid(disable)
>> atomic_inc()
>> recount == 1
>> atomic_dec()
>> recount == 0
>>
>> __ctcu_set_etr_traceid(disable)
>> Lock and write disable state to
>> device
>>
>> __ctcu_set_etr_traceid(enable)
>> Lock and write enable state to
>> device
>>
>>
>> As you can see this leaves the device in an enabled state but the
>> refcount is 0.
> Yes, you are right. I didnt consider this scenario. We definitely need
> spinlock here.
>
>>
>> This is also quite large if you use atomic types:
>>
>> /* refcnt for each traceid of each sink */
>> atomic_t traceid_refcnt[ATID_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
>>
>> Presumably you can't have the refcount for each ID be higher than the
>> max number of TPDMs connected? If you make the locked area a bit wider
>> you don't need atomic types and also solve the above problem. So you
>> could do u8, or DECLARE_BITMAP() and bitmap_read() etc to read 3 bit
>> values. Or however wide it needs to be.
> The original purpose of using atomic here is trying to narrow the locked
> area.
>
> I think u8 is ok here.
> u8 traceid_refcnt[ATID_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP] will cost
> 224 bytes, I think it's acceptable here.
>
> Thanks,
> Jie
>
Yep u8 sounds ok then
On 29/01/2025 12:46 am, Jie Gan wrote:
>
>
> On 1/28/2025 7:55 PM, James Clark wrote:
>>
>>
>> On 24/01/2025 7:25 am, Jie Gan wrote:
>>> The Coresight TMC Control Unit hosts miscellaneous configuration
>>> registers
>>> which control various features related to TMC ETR sink.
>>>
>>> Based on the trace ID, which is programmed in the related CTCU ATID
>>> register of a specific ETR, trace data with that trace ID gets into
>>> the ETR buffer, while other trace data gets dropped.
>>>
>>> Enabling source device sets one bit of the ATID register based on
>>> source device's trace ID.
>>> Disabling source device resets the bit according to the source
>>> device's trace ID.
>>>
>>> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
>>> ---
>>> drivers/hwtracing/coresight/Kconfig | 12 +
>>> drivers/hwtracing/coresight/Makefile | 1 +
>>> drivers/hwtracing/coresight/coresight-ctcu.c | 276 +++++++++++++++++++
>>> drivers/hwtracing/coresight/coresight-ctcu.h | 30 ++
>>> include/linux/coresight.h | 3 +-
>>> 5 files changed, 321 insertions(+), 1 deletion(-)
>>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
>>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>> >
>>
>> [...]
>>
>>> +/*
>>> + * ctcu_set_etr_traceid: Retrieve the ATID offset and trace ID.
>>> + *
>>> + * Returns 0 indicates success. None-zero result means failure.
>>> + */
>>> +static int ctcu_set_etr_traceid(struct coresight_device *csdev,
>>> struct coresight_path *cs_path,
>>> + bool enable)
>>> +{
>>> + struct coresight_device *sink = coresight_get_sink(cs_path->path);
>>> + struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>> + u8 trace_id = cs_path->trace_id;
>>> + int port_num;
>>> +
>>> + if ((sink == NULL) || !IS_VALID_CS_TRACE_ID(trace_id) ||
>>> IS_ERR_OR_NULL(drvdata)) {
>>> + dev_err(&csdev->dev, "Invalid parameters\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + port_num = ctcu_get_active_port(sink, csdev);
>>> + if (port_num < 0)
>>> + return -EINVAL;
>>> +
>>> + /*
>>> + * Skip the disable session if more than one TPDM device that
>>> + * connected to the same TPDA device has been enabled.
>>> + */
>>> + if (enable)
>>> + atomic_inc(&drvdata->traceid_refcnt[port_num][trace_id]);
>>> + else {
>>> + if (atomic_dec_return(&drvdata->traceid_refcnt[port_num]
>>> [trace_id]) > 0) {
>>> + dev_dbg(&csdev->dev, "Skip the disable session\n");
>>> + return 0;
>>> + }
>>> + }
>>> +
>>> + dev_dbg(&csdev->dev, "traceid is %d\n", cs_path->trace_id);
>>> +
>>> + return __ctcu_set_etr_traceid(csdev, trace_id, port_num, enable);
>>
>> Hi Jie,
>>
>> Using atomic_dec_return() here doesn't prevent
>> __ctcu_set_etr_traceid() from running concurrent enable and disables.
>> Once you pass the atomic_dec_return() a second call to enable it will
>> mess it up.
>>
>> I think you need a spinlock around the whole thing and then the
>> refcounts don't need to be atomics.
>>
> Hi, James
> Thanks for comment. I may not fully tested my codes here. What I was
> thinking is there's no way the refcnt could become a negative number
> under current framework. So I just added spinlock in
> __ctcu_set_etr_traceid() to ensure concurrent sessions correctly
> manipulate the register.
>
> As the trace_id related to the bit of the ATID register, I think the
> concurrent processes are working fine with spinlock around read/write
> register.
>
> I may not fully got your point here. Please help me to correct it.
>
> Thanks,
> Jie
>
>
No it can't become negative, but the refcount can be a different state
to the one that was actually written:
CPU0 CPU1
---- ----
ctcu_set_etr_traceid(enable)
ctcu_set_etr_traceid(disable)
atomic_inc()
recount == 1
atomic_dec()
recount == 0
__ctcu_set_etr_traceid(disable)
Lock and write disable state to
device
__ctcu_set_etr_traceid(enable)
Lock and write enable state to
device
As you can see this leaves the device in an enabled state but the
refcount is 0.
This is also quite large if you use atomic types:
/* refcnt for each traceid of each sink */
atomic_t traceid_refcnt[ATID_MAX_NUM][CORESIGHT_TRACE_ID_RES_TOP];
Presumably you can't have the refcount for each ID be higher than the
max number of TPDMs connected? If you make the locked area a bit wider
you don't need atomic types and also solve the above problem. So you
could do u8, or DECLARE_BITMAP() and bitmap_read() etc to read 3 bit
values. Or however wide it needs to be.
On 24/01/2025 7:25 am, Jie Gan wrote:
> The Coresight TMC Control Unit hosts miscellaneous configuration registers
> which control various features related to TMC ETR sink.
>
> Based on the trace ID, which is programmed in the related CTCU ATID
> register of a specific ETR, trace data with that trace ID gets into
> the ETR buffer, while other trace data gets dropped.
>
> Enabling source device sets one bit of the ATID register based on
> source device's trace ID.
> Disabling source device resets the bit according to the source
> device's trace ID.
>
> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
> ---
> drivers/hwtracing/coresight/Kconfig | 12 +
> drivers/hwtracing/coresight/Makefile | 1 +
> drivers/hwtracing/coresight/coresight-ctcu.c | 276 +++++++++++++++++++
> drivers/hwtracing/coresight/coresight-ctcu.h | 30 ++
> include/linux/coresight.h | 3 +-
> 5 files changed, 321 insertions(+), 1 deletion(-)
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>
[...]
> +/*
> + * ctcu_set_etr_traceid: Retrieve the ATID offset and trace ID.
> + *
> + * Returns 0 indicates success. None-zero result means failure.
> + */
> +static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight_path *cs_path,
> + bool enable)
> +{
> + struct coresight_device *sink = coresight_get_sink(cs_path->path);
> + struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> + u8 trace_id = cs_path->trace_id;
> + int port_num;
> +
> + if ((sink == NULL) || !IS_VALID_CS_TRACE_ID(trace_id) || IS_ERR_OR_NULL(drvdata)) {
> + dev_err(&csdev->dev, "Invalid parameters\n");
> + return -EINVAL;
> + }
> +
> + port_num = ctcu_get_active_port(sink, csdev);
> + if (port_num < 0)
> + return -EINVAL;
> +
> + /*
> + * Skip the disable session if more than one TPDM device that
> + * connected to the same TPDA device has been enabled.
> + */
> + if (enable)
> + atomic_inc(&drvdata->traceid_refcnt[port_num][trace_id]);
> + else {
> + if (atomic_dec_return(&drvdata->traceid_refcnt[port_num][trace_id]) > 0) {
> + dev_dbg(&csdev->dev, "Skip the disable session\n");
> + return 0;
> + }
> + }
> +
> + dev_dbg(&csdev->dev, "traceid is %d\n", cs_path->trace_id);
> +
> + return __ctcu_set_etr_traceid(csdev, trace_id, port_num, enable);
Hi Jie,
Using atomic_dec_return() here doesn't prevent __ctcu_set_etr_traceid()
from running concurrent enable and disables. Once you pass the
atomic_dec_return() a second call to enable it will mess it up.
I think you need a spinlock around the whole thing and then the
refcounts don't need to be atomics.
On 24/01/2025 7:25 am, Jie Gan wrote:
> Add 'struct coresight_path' to store the data that is needed by
> coresight_enable_path/coresight_disable_path. The structure
> will be transmitted to the helper and sink device to enable
> related funcationalities.
>
> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 87 ++++++++++++++-----
> drivers/hwtracing/coresight/coresight-etb10.c | 3 +-
> .../hwtracing/coresight/coresight-etm-perf.c | 52 ++++++-----
> .../hwtracing/coresight/coresight-etm-perf.h | 2 +-
> drivers/hwtracing/coresight/coresight-priv.h | 21 +++--
> drivers/hwtracing/coresight/coresight-sysfs.c | 32 +++----
> .../hwtracing/coresight/coresight-tmc-etf.c | 3 +-
> .../hwtracing/coresight/coresight-tmc-etr.c | 6 +-
> drivers/hwtracing/coresight/coresight-trbe.c | 4 +-
> drivers/hwtracing/coresight/ultrasoc-smb.c | 3 +-
> 10 files changed, 137 insertions(+), 76 deletions(-)
>
[...]
> INIT_LIST_HEAD(path);
> + cs_path->path = path;
> + /*
> + * Since not all source devices have a defined trace_id function,
> + * make sure to check for it before use.
> + *
> + * Assert the mode is CS_MODE_SYSFS, the trace_id will be assigned
> + * again later if the mode is CS_MODE_PERF.
> + */
> + if (source_ops(source)->trace_id != NULL) {
> + rc = source_ops(source)->trace_id(source, CS_MODE_SYSFS, NULL);
I don't think we should do this. Doesn't this consume two trace IDs for
each session? And I'm not even sure if it's released properly if it's
overwritten.
It should be possible to consolidate the all the trace ID allocation to
a single step when building the path, or another function that gets
called just after the path is built. At the moment the ID can be
allocated from about 5 different places and it's quite hard to
understand, especially with these new changes. I have some of it coded
up, let me finish it off and I can share it.
> + if(IS_VALID_CS_TRACE_ID(rc))
> + cs_path->trace_id = rc;
> + else
> + cs_path->trace_id = 0;
> + }
> + else
> + cs_path->trace_id = 0;
[...]
> +/**
> + * struct coresight_path - data needed by enable/disable path
> + * @handle: perf aux handle for ETM.
> + * @path: path from source to sink.
> + * @trace_id: trace_id of the whole path.
> + */
> +struct coresight_path {
> + struct perf_output_handle *handle;
This is only needed to avoid adding *handle to the enable function call
signature, but having it here implies it needs to be stored. And then we
need to manage the lifecycle of it by nulling it on deletion. All of
this can be avoided by just adding handle to enable().
Unrelated to this patch, but I'm not sure why we were passing around
void* for handle either. It just makes the code hard to read and implies
some flexibility that doesn't exist. It's always "struct
perf_output_handle", so we can change void* to that in the enable
functions. I also have a patch for this that I'll share in a bit.
> + struct list_head *path;
> + u8 trace_id;
> +};
> +
> static inline void coresight_insert_barrier_packet(void *buf)
> {
> if (buf)
> @@ -132,16 +144,15 @@ static inline void CS_UNLOCK(void __iomem *addr)
> } while (0);
> }
>
> -void coresight_disable_path(struct list_head *path);
> -int coresight_enable_path(struct list_head *path, enum cs_mode mode,
> - void *sink_data);
> +void coresight_disable_path(struct coresight_path *cs_path);
> +int coresight_enable_path(struct coresight_path *cs_path, enum cs_mode mode);
> struct coresight_device *coresight_get_sink(struct list_head *path);
This needs to be exported otherwise the build fails because you use it
in a module in another commit. I assume you are building as static?
On 23/01/2025 6:28 am, Jie Gan wrote:
>
>
> On 1/13/2025 8:02 PM, James Clark wrote:
>>
>>
>> On 26/12/2024 1:10 am, Jie Gan wrote:
>>> Add 'trace_id' function pointer in ops. It's responsible for
>>> retrieving the device's trace ID.
>>>
>>> Add 'struct cs_sink_data' to store the data that is needed by
>>> coresight_enable_path/coresight_disable_path. The structure
>>> will be transmitted to the helper and sink device to enable
>>> related funcationalities.
>>>
>>
>> The new cs_sink_data struct is quite specific to this change. Can we
>> start passing the path around to enable/disable functions, that will
>> allow devices to gather anything they want in the future. Because we
>> already have coresight_get_sink(path), coresight_get_source(path) etc.
>>
>> And see below, but for this case we can also change the path struct to
>> contain the trace ID. Then all the new functions, allocations and
>> searches for the trace ID are unecessary. The CTCU will have access to
>> the path, and by the time its enable function is called the trace ID
>> is already assigned.
>>
>> It's also easier to understand at which point a trace ID is allocated,
>> rather than adding the trace_id() callbacks from everywhere which
>> could potentially either read or allocate. I suppose that's "safer"
>> because maybe it's not allocated, but I can't see what case it would
>> happen in reverse.
>>
>>> Signed-off-by: Jie Gan <quic_jiegan(a)quicinc.com>
>>> ---
>>> drivers/hwtracing/coresight/coresight-core.c | 59 +++++++++++++++----
>>> drivers/hwtracing/coresight/coresight-etb10.c | 3 +-
>>> .../hwtracing/coresight/coresight-etm-perf.c | 37 ++++++++++--
>>> .../coresight/coresight-etm3x-core.c | 30 ++++++++++
>>> .../coresight/coresight-etm4x-core.c | 29 +++++++++
>>> drivers/hwtracing/coresight/coresight-priv.h | 13 +++-
>>> drivers/hwtracing/coresight/coresight-stm.c | 22 +++++++
>>> drivers/hwtracing/coresight/coresight-sysfs.c | 24 +++++++-
>>> .../hwtracing/coresight/coresight-tmc-etf.c | 3 +-
>>> .../hwtracing/coresight/coresight-tmc-etr.c | 6 +-
>>> drivers/hwtracing/coresight/coresight-tpda.c | 20 +++++++
>>> drivers/hwtracing/coresight/coresight-trbe.c | 4 +-
>>> drivers/hwtracing/coresight/ultrasoc-smb.c | 3 +-
>>> include/linux/coresight.h | 6 ++
>>> 14 files changed, 234 insertions(+), 25 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/
>>> hwtracing/coresight/coresight-core.c
>>> index 0a9380350fb5..2e560b425fd4 100644
>>> --- a/drivers/hwtracing/coresight/coresight-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>>> @@ -23,6 +23,7 @@
>>> #include "coresight-etm-perf.h"
>>> #include "coresight-priv.h"
>>> #include "coresight-syscfg.h"
>>> +#include "coresight-trace-id.h"
>>> /*
>>> * Mutex used to lock all sysfs enable and disable actions and
>>> loading and
>>> @@ -331,12 +332,12 @@ static int coresight_enable_helper(struct
>>> coresight_device *csdev,
>>> return helper_ops(csdev)->enable(csdev, mode, data);
>>> }
>>> -static void coresight_disable_helper(struct coresight_device *csdev)
>>> +static void coresight_disable_helper(struct coresight_device *csdev,
>>> void *data)
>>> {
>>> - helper_ops(csdev)->disable(csdev, NULL);
>>> + helper_ops(csdev)->disable(csdev, data);
>>> }
>>> -static void coresight_disable_helpers(struct coresight_device *csdev)
>>> +static void coresight_disable_helpers(struct coresight_device
>>> *csdev, void *data)
>>> {
>>> int i;
>>> struct coresight_device *helper;
>>> @@ -344,7 +345,7 @@ static void coresight_disable_helpers(struct
>>> coresight_device *csdev)
>>> for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
>>> helper = csdev->pdata->out_conns[i]->dest_dev;
>>> if (helper && coresight_is_helper(helper))
>>> - coresight_disable_helper(helper);
>>> + coresight_disable_helper(helper, data);
>>> }
>>> }
>>> @@ -361,7 +362,7 @@ static void coresight_disable_helpers(struct
>>> coresight_device *csdev)
>>> void coresight_disable_source(struct coresight_device *csdev, void
>>> *data)
>>> {
>>> source_ops(csdev)->disable(csdev, data);
>>> - coresight_disable_helpers(csdev);
>>> + coresight_disable_helpers(csdev, NULL);
>>> }
>>> EXPORT_SYMBOL_GPL(coresight_disable_source);
>>> @@ -371,7 +372,8 @@ EXPORT_SYMBOL_GPL(coresight_disable_source);
>>> * disabled.
>>> */
>>> static void coresight_disable_path_from(struct list_head *path,
>>> - struct coresight_node *nd)
>>> + struct coresight_node *nd,
>>> + void *sink_data)
>>> {
>>> u32 type;
>>> struct coresight_device *csdev, *parent, *child;
>>> @@ -417,13 +419,13 @@ static void coresight_disable_path_from(struct
>>> list_head *path,
>>> }
>>> /* Disable all helpers adjacent along the path last */
>>> - coresight_disable_helpers(csdev);
>>> + coresight_disable_helpers(csdev, sink_data);
>>> }
>>> }
>>> -void coresight_disable_path(struct list_head *path)
>>> +void coresight_disable_path(struct list_head *path, void *sink_data)
>>> {
>>> - coresight_disable_path_from(path, NULL);
>>> + coresight_disable_path_from(path, NULL, sink_data);
>>> }
>>> EXPORT_SYMBOL_GPL(coresight_disable_path);
>>> @@ -505,10 +507,47 @@ int coresight_enable_path(struct list_head
>>> *path, enum cs_mode mode,
>>> out:
>>> return ret;
>>> err:
>>> - coresight_disable_path_from(path, nd);
>>> + coresight_disable_path_from(path, nd, sink_data);
>>> goto out;
>>> }
>>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>>> + struct coresight_trace_id_map *id_map)
>>> +{
>>> + int trace_id, type;
>>> + struct coresight_device *csdev;
>>> + struct coresight_node *nd;
>>> +
>>> + list_for_each_entry(nd, path, link) {
>>
>> What do you think about also changing the path to this:
>>
>> struct coresight_path {
>> struct list_head *path,
>> u8 trace_id
>> };
>>
>> That would avoid having to traverse the path on every enable and would
>> remove this function. You could also cache the trace ID in the CTCU
>> for a similar benefit, but it wouldn't remove the need to call this at
>> least once.
>>
>> The expensive part should be the create path part, after that enable
>> and disable should be cheap because they happen on schedule for Perf
>> mode. We should be avoiding allocations and searches.
>>
>>> + csdev = nd->csdev;
>>> + type = csdev->type;
>>> +
>>> + switch (type) {
>>> + case CORESIGHT_DEV_TYPE_SOURCE:
>>> + if (source_ops(csdev)->trace_id != NULL) {
>>> + trace_id = source_ops(csdev)->trace_id(csdev,
>>> + mode,
>>> + id_map);
>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>> + goto out;
>>> + }
>>> + break;
>>> + case CORESIGHT_DEV_TYPE_LINK:
>>> + if (link_ops(csdev)->trace_id != NULL) {
>>> + trace_id = link_ops(csdev)->trace_id(csdev);
>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>> + goto out;
>>> + }
>>> + break;
>>> + default:
>>> + break;
>>> + }
>>> + }
>>> + return -EINVAL;
>>> +out:
>>> + return trace_id;
>>> +}
>>> +
>>> struct coresight_device *coresight_get_sink(struct list_head *path)
>>> {
>>> struct coresight_device *csdev;
>>> diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/
>>> hwtracing/coresight/coresight-etb10.c
>>> index aea9ac9c4bd0..904b5531c256 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etb10.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etb10.c
>>> @@ -173,7 +173,8 @@ static int etb_enable_perf(struct
>>> coresight_device *csdev, void *data)
>>> pid_t pid;
>>> unsigned long flags;
>>> struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>> - struct perf_output_handle *handle = data;
>>> + struct cs_sink_data *sink_data = (struct cs_sink_data *)data;
>>> + struct perf_output_handle *handle = sink_data->handle;
>>> struct cs_buffers *buf = etm_perf_sink_config(handle);
>>> spin_lock_irqsave(&drvdata->spinlock, flags);
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/
>>> drivers/hwtracing/coresight/coresight-etm-perf.c
>>> index ad6a8f4b70b6..e676edd42ddc 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm-perf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
>>> @@ -459,6 +459,7 @@ static void etm_event_start(struct perf_event
>>> *event, int flags)
>>> struct perf_output_handle *handle = &ctxt->handle;
>>> struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
>>> struct list_head *path;
>>> + struct cs_sink_data *sink_data = NULL;
>>> u64 hw_id;
>>> u8 trace_id;
>>> @@ -498,9 +499,20 @@ static void etm_event_start(struct perf_event
>>> *event, int flags)
>>> if (WARN_ON_ONCE(!sink))
>>> goto fail_end_stop;
>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>
>> kzalloc can't be called from here. Check dmesg for the warning. That's
>> another reason to do this change on the path. Because the path is
>> allocated on etm_setup_aux() where allocations are allowed.
>>
> Hi, James
> I just tried with following command and did not observe any warning info
> from dmesg, may I ask what's the issue may suffered here?
>
You might be missing some debugging configs like lockdep etc. The
warning is that etm_event_start() is a non-sleepable context and kzalloc
is sleepable. Even if it wasn't an error we still wouldn't want to do
it, etm_event_start() and stop are called too frequently.
> root@qemuarm64:/data# ./perf record -e cs_etm/@tmc_etr0/ --per-thread ls
> configs kernel.txt logs lost+found misc
> perf perf.data perf.data.old root time
> tzstorage weston
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.145 MB perf.data ]
>
> For the new patch version, I implemented an 8-bit hash table in the CTCU
> driver data to handle situations where multiple TPDMs are connected to
> the same TPDA device have been enabled. As we know, TPDMs share the
> trace_id of the TPDA device they are connected to. If we reset the bit
> based on the trace_id without checking the enabled refcount, it causes
> an issue where trace data from other enabled TPDM devices (sharing the
> same trace_id) cannot enter the ETR buffer, as it gets filtered out by
> the CTCU.
I think sharing the code or a diagram might be easier to follow here.
The mention of a refcount makes sense but I don't follow the need for a
hash table. There are other places where single devices are shared by
multiple paths, like funnels, and they're all done with refcounts.
> I need allocate memory when implement hash table(add/remove key entry)
> in coresight_enable_path flow, but you mentioned we cannot call kzalloc
> from here.
>
> Thanks,
> Jie
>
Why not allocate on setup_aux()? That's called by userspace before the
session starts, and then the path is fixed from that point onwards so
you shouldn't need to do any more allocations. That's how it's setup
currently anyway.
The system on chip (SoC) consists of main APSS(Applications processor
subsytem) and additional processors like modem, lpass. There is
coresight-etm driver for etm trace of APSS. Coresight remote etm driver
is for enabling and disabling the etm trace of remote processors.
It uses QMI interface to communicate with remote processors' software
and uses coresight framework to configure the connection from remote
etm source to TMC sinks.
Example to capture the remote etm trace:
Enable source:
echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink
echo 1 > /sys/bus/coresight/devices/remote_etm0/enable_source
Capture the trace:
cat /dev/tmc_etf0 > /data/remote_etm.bin
Disable source:
echo 0 > /sys/bus/coresight/devices/remote_etm0/enable_source
Changes since V3:
1. Use different compatible for different remote etms in dt.
2. Get qmi instance id from the match table data in driver.
Change since V2:
1. Change qcom,inst-id to qcom,qmi-id
2. Fix the error in code for type of remote_etm_remove
3. Depend on QMI helper in Kconfig
Changes since V1:
1. Remove unused content
2. Use CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS as remote etm source type.
3. Use enabled instead of enable in driver data.
4. Validate instance id value where it's read from the DT.
Mao Jinlong (2):
dt-bindings: arm: Update compatible for remote etm
coresight: Add remote etm support
.../arm/qcom,coresight-remote-etm.yaml | 11 +-
drivers/hwtracing/coresight/Kconfig | 13 +
drivers/hwtracing/coresight/Makefile | 1 +
drivers/hwtracing/coresight/coresight-qmi.h | 89 +++++
.../coresight/coresight-remote-etm.c | 316 ++++++++++++++++++
5 files changed, 428 insertions(+), 2 deletions(-)
create mode 100644 drivers/hwtracing/coresight/coresight-qmi.h
create mode 100644 drivers/hwtracing/coresight/coresight-remote-etm.c
--
2.17.1
On 14/01/2025 7:27 pm, Krzysztof Kozlowski wrote:
> Replace ternary (condition ? "enable" : "disable") syntax with helpers
> from string_choices.h because:
> 1. Simple function call with one argument is easier to read. Ternary
> operator has three arguments and with wrapping might lead to quite
> long code.
> 2. Is slightly shorter thus also easier to read.
> 3. It brings uniformity in the text - same string.
> 4. Allows deduping by the linker, which results in a smaller binary
> file.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski(a)linaro.org>
> ---
> drivers/hwtracing/coresight/coresight-config.c | 3 ++-
> drivers/hwtracing/coresight/coresight-cpu-debug.c | 3 ++-
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
Reviewed-by: James Clark <james.clark(a)linaro.org>