* [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver
@ 2024-12-26 1:10 Jie Gan
2024-12-26 1:10 ` [PATCH v8 1/5] Coresight: Add support for new APB clock name Jie Gan
` (5 more replies)
0 siblings, 6 replies; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
The Coresight TMC Control Unit(CTCU) device hosts miscellaneous configuration
registers to control various features related to TMC ETR device.
The CTCU device works as a helper device physically connected to the TMC ETR device.
---------------------------------------------------------
|ETR0| |ETR1|
. \ / .
. \ / .
. \ / .
. \ / .
---------------------------------------------------
ETR0ATID0-ETR0ATID3 CTCU ETR1ATID0-ETR1ATID3
---------------------------------------------------
Each ETR has four ATID registers with 128 bits long in total.
e.g. ETR0ATID0-ETR0ATID3 registers are used by ETR0 device.
Based on the trace id which is programed in CTCU ATID register of
specific ETR, trace data with that trace id can get into ETR's buffer
while other trace data gets ignored. The number of CTCU ATID registers
depends on the number of defined TMC ETR devices. For example, two TMC
ETR devices need eight ATID registers. ETR0 with ETR0ATID0-ETR0ATID3
and ETR1 with ETR1ATID0-ETRATID3.
The significant challenge in enabling the data filter function is how
to collect the trace ID of the source device. The introduction of
trace_id callback function addresses this challenge. The callback function
collects trace ID of the device and return it back. The trace ID will be
stored in the structure called cs_sink_data and transmitted to helper
and sink devices.
The cs_sink_data structure is created to address how to transmit
parameters needs by coresight_enable_path/coresight_disbale_path
functions.
Here is an example of the struct cs_sink_data:
struct cs_sink_data {
struct perf_output_handle *handle; //used by perf mode
struct coresight_device *sink; //used to retrieve atid_offset
u32 traceid; //traceid needed by CTCU
};
The atid_offset mentioned before is the offset to ATID register in CTCU
device.
Enabling the source device will configure one bit in the ATID register based
on its trace ID.
Disabling the source devices will reset the bit in the AITD register
based on its trace ID.
Useage:
Enable:
STM device with trace ID 5 and ETR0 is activated.
Bitmap before the enablement:
ETR0ATID0:
31..................543210
==========================
0000000000000000000000...0
==========================
Bitmap after the enablement:
31..................543210
==========================
0000000000000...0000100000
==========================
The bit 5 of the ETR0ATID0 register is configured to 1 when enabling the
STM device.
Disable:
STM device with trace ID 5 and ETR0 is activated.
Bitmap before the disablement:
ETR0ATID0:
31................6543210
=========================
000000000010111...0100000
=========================
Bitmap after the disablement
ETR0ATID0:
31................6543210
=========================
000000000010111...0000000
=========================
The bit 5 of the ETR0ATID0 register is reset to 0 when disabling the STM
device.
---
Changes in V2:
1. Rename the device to Coresight Control Unit.
2. Introduce the trace_id function pointer to address the challeng how to
properly collect the trace ID of the device.
3. Introduce a new way to define the qcom,ccu-atid-offset property in
device tree.
4. Disabling the filter function blocked on acquiring the ATID-offset,
which will be addressed in a separate patch once it’s ready.
Link to V1 - https://lore.kernel.org/lkml/20240618072726.3767974-1-quic_jiegan@quicinc.com/T/#t
Changes in V3:
1. Rename the device to Coresight TMC Control Unit(CTCU).
2. Introduce a new way to define the platform related configs. The new
structure, qcom_ctcu_config, is used to store configurations specific
to a platform. Each platform should have its own qcom_ctcu_config structure.
3. In perf mode, the ETM devices allocate their trace IDs using the
perf_sink_id_map. In sysfs mode, the ETM devices allocate their trace
IDs using the id_map_default.
4. Considering the scenario where both ETR devices might be enabled simultaneously
with multiple sources, retrieving and using trace IDs instead of id_map is more effective
for the CTCU device in sysfs mode. For example, We can configure one ETR as sink for high
throughput trace data like ETM and another ETR for low throughput trace data like STM.
In this case, STM data won’t be flushed out by ETM data quickly. However, if we use id_map to
manage the trace IDs, we need to create a separate id_map for each ETR device. Addtionally, We
would need to iterate through the entire id_map for each configuration.
5. Add support for apb's clock name "apb". If the function fails to obtain the clock with
the name "apb_pclk", it will attempt to acquire the clock with the name "apb".
Link to V2 - https://lore.kernel.org/linux-arm-msm/20240705090049.1656986-1-quic_jiegan@quicinc.com/T/#t
Changes in V4:
1. Add TMC description in binding file.
2. Restrict the number of ports for the CTCU device to a range of 0 to 1 in the binding file,
because the maximum number of CTCU devices is 2 for existing projects.
Link to V3 - https://lore.kernel.org/linux-arm-kernel/20240812024141.2867655-1-quic_jiegan@quicinc.com/
Changes in V5:
1. Fix the format issue for description paragrah in dt binding file.
2. Previous discussion for why use "in-ports" property instead of "ports".
Link to V4 - https://lore.kernel.org/linux-arm-msm/20240828012706.543605-1-quic_jiegan@quicinc.com/
Changes in V6:
1. Collected reviewed-by tag from Rob for dt-binding patch.
2. Rebased on tag next-20241008.
3. Dropped all depends-on tags.
Link to V5 - https://lore.kernel.org/linux-arm-msm/20240909033458.3118238-1-quic_jiegan@quicinc.com/
Changes in V7:
1. Rebased on tag next-20241204.
2. Fix format issue for dts patch.
- Padding the address part to 8 digits
Link to V6 - https://lore.kernel.org/linux-arm-msm/20241009112503.1851585-1-quic_jiegan@quicinc.com/
Changes in V8:
1. Rebased on tag next-20241220.
2. Use raw_spinlock_t instead of spinlock_t.
3. Remove redundant codes in CTCU driver:
- Eliminate unnecessary parameter validations.
- Correct log level when an error occurs.
- Optimize codes.
4. Correct the subject prefix for DT patch.
5. Collected reviewed-by tag from Konrad Dybcib for DT patch.
Link to V7 - https://lore.kernel.org/all/20241210031545.3468561-1-quic_jiegan@quicinc.com/
Jie Gan (5):
Coresight: Add support for new APB clock name
Coresight: Add trace_id function to retrieving the trace ID
dt-bindings: arm: Add Coresight TMC Control Unit hardware
Coresight: Add Coresight TMC Control Unit driver
arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes
.../bindings/arm/qcom,coresight-ctcu.yaml | 84 ++++++
arch/arm64/boot/dts/qcom/sa8775p.dtsi | 153 ++++++++++
drivers/hwtracing/coresight/Kconfig | 8 +
drivers/hwtracing/coresight/Makefile | 1 +
drivers/hwtracing/coresight/coresight-core.c | 59 +++-
drivers/hwtracing/coresight/coresight-ctcu.c | 273 ++++++++++++++++++
drivers/hwtracing/coresight/coresight-ctcu.h | 21 ++
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 | 16 +-
20 files changed, 781 insertions(+), 28 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v8 1/5] Coresight: Add support for new APB clock name
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
@ 2024-12-26 1:10 ` Jie Gan
2025-01-13 11:33 ` James Clark
2024-12-26 1:10 ` [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID Jie Gan
` (4 subsequent siblings)
5 siblings, 1 reply; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
Add support for new APB clock-name. If the function fails
to obtain the clock with the name "apb_pclk", it will
attempt to acquire the clock with the name "apb".
Signed-off-by: Jie Gan <quic_jiegan@quicinc.com>
---
include/linux/coresight.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 17276965ff1d..157c4bd009a1 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -459,8 +459,11 @@ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev)
int ret;
pclk = clk_get(dev, "apb_pclk");
- if (IS_ERR(pclk))
- return NULL;
+ if (IS_ERR(pclk)) {
+ pclk = clk_get(dev, "apb");
+ if (IS_ERR(pclk))
+ return NULL;
+ }
ret = clk_prepare_enable(pclk);
if (ret) {
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
2024-12-26 1:10 ` [PATCH v8 1/5] Coresight: Add support for new APB clock name Jie Gan
@ 2024-12-26 1:10 ` Jie Gan
2025-01-13 12:02 ` James Clark
2024-12-26 1:10 ` [PATCH v8 3/5] dt-bindings: arm: Add Coresight TMC Control Unit hardware Jie Gan
` (3 subsequent siblings)
5 siblings, 1 reply; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
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.
Signed-off-by: Jie Gan <quic_jiegan@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) {
+ 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);
+ if (!sink_data)
+ goto fail_end_stop;
+
+ sink_data->sink = sink;
+ sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
+ &sink->perf_sink_id_map);
+ sink_data->handle = handle;
+
/* Nothing will happen without a path */
- if (coresight_enable_path(path, CS_MODE_PERF, handle))
+ if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
+ kfree(sink_data);
goto fail_end_stop;
+ }
/* Finally enable the tracer */
if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
@@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event *event, int flags)
perf_report_aux_output_id(event, hw_id);
}
+ kfree(sink_data);
out:
/* Tell the perf core the event is alive */
event->hw.state = 0;
@@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event *event, int flags)
return;
fail_disable_path:
- coresight_disable_path(path);
+ coresight_disable_path(path, sink_data);
+ kfree(sink_data);
fail_end_stop:
/*
* Check if the handle is still associated with the event,
@@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
struct perf_output_handle *handle = &ctxt->handle;
struct etm_event_data *event_data;
struct list_head *path;
+ struct cs_sink_data *sink_data = NULL;
/*
* If we still have access to the event_data via handle,
@@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event *event, int mode)
if (!sink)
return;
+ sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
+ if (!sink_data)
+ return;
+
/* stop tracer */
coresight_disable_source(csdev, event);
@@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event *event, int mode)
* have to do anything here.
*/
if (handle->event && (mode & PERF_EF_UPDATE)) {
- if (WARN_ON_ONCE(handle->event != event))
+ if (WARN_ON_ONCE(handle->event != event)) {
+ kfree(sink_data);
return;
+ }
/* update trace information */
- if (!sink_ops(sink)->update_buffer)
+ if (!sink_ops(sink)->update_buffer) {
+ kfree(sink_data);
return;
+ }
size = sink_ops(sink)->update_buffer(sink, handle,
event_data->snk_config);
@@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event *event, int mode)
WARN_ON(size);
}
+ sink_data->sink = sink;
+ sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
+ &sink->perf_sink_id_map);
/* Disabling the path make its elements available to other sessions */
- coresight_disable_path(path);
+ coresight_disable_path(path, sink_data);
+ kfree(sink_data);
}
static int etm_event_add(struct perf_event *event, int mode)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index c103f4c70f5d..0f095fab7e0a 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -697,10 +697,40 @@ static void etm_disable(struct coresight_device *csdev,
coresight_set_mode(csdev, CS_MODE_DISABLED);
}
+static int etm_trace_id(struct coresight_device *csdev,
+ enum cs_mode mode,
+ struct coresight_trace_id_map *id_map)
+{
+ int trace_id;
+ struct etm_drvdata *drvdata;
+
+ if (csdev == NULL)
+ return -EINVAL;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ trace_id = etm_read_alloc_trace_id(drvdata);
+ break;
+ case CS_MODE_PERF:
+ trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->traceid = (u8)trace_id;
+ break;
+ default:
+ trace_id = -EINVAL;
+ break;
+ }
+
+ return trace_id;
+}
+
+
static const struct coresight_ops_source etm_source_ops = {
.cpu_id = etm_cpu_id,
.enable = etm_enable,
.disable = etm_disable,
+ .trace_id = etm_trace_id,
};
static const struct coresight_ops etm_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index dd8c74f893db..bac9ea371688 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1025,10 +1025,39 @@ static void etm4_disable(struct coresight_device *csdev,
coresight_set_mode(csdev, CS_MODE_DISABLED);
}
+static int etm4_trace_id(struct coresight_device *csdev,
+ enum cs_mode mode,
+ struct coresight_trace_id_map *id_map)
+{
+ int trace_id;
+ struct etmv4_drvdata *drvdata;
+
+ if (csdev == NULL)
+ return -EINVAL;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ trace_id = etm4_read_alloc_trace_id(drvdata);
+ break;
+ case CS_MODE_PERF:
+ trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->trcid = (u8)trace_id;
+ break;
+ default:
+ trace_id = -EINVAL;
+ break;
+ }
+
+ return trace_id;
+}
+
static const struct coresight_ops_source etm4_source_ops = {
.cpu_id = etm4_cpu_id,
.enable = etm4_enable,
.disable = etm4_disable,
+ .trace_id = etm4_trace_id,
};
static const struct coresight_ops etm4_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 05f891ca6b5c..6a95a3ba9339 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -105,6 +105,15 @@ struct cs_buffers {
void **data_pages;
};
+/**
+ * struct cs_sink_data - data used by coresight_enable_path/coresight_disable_path
+ */
+struct cs_sink_data {
+ struct perf_output_handle *handle;
+ struct coresight_device *sink;
+ u8 traceid;
+};
+
static inline void coresight_insert_barrier_packet(void *buf)
{
if (buf)
@@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
} while (0);
}
-void coresight_disable_path(struct list_head *path);
+void coresight_disable_path(struct list_head *path, void *sink_data);
int coresight_enable_path(struct list_head *path, enum cs_mode mode,
void *sink_data);
+int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
+ struct coresight_trace_id_map *id_map);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct coresight_device *coresight_get_sink_by_id(u32 id);
struct coresight_device *
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index b581a30a1cd9..5709eda77d9b 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device *csdev,
}
}
+static int stm_trace_id(struct coresight_device *csdev,
+ enum cs_mode mode,
+ struct coresight_trace_id_map *id_map)
+{
+ int trace_id;
+ struct stm_drvdata *drvdata;
+
+ if (csdev == NULL)
+ return -EINVAL;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+ trace_id = drvdata->traceid;
+ if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ trace_id = coresight_trace_id_get_system_id();
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->traceid = (u8)trace_id;
+ }
+
+ return trace_id;
+}
+
static const struct coresight_ops_source stm_source_ops = {
.enable = stm_enable,
.disable = stm_disable,
+ .trace_id = stm_trace_id,
};
static const struct coresight_ops stm_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index a01c9e54e2ed..8816bccba374 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
int cpu, ret = 0;
struct coresight_device *sink;
struct list_head *path;
+ struct cs_sink_data *sink_data;
enum coresight_dev_subtype_source subtype;
u32 hash;
@@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
goto out;
}
- ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
+ sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
+ if (!sink_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS, NULL);
+ sink_data->sink = sink;
+ ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
if (ret)
goto err_path;
@@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
break;
}
+ kfree(sink_data);
out:
mutex_unlock(&coresight_mutex);
return ret;
err_source:
- coresight_disable_path(path);
+ coresight_disable_path(path, sink_data);
err_path:
coresight_release_path(path);
+ kfree(sink_data);
goto out;
}
EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
@@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
{
int cpu, ret;
struct list_head *path = NULL;
+ struct cs_sink_data *sink_data = NULL;
u32 hash;
mutex_lock(&coresight_mutex);
@@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
if (!coresight_disable_source_sysfs(csdev, NULL))
goto out;
+ sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
+ if (!sink_data)
+ goto out;
+
switch (csdev->subtype.source_subtype) {
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
cpu = source_ops(csdev)->cpu_id(csdev);
@@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
break;
}
- coresight_disable_path(path);
+ sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
+ sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS, NULL);
+ coresight_disable_path(path, sink_data);
coresight_release_path(path);
+ kfree(sink_data);
out:
mutex_unlock(&coresight_mutex);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d4f641cd9de6..7dc536eba3e2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
pid_t pid;
unsigned long flags;
struct tmc_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-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index a48bb85d0e7f..90a4058c9959 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
- 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 etr_perf_buffer *etr_perf;
switch (mode) {
@@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
pid_t pid;
unsigned long flags;
struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
spin_lock_irqsave(&drvdata->spinlock, flags);
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 189a4abc2561..05622333f2d2 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -241,9 +241,29 @@ static void tpda_disable(struct coresight_device *csdev,
dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
}
+static int tpda_trace_id(struct coresight_device *csdev)
+{
+ int trace_id;
+ struct tpda_drvdata *drvdata;
+
+ if (csdev == NULL)
+ return -EINVAL;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+ trace_id = drvdata->atid;
+ if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ trace_id = coresight_trace_id_get_system_id();
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->atid = (u8)trace_id;
+ }
+
+ return trace_id;
+}
+
static const struct coresight_ops_link tpda_link_ops = {
.enable = tpda_enable,
.disable = tpda_disable,
+ .trace_id = tpda_trace_id,
};
static const struct coresight_ops tpda_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 919804b12a67..6680d3c69906 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -21,6 +21,7 @@
#include "coresight-self-hosted-trace.h"
#include "coresight-trbe.h"
+#include "coresight-priv.h"
#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
@@ -1012,7 +1013,8 @@ static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
{
struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
- 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 trbe_buf *buf = etm_perf_sink_config(handle);
WARN_ON(cpudata->cpu != smp_processor_id());
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index dc3c9504dd7c..99e0eb33c01f 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -216,7 +216,8 @@ static void smb_enable_sysfs(struct coresight_device *csdev)
static int smb_enable_perf(struct coresight_device *csdev, void *data)
{
struct smb_drv_data *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);
pid_t pid;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 157c4bd009a1..1929f0088c0f 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -368,6 +368,7 @@ struct coresight_ops_sink {
* Operations available for links.
* @enable: enables flow between iport and oport.
* @disable: disables flow between iport and oport.
+ * @trace_id: Collect the traceid.
*/
struct coresight_ops_link {
int (*enable)(struct coresight_device *csdev,
@@ -376,6 +377,7 @@ struct coresight_ops_link {
void (*disable)(struct coresight_device *csdev,
struct coresight_connection *in,
struct coresight_connection *out);
+ int (*trace_id)(struct coresight_device *csdev);
};
/**
@@ -385,6 +387,7 @@ struct coresight_ops_link {
* is associated to.
* @enable: enables tracing for a source.
* @disable: disables tracing for a source.
+ * @trace_id: collect the traceid.
*/
struct coresight_ops_source {
int (*cpu_id)(struct coresight_device *csdev);
@@ -392,6 +395,9 @@ struct coresight_ops_source {
enum cs_mode mode, struct coresight_trace_id_map *id_map);
void (*disable)(struct coresight_device *csdev,
struct perf_event *event);
+ int (*trace_id)(struct coresight_device *csdev,
+ enum cs_mode mode,
+ struct coresight_trace_id_map *id_map);
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 3/5] dt-bindings: arm: Add Coresight TMC Control Unit hardware
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
2024-12-26 1:10 ` [PATCH v8 1/5] Coresight: Add support for new APB clock name Jie Gan
2024-12-26 1:10 ` [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID Jie Gan
@ 2024-12-26 1:10 ` Jie Gan
2024-12-26 1:10 ` [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
` (2 subsequent siblings)
5 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
Add binding file to specify how to define a Coresight TMC
Control Unit device in device tree.
It is responsible for controlling the data filter function
based on the source device's Trace ID for TMC ETR device.
The trace data with that Trace id can get into ETR's buffer
while other trace data gets ignored.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Jie Gan <quic_jiegan@quicinc.com>
---
.../bindings/arm/qcom,coresight-ctcu.yaml | 84 +++++++++++++++++++
1 file changed, 84 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
new file mode 100644
index 000000000000..843b52eaf872
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom,coresight-ctcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CoreSight TMC Control Unit
+
+maintainers:
+ - Yuanfang Zhang <quic_yuanfang@quicinc.com>
+ - Mao Jinlong <quic_jinlmao@quicinc.com>
+ - Jie Gan <quic_jiegan@quicinc.com>
+
+description: |
+ The Trace Memory Controller(TMC) is used for Embedded Trace Buffer(ETB),
+ Embedded Trace FIFO(ETF) and Embedded Trace Router(ETR) configurations.
+ The configuration mode (ETB, ETF, ETR) is discovered at boot time when
+ the device is probed.
+
+ The Coresight TMC Control unit controls various Coresight behaviors.
+ It works as a helper device when connected to TMC ETR device.
+ It is responsible for controlling the data filter function based on
+ the source device's Trace ID for TMC ETR device. The trace data with
+ that Trace id can get into ETR's buffer while other trace data gets
+ ignored.
+
+properties:
+ compatible:
+ enum:
+ - qcom,sa8775p-ctcu
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: apb
+
+ in-ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ patternProperties:
+ '^port(@[0-1])?$':
+ description: Input connections from CoreSight Trace bus
+ $ref: /schemas/graph.yaml#/properties/port
+
+required:
+ - compatible
+ - reg
+ - in-ports
+
+additionalProperties: false
+
+examples:
+ - |
+ ctcu@1001000 {
+ compatible = "qcom,sa8775p-ctcu";
+ reg = <0x1001000 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb";
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ctcu_in_port0: endpoint {
+ remote-endpoint = <&etr0_out_port>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ ctcu_in_port1: endpoint {
+ remote-endpoint = <&etr1_out_port>;
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
` (2 preceding siblings ...)
2024-12-26 1:10 ` [PATCH v8 3/5] dt-bindings: arm: Add Coresight TMC Control Unit hardware Jie Gan
@ 2024-12-26 1:10 ` Jie Gan
2025-01-13 12:05 ` James Clark
2024-12-26 1:10 ` [PATCH v8 5/5] arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes Jie Gan
2025-01-09 7:22 ` [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
5 siblings, 1 reply; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
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@quicinc.com>
---
drivers/hwtracing/coresight/Kconfig | 8 +
drivers/hwtracing/coresight/Makefile | 1 +
drivers/hwtracing/coresight/coresight-ctcu.c | 273 +++++++++++++++++++
drivers/hwtracing/coresight/coresight-ctcu.h | 21 ++
include/linux/coresight.h | 3 +-
5 files changed, 305 insertions(+), 1 deletion(-)
create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 06f0a7594169..152eab0b9b2a 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -133,6 +133,14 @@ config CORESIGHT_STM
To compile this driver as a module, choose M here: the
module will be called coresight-stm.
+config CORESIGHT_CTCU
+ tristate "CoreSight TMC Control Unit driver"
+ help
+ This driver provides support for CoreSight TMC Control Unit
+ that hosts miscellaneous configuration registers. This is
+ primarily used for controlling the behaviors of the TMC
+ ETR device.
+
config CORESIGHT_CPU_DEBUG
tristate "CoreSight CPU Debug driver"
depends on ARM || ARM64
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 4ba478211b31..1b7869910a12 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -51,3 +51,4 @@ coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \
coresight-cti-sysfs.o
obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
+obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
diff --git a/drivers/hwtracing/coresight/coresight-ctcu.c b/drivers/hwtracing/coresight/coresight-ctcu.c
new file mode 100644
index 000000000000..7650dbe9a41e
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "coresight-ctcu.h"
+#include "coresight-priv.h"
+#include "coresight-trace-id.h"
+
+DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
+
+#define ctcu_writel(drvdata, val, offset) __raw_writel((val), drvdata->base + offset)
+#define ctcu_readl(drvdata, offset) __raw_readl(drvdata->base + offset)
+
+/* The TMC Coresight Control Unit uses four ATID registers to control the data filter function based
+ * on the trace ID for each TMC ETR sink. The length of each ATID register is 32 bits. Therefore,
+ * the ETR has a related field in CTCU that is 128 bits long. Each trace ID is represented by one
+ * bit in that filed.
+ * e.g. ETR0ATID0 layout, set bit 5 for traceid 5
+ * bit5
+ * ------------------------------------------------------
+ * | |28| |24| |20| |16| |12| |8| 1|4| |0|
+ * ------------------------------------------------------
+ *
+ * e.g. ETR0:
+ * 127 0 from ATID_offset for ETR0ATID0
+ * -------------------------
+ * |ATID3|ATID2|ATID1|ATID0|
+ *
+ */
+#define CTCU_ATID_REG_OFFSET(traceid, atid_offset) \
+ ((traceid / 32) * 4 + atid_offset)
+
+#define CTCU_ATID_REG_BIT(traceid) (traceid % 32)
+#define CTCU_ATID_REG_SIZE 0x10
+
+struct ctcu_atid_config {
+ const uint32_t atid_offset;
+ const uint32_t port_num;
+};
+
+struct ctcu_config {
+ const struct ctcu_atid_config *atid_config;
+ int num_atid_config;
+};
+
+static const struct ctcu_atid_config sa8775p_atid_cfgs[] = {
+ {0xf8, 0},
+ {0x108, 1},
+};
+
+static const struct ctcu_config sa8775p_cfgs = {
+ .atid_config = sa8775p_atid_cfgs,
+ .num_atid_config = ARRAY_SIZE(sa8775p_atid_cfgs),
+};
+
+/*
+ * __ctcu_set_etr_traceid: Set bit in the ATID register based on trace ID when enable is true.
+ * Reset the bit of the ATID register based on trace ID when enable is false.
+ *
+ * @csdev: coresight_device struct related to the device
+ * @traceid: trace ID of the source tracer.
+ * @enable: True for set bit and false for reset bit.
+ *
+ * Returns 0 indicates success. Non-zero result means failure.
+ */
+static int __ctcu_set_etr_traceid(struct coresight_device *csdev,
+ u8 traceid,
+ int port_num,
+ bool enable)
+{
+ uint32_t atid_offset, reg_offset, val;
+ struct ctcu_drvdata *drvdata;
+ int bit;
+
+ if (!IS_VALID_CS_TRACE_ID(traceid))
+ return -EINVAL;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+ if (IS_ERR_OR_NULL(drvdata))
+ return -EINVAL;
+
+ atid_offset = drvdata->atid_offset[port_num];
+ if (atid_offset == 0)
+ return -EINVAL;
+
+ guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
+ CS_UNLOCK(drvdata->base);
+
+ bit = CTCU_ATID_REG_BIT(traceid);
+ reg_offset = CTCU_ATID_REG_OFFSET(traceid, atid_offset);
+ if (reg_offset - atid_offset > CTCU_ATID_REG_SIZE) {
+ CS_LOCK(drvdata);
+ return -EINVAL;
+ }
+
+ val = ctcu_readl(drvdata, reg_offset);
+ if (enable)
+ val = val | BIT(bit);
+ else
+ val = val & ~BIT(bit);
+
+ ctcu_writel(drvdata, val, reg_offset);
+ CS_LOCK(drvdata->base);
+
+ return 0;
+}
+
+static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper)
+{
+ int i;
+
+ for (i = 0; i < sink->pdata->nr_outconns; ++i) {
+ if (sink->pdata->out_conns[i]->dest_dev)
+ return sink->pdata->out_conns[i]->dest_port;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * 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 cs_sink_data *sink_data,
+ bool enable)
+{
+ int port_num;
+
+ if (!IS_VALID_CS_TRACE_ID(sink_data->traceid) ||
+ (sink_data->sink == NULL)) {
+ dev_err(&csdev->dev, "Invalid parameters\n");
+ return -EINVAL;
+ }
+
+ port_num = ctcu_get_active_port(sink_data->sink, csdev);
+ if (port_num < 0)
+ return -EINVAL;
+
+ dev_dbg(&csdev->dev, "traceid is %d\n", sink_data->traceid);
+
+ return __ctcu_set_etr_traceid(csdev, sink_data->traceid, port_num, enable);
+}
+
+static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
+{
+ struct cs_sink_data *sink_data = (struct cs_sink_data *)data;
+
+ return ctcu_set_etr_traceid(csdev, sink_data, true);
+}
+
+static int ctcu_disable(struct coresight_device *csdev, void *data)
+{
+ struct cs_sink_data *sink_data = (struct cs_sink_data *)data;
+
+ return ctcu_set_etr_traceid(csdev, sink_data, false);
+}
+
+static const struct coresight_ops_helper ctcu_helper_ops = {
+ .enable = ctcu_enable,
+ .disable = ctcu_disable,
+};
+
+static const struct coresight_ops ctcu_ops = {
+ .helper_ops = &ctcu_helper_ops,
+};
+
+static int ctcu_probe(struct platform_device *pdev)
+{
+ int i;
+ void __iomem *base;
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct ctcu_drvdata *drvdata;
+ struct coresight_desc desc = { 0 };
+ const struct ctcu_config *cfgs;
+ const struct ctcu_atid_config *atid_cfg;
+
+ desc.name = coresight_alloc_device_name(&ctcu_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ dev->platform_data = pdata;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (!base)
+ return -ENOMEM;
+
+ drvdata->apb_clk = coresight_get_enable_apb_pclk(dev);
+ if (IS_ERR(drvdata->apb_clk))
+ return -ENODEV;
+
+ cfgs = of_device_get_match_data(dev);
+ if (cfgs) {
+ if (cfgs->num_atid_config <= ATID_MAX_NUM) {
+ for (i = 0; i < cfgs->num_atid_config; i++) {
+ atid_cfg = &cfgs->atid_config[i];
+ drvdata->atid_offset[i] = atid_cfg->atid_offset;
+ }
+ }
+ }
+
+ drvdata->base = base;
+ drvdata->dev = dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc.type = CORESIGHT_DEV_TYPE_HELPER;
+ desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU;
+ desc.pdata = pdata;
+ desc.dev = dev;
+ desc.ops = &ctcu_ops;
+
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev)) {
+ if (!IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_put(drvdata->apb_clk);
+
+ return PTR_ERR(drvdata->csdev);
+ }
+
+ return 0;
+}
+
+static void ctcu_remove(struct platform_device *pdev)
+{
+ struct ctcu_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ if (!IS_ERR_OR_NULL(drvdata->apb_clk))
+ clk_put(drvdata->apb_clk);
+}
+
+static const struct of_device_id ctcu_match[] = {
+ {.compatible = "qcom,sa8775p-ctcu", .data = &sa8775p_cfgs},
+ {}
+};
+
+static struct platform_driver ctcu_driver = {
+ .probe = ctcu_probe,
+ .remove = ctcu_remove,
+ .driver = {
+ .name = "coresight-ctcu",
+ .of_match_table = ctcu_match,
+ .suppress_bind_attrs = true,
+ },
+};
+module_platform_driver(ctcu_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CoreSight TMC Control Unit driver");
diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h
new file mode 100644
index 000000000000..fc85f3377872
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-ctcu.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CORESIGHT_CTCU_H
+#define _CORESIGHT_CTCU_H
+
+#define ATID_MAX_NUM 5
+
+struct ctcu_drvdata {
+ void __iomem *base;
+ struct clk *apb_clk;
+ phys_addr_t pbase;
+ struct device *dev;
+ struct coresight_device *csdev;
+ raw_spinlock_t spin_lock;
+ uint32_t atid_offset[ATID_MAX_NUM];
+};
+
+#endif
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 1929f0088c0f..18bb4de1d1e4 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -71,7 +71,8 @@ enum coresight_dev_subtype_source {
enum coresight_dev_subtype_helper {
CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
- CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
+ CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI,
+ CORESIGHT_DEV_SUBTYPE_HELPER_CTCU,
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 5/5] arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
` (3 preceding siblings ...)
2024-12-26 1:10 ` [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
@ 2024-12-26 1:10 ` Jie Gan
2025-01-09 7:22 ` [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
5 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2024-12-26 1:10 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Konrad Dybcio
Add CTCU and ETR nodes in DT to enable related functionalities.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Jie Gan <quic_jiegan@quicinc.com>
---
arch/arm64/boot/dts/qcom/sa8775p.dtsi | 153 ++++++++++++++++++++++++++
1 file changed, 153 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi
index 368bcf7c9802..05acf93cf8e2 100644
--- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi
@@ -2412,6 +2412,35 @@ crypto: crypto@1dfa000 {
interconnect-names = "memory";
};
+ ctcu@4001000 {
+ compatible = "qcom,sa8775p-ctcu";
+ reg = <0x0 0x04001000 0x0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb";
+
+ in-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ ctcu_in0: endpoint {
+ remote-endpoint = <&etr0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ctcu_in1: endpoint {
+ remote-endpoint = <&etr1_out>;
+ };
+ };
+ };
+ };
+
stm: stm@4002000 {
compatible = "arm,coresight-stm", "arm,primecell";
reg = <0x0 0x4002000 0x0 0x1000>,
@@ -2615,6 +2644,122 @@ qdss_funnel_in1: endpoint {
};
};
+ replicator@4046000 {
+ compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
+ reg = <0x0 0x04046000 0x0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ in-ports {
+ port {
+ qdss_rep_in: endpoint {
+ remote-endpoint = <&swao_rep_out0>;
+ };
+ };
+ };
+
+ out-ports {
+ port {
+ qdss_rep_out0: endpoint {
+ remote-endpoint = <&etr_rep_in>;
+ };
+ };
+ };
+ };
+
+ tmc_etr: tmc@4048000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x0 0x04048000 0x0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ iommus = <&apps_smmu 0x04c0 0x00>;
+
+ arm,scatter-gather;
+
+ in-ports {
+ port {
+ etr0_in: endpoint {
+ remote-endpoint = <&etr_rep_out0>;
+ };
+ };
+ };
+
+ out-ports {
+ port {
+ etr0_out: endpoint {
+ remote-endpoint = <&ctcu_in0>;
+ };
+ };
+ };
+ };
+
+ replicator@404e000 {
+ compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
+ reg = <0x0 0x0404e000 0x0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+
+ in-ports {
+ port {
+ etr_rep_in: endpoint {
+ remote-endpoint = <&qdss_rep_out0>;
+ };
+ };
+ };
+
+ out-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ etr_rep_out0: endpoint {
+ remote-endpoint = <&etr0_in>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ etr_rep_out1: endpoint {
+ remote-endpoint = <&etr1_in>;
+ };
+ };
+ };
+ };
+
+ tmc_etr1: tmc@404f000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x0 0x0404f000 0x0 0x1000>;
+
+ clocks = <&aoss_qmp>;
+ clock-names = "apb_pclk";
+ iommus = <&apps_smmu 0x04a0 0x40>;
+
+ arm,scatter-gather;
+ arm,buffer-size = <0x400000>;
+
+ in-ports {
+ port {
+ etr1_in: endpoint {
+ remote-endpoint = <&etr_rep_out1>;
+ };
+ };
+ };
+
+ out-ports {
+ port {
+ etr1_out: endpoint {
+ remote-endpoint = <&ctcu_in1>;
+ };
+ };
+ };
+ };
+
funnel@4b04000 {
compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
reg = <0x0 0x4b04000 0x0 0x1000>;
@@ -2690,6 +2835,14 @@ out-ports {
#address-cells = <1>;
#size-cells = <0>;
+ port@0 {
+ reg = <0>;
+
+ swao_rep_out0: endpoint {
+ remote-endpoint = <&qdss_rep_in>;
+ };
+ };
+
port@1 {
reg = <1>;
swao_rep_out1: endpoint {
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
` (4 preceding siblings ...)
2024-12-26 1:10 ` [PATCH v8 5/5] arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes Jie Gan
@ 2025-01-09 7:22 ` Jie Gan
5 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2025-01-09 7:22 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
Maxime Coquelin, Alexandre Torgue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32
On 12/26/2024 9:10 AM, Jie Gan wrote:
> The Coresight TMC Control Unit(CTCU) device hosts miscellaneous configuration
> registers to control various features related to TMC ETR device.
>
[...]
>
> Changes in V8:
> 1. Rebased on tag next-20241220.
> 2. Use raw_spinlock_t instead of spinlock_t.
> 3. Remove redundant codes in CTCU driver:
> - Eliminate unnecessary parameter validations.
> - Correct log level when an error occurs.
> - Optimize codes.
> 4. Correct the subject prefix for DT patch.
> 5. Collected reviewed-by tag from Konrad Dybcib for DT patch.
> Link to V7 - https://lore.kernel.org/all/20241210031545.3468561-1-quic_jiegan@quicinc.com/
>
Kindly reminder.
Can you please help to review the patch series?
Thanks,
Jie
> Jie Gan (5):
> Coresight: Add support for new APB clock name
> Coresight: Add trace_id function to retrieving the trace ID
> dt-bindings: arm: Add Coresight TMC Control Unit hardware
> Coresight: Add Coresight TMC Control Unit driver
> arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes
>
> .../bindings/arm/qcom,coresight-ctcu.yaml | 84 ++++++
> arch/arm64/boot/dts/qcom/sa8775p.dtsi | 153 ++++++++++
> drivers/hwtracing/coresight/Kconfig | 8 +
> drivers/hwtracing/coresight/Makefile | 1 +
> drivers/hwtracing/coresight/coresight-core.c | 59 +++-
> drivers/hwtracing/coresight/coresight-ctcu.c | 273 ++++++++++++++++++
> drivers/hwtracing/coresight/coresight-ctcu.h | 21 ++
> 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 | 16 +-
> 20 files changed, 781 insertions(+), 28 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 1/5] Coresight: Add support for new APB clock name
2024-12-26 1:10 ` [PATCH v8 1/5] Coresight: Add support for new APB clock name Jie Gan
@ 2025-01-13 11:33 ` James Clark
0 siblings, 0 replies; 21+ messages in thread
From: James Clark @ 2025-01-13 11:33 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 26/12/2024 1:10 am, Jie Gan wrote:
> Add support for new APB clock-name. If the function fails
> to obtain the clock with the name "apb_pclk", it will
> attempt to acquire the clock with the name "apb".
>
> Signed-off-by: Jie Gan <quic_jiegan@quicinc.com>
> ---
> include/linux/coresight.h | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index 17276965ff1d..157c4bd009a1 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -459,8 +459,11 @@ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev)
> int ret;
>
> pclk = clk_get(dev, "apb_pclk");
> - if (IS_ERR(pclk))
> - return NULL;
> + if (IS_ERR(pclk)) {
> + pclk = clk_get(dev, "apb");
> + if (IS_ERR(pclk))
> + return NULL;
> + }
>
> ret = clk_prepare_enable(pclk);
> if (ret) {
Reviewed-by: James Clark <james.clark@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2024-12-26 1:10 ` [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID Jie Gan
@ 2025-01-13 12:02 ` James Clark
2025-01-14 2:51 ` Jie Gan
2025-01-23 6:28 ` Jie Gan
0 siblings, 2 replies; 21+ messages in thread
From: James Clark @ 2025-01-13 12:02 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
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@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.
> + if (!sink_data)
> + goto fail_end_stop;
> +
> + sink_data->sink = sink;
> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
> + &sink->perf_sink_id_map);
> + sink_data->handle = handle;
> +
> /* Nothing will happen without a path */
> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
> + kfree(sink_data);
> goto fail_end_stop;
> + }
>
> /* Finally enable the tracer */
> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event *event, int flags)
> perf_report_aux_output_id(event, hw_id);
> }
>
> + kfree(sink_data);
> out:
> /* Tell the perf core the event is alive */
> event->hw.state = 0;
> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event *event, int flags)
> return;
>
> fail_disable_path:
> - coresight_disable_path(path);
> + coresight_disable_path(path, sink_data);
> + kfree(sink_data);
> fail_end_stop:
> /*
> * Check if the handle is still associated with the event,
> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
> struct perf_output_handle *handle = &ctxt->handle;
> struct etm_event_data *event_data;
> struct list_head *path;
> + struct cs_sink_data *sink_data = NULL;
>
> /*
> * If we still have access to the event_data via handle,
> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event *event, int mode)
> if (!sink)
> return;
>
> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
Same problem as above.
> + if (!sink_data)
> + return;
> +
> /* stop tracer */
> coresight_disable_source(csdev, event);
>
> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event *event, int mode)
> * have to do anything here.
> */
> if (handle->event && (mode & PERF_EF_UPDATE)) {
> - if (WARN_ON_ONCE(handle->event != event))
> + if (WARN_ON_ONCE(handle->event != event)) {
> + kfree(sink_data);
> return;
> + }
>
> /* update trace information */
> - if (!sink_ops(sink)->update_buffer)
> + if (!sink_ops(sink)->update_buffer) {
> + kfree(sink_data);
> return;
> + }
>
> size = sink_ops(sink)->update_buffer(sink, handle,
> event_data->snk_config);
> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event *event, int mode)
> WARN_ON(size);
> }
>
> + sink_data->sink = sink;
> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
> + &sink->perf_sink_id_map);
> /* Disabling the path make its elements available to other sessions */
> - coresight_disable_path(path);
> + coresight_disable_path(path, sink_data);
> + kfree(sink_data);
> }
>
> static int etm_event_add(struct perf_event *event, int mode)
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> index c103f4c70f5d..0f095fab7e0a 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> @@ -697,10 +697,40 @@ static void etm_disable(struct coresight_device *csdev,
> coresight_set_mode(csdev, CS_MODE_DISABLED);
> }
>
> +static int etm_trace_id(struct coresight_device *csdev,
> + enum cs_mode mode,
> + struct coresight_trace_id_map *id_map)
> +{
> + int trace_id;
> + struct etm_drvdata *drvdata;
> +
> + if (csdev == NULL)
> + return -EINVAL;
> +
> + drvdata = dev_get_drvdata(csdev->dev.parent);
> + switch (mode) {
> + case CS_MODE_SYSFS:
> + trace_id = etm_read_alloc_trace_id(drvdata);
> + break;
> + case CS_MODE_PERF:
> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
> + if (IS_VALID_CS_TRACE_ID(trace_id))
> + drvdata->traceid = (u8)trace_id;
> + break;
> + default:
> + trace_id = -EINVAL;
> + break;
> + }
> +
> + return trace_id;
> +}
> +
> +
> static const struct coresight_ops_source etm_source_ops = {
> .cpu_id = etm_cpu_id,
> .enable = etm_enable,
> .disable = etm_disable,
> + .trace_id = etm_trace_id,
> };
>
> static const struct coresight_ops etm_cs_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index dd8c74f893db..bac9ea371688 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct coresight_device *csdev,
> coresight_set_mode(csdev, CS_MODE_DISABLED);
> }
>
> +static int etm4_trace_id(struct coresight_device *csdev,
> + enum cs_mode mode,
> + struct coresight_trace_id_map *id_map)
> +{
> + int trace_id;
> + struct etmv4_drvdata *drvdata;
> +
> + if (csdev == NULL)
> + return -EINVAL;
> +
> + drvdata = dev_get_drvdata(csdev->dev.parent);
> + switch (mode) {
> + case CS_MODE_SYSFS:
> + trace_id = etm4_read_alloc_trace_id(drvdata);
> + break;
> + case CS_MODE_PERF:
> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu, id_map);
> + if (IS_VALID_CS_TRACE_ID(trace_id))
> + drvdata->trcid = (u8)trace_id;
> + break;
> + default:
> + trace_id = -EINVAL;
> + break;
> + }
> +
> + return trace_id;
> +}
> +
> static const struct coresight_ops_source etm4_source_ops = {
> .cpu_id = etm4_cpu_id,
> .enable = etm4_enable,
> .disable = etm4_disable,
> + .trace_id = etm4_trace_id,
> };
>
> static const struct coresight_ops etm4_cs_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index 05f891ca6b5c..6a95a3ba9339 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -105,6 +105,15 @@ struct cs_buffers {
> void **data_pages;
> };
>
> +/**
> + * struct cs_sink_data - data used by coresight_enable_path/coresight_disable_path
> + */
> +struct cs_sink_data {
> + struct perf_output_handle *handle;
> + struct coresight_device *sink;
> + u8 traceid;
> +};
> +
> static inline void coresight_insert_barrier_packet(void *buf)
> {
> if (buf)
> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
> } while (0);
> }
>
> -void coresight_disable_path(struct list_head *path);
> +void coresight_disable_path(struct list_head *path, void *sink_data);
> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
> void *sink_data);
> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
> + struct coresight_trace_id_map *id_map);
> struct coresight_device *coresight_get_sink(struct list_head *path);
> struct coresight_device *coresight_get_sink_by_id(u32 id);
> struct coresight_device *
> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
> index b581a30a1cd9..5709eda77d9b 100644
> --- a/drivers/hwtracing/coresight/coresight-stm.c
> +++ b/drivers/hwtracing/coresight/coresight-stm.c
> @@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device *csdev,
> }
> }
>
> +static int stm_trace_id(struct coresight_device *csdev,
> + enum cs_mode mode,
> + struct coresight_trace_id_map *id_map)
> +{
> + int trace_id;
> + struct stm_drvdata *drvdata;
> +
> + if (csdev == NULL)
> + return -EINVAL;
> +
> + drvdata = dev_get_drvdata(csdev->dev.parent);
> + trace_id = drvdata->traceid;
> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
Trace ID is static and always set for STM so this isn't necessary, just
return drvdata->traceid which would already be valid otherwise the
device wouldn't be registered.
> + trace_id = coresight_trace_id_get_system_id();
> + if (IS_VALID_CS_TRACE_ID(trace_id))
> + drvdata->traceid = (u8)trace_id;
> + }
> +
> + return trace_id;
> +}
> +
> static const struct coresight_ops_source stm_source_ops = {
> .enable = stm_enable,
> .disable = stm_disable,
> + .trace_id = stm_trace_id,
> };
>
> static const struct coresight_ops stm_cs_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
> index a01c9e54e2ed..8816bccba374 100644
> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
> int cpu, ret = 0;
> struct coresight_device *sink;
> struct list_head *path;
> + struct cs_sink_data *sink_data;
> enum coresight_dev_subtype_source subtype;
> u32 hash;
>
> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
> goto out;
> }
>
> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
> + if (!sink_data) {
> + ret = -ENOMEM;
> + goto out;
> + }
> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS, NULL);
> + sink_data->sink = sink;
> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
> if (ret)
> goto err_path;
>
> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
> break;
> }
>
> + kfree(sink_data);
> out:
> mutex_unlock(&coresight_mutex);
> return ret;
>
> err_source:
> - coresight_disable_path(path);
> + coresight_disable_path(path, sink_data);
>
> err_path:
> coresight_release_path(path);
> + kfree(sink_data);
> goto out;
> }
> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
> {
> int cpu, ret;
> struct list_head *path = NULL;
> + struct cs_sink_data *sink_data = NULL;
> u32 hash;
>
> mutex_lock(&coresight_mutex);
> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
> if (!coresight_disable_source_sysfs(csdev, NULL))
> goto out;
>
> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
> + if (!sink_data)
> + goto out;
> +
> switch (csdev->subtype.source_subtype) {
> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
> cpu = source_ops(csdev)->cpu_id(csdev);
> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct coresight_device *csdev)
> break;
> }
>
> - coresight_disable_path(path);
> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS, NULL);
> + coresight_disable_path(path, sink_data);
> coresight_release_path(path);
> + kfree(sink_data);
>
> out:
> mutex_unlock(&coresight_mutex);
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index d4f641cd9de6..7dc536eba3e2 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
> pid_t pid;
> unsigned long flags;
> struct tmc_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-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index a48bb85d0e7f..90a4058c9959 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
> enum cs_mode mode, void *data)
> {
> - 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 etr_perf_buffer *etr_perf;
>
> switch (mode) {
> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
> pid_t pid;
> unsigned long flags;
> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index 189a4abc2561..05622333f2d2 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -241,9 +241,29 @@ static void tpda_disable(struct coresight_device *csdev,
> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
> }
>
> +static int tpda_trace_id(struct coresight_device *csdev)
> +{
> + int trace_id;
> + struct tpda_drvdata *drvdata;
> +
> + if (csdev == NULL)
> + return -EINVAL;
> +
> + drvdata = dev_get_drvdata(csdev->dev.parent);
> + trace_id = drvdata->atid;
> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
Same comment as STM. This is always set so no ned to try to assign
another one.
> + trace_id = coresight_trace_id_get_system_id();
> + if (IS_VALID_CS_TRACE_ID(trace_id))
> + drvdata->atid = (u8)trace_id;
> + }
> +
> + return trace_id;
> +}
> +
> static const struct coresight_ops_link tpda_link_ops = {
> .enable = tpda_enable,
> .disable = tpda_disable,
> + .trace_id = tpda_trace_id,
> };
>
> static const struct coresight_ops tpda_cs_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
> index 919804b12a67..6680d3c69906 100644
> --- a/drivers/hwtracing/coresight/coresight-trbe.c
> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
> @@ -21,6 +21,7 @@
>
> #include "coresight-self-hosted-trace.h"
> #include "coresight-trbe.h"
> +#include "coresight-priv.h"
>
> #define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
>
> @@ -1012,7 +1013,8 @@ static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
> {
> struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
> - 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 trbe_buf *buf = etm_perf_sink_config(handle);
>
> WARN_ON(cpudata->cpu != smp_processor_id());
> diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
> index dc3c9504dd7c..99e0eb33c01f 100644
> --- a/drivers/hwtracing/coresight/ultrasoc-smb.c
> +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
> @@ -216,7 +216,8 @@ static void smb_enable_sysfs(struct coresight_device *csdev)
> static int smb_enable_perf(struct coresight_device *csdev, void *data)
> {
> struct smb_drv_data *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);
> pid_t pid;
>
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index 157c4bd009a1..1929f0088c0f 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -368,6 +368,7 @@ struct coresight_ops_sink {
> * Operations available for links.
> * @enable: enables flow between iport and oport.
> * @disable: disables flow between iport and oport.
> + * @trace_id: Collect the traceid.
> */
> struct coresight_ops_link {
> int (*enable)(struct coresight_device *csdev,
> @@ -376,6 +377,7 @@ struct coresight_ops_link {
> void (*disable)(struct coresight_device *csdev,
> struct coresight_connection *in,
> struct coresight_connection *out);
> + int (*trace_id)(struct coresight_device *csdev);
> };
>
> /**
> @@ -385,6 +387,7 @@ struct coresight_ops_link {
> * is associated to.
> * @enable: enables tracing for a source.
> * @disable: disables tracing for a source.
> + * @trace_id: collect the traceid.
> */
> struct coresight_ops_source {
> int (*cpu_id)(struct coresight_device *csdev);
> @@ -392,6 +395,9 @@ struct coresight_ops_source {
> enum cs_mode mode, struct coresight_trace_id_map *id_map);
> void (*disable)(struct coresight_device *csdev,
> struct perf_event *event);
> + int (*trace_id)(struct coresight_device *csdev,
> + enum cs_mode mode,
> + struct coresight_trace_id_map *id_map);
> };
>
> /**
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver
2024-12-26 1:10 ` [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
@ 2025-01-13 12:05 ` James Clark
2025-01-14 1:50 ` Jie Gan
0 siblings, 1 reply; 21+ messages in thread
From: James Clark @ 2025-01-13 12:05 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 26/12/2024 1:10 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@quicinc.com>
> ---
> drivers/hwtracing/coresight/Kconfig | 8 +
> drivers/hwtracing/coresight/Makefile | 1 +
> drivers/hwtracing/coresight/coresight-ctcu.c | 273 +++++++++++++++++++
> drivers/hwtracing/coresight/coresight-ctcu.h | 21 ++
> include/linux/coresight.h | 3 +-
> 5 files changed, 305 insertions(+), 1 deletion(-)
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>
> diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
> index 06f0a7594169..152eab0b9b2a 100644
> --- a/drivers/hwtracing/coresight/Kconfig
> +++ b/drivers/hwtracing/coresight/Kconfig
> @@ -133,6 +133,14 @@ config CORESIGHT_STM
> To compile this driver as a module, choose M here: the
> module will be called coresight-stm.
>
> +config CORESIGHT_CTCU
> + tristate "CoreSight TMC Control Unit driver"
> + help
> + This driver provides support for CoreSight TMC Control Unit
> + that hosts miscellaneous configuration registers. This is
> + primarily used for controlling the behaviors of the TMC
> + ETR device.
> +
> config CORESIGHT_CPU_DEBUG
> tristate "CoreSight CPU Debug driver"
> depends on ARM || ARM64
> diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
> index 4ba478211b31..1b7869910a12 100644
> --- a/drivers/hwtracing/coresight/Makefile
> +++ b/drivers/hwtracing/coresight/Makefile
> @@ -51,3 +51,4 @@ coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \
> coresight-cti-sysfs.o
> obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
> obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
> +obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
> diff --git a/drivers/hwtracing/coresight/coresight-ctcu.c b/drivers/hwtracing/coresight/coresight-ctcu.c
> new file mode 100644
> index 000000000000..7650dbe9a41e
> --- /dev/null
> +++ b/drivers/hwtracing/coresight/coresight-ctcu.c
> @@ -0,0 +1,273 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/coresight.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include "coresight-ctcu.h"
> +#include "coresight-priv.h"
> +#include "coresight-trace-id.h"
> +
> +DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
> +
> +#define ctcu_writel(drvdata, val, offset) __raw_writel((val), drvdata->base + offset)
> +#define ctcu_readl(drvdata, offset) __raw_readl(drvdata->base + offset)
> +
> +/* The TMC Coresight Control Unit uses four ATID registers to control the data filter function based
> + * on the trace ID for each TMC ETR sink. The length of each ATID register is 32 bits. Therefore,
> + * the ETR has a related field in CTCU that is 128 bits long. Each trace ID is represented by one
> + * bit in that filed.
> + * e.g. ETR0ATID0 layout, set bit 5 for traceid 5
> + * bit5
> + * ------------------------------------------------------
> + * | |28| |24| |20| |16| |12| |8| 1|4| |0|
> + * ------------------------------------------------------
> + *
> + * e.g. ETR0:
> + * 127 0 from ATID_offset for ETR0ATID0
> + * -------------------------
> + * |ATID3|ATID2|ATID1|ATID0|
> + *
> + */
> +#define CTCU_ATID_REG_OFFSET(traceid, atid_offset) \
> + ((traceid / 32) * 4 + atid_offset)
> +
> +#define CTCU_ATID_REG_BIT(traceid) (traceid % 32)
> +#define CTCU_ATID_REG_SIZE 0x10
> +
> +struct ctcu_atid_config {
> + const uint32_t atid_offset;
> + const uint32_t port_num;
> +};
> +
> +struct ctcu_config {
> + const struct ctcu_atid_config *atid_config;
> + int num_atid_config;
> +};
> +
> +static const struct ctcu_atid_config sa8775p_atid_cfgs[] = {
> + {0xf8, 0},
> + {0x108, 1},
> +};
> +
> +static const struct ctcu_config sa8775p_cfgs = {
> + .atid_config = sa8775p_atid_cfgs,
> + .num_atid_config = ARRAY_SIZE(sa8775p_atid_cfgs),
> +};
> +
> +/*
> + * __ctcu_set_etr_traceid: Set bit in the ATID register based on trace ID when enable is true.
> + * Reset the bit of the ATID register based on trace ID when enable is false.
> + *
> + * @csdev: coresight_device struct related to the device
> + * @traceid: trace ID of the source tracer.
> + * @enable: True for set bit and false for reset bit.
> + *
> + * Returns 0 indicates success. Non-zero result means failure.
> + */
> +static int __ctcu_set_etr_traceid(struct coresight_device *csdev,
> + u8 traceid,
> + int port_num,
> + bool enable)
> +{
> + uint32_t atid_offset, reg_offset, val;
> + struct ctcu_drvdata *drvdata;
> + int bit;
> +
> + if (!IS_VALID_CS_TRACE_ID(traceid))
> + return -EINVAL;
Minor point, but this was already done in the calling function.
> +
> + drvdata = dev_get_drvdata(csdev->dev.parent);
> + if (IS_ERR_OR_NULL(drvdata))
> + return -EINVAL;
> +
> + atid_offset = drvdata->atid_offset[port_num];
> + if (atid_offset == 0)
> + return -EINVAL;
> +
> + guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
> + CS_UNLOCK(drvdata->base);
> +
> + bit = CTCU_ATID_REG_BIT(traceid);
> + reg_offset = CTCU_ATID_REG_OFFSET(traceid, atid_offset);
The locks only need to be around the read/write below. bit and
reg_offset are all local and shouldn't be affected. Doesn't really make
a difference but makes the code a bit more readable.
> + if (reg_offset - atid_offset > CTCU_ATID_REG_SIZE) {
> + CS_LOCK(drvdata);
> + return -EINVAL;
> + }
> +
> + val = ctcu_readl(drvdata, reg_offset);
> + if (enable)
> + val = val | BIT(bit);
> + else
> + val = val & ~BIT(bit);
> +
> + ctcu_writel(drvdata, val, reg_offset);
> + CS_LOCK(drvdata->base);
> +
> + return 0;
> +}
> +
> +static int ctcu_get_active_port(struct coresight_device *sink, struct coresight_device *helper)
> +{
> + int i;
> +
> + for (i = 0; i < sink->pdata->nr_outconns; ++i) {
> + if (sink->pdata->out_conns[i]->dest_dev)
> + return sink->pdata->out_conns[i]->dest_port;
> + }
> +
> + return -EINVAL;
> +}
> +
> +/*
> + * 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 cs_sink_data *sink_data,
> + bool enable)
> +{
> + int port_num;
> +
> + if (!IS_VALID_CS_TRACE_ID(sink_data->traceid) ||
> + (sink_data->sink == NULL)) {
> + dev_err(&csdev->dev, "Invalid parameters\n");
> + return -EINVAL;
> + }
> +
> + port_num = ctcu_get_active_port(sink_data->sink, csdev);
> + if (port_num < 0)
> + return -EINVAL;
> +
> + dev_dbg(&csdev->dev, "traceid is %d\n", sink_data->traceid);
> +
> + return __ctcu_set_etr_traceid(csdev, sink_data->traceid, port_num, enable);
> +}
> +
> +static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode,
> + void *data)
> +{
> + struct cs_sink_data *sink_data = (struct cs_sink_data *)data;
> +
> + return ctcu_set_etr_traceid(csdev, sink_data, true);
> +}
> +
> +static int ctcu_disable(struct coresight_device *csdev, void *data)
> +{
> + struct cs_sink_data *sink_data = (struct cs_sink_data *)data;
> +
> + return ctcu_set_etr_traceid(csdev, sink_data, false);
> +}
> +
> +static const struct coresight_ops_helper ctcu_helper_ops = {
> + .enable = ctcu_enable,
> + .disable = ctcu_disable,
> +};
> +
> +static const struct coresight_ops ctcu_ops = {
> + .helper_ops = &ctcu_helper_ops,
> +};
> +
> +static int ctcu_probe(struct platform_device *pdev)
> +{
> + int i;
> + void __iomem *base;
> + struct device *dev = &pdev->dev;
> + struct coresight_platform_data *pdata;
> + struct ctcu_drvdata *drvdata;
> + struct coresight_desc desc = { 0 };
> + const struct ctcu_config *cfgs;
> + const struct ctcu_atid_config *atid_cfg;
> +
> + desc.name = coresight_alloc_device_name(&ctcu_devs, dev);
> + if (!desc.name)
> + return -ENOMEM;
> +
> + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> + if (!drvdata)
> + return -ENOMEM;
> +
> + pdata = coresight_get_platform_data(dev);
> + if (IS_ERR(pdata))
> + return PTR_ERR(pdata);
> + dev->platform_data = pdata;
> +
> + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
> + if (!base)
> + return -ENOMEM;
> +
> + drvdata->apb_clk = coresight_get_enable_apb_pclk(dev);
> + if (IS_ERR(drvdata->apb_clk))
> + return -ENODEV;
> +
> + cfgs = of_device_get_match_data(dev);
> + if (cfgs) {
> + if (cfgs->num_atid_config <= ATID_MAX_NUM) {
> + for (i = 0; i < cfgs->num_atid_config; i++) {
> + atid_cfg = &cfgs->atid_config[i];
> + drvdata->atid_offset[i] = atid_cfg->atid_offset;
> + }
> + }
> + }
> +
> + drvdata->base = base;
> + drvdata->dev = dev;
> + platform_set_drvdata(pdev, drvdata);
> +
> + desc.type = CORESIGHT_DEV_TYPE_HELPER;
> + desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CTCU;
> + desc.pdata = pdata;
> + desc.dev = dev;
> + desc.ops = &ctcu_ops;
> +
> + drvdata->csdev = coresight_register(&desc);
> + if (IS_ERR(drvdata->csdev)) {
> + if (!IS_ERR_OR_NULL(drvdata->apb_clk))
> + clk_put(drvdata->apb_clk);
> +
> + return PTR_ERR(drvdata->csdev);
> + }
> +
> + return 0;
> +}
> +
> +static void ctcu_remove(struct platform_device *pdev)
> +{
> + struct ctcu_drvdata *drvdata = platform_get_drvdata(pdev);
> +
> + coresight_unregister(drvdata->csdev);
> + if (!IS_ERR_OR_NULL(drvdata->apb_clk))
> + clk_put(drvdata->apb_clk);
> +}
> +
> +static const struct of_device_id ctcu_match[] = {
> + {.compatible = "qcom,sa8775p-ctcu", .data = &sa8775p_cfgs},
> + {}
> +};
> +
> +static struct platform_driver ctcu_driver = {
> + .probe = ctcu_probe,
> + .remove = ctcu_remove,
> + .driver = {
> + .name = "coresight-ctcu",
> + .of_match_table = ctcu_match,
> + .suppress_bind_attrs = true,
> + },
> +};
> +module_platform_driver(ctcu_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("CoreSight TMC Control Unit driver");
> diff --git a/drivers/hwtracing/coresight/coresight-ctcu.h b/drivers/hwtracing/coresight/coresight-ctcu.h
> new file mode 100644
> index 000000000000..fc85f3377872
> --- /dev/null
> +++ b/drivers/hwtracing/coresight/coresight-ctcu.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _CORESIGHT_CTCU_H
> +#define _CORESIGHT_CTCU_H
> +
> +#define ATID_MAX_NUM 5
> +
> +struct ctcu_drvdata {
> + void __iomem *base;
> + struct clk *apb_clk;
> + phys_addr_t pbase;
> + struct device *dev;
> + struct coresight_device *csdev;
> + raw_spinlock_t spin_lock;
> + uint32_t atid_offset[ATID_MAX_NUM];
> +};
> +
> +#endif
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index 1929f0088c0f..18bb4de1d1e4 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -71,7 +71,8 @@ enum coresight_dev_subtype_source {
>
> enum coresight_dev_subtype_helper {
> CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
> - CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
> + CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI,
> + CORESIGHT_DEV_SUBTYPE_HELPER_CTCU,
> };
>
> /**
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver
2025-01-13 12:05 ` James Clark
@ 2025-01-14 1:50 ` Jie Gan
0 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2025-01-14 1:50 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 1/13/2025 8:05 PM, James Clark wrote:
>
>
> On 26/12/2024 1:10 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@quicinc.com>
>> ---
>> drivers/hwtracing/coresight/Kconfig | 8 +
>> drivers/hwtracing/coresight/Makefile | 1 +
>> drivers/hwtracing/coresight/coresight-ctcu.c | 273 +++++++++++++++++++
>> drivers/hwtracing/coresight/coresight-ctcu.h | 21 ++
>> include/linux/coresight.h | 3 +-
>> 5 files changed, 305 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.c
>> create mode 100644 drivers/hwtracing/coresight/coresight-ctcu.h
>>
>> diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/
>> coresight/Kconfig
>> index 06f0a7594169..152eab0b9b2a 100644
>> --- a/drivers/hwtracing/coresight/Kconfig
>> +++ b/drivers/hwtracing/coresight/Kconfig
>> @@ -133,6 +133,14 @@ config CORESIGHT_STM
>> To compile this driver as a module, choose M here: the
>> module will be called coresight-stm.
>> +config CORESIGHT_CTCU
>> + tristate "CoreSight TMC Control Unit driver"
>> + help
>> + This driver provides support for CoreSight TMC Control Unit
>> + that hosts miscellaneous configuration registers. This is
>> + primarily used for controlling the behaviors of the TMC
>> + ETR device.
>> +
>> config CORESIGHT_CPU_DEBUG
>> tristate "CoreSight CPU Debug driver"
>> depends on ARM || ARM64
>> diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/
>> coresight/Makefile
>> index 4ba478211b31..1b7869910a12 100644
>> --- a/drivers/hwtracing/coresight/Makefile
>> +++ b/drivers/hwtracing/coresight/Makefile
>> @@ -51,3 +51,4 @@ coresight-cti-y := coresight-cti-core.o
>> coresight-cti-platform.o \
>> coresight-cti-sysfs.o
>> obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
>> obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
>> +obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
>> diff --git a/drivers/hwtracing/coresight/coresight-ctcu.c b/drivers/
>> hwtracing/coresight/coresight-ctcu.c
>> new file mode 100644
>> index 000000000000..7650dbe9a41e
>> --- /dev/null
>> +++ b/drivers/hwtracing/coresight/coresight-ctcu.c
>> @@ -0,0 +1,273 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights
>> reserved.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/coresight.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +
>> +#include "coresight-ctcu.h"
>> +#include "coresight-priv.h"
>> +#include "coresight-trace-id.h"
>> +
>> +DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu");
>> +
>> +#define ctcu_writel(drvdata, val, offset) __raw_writel((val),
>> drvdata->base + offset)
>> +#define ctcu_readl(drvdata, offset) __raw_readl(drvdata->base
>> + offset)
>> +
>> +/* The TMC Coresight Control Unit uses four ATID registers to control
>> the data filter function based
>> + * on the trace ID for each TMC ETR sink. The length of each ATID
>> register is 32 bits. Therefore,
>> + * the ETR has a related field in CTCU that is 128 bits long. Each
>> trace ID is represented by one
>> + * bit in that filed.
>> + * e.g. ETR0ATID0 layout, set bit 5 for traceid 5
>> + * bit5
>> + * ------------------------------------------------------
>> + * | |28| |24| |20| |16| |12| |8| 1|4| |0|
>> + * ------------------------------------------------------
>> + *
>> + * e.g. ETR0:
>> + * 127 0 from ATID_offset for ETR0ATID0
>> + * -------------------------
>> + * |ATID3|ATID2|ATID1|ATID0|
>> + *
>> + */
>> +#define CTCU_ATID_REG_OFFSET(traceid, atid_offset) \
>> + ((traceid / 32) * 4 + atid_offset)
>> +
>> +#define CTCU_ATID_REG_BIT(traceid) (traceid % 32)
>> +#define CTCU_ATID_REG_SIZE 0x10
>> +
>> +struct ctcu_atid_config {
>> + const uint32_t atid_offset;
>> + const uint32_t port_num;
>> +};
>> +
>> +struct ctcu_config {
>> + const struct ctcu_atid_config *atid_config;
>> + int num_atid_config;
>> +};
>> +
>> +static const struct ctcu_atid_config sa8775p_atid_cfgs[] = {
>> + {0xf8, 0},
>> + {0x108, 1},
>> +};
>> +
>> +static const struct ctcu_config sa8775p_cfgs = {
>> + .atid_config = sa8775p_atid_cfgs,
>> + .num_atid_config = ARRAY_SIZE(sa8775p_atid_cfgs),
>> +};
>> +
>> +/*
>> + * __ctcu_set_etr_traceid: Set bit in the ATID register based on
>> trace ID when enable is true.
>> + * Reset the bit of the ATID register based on trace ID when enable
>> is false.
>> + *
>> + * @csdev: coresight_device struct related to the device
>> + * @traceid: trace ID of the source tracer.
>> + * @enable: True for set bit and false for reset bit.
>> + *
>> + * Returns 0 indicates success. Non-zero result means failure.
>> + */
>> +static int __ctcu_set_etr_traceid(struct coresight_device *csdev,
>> + u8 traceid,
>> + int port_num,
>> + bool enable)
>> +{
>> + uint32_t atid_offset, reg_offset, val;
>> + struct ctcu_drvdata *drvdata;
>> + int bit;
>> +
>> + if (!IS_VALID_CS_TRACE_ID(traceid))
>> + return -EINVAL;
>
> Minor point, but this was already done in the calling function.
Thanks for comment. Totally agree with you, it's redundant codes here.
I will remove it in next version.
>
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + if (IS_ERR_OR_NULL(drvdata))
>> + return -EINVAL;
>> +
>> + atid_offset = drvdata->atid_offset[port_num];
>> + if (atid_offset == 0)
>> + return -EINVAL;
>> +
>> + guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
>> + CS_UNLOCK(drvdata->base);
>> +
>> + bit = CTCU_ATID_REG_BIT(traceid);
>> + reg_offset = CTCU_ATID_REG_OFFSET(traceid, atid_offset);
>
> The locks only need to be around the read/write below. bit and
> reg_offset are all local and shouldn't be affected. Doesn't really make
> a difference but makes the code a bit more readable.
Yes, agree with you. It makes sense and is easier to read. Will move the
CS_UNLOCK to the proper position.
>
>> + if (reg_offset - atid_offset > CTCU_ATID_REG_SIZE) {
>> + CS_LOCK(drvdata);
>> + return -EINVAL;
>> + }
>> +
>> + val = ctcu_readl(drvdata, reg_offset);
>> + if (enable)
>> + val = val | BIT(bit);
>> + else
>> + val = val & ~BIT(bit);
>> +
>> + ctcu_writel(drvdata, val, reg_offset);
>> + CS_LOCK(drvdata->base);
>> +
>> + return 0;
>> +}
>> +
[...]
Thanks,
Jie
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-13 12:02 ` James Clark
@ 2025-01-14 2:51 ` Jie Gan
2025-01-14 10:07 ` James Clark
2025-01-23 6:28 ` Jie Gan
1 sibling, 1 reply; 21+ messages in thread
From: Jie Gan @ 2025-01-14 2:51 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
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.
>
Thank you for comment. I will try this solution.
The biggest challenge for the patch is how to correctly read trace_id
from source device and passthrough it to helper device as the source
device always the last one to enable. I believe your proposed solution
is better than mine and has minimal impact on the basic framework, but I
think we still need read_trace in source_ops and link_ops. Then we can
read the trace_id in coresight_build_path function and save it to the
coresight_path to avoid redundant searching?
>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
without traverse the path.
But we still need to check the type of the coresight device, because the
TPDM does not have traceid and we use the trace_id from the TPDA device
that the TPDM connected. That's why I added trace_id to link_ops.
> 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.
>
I can move the read trace_id logic to build_path function, I believe
it's better than current solution.
>> + 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.
>
Will fix it.
>> + if (!sink_data)
>> + goto fail_end_stop;
>> +
>> + sink_data->sink = sink;
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>> + &sink->perf_sink_id_map);
>> + sink_data->handle = handle;
>> +
>> /* Nothing will happen without a path */
>> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
>> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
>> + kfree(sink_data);
>> goto fail_end_stop;
>> + }
>> /* Finally enable the tracer */
>> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
>> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event
>> *event, int flags)
>> perf_report_aux_output_id(event, hw_id);
>> }
>> + kfree(sink_data);
>> out:
>> /* Tell the perf core the event is alive */
>> event->hw.state = 0;
>> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event
>> *event, int flags)
>> return;
>> fail_disable_path:
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> + kfree(sink_data);
>> fail_end_stop:
>> /*
>> * Check if the handle is still associated with the event,
>> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> struct perf_output_handle *handle = &ctxt->handle;
>> struct etm_event_data *event_data;
>> struct list_head *path;
>> + struct cs_sink_data *sink_data = NULL;
>> /*
>> * If we still have access to the event_data via handle,
>> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> if (!sink)
>> return;
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>
> Same problem as above.
>
>> + if (!sink_data)
>> + return;
>> +
>> /* stop tracer */
>> coresight_disable_source(csdev, event);
>> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> * have to do anything here.
>> */
>> if (handle->event && (mode & PERF_EF_UPDATE)) {
>> - if (WARN_ON_ONCE(handle->event != event))
>> + if (WARN_ON_ONCE(handle->event != event)) {
>> + kfree(sink_data);
>> return;
>> + }
>> /* update trace information */
>> - if (!sink_ops(sink)->update_buffer)
>> + if (!sink_ops(sink)->update_buffer) {
>> + kfree(sink_data);
>> return;
>> + }
>> size = sink_ops(sink)->update_buffer(sink, handle,
>> event_data->snk_config);
>> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> WARN_ON(size);
>> }
>> + sink_data->sink = sink;
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>> + &sink->perf_sink_id_map);
>> /* Disabling the path make its elements available to other
>> sessions */
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> + kfree(sink_data);
>> }
>> static int etm_event_add(struct perf_event *event, int mode)
>> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/
>> drivers/hwtracing/coresight/coresight-etm3x-core.c
>> index c103f4c70f5d..0f095fab7e0a 100644
>> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
>> @@ -697,10 +697,40 @@ static void etm_disable(struct coresight_device
>> *csdev,
>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>> }
>> +static int etm_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct etm_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + switch (mode) {
>> + case CS_MODE_SYSFS:
>> + trace_id = etm_read_alloc_trace_id(drvdata);
>> + break;
>> + case CS_MODE_PERF:
>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>> id_map);
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->traceid = (u8)trace_id;
>> + break;
>> + default:
>> + trace_id = -EINVAL;
>> + break;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> +
>> static const struct coresight_ops_source etm_source_ops = {
>> .cpu_id = etm_cpu_id,
>> .enable = etm_enable,
>> .disable = etm_disable,
>> + .trace_id = etm_trace_id,
>> };
>> static const struct coresight_ops etm_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/
>> drivers/hwtracing/coresight/coresight-etm4x-core.c
>> index dd8c74f893db..bac9ea371688 100644
>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct
>> coresight_device *csdev,
>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>> }
>> +static int etm4_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct etmv4_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + switch (mode) {
>> + case CS_MODE_SYSFS:
>> + trace_id = etm4_read_alloc_trace_id(drvdata);
>> + break;
>> + case CS_MODE_PERF:
>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>> id_map);
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->trcid = (u8)trace_id;
>> + break;
>> + default:
>> + trace_id = -EINVAL;
>> + break;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> static const struct coresight_ops_source etm4_source_ops = {
>> .cpu_id = etm4_cpu_id,
>> .enable = etm4_enable,
>> .disable = etm4_disable,
>> + .trace_id = etm4_trace_id,
>> };
>> static const struct coresight_ops etm4_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/
>> hwtracing/coresight/coresight-priv.h
>> index 05f891ca6b5c..6a95a3ba9339 100644
>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>> @@ -105,6 +105,15 @@ struct cs_buffers {
>> void **data_pages;
>> };
>> +/**
>> + * struct cs_sink_data - data used by coresight_enable_path/
>> coresight_disable_path
>> + */
>> +struct cs_sink_data {
>> + struct perf_output_handle *handle;
>> + struct coresight_device *sink;
>> + u8 traceid;
>> +};
>> +
>> static inline void coresight_insert_barrier_packet(void *buf)
>> {
>> if (buf)
>> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
>> } while (0);
>> }
>> -void coresight_disable_path(struct list_head *path);
>> +void coresight_disable_path(struct list_head *path, void *sink_data);
>> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
>> void *sink_data);
>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map);
>> struct coresight_device *coresight_get_sink(struct list_head *path);
>> struct coresight_device *coresight_get_sink_by_id(u32 id);
>> struct coresight_device *
>> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/
>> hwtracing/coresight/coresight-stm.c
>> index b581a30a1cd9..5709eda77d9b 100644
>> --- a/drivers/hwtracing/coresight/coresight-stm.c
>> +++ b/drivers/hwtracing/coresight/coresight-stm.c
>> @@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device
>> *csdev,
>> }
>> }
>> +static int stm_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct stm_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + trace_id = drvdata->traceid;
>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>
> Trace ID is static and always set for STM so this isn't necessary, just
> return drvdata->traceid which would already be valid otherwise the
> device wouldn't be registered.
>
Thanks for comment.
Will fix in next version
>> + trace_id = coresight_trace_id_get_system_id();
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->traceid = (u8)trace_id;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> static const struct coresight_ops_source stm_source_ops = {
>> .enable = stm_enable,
>> .disable = stm_disable,
>> + .trace_id = stm_trace_id,
>> };
>> static const struct coresight_ops stm_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/
>> hwtracing/coresight/coresight-sysfs.c
>> index a01c9e54e2ed..8816bccba374 100644
>> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
>> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
>> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct coresight_device
>> *csdev)
>> int cpu, ret = 0;
>> struct coresight_device *sink;
>> struct list_head *path;
>> + struct cs_sink_data *sink_data;
>> enum coresight_dev_subtype_source subtype;
>> u32 hash;
>> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct
>> coresight_device *csdev)
>> goto out;
>> }
>> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>> + if (!sink_data) {
>> + ret = -ENOMEM;
>> + goto out;
>> + }
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>> NULL);
>> + sink_data->sink = sink;
>> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
>> if (ret)
>> goto err_path;
>> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct
>> coresight_device *csdev)
>> break;
>> }
>> + kfree(sink_data);
>> out:
>> mutex_unlock(&coresight_mutex);
>> return ret;
>> err_source:
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> err_path:
>> coresight_release_path(path);
>> + kfree(sink_data);
>> goto out;
>> }
>> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
>> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> {
>> int cpu, ret;
>> struct list_head *path = NULL;
>> + struct cs_sink_data *sink_data = NULL;
>> u32 hash;
>> mutex_lock(&coresight_mutex);
>> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> if (!coresight_disable_source_sysfs(csdev, NULL))
>> goto out;
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>> + if (!sink_data)
>> + goto out;
>> +
>> switch (csdev->subtype.source_subtype) {
>> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
>> cpu = source_ops(csdev)->cpu_id(csdev);
>> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> break;
>> }
>> - coresight_disable_path(path);
>> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>> NULL);
>> + coresight_disable_path(path, sink_data);
>> coresight_release_path(path);
>> + kfree(sink_data);
>> out:
>> mutex_unlock(&coresight_mutex);
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index d4f641cd9de6..7dc536eba3e2 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct
>> coresight_device *csdev, void *data)
>> pid_t pid;
>> unsigned long flags;
>> struct tmc_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-tmc-etr.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index a48bb85d0e7f..90a4058c9959 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct
>> coresight_device *csdev)
>> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>> enum cs_mode mode, void *data)
>> {
>> - 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 etr_perf_buffer *etr_perf;
>> switch (mode) {
>> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct
>> coresight_device *csdev, void *data)
>> pid_t pid;
>> unsigned long flags;
>> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>> spin_lock_irqsave(&drvdata->spinlock, flags);
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/
>> hwtracing/coresight/coresight-tpda.c
>> index 189a4abc2561..05622333f2d2 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -241,9 +241,29 @@ static void tpda_disable(struct coresight_device
>> *csdev,
>> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
>> }
>> +static int tpda_trace_id(struct coresight_device *csdev)
>> +{
>> + int trace_id;
>> + struct tpda_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + trace_id = drvdata->atid;
>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>
> Same comment as STM. This is always set so no ned to try to assign
> another one.
>
Will fix.
[...]
Thanks,
Jie
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-14 2:51 ` Jie Gan
@ 2025-01-14 10:07 ` James Clark
2025-01-15 1:44 ` Jie Gan
0 siblings, 1 reply; 21+ messages in thread
From: James Clark @ 2025-01-14 10:07 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 14/01/2025 2:51 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.
>>
> Thank you for comment. I will try this solution.
> The biggest challenge for the patch is how to correctly read trace_id
> from source device and passthrough it to helper device as the source
> device always the last one to enable. I believe your proposed solution
> is better than mine and has minimal impact on the basic framework, but I
> think we still need read_trace in source_ops and link_ops. Then we can
> read the trace_id in coresight_build_path function and save it to the
> coresight_path to avoid redundant searching?
>
>
>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
> without traverse the path.
>
> But we still need to check the type of the coresight device, because the
> TPDM does not have traceid and we use the trace_id from the TPDA device
> that the TPDM connected. That's why I added trace_id to link_ops.
>
But if any device that allocates a trace ID saves it into the path, then
as long as any other device that needs the ID is enabled after that it
just reads it from the path directly. Assuming we pass the path to every
enable and disable function.
We wouldn't need coresight_read_traceid() if it always happens that way
around, which I think it currently does?
>
>> 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.
>>
> I can move the read trace_id logic to build_path function, I believe
> it's better than current solution.
>
>>> + 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.
>>
> Will fix it.
>
>
>>> + if (!sink_data)
>>> + goto fail_end_stop;
>>> +
>>> + sink_data->sink = sink;
>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>> + &sink->perf_sink_id_map);
>>> + sink_data->handle = handle;
>>> +
>>> /* Nothing will happen without a path */
>>> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
>>> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
>>> + kfree(sink_data);
>>> goto fail_end_stop;
>>> + }
>>> /* Finally enable the tracer */
>>> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
>>> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event
>>> *event, int flags)
>>> perf_report_aux_output_id(event, hw_id);
>>> }
>>> + kfree(sink_data);
>>> out:
>>> /* Tell the perf core the event is alive */
>>> event->hw.state = 0;
>>> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event
>>> *event, int flags)
>>> return;
>>> fail_disable_path:
>>> - coresight_disable_path(path);
>>> + coresight_disable_path(path, sink_data);
>>> + kfree(sink_data);
>>> fail_end_stop:
>>> /*
>>> * Check if the handle is still associated with the event,
>>> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event
>>> *event, int mode)
>>> struct perf_output_handle *handle = &ctxt->handle;
>>> struct etm_event_data *event_data;
>>> struct list_head *path;
>>> + struct cs_sink_data *sink_data = NULL;
>>> /*
>>> * If we still have access to the event_data via handle,
>>> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event
>>> *event, int mode)
>>> if (!sink)
>>> return;
>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>
>> Same problem as above.
>>
>>> + if (!sink_data)
>>> + return;
>>> +
>>> /* stop tracer */
>>> coresight_disable_source(csdev, event);
>>> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event
>>> *event, int mode)
>>> * have to do anything here.
>>> */
>>> if (handle->event && (mode & PERF_EF_UPDATE)) {
>>> - if (WARN_ON_ONCE(handle->event != event))
>>> + if (WARN_ON_ONCE(handle->event != event)) {
>>> + kfree(sink_data);
>>> return;
>>> + }
>>> /* update trace information */
>>> - if (!sink_ops(sink)->update_buffer)
>>> + if (!sink_ops(sink)->update_buffer) {
>>> + kfree(sink_data);
>>> return;
>>> + }
>>> size = sink_ops(sink)->update_buffer(sink, handle,
>>> event_data->snk_config);
>>> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event
>>> *event, int mode)
>>> WARN_ON(size);
>>> }
>>> + sink_data->sink = sink;
>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>> + &sink->perf_sink_id_map);
>>> /* Disabling the path make its elements available to other
>>> sessions */
>>> - coresight_disable_path(path);
>>> + coresight_disable_path(path, sink_data);
>>> + kfree(sink_data);
>>> }
>>> static int etm_event_add(struct perf_event *event, int mode)
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/
>>> drivers/hwtracing/coresight/coresight-etm3x-core.c
>>> index c103f4c70f5d..0f095fab7e0a 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>> @@ -697,10 +697,40 @@ static void etm_disable(struct coresight_device
>>> *csdev,
>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>> }
>>> +static int etm_trace_id(struct coresight_device *csdev,
>>> + enum cs_mode mode,
>>> + struct coresight_trace_id_map *id_map)
>>> +{
>>> + int trace_id;
>>> + struct etm_drvdata *drvdata;
>>> +
>>> + if (csdev == NULL)
>>> + return -EINVAL;
>>> +
>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>> + switch (mode) {
>>> + case CS_MODE_SYSFS:
>>> + trace_id = etm_read_alloc_trace_id(drvdata);
>>> + break;
>>> + case CS_MODE_PERF:
>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>>> id_map);
>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>> + drvdata->traceid = (u8)trace_id;
>>> + break;
>>> + default:
>>> + trace_id = -EINVAL;
>>> + break;
>>> + }
>>> +
>>> + return trace_id;
>>> +}
>>> +
>>> +
>>> static const struct coresight_ops_source etm_source_ops = {
>>> .cpu_id = etm_cpu_id,
>>> .enable = etm_enable,
>>> .disable = etm_disable,
>>> + .trace_id = etm_trace_id,
>>> };
>>> static const struct coresight_ops etm_cs_ops = {
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/
>>> drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> index dd8c74f893db..bac9ea371688 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct
>>> coresight_device *csdev,
>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>> }
>>> +static int etm4_trace_id(struct coresight_device *csdev,
>>> + enum cs_mode mode,
>>> + struct coresight_trace_id_map *id_map)
>>> +{
>>> + int trace_id;
>>> + struct etmv4_drvdata *drvdata;
>>> +
>>> + if (csdev == NULL)
>>> + return -EINVAL;
>>> +
>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>> + switch (mode) {
>>> + case CS_MODE_SYSFS:
>>> + trace_id = etm4_read_alloc_trace_id(drvdata);
>>> + break;
>>> + case CS_MODE_PERF:
>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>>> id_map);
>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>> + drvdata->trcid = (u8)trace_id;
>>> + break;
>>> + default:
>>> + trace_id = -EINVAL;
>>> + break;
>>> + }
>>> +
>>> + return trace_id;
>>> +}
>>> +
>>> static const struct coresight_ops_source etm4_source_ops = {
>>> .cpu_id = etm4_cpu_id,
>>> .enable = etm4_enable,
>>> .disable = etm4_disable,
>>> + .trace_id = etm4_trace_id,
>>> };
>>> static const struct coresight_ops etm4_cs_ops = {
>>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/
>>> hwtracing/coresight/coresight-priv.h
>>> index 05f891ca6b5c..6a95a3ba9339 100644
>>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>>> @@ -105,6 +105,15 @@ struct cs_buffers {
>>> void **data_pages;
>>> };
>>> +/**
>>> + * struct cs_sink_data - data used by coresight_enable_path/
>>> coresight_disable_path
>>> + */
>>> +struct cs_sink_data {
>>> + struct perf_output_handle *handle;
>>> + struct coresight_device *sink;
>>> + u8 traceid;
>>> +};
>>> +
>>> static inline void coresight_insert_barrier_packet(void *buf)
>>> {
>>> if (buf)
>>> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
>>> } while (0);
>>> }
>>> -void coresight_disable_path(struct list_head *path);
>>> +void coresight_disable_path(struct list_head *path, void *sink_data);
>>> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
>>> void *sink_data);
>>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>>> + struct coresight_trace_id_map *id_map);
>>> struct coresight_device *coresight_get_sink(struct list_head *path);
>>> struct coresight_device *coresight_get_sink_by_id(u32 id);
>>> struct coresight_device *
>>> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/
>>> hwtracing/coresight/coresight-stm.c
>>> index b581a30a1cd9..5709eda77d9b 100644
>>> --- a/drivers/hwtracing/coresight/coresight-stm.c
>>> +++ b/drivers/hwtracing/coresight/coresight-stm.c
>>> @@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device
>>> *csdev,
>>> }
>>> }
>>> +static int stm_trace_id(struct coresight_device *csdev,
>>> + enum cs_mode mode,
>>> + struct coresight_trace_id_map *id_map)
>>> +{
>>> + int trace_id;
>>> + struct stm_drvdata *drvdata;
>>> +
>>> + if (csdev == NULL)
>>> + return -EINVAL;
>>> +
>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>> + trace_id = drvdata->traceid;
>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>
>> Trace ID is static and always set for STM so this isn't necessary,
>> just return drvdata->traceid which would already be valid otherwise
>> the device wouldn't be registered.
>>
> Thanks for comment.
> Will fix in next version
>
>
>>> + trace_id = coresight_trace_id_get_system_id();
>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>> + drvdata->traceid = (u8)trace_id;
>>> + }
>>> +
>>> + return trace_id;
>>> +}
>>> +
>>> static const struct coresight_ops_source stm_source_ops = {
>>> .enable = stm_enable,
>>> .disable = stm_disable,
>>> + .trace_id = stm_trace_id,
>>> };
>>> static const struct coresight_ops stm_cs_ops = {
>>> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/
>>> hwtracing/coresight/coresight-sysfs.c
>>> index a01c9e54e2ed..8816bccba374 100644
>>> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
>>> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
>>> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct
>>> coresight_device *csdev)
>>> int cpu, ret = 0;
>>> struct coresight_device *sink;
>>> struct list_head *path;
>>> + struct cs_sink_data *sink_data;
>>> enum coresight_dev_subtype_source subtype;
>>> u32 hash;
>>> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct
>>> coresight_device *csdev)
>>> goto out;
>>> }
>>> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>> + if (!sink_data) {
>>> + ret = -ENOMEM;
>>> + goto out;
>>> + }
>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>>> NULL);
>>> + sink_data->sink = sink;
>>> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
>>> if (ret)
>>> goto err_path;
>>> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct
>>> coresight_device *csdev)
>>> break;
>>> }
>>> + kfree(sink_data);
>>> out:
>>> mutex_unlock(&coresight_mutex);
>>> return ret;
>>> err_source:
>>> - coresight_disable_path(path);
>>> + coresight_disable_path(path, sink_data);
>>> err_path:
>>> coresight_release_path(path);
>>> + kfree(sink_data);
>>> goto out;
>>> }
>>> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
>>> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct
>>> coresight_device *csdev)
>>> {
>>> int cpu, ret;
>>> struct list_head *path = NULL;
>>> + struct cs_sink_data *sink_data = NULL;
>>> u32 hash;
>>> mutex_lock(&coresight_mutex);
>>> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct
>>> coresight_device *csdev)
>>> if (!coresight_disable_source_sysfs(csdev, NULL))
>>> goto out;
>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>> + if (!sink_data)
>>> + goto out;
>>> +
>>> switch (csdev->subtype.source_subtype) {
>>> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
>>> cpu = source_ops(csdev)->cpu_id(csdev);
>>> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct
>>> coresight_device *csdev)
>>> break;
>>> }
>>> - coresight_disable_path(path);
>>> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>>> NULL);
>>> + coresight_disable_path(path, sink_data);
>>> coresight_release_path(path);
>>> + kfree(sink_data);
>>> out:
>>> mutex_unlock(&coresight_mutex);
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/
>>> drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> index d4f641cd9de6..7dc536eba3e2 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct
>>> coresight_device *csdev, void *data)
>>> pid_t pid;
>>> unsigned long flags;
>>> struct tmc_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-tmc-etr.c b/
>>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> index a48bb85d0e7f..90a4058c9959 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct
>>> coresight_device *csdev)
>>> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>>> enum cs_mode mode, void *data)
>>> {
>>> - 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 etr_perf_buffer *etr_perf;
>>> switch (mode) {
>>> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct
>>> coresight_device *csdev, void *data)
>>> pid_t pid;
>>> unsigned long flags;
>>> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>>> spin_lock_irqsave(&drvdata->spinlock, flags);
>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/
>>> hwtracing/coresight/coresight-tpda.c
>>> index 189a4abc2561..05622333f2d2 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>> @@ -241,9 +241,29 @@ static void tpda_disable(struct coresight_device
>>> *csdev,
>>> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
>>> }
>>> +static int tpda_trace_id(struct coresight_device *csdev)
>>> +{
>>> + int trace_id;
>>> + struct tpda_drvdata *drvdata;
>>> +
>>> + if (csdev == NULL)
>>> + return -EINVAL;
>>> +
>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>> + trace_id = drvdata->atid;
>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>
>> Same comment as STM. This is always set so no ned to try to assign
>> another one.
>>
> Will fix.
>
> [...]
>
> Thanks,
> Jie
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-14 10:07 ` James Clark
@ 2025-01-15 1:44 ` Jie Gan
2025-01-15 12:29 ` James Clark
0 siblings, 1 reply; 21+ messages in thread
From: Jie Gan @ 2025-01-15 1:44 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 1/14/2025 6:07 PM, James Clark wrote:
>
>
> On 14/01/2025 2:51 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.
>>>
>> Thank you for comment. I will try this solution.
>> The biggest challenge for the patch is how to correctly read trace_id
>> from source device and passthrough it to helper device as the source
>> device always the last one to enable. I believe your proposed solution
>> is better than mine and has minimal impact on the basic framework, but
>> I think we still need read_trace in source_ops and link_ops. Then we
>> can read the trace_id in coresight_build_path function and save it to
>> the coresight_path to avoid redundant searching?
>>
>>
>>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
>> without traverse the path.
>>
>> But we still need to check the type of the coresight device, because
>> the TPDM does not have traceid and we use the trace_id from the TPDA
>> device that the TPDM connected. That's why I added trace_id to link_ops.
>>
>
> But if any device that allocates a trace ID saves it into the path, then
> as long as any other device that needs the ID is enabled after that it
> just reads it from the path directly. Assuming we pass the path to every
> enable and disable function.
>
> We wouldn't need coresight_read_traceid() if it always happens that way
> around, which I think it currently does?
>
I got your point here. You are right. If we passed path to the helper
device, just use coresight_get_source to obtain the source device, then
call the source_ops->trace_id to obtain the trace_id. So we definitely
dont need a standalone function, coresight_read_traceid().
Besides, I still need a function to retrive the trace_id of the TPDA
device if the source device is TPDM, right?
Thanks,
Jie
>>
>>> 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.
>>>
>> I can move the read trace_id logic to build_path function, I believe
>> it's better than current solution.
>>
>>>> + 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.
>>>
>> Will fix it.
>>
>>
>>>> + if (!sink_data)
>>>> + goto fail_end_stop;
>>>> +
>>>> + sink_data->sink = sink;
>>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>>> + &sink->perf_sink_id_map);
>>>> + sink_data->handle = handle;
>>>> +
>>>> /* Nothing will happen without a path */
>>>> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
>>>> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
>>>> + kfree(sink_data);
>>>> goto fail_end_stop;
>>>> + }
>>>> /* Finally enable the tracer */
>>>> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
>>>> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event
>>>> *event, int flags)
>>>> perf_report_aux_output_id(event, hw_id);
>>>> }
>>>> + kfree(sink_data);
>>>> out:
>>>> /* Tell the perf core the event is alive */
>>>> event->hw.state = 0;
>>>> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event
>>>> *event, int flags)
>>>> return;
>>>> fail_disable_path:
>>>> - coresight_disable_path(path);
>>>> + coresight_disable_path(path, sink_data);
>>>> + kfree(sink_data);
>>>> fail_end_stop:
>>>> /*
>>>> * Check if the handle is still associated with the event,
>>>> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event
>>>> *event, int mode)
>>>> struct perf_output_handle *handle = &ctxt->handle;
>>>> struct etm_event_data *event_data;
>>>> struct list_head *path;
>>>> + struct cs_sink_data *sink_data = NULL;
>>>> /*
>>>> * If we still have access to the event_data via handle,
>>>> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event
>>>> *event, int mode)
>>>> if (!sink)
>>>> return;
>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>
>>> Same problem as above.
>>>
>>>> + if (!sink_data)
>>>> + return;
>>>> +
>>>> /* stop tracer */
>>>> coresight_disable_source(csdev, event);
>>>> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event
>>>> *event, int mode)
>>>> * have to do anything here.
>>>> */
>>>> if (handle->event && (mode & PERF_EF_UPDATE)) {
>>>> - if (WARN_ON_ONCE(handle->event != event))
>>>> + if (WARN_ON_ONCE(handle->event != event)) {
>>>> + kfree(sink_data);
>>>> return;
>>>> + }
>>>> /* update trace information */
>>>> - if (!sink_ops(sink)->update_buffer)
>>>> + if (!sink_ops(sink)->update_buffer) {
>>>> + kfree(sink_data);
>>>> return;
>>>> + }
>>>> size = sink_ops(sink)->update_buffer(sink, handle,
>>>> event_data->snk_config);
>>>> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event
>>>> *event, int mode)
>>>> WARN_ON(size);
>>>> }
>>>> + sink_data->sink = sink;
>>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>>> + &sink->perf_sink_id_map);
>>>> /* Disabling the path make its elements available to other
>>>> sessions */
>>>> - coresight_disable_path(path);
>>>> + coresight_disable_path(path, sink_data);
>>>> + kfree(sink_data);
>>>> }
>>>> static int etm_event_add(struct perf_event *event, int mode)
>>>> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/
>>>> drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>> index c103f4c70f5d..0f095fab7e0a 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>> @@ -697,10 +697,40 @@ static void etm_disable(struct
>>>> coresight_device *csdev,
>>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>>> }
>>>> +static int etm_trace_id(struct coresight_device *csdev,
>>>> + enum cs_mode mode,
>>>> + struct coresight_trace_id_map *id_map)
>>>> +{
>>>> + int trace_id;
>>>> + struct etm_drvdata *drvdata;
>>>> +
>>>> + if (csdev == NULL)
>>>> + return -EINVAL;
>>>> +
>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>> + switch (mode) {
>>>> + case CS_MODE_SYSFS:
>>>> + trace_id = etm_read_alloc_trace_id(drvdata);
>>>> + break;
>>>> + case CS_MODE_PERF:
>>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>>>> id_map);
>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>> + drvdata->traceid = (u8)trace_id;
>>>> + break;
>>>> + default:
>>>> + trace_id = -EINVAL;
>>>> + break;
>>>> + }
>>>> +
>>>> + return trace_id;
>>>> +}
>>>> +
>>>> +
>>>> static const struct coresight_ops_source etm_source_ops = {
>>>> .cpu_id = etm_cpu_id,
>>>> .enable = etm_enable,
>>>> .disable = etm_disable,
>>>> + .trace_id = etm_trace_id,
>>>> };
>>>> static const struct coresight_ops etm_cs_ops = {
>>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/
>>>> drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>> index dd8c74f893db..bac9ea371688 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct
>>>> coresight_device *csdev,
>>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>>> }
>>>> +static int etm4_trace_id(struct coresight_device *csdev,
>>>> + enum cs_mode mode,
>>>> + struct coresight_trace_id_map *id_map)
>>>> +{
>>>> + int trace_id;
>>>> + struct etmv4_drvdata *drvdata;
>>>> +
>>>> + if (csdev == NULL)
>>>> + return -EINVAL;
>>>> +
>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>> + switch (mode) {
>>>> + case CS_MODE_SYSFS:
>>>> + trace_id = etm4_read_alloc_trace_id(drvdata);
>>>> + break;
>>>> + case CS_MODE_PERF:
>>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>>>> id_map);
>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>> + drvdata->trcid = (u8)trace_id;
>>>> + break;
>>>> + default:
>>>> + trace_id = -EINVAL;
>>>> + break;
>>>> + }
>>>> +
>>>> + return trace_id;
>>>> +}
>>>> +
>>>> static const struct coresight_ops_source etm4_source_ops = {
>>>> .cpu_id = etm4_cpu_id,
>>>> .enable = etm4_enable,
>>>> .disable = etm4_disable,
>>>> + .trace_id = etm4_trace_id,
>>>> };
>>>> static const struct coresight_ops etm4_cs_ops = {
>>>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/
>>>> hwtracing/coresight/coresight-priv.h
>>>> index 05f891ca6b5c..6a95a3ba9339 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>>>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>>>> @@ -105,6 +105,15 @@ struct cs_buffers {
>>>> void **data_pages;
>>>> };
>>>> +/**
>>>> + * struct cs_sink_data - data used by coresight_enable_path/
>>>> coresight_disable_path
>>>> + */
>>>> +struct cs_sink_data {
>>>> + struct perf_output_handle *handle;
>>>> + struct coresight_device *sink;
>>>> + u8 traceid;
>>>> +};
>>>> +
>>>> static inline void coresight_insert_barrier_packet(void *buf)
>>>> {
>>>> if (buf)
>>>> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
>>>> } while (0);
>>>> }
>>>> -void coresight_disable_path(struct list_head *path);
>>>> +void coresight_disable_path(struct list_head *path, void *sink_data);
>>>> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
>>>> void *sink_data);
>>>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>>>> + struct coresight_trace_id_map *id_map);
>>>> struct coresight_device *coresight_get_sink(struct list_head *path);
>>>> struct coresight_device *coresight_get_sink_by_id(u32 id);
>>>> struct coresight_device *
>>>> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/
>>>> hwtracing/coresight/coresight-stm.c
>>>> index b581a30a1cd9..5709eda77d9b 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-stm.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-stm.c
>>>> @@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device
>>>> *csdev,
>>>> }
>>>> }
>>>> +static int stm_trace_id(struct coresight_device *csdev,
>>>> + enum cs_mode mode,
>>>> + struct coresight_trace_id_map *id_map)
>>>> +{
>>>> + int trace_id;
>>>> + struct stm_drvdata *drvdata;
>>>> +
>>>> + if (csdev == NULL)
>>>> + return -EINVAL;
>>>> +
>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>> + trace_id = drvdata->traceid;
>>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>>
>>> Trace ID is static and always set for STM so this isn't necessary,
>>> just return drvdata->traceid which would already be valid otherwise
>>> the device wouldn't be registered.
>>>
>> Thanks for comment.
>> Will fix in next version
>>
>>
>>>> + trace_id = coresight_trace_id_get_system_id();
>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>> + drvdata->traceid = (u8)trace_id;
>>>> + }
>>>> +
>>>> + return trace_id;
>>>> +}
>>>> +
>>>> static const struct coresight_ops_source stm_source_ops = {
>>>> .enable = stm_enable,
>>>> .disable = stm_disable,
>>>> + .trace_id = stm_trace_id,
>>>> };
>>>> static const struct coresight_ops stm_cs_ops = {
>>>> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/
>>>> drivers/ hwtracing/coresight/coresight-sysfs.c
>>>> index a01c9e54e2ed..8816bccba374 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
>>>> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct
>>>> coresight_device *csdev)
>>>> int cpu, ret = 0;
>>>> struct coresight_device *sink;
>>>> struct list_head *path;
>>>> + struct cs_sink_data *sink_data;
>>>> enum coresight_dev_subtype_source subtype;
>>>> u32 hash;
>>>> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct
>>>> coresight_device *csdev)
>>>> goto out;
>>>> }
>>>> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>> + if (!sink_data) {
>>>> + ret = -ENOMEM;
>>>> + goto out;
>>>> + }
>>>> + sink_data->traceid = coresight_read_traceid(path,
>>>> CS_MODE_SYSFS, NULL);
>>>> + sink_data->sink = sink;
>>>> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
>>>> if (ret)
>>>> goto err_path;
>>>> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct
>>>> coresight_device *csdev)
>>>> break;
>>>> }
>>>> + kfree(sink_data);
>>>> out:
>>>> mutex_unlock(&coresight_mutex);
>>>> return ret;
>>>> err_source:
>>>> - coresight_disable_path(path);
>>>> + coresight_disable_path(path, sink_data);
>>>> err_path:
>>>> coresight_release_path(path);
>>>> + kfree(sink_data);
>>>> goto out;
>>>> }
>>>> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
>>>> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct
>>>> coresight_device *csdev)
>>>> {
>>>> int cpu, ret;
>>>> struct list_head *path = NULL;
>>>> + struct cs_sink_data *sink_data = NULL;
>>>> u32 hash;
>>>> mutex_lock(&coresight_mutex);
>>>> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct
>>>> coresight_device *csdev)
>>>> if (!coresight_disable_source_sysfs(csdev, NULL))
>>>> goto out;
>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>> + if (!sink_data)
>>>> + goto out;
>>>> +
>>>> switch (csdev->subtype.source_subtype) {
>>>> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
>>>> cpu = source_ops(csdev)->cpu_id(csdev);
>>>> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct
>>>> coresight_device *csdev)
>>>> break;
>>>> }
>>>> - coresight_disable_path(path);
>>>> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
>>>> + sink_data->traceid = coresight_read_traceid(path,
>>>> CS_MODE_SYSFS, NULL);
>>>> + coresight_disable_path(path, sink_data);
>>>> coresight_release_path(path);
>>>> + kfree(sink_data);
>>>> out:
>>>> mutex_unlock(&coresight_mutex);
>>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/
>>>> drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>> index d4f641cd9de6..7dc536eba3e2 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct
>>>> coresight_device *csdev, void *data)
>>>> pid_t pid;
>>>> unsigned long flags;
>>>> struct tmc_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-tmc-etr.c b/
>>>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> index a48bb85d0e7f..90a4058c9959 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct
>>>> coresight_device *csdev)
>>>> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>>>> enum cs_mode mode, void *data)
>>>> {
>>>> - 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 etr_perf_buffer *etr_perf;
>>>> switch (mode) {
>>>> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct
>>>> coresight_device *csdev, void *data)
>>>> pid_t pid;
>>>> unsigned long flags;
>>>> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>>>> spin_lock_irqsave(&drvdata->spinlock, flags);
>>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/
>>>> hwtracing/coresight/coresight-tpda.c
>>>> index 189a4abc2561..05622333f2d2 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>>> @@ -241,9 +241,29 @@ static void tpda_disable(struct
>>>> coresight_device *csdev,
>>>> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in-
>>>> >dest_port);
>>>> }
>>>> +static int tpda_trace_id(struct coresight_device *csdev)
>>>> +{
>>>> + int trace_id;
>>>> + struct tpda_drvdata *drvdata;
>>>> +
>>>> + if (csdev == NULL)
>>>> + return -EINVAL;
>>>> +
>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>> + trace_id = drvdata->atid;
>>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>>
>>> Same comment as STM. This is always set so no ned to try to assign
>>> another one.
>>>
>> Will fix.
>>
>> [...]
>>
>> Thanks,
>> Jie
>>
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-15 1:44 ` Jie Gan
@ 2025-01-15 12:29 ` James Clark
2025-01-16 3:01 ` Jie Gan
0 siblings, 1 reply; 21+ messages in thread
From: James Clark @ 2025-01-15 12:29 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 15/01/2025 1:44 am, Jie Gan wrote:
>
>
> On 1/14/2025 6:07 PM, James Clark wrote:
>>
>>
>> On 14/01/2025 2:51 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.
>>>>
>>> Thank you for comment. I will try this solution.
>>> The biggest challenge for the patch is how to correctly read trace_id
>>> from source device and passthrough it to helper device as the source
>>> device always the last one to enable. I believe your proposed
>>> solution is better than mine and has minimal impact on the basic
>>> framework, but I think we still need read_trace in source_ops and
>>> link_ops. Then we can read the trace_id in coresight_build_path
>>> function and save it to the coresight_path to avoid redundant searching?
>>>
>>>
>>>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
>>> without traverse the path.
>>>
>>> But we still need to check the type of the coresight device, because
>>> the TPDM does not have traceid and we use the trace_id from the TPDA
>>> device that the TPDM connected. That's why I added trace_id to link_ops.
>>>
>>
>> But if any device that allocates a trace ID saves it into the path,
>> then as long as any other device that needs the ID is enabled after
>> that it just reads it from the path directly. Assuming we pass the
>> path to every enable and disable function.
>>
>> We wouldn't need coresight_read_traceid() if it always happens that
>> way around, which I think it currently does?
>>
> I got your point here. You are right. If we passed path to the helper
> device, just use coresight_get_source to obtain the source device, then
> call the source_ops->trace_id to obtain the trace_id. So we definitely
> dont need a standalone function, coresight_read_traceid().
>
> Besides, I still need a function to retrive the trace_id of the TPDA
> device if the source device is TPDM, right?
>
>
> Thanks,
> Jie
>
Yes, and that would require a search as the TPDA not always at one end
of the path like coresight_get_source() and coresight_get_sink(). Which
is why I was thinking it might be good to save the trace ID in the path
struct to avoid it.
>>>
>>>> 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.
>>>>
>>> I can move the read trace_id logic to build_path function, I believe
>>> it's better than current solution.
>>>
>>>>> + 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.
>>>>
>>> Will fix it.
>>>
>>>
>>>>> + if (!sink_data)
>>>>> + goto fail_end_stop;
>>>>> +
>>>>> + sink_data->sink = sink;
>>>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>>>> + &sink->perf_sink_id_map);
>>>>> + sink_data->handle = handle;
>>>>> +
>>>>> /* Nothing will happen without a path */
>>>>> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
>>>>> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
>>>>> + kfree(sink_data);
>>>>> goto fail_end_stop;
>>>>> + }
>>>>> /* Finally enable the tracer */
>>>>> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
>>>>> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event
>>>>> *event, int flags)
>>>>> perf_report_aux_output_id(event, hw_id);
>>>>> }
>>>>> + kfree(sink_data);
>>>>> out:
>>>>> /* Tell the perf core the event is alive */
>>>>> event->hw.state = 0;
>>>>> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event
>>>>> *event, int flags)
>>>>> return;
>>>>> fail_disable_path:
>>>>> - coresight_disable_path(path);
>>>>> + coresight_disable_path(path, sink_data);
>>>>> + kfree(sink_data);
>>>>> fail_end_stop:
>>>>> /*
>>>>> * Check if the handle is still associated with the event,
>>>>> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event
>>>>> *event, int mode)
>>>>> struct perf_output_handle *handle = &ctxt->handle;
>>>>> struct etm_event_data *event_data;
>>>>> struct list_head *path;
>>>>> + struct cs_sink_data *sink_data = NULL;
>>>>> /*
>>>>> * If we still have access to the event_data via handle,
>>>>> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event
>>>>> *event, int mode)
>>>>> if (!sink)
>>>>> return;
>>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>>
>>>> Same problem as above.
>>>>
>>>>> + if (!sink_data)
>>>>> + return;
>>>>> +
>>>>> /* stop tracer */
>>>>> coresight_disable_source(csdev, event);
>>>>> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event
>>>>> *event, int mode)
>>>>> * have to do anything here.
>>>>> */
>>>>> if (handle->event && (mode & PERF_EF_UPDATE)) {
>>>>> - if (WARN_ON_ONCE(handle->event != event))
>>>>> + if (WARN_ON_ONCE(handle->event != event)) {
>>>>> + kfree(sink_data);
>>>>> return;
>>>>> + }
>>>>> /* update trace information */
>>>>> - if (!sink_ops(sink)->update_buffer)
>>>>> + if (!sink_ops(sink)->update_buffer) {
>>>>> + kfree(sink_data);
>>>>> return;
>>>>> + }
>>>>> size = sink_ops(sink)->update_buffer(sink, handle,
>>>>> event_data->snk_config);
>>>>> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event
>>>>> *event, int mode)
>>>>> WARN_ON(size);
>>>>> }
>>>>> + sink_data->sink = sink;
>>>>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>>>>> + &sink->perf_sink_id_map);
>>>>> /* Disabling the path make its elements available to other
>>>>> sessions */
>>>>> - coresight_disable_path(path);
>>>>> + coresight_disable_path(path, sink_data);
>>>>> + kfree(sink_data);
>>>>> }
>>>>> static int etm_event_add(struct perf_event *event, int mode)
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/
>>>>> drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>>> index c103f4c70f5d..0f095fab7e0a 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
>>>>> @@ -697,10 +697,40 @@ static void etm_disable(struct
>>>>> coresight_device *csdev,
>>>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>>>> }
>>>>> +static int etm_trace_id(struct coresight_device *csdev,
>>>>> + enum cs_mode mode,
>>>>> + struct coresight_trace_id_map *id_map)
>>>>> +{
>>>>> + int trace_id;
>>>>> + struct etm_drvdata *drvdata;
>>>>> +
>>>>> + if (csdev == NULL)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>>> + switch (mode) {
>>>>> + case CS_MODE_SYSFS:
>>>>> + trace_id = etm_read_alloc_trace_id(drvdata);
>>>>> + break;
>>>>> + case CS_MODE_PERF:
>>>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata-
>>>>> >cpu, id_map);
>>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>>> + drvdata->traceid = (u8)trace_id;
>>>>> + break;
>>>>> + default:
>>>>> + trace_id = -EINVAL;
>>>>> + break;
>>>>> + }
>>>>> +
>>>>> + return trace_id;
>>>>> +}
>>>>> +
>>>>> +
>>>>> static const struct coresight_ops_source etm_source_ops = {
>>>>> .cpu_id = etm_cpu_id,
>>>>> .enable = etm_enable,
>>>>> .disable = etm_disable,
>>>>> + .trace_id = etm_trace_id,
>>>>> };
>>>>> static const struct coresight_ops etm_cs_ops = {
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/
>>>>> drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>>> index dd8c74f893db..bac9ea371688 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>>>> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct
>>>>> coresight_device *csdev,
>>>>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>>>>> }
>>>>> +static int etm4_trace_id(struct coresight_device *csdev,
>>>>> + enum cs_mode mode,
>>>>> + struct coresight_trace_id_map *id_map)
>>>>> +{
>>>>> + int trace_id;
>>>>> + struct etmv4_drvdata *drvdata;
>>>>> +
>>>>> + if (csdev == NULL)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>>> + switch (mode) {
>>>>> + case CS_MODE_SYSFS:
>>>>> + trace_id = etm4_read_alloc_trace_id(drvdata);
>>>>> + break;
>>>>> + case CS_MODE_PERF:
>>>>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata-
>>>>> >cpu, id_map);
>>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>>> + drvdata->trcid = (u8)trace_id;
>>>>> + break;
>>>>> + default:
>>>>> + trace_id = -EINVAL;
>>>>> + break;
>>>>> + }
>>>>> +
>>>>> + return trace_id;
>>>>> +}
>>>>> +
>>>>> static const struct coresight_ops_source etm4_source_ops = {
>>>>> .cpu_id = etm4_cpu_id,
>>>>> .enable = etm4_enable,
>>>>> .disable = etm4_disable,
>>>>> + .trace_id = etm4_trace_id,
>>>>> };
>>>>> static const struct coresight_ops etm4_cs_ops = {
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/
>>>>> drivers/ hwtracing/coresight/coresight-priv.h
>>>>> index 05f891ca6b5c..6a95a3ba9339 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>>>>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>>>>> @@ -105,6 +105,15 @@ struct cs_buffers {
>>>>> void **data_pages;
>>>>> };
>>>>> +/**
>>>>> + * struct cs_sink_data - data used by coresight_enable_path/
>>>>> coresight_disable_path
>>>>> + */
>>>>> +struct cs_sink_data {
>>>>> + struct perf_output_handle *handle;
>>>>> + struct coresight_device *sink;
>>>>> + u8 traceid;
>>>>> +};
>>>>> +
>>>>> static inline void coresight_insert_barrier_packet(void *buf)
>>>>> {
>>>>> if (buf)
>>>>> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
>>>>> } while (0);
>>>>> }
>>>>> -void coresight_disable_path(struct list_head *path);
>>>>> +void coresight_disable_path(struct list_head *path, void *sink_data);
>>>>> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
>>>>> void *sink_data);
>>>>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>>>>> + struct coresight_trace_id_map *id_map);
>>>>> struct coresight_device *coresight_get_sink(struct list_head *path);
>>>>> struct coresight_device *coresight_get_sink_by_id(u32 id);
>>>>> struct coresight_device *
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/
>>>>> hwtracing/coresight/coresight-stm.c
>>>>> index b581a30a1cd9..5709eda77d9b 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-stm.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-stm.c
>>>>> @@ -281,9 +281,31 @@ static void stm_disable(struct
>>>>> coresight_device *csdev,
>>>>> }
>>>>> }
>>>>> +static int stm_trace_id(struct coresight_device *csdev,
>>>>> + enum cs_mode mode,
>>>>> + struct coresight_trace_id_map *id_map)
>>>>> +{
>>>>> + int trace_id;
>>>>> + struct stm_drvdata *drvdata;
>>>>> +
>>>>> + if (csdev == NULL)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>>> + trace_id = drvdata->traceid;
>>>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>>>
>>>> Trace ID is static and always set for STM so this isn't necessary,
>>>> just return drvdata->traceid which would already be valid otherwise
>>>> the device wouldn't be registered.
>>>>
>>> Thanks for comment.
>>> Will fix in next version
>>>
>>>
>>>>> + trace_id = coresight_trace_id_get_system_id();
>>>>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>>>>> + drvdata->traceid = (u8)trace_id;
>>>>> + }
>>>>> +
>>>>> + return trace_id;
>>>>> +}
>>>>> +
>>>>> static const struct coresight_ops_source stm_source_ops = {
>>>>> .enable = stm_enable,
>>>>> .disable = stm_disable,
>>>>> + .trace_id = stm_trace_id,
>>>>> };
>>>>> static const struct coresight_ops stm_cs_ops = {
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/
>>>>> drivers/ hwtracing/coresight/coresight-sysfs.c
>>>>> index a01c9e54e2ed..8816bccba374 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
>>>>> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> int cpu, ret = 0;
>>>>> struct coresight_device *sink;
>>>>> struct list_head *path;
>>>>> + struct cs_sink_data *sink_data;
>>>>> enum coresight_dev_subtype_source subtype;
>>>>> u32 hash;
>>>>> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> goto out;
>>>>> }
>>>>> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
>>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>>> + if (!sink_data) {
>>>>> + ret = -ENOMEM;
>>>>> + goto out;
>>>>> + }
>>>>> + sink_data->traceid = coresight_read_traceid(path,
>>>>> CS_MODE_SYSFS, NULL);
>>>>> + sink_data->sink = sink;
>>>>> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
>>>>> if (ret)
>>>>> goto err_path;
>>>>> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> break;
>>>>> }
>>>>> + kfree(sink_data);
>>>>> out:
>>>>> mutex_unlock(&coresight_mutex);
>>>>> return ret;
>>>>> err_source:
>>>>> - coresight_disable_path(path);
>>>>> + coresight_disable_path(path, sink_data);
>>>>> err_path:
>>>>> coresight_release_path(path);
>>>>> + kfree(sink_data);
>>>>> goto out;
>>>>> }
>>>>> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
>>>>> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> {
>>>>> int cpu, ret;
>>>>> struct list_head *path = NULL;
>>>>> + struct cs_sink_data *sink_data = NULL;
>>>>> u32 hash;
>>>>> mutex_lock(&coresight_mutex);
>>>>> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> if (!coresight_disable_source_sysfs(csdev, NULL))
>>>>> goto out;
>>>>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>>>>> + if (!sink_data)
>>>>> + goto out;
>>>>> +
>>>>> switch (csdev->subtype.source_subtype) {
>>>>> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
>>>>> cpu = source_ops(csdev)->cpu_id(csdev);
>>>>> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> break;
>>>>> }
>>>>> - coresight_disable_path(path);
>>>>> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
>>>>> + sink_data->traceid = coresight_read_traceid(path,
>>>>> CS_MODE_SYSFS, NULL);
>>>>> + coresight_disable_path(path, sink_data);
>>>>> coresight_release_path(path);
>>>>> + kfree(sink_data);
>>>>> out:
>>>>> mutex_unlock(&coresight_mutex);
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/
>>>>> drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>>> index d4f641cd9de6..7dc536eba3e2 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>>>> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct
>>>>> coresight_device *csdev, void *data)
>>>>> pid_t pid;
>>>>> unsigned long flags;
>>>>> struct tmc_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-tmc-etr.c b/
>>>>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>>> index a48bb85d0e7f..90a4058c9959 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>>>> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct
>>>>> coresight_device *csdev)
>>>>> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>>>>> enum cs_mode mode, void *data)
>>>>> {
>>>>> - 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 etr_perf_buffer *etr_perf;
>>>>> switch (mode) {
>>>>> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct
>>>>> coresight_device *csdev, void *data)
>>>>> pid_t pid;
>>>>> unsigned long flags;
>>>>> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>>>>> spin_lock_irqsave(&drvdata->spinlock, flags);
>>>>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/
>>>>> drivers/ hwtracing/coresight/coresight-tpda.c
>>>>> index 189a4abc2561..05622333f2d2 100644
>>>>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>>>>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>>>>> @@ -241,9 +241,29 @@ static void tpda_disable(struct
>>>>> coresight_device *csdev,
>>>>> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in-
>>>>> >dest_port);
>>>>> }
>>>>> +static int tpda_trace_id(struct coresight_device *csdev)
>>>>> +{
>>>>> + int trace_id;
>>>>> + struct tpda_drvdata *drvdata;
>>>>> +
>>>>> + if (csdev == NULL)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>>>>> + trace_id = drvdata->atid;
>>>>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>>>>
>>>> Same comment as STM. This is always set so no ned to try to assign
>>>> another one.
>>>>
>>> Will fix.
>>>
>>> [...]
>>>
>>> Thanks,
>>> Jie
>>>
>>
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-15 12:29 ` James Clark
@ 2025-01-16 3:01 ` Jie Gan
2025-01-16 10:17 ` James Clark
0 siblings, 1 reply; 21+ messages in thread
From: Jie Gan @ 2025-01-16 3:01 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 1/15/2025 8:29 PM, James Clark wrote:
>
>
> On 15/01/2025 1:44 am, Jie Gan wrote:
>>
>>
>> On 1/14/2025 6:07 PM, James Clark wrote:
>>>
>>>
>>> On 14/01/2025 2:51 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.
>>>>>
>>>> Thank you for comment. I will try this solution.
>>>> The biggest challenge for the patch is how to correctly read
>>>> trace_id from source device and passthrough it to helper device as
>>>> the source device always the last one to enable. I believe your
>>>> proposed solution is better than mine and has minimal impact on the
>>>> basic framework, but I think we still need read_trace in source_ops
>>>> and link_ops. Then we can read the trace_id in coresight_build_path
>>>> function and save it to the coresight_path to avoid redundant
>>>> searching?
>>>>
>>>>
>>>>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
>>>> without traverse the path.
>>>>
>>>> But we still need to check the type of the coresight device, because
>>>> the TPDM does not have traceid and we use the trace_id from the TPDA
>>>> device that the TPDM connected. That's why I added trace_id to
>>>> link_ops.
>>>>
>>>
>>> But if any device that allocates a trace ID saves it into the path,
>>> then as long as any other device that needs the ID is enabled after
>>> that it just reads it from the path directly. Assuming we pass the
>>> path to every enable and disable function.
>>>
>>> We wouldn't need coresight_read_traceid() if it always happens that
>>> way around, which I think it currently does?
>>>
>> I got your point here. You are right. If we passed path to the helper
>> device, just use coresight_get_source to obtain the source device,
>> then call the source_ops->trace_id to obtain the trace_id. So we
>> definitely dont need a standalone function, coresight_read_traceid().
>>
>> Besides, I still need a function to retrive the trace_id of the TPDA
>> device if the source device is TPDM, right?
>>
>>
>> Thanks,
>> Jie
>>
>
> Yes, and that would require a search as the TPDA not always at one end
> of the path like coresight_get_source() and coresight_get_sink(). Which
> is why I was thinking it might be good to save the trace ID in the path
> struct to avoid it.
>
As you proposed, I created coresight_path structure as below:
struct coresight_path {
struct perf_output_handle *handle;
struct list_head *path;
u8 trace_id;
};
In coresight_enable_path, I modified the parameters that transmitted to
helper device:
struct coresight_path *cs_path;
coresight_enable_helpers(csdev, mode, sink_data) ->
coresight_enable_helpers(csdev, mode, cs_path)
The cs_path will be constructed and initialized in coresight_build_path
function.
For perf mode, the trace_id is collected within etm_setup_aux and stored
in cs_path->trace_id to avoid extra cost of retrieving the trace_id;
For sysfs mode, I let the CTCU device to retrieving the trace_id with
path. The TPDA device is located close to the TPDM, making the cost of
searching for the TPDA device acceptable.
The cs_path will be stored in the same manner as the previous path.
How do you think about this solution?
Thanks,
Jie
[...]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-16 3:01 ` Jie Gan
@ 2025-01-16 10:17 ` James Clark
2025-01-17 2:31 ` Jie Gan
0 siblings, 1 reply; 21+ messages in thread
From: James Clark @ 2025-01-16 10:17 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 16/01/2025 3:01 am, Jie Gan wrote:
>
>
> On 1/15/2025 8:29 PM, James Clark wrote:
>>
>>
>> On 15/01/2025 1:44 am, Jie Gan wrote:
>>>
>>>
>>> On 1/14/2025 6:07 PM, James Clark wrote:
>>>>
>>>>
>>>> On 14/01/2025 2:51 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.
>>>>>>
>>>>> Thank you for comment. I will try this solution.
>>>>> The biggest challenge for the patch is how to correctly read
>>>>> trace_id from source device and passthrough it to helper device as
>>>>> the source device always the last one to enable. I believe your
>>>>> proposed solution is better than mine and has minimal impact on the
>>>>> basic framework, but I think we still need read_trace in source_ops
>>>>> and link_ops. Then we can read the trace_id in coresight_build_path
>>>>> function and save it to the coresight_path to avoid redundant
>>>>> searching?
>>>>>
>>>>>
>>>>>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
>>>>> without traverse the path.
>>>>>
>>>>> But we still need to check the type of the coresight device,
>>>>> because the TPDM does not have traceid and we use the trace_id from
>>>>> the TPDA device that the TPDM connected. That's why I added
>>>>> trace_id to link_ops.
>>>>>
>>>>
>>>> But if any device that allocates a trace ID saves it into the path,
>>>> then as long as any other device that needs the ID is enabled after
>>>> that it just reads it from the path directly. Assuming we pass the
>>>> path to every enable and disable function.
>>>>
>>>> We wouldn't need coresight_read_traceid() if it always happens that
>>>> way around, which I think it currently does?
>>>>
>>> I got your point here. You are right. If we passed path to the helper
>>> device, just use coresight_get_source to obtain the source device,
>>> then call the source_ops->trace_id to obtain the trace_id. So we
>>> definitely dont need a standalone function, coresight_read_traceid().
>>>
>>> Besides, I still need a function to retrive the trace_id of the TPDA
>>> device if the source device is TPDM, right?
>>>
>>>
>>> Thanks,
>>> Jie
>>>
>>
>> Yes, and that would require a search as the TPDA not always at one end
>> of the path like coresight_get_source() and coresight_get_sink().
>> Which is why I was thinking it might be good to save the trace ID in
>> the path struct to avoid it.
>>
> As you proposed, I created coresight_path structure as below:
> struct coresight_path {
> struct perf_output_handle *handle;
What's the perf handle for? Seems like this change for the CTCU only
requires access to the trace_id which is added below.
> struct list_head *path;
> u8 trace_id;
> };
>
> In coresight_enable_path, I modified the parameters that transmitted to
> helper device:
> struct coresight_path *cs_path;
>
> coresight_enable_helpers(csdev, mode, sink_data) ->
> coresight_enable_helpers(csdev, mode, cs_path)
>
> The cs_path will be constructed and initialized in coresight_build_path
> function.
>
> For perf mode, the trace_id is collected within etm_setup_aux and stored
> in cs_path->trace_id to avoid extra cost of retrieving the trace_id;
>
Looks good.
> For sysfs mode, I let the CTCU device to retrieving the trace_id with
> path. The TPDA device is located close to the TPDM, making the cost of
> searching for the TPDA device acceptable.
>
> The cs_path will be stored in the same manner as the previous path.
>
> How do you think about this solution?
>
Can it not be done the same way as Perf, at least for consistency? If
the enable helper function already gets access to the path, and the path
already has the trace ID, why is any search required?
> Thanks,
> Jie
>
> [...]
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-16 10:17 ` James Clark
@ 2025-01-17 2:31 ` Jie Gan
0 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2025-01-17 2:31 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 1/16/2025 6:17 PM, James Clark wrote:
>
>
> On 16/01/2025 3:01 am, Jie Gan wrote:
>>
>>
>> On 1/15/2025 8:29 PM, James Clark wrote:
>>>
>>>
>>> On 15/01/2025 1:44 am, Jie Gan wrote:
>>>>
>>>>
>>>> On 1/14/2025 6:07 PM, James Clark wrote:
>>>>>
>>>>>
>>>>> On 14/01/2025 2:51 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.
>>>>>>>
>>>>>> Thank you for comment. I will try this solution.
>>>>>> The biggest challenge for the patch is how to correctly read
>>>>>> trace_id from source device and passthrough it to helper device as
>>>>>> the source device always the last one to enable. I believe your
>>>>>> proposed solution is better than mine and has minimal impact on
>>>>>> the basic framework, but I think we still need read_trace in
>>>>>> source_ops and link_ops. Then we can read the trace_id in
>>>>>> coresight_build_path function and save it to the coresight_path to
>>>>>> avoid redundant searching?
>>>>>>
>>>>>>
>>>>>>>> Signed-off-by: Jie Gan <quic_jiegan@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's better, I can simplify the coresight_read_traceid function
>>>>>> without traverse the path.
>>>>>>
>>>>>> But we still need to check the type of the coresight device,
>>>>>> because the TPDM does not have traceid and we use the trace_id
>>>>>> from the TPDA device that the TPDM connected. That's why I added
>>>>>> trace_id to link_ops.
>>>>>>
>>>>>
>>>>> But if any device that allocates a trace ID saves it into the path,
>>>>> then as long as any other device that needs the ID is enabled after
>>>>> that it just reads it from the path directly. Assuming we pass the
>>>>> path to every enable and disable function.
>>>>>
>>>>> We wouldn't need coresight_read_traceid() if it always happens that
>>>>> way around, which I think it currently does?
>>>>>
>>>> I got your point here. You are right. If we passed path to the
>>>> helper device, just use coresight_get_source to obtain the source
>>>> device, then call the source_ops->trace_id to obtain the trace_id.
>>>> So we definitely dont need a standalone function,
>>>> coresight_read_traceid().
>>>>
>>>> Besides, I still need a function to retrive the trace_id of the TPDA
>>>> device if the source device is TPDM, right?
>>>>
>>>>
>>>> Thanks,
>>>> Jie
>>>>
>>>
>>> Yes, and that would require a search as the TPDA not always at one
>>> end of the path like coresight_get_source() and coresight_get_sink().
>>> Which is why I was thinking it might be good to save the trace ID in
>>> the path struct to avoid it.
>>>
>> As you proposed, I created coresight_path structure as below:
>> struct coresight_path {
>> struct perf_output_handle *handle;
>
> What's the perf handle for? Seems like this change for the CTCU only
> requires access to the trace_id which is added below.
In perf mode, the handle as the "sink_data" has been transmitted to
coresight_enable_path function.
etm_event_start:
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
struct perf_output_handle *handle = &ctxt->handle;
...
if (coresight_enable_path(cs_path, CS_MODE_PERF, handle))
...
Then, the handle as the "sink_data", it will be transmitted to
coresight_enable_helpers and coresight_enable_sink.
As I mentioned before, I modified following codes in coresight_enable_path:
coresight_enable_helpers(csdev, mode, sink_data) ->
coresight_enable_helpers(csdev, mode, cs_path)
So, I need to consider how to correctly to handle the "handle"
parameter! That's why I added it to the coresight_path, ensure the
'handle' is correctly referenced wherever necessary.
>
>> struct list_head *path;
>> u8 trace_id;
>> };
>>
>> In coresight_enable_path, I modified the parameters that transmitted
>> to helper device:
>> struct coresight_path *cs_path;
>>
>> coresight_enable_helpers(csdev, mode, sink_data) ->
>> coresight_enable_helpers(csdev, mode, cs_path)
>>
>> The cs_path will be constructed and initialized in
>> coresight_build_path function.
>>
>> For perf mode, the trace_id is collected within etm_setup_aux and
>> stored in cs_path->trace_id to avoid extra cost of retrieving the
>> trace_id;
>>
>
> Looks good.
>
>> For sysfs mode, I let the CTCU device to retrieving the trace_id with
>> path. The TPDA device is located close to the TPDM, making the cost of
>> searching for the TPDA device acceptable.
>>
>> The cs_path will be stored in the same manner as the previous path.
>>
>> How do you think about this solution?
>>
>
> Can it not be done the same way as Perf, at least for consistency? If
> the enable helper function already gets access to the path, and the path
> already has the trace ID, why is any search required?
Hi, James
For sysfs mode, We need to retrieve the trace_id once within the enable
function, then cache it to coresight_path. (As discussed before, there
is a special case of the source device is TPDM!)
Consider the CTCU is the helper device of the TMC ETR device, not all
path need the trace_id(other sink, etf), so I put the retrieving logic
in the CTCU driver(within CTCU enable).
For the disable function, we just use the cached trace_id in
coresight_path to disable the trace_id filter functionality.
Or I was thinking another solution in coresight_build_path, We assume
only the sysfs mode needs to retrieve the trace_id when construct path.
So we can call source_ops(csdev)->trace_id once, hopefully the source
device is not TPDM! If not, we will try to locate the TPDA device, then
call link_ops(csdev)->trace_id to read the trace_id. And for perf mode,
we still use the solution I mentioned before.
How do you think about it, which one do you prefer? Or any other proposal?
Thanks,
Jie
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-13 12:02 ` James Clark
2025-01-14 2:51 ` Jie Gan
@ 2025-01-23 6:28 ` Jie Gan
2025-01-23 9:47 ` James Clark
1 sibling, 1 reply; 21+ messages in thread
From: Jie Gan @ 2025-01-23 6:28 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
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@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?
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 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
>> + if (!sink_data)
>> + goto fail_end_stop;
>> +
>> + sink_data->sink = sink;
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>> + &sink->perf_sink_id_map);
>> + sink_data->handle = handle;
>> +
>> /* Nothing will happen without a path */
>> - if (coresight_enable_path(path, CS_MODE_PERF, handle))
>> + if (coresight_enable_path(path, CS_MODE_PERF, sink_data)) {
>> + kfree(sink_data);
>> goto fail_end_stop;
>> + }
>> /* Finally enable the tracer */
>> if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF,
>> @@ -526,6 +538,7 @@ static void etm_event_start(struct perf_event
>> *event, int flags)
>> perf_report_aux_output_id(event, hw_id);
>> }
>> + kfree(sink_data);
>> out:
>> /* Tell the perf core the event is alive */
>> event->hw.state = 0;
>> @@ -534,7 +547,8 @@ static void etm_event_start(struct perf_event
>> *event, int flags)
>> return;
>> fail_disable_path:
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> + kfree(sink_data);
>> fail_end_stop:
>> /*
>> * Check if the handle is still associated with the event,
>> @@ -559,6 +573,7 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> struct perf_output_handle *handle = &ctxt->handle;
>> struct etm_event_data *event_data;
>> struct list_head *path;
>> + struct cs_sink_data *sink_data = NULL;
>> /*
>> * If we still have access to the event_data via handle,
>> @@ -603,6 +618,10 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> if (!sink)
>> return;
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>
> Same problem as above.
>
>> + if (!sink_data)
>> + return;
>> +
>> /* stop tracer */
>> coresight_disable_source(csdev, event);
>> @@ -616,12 +635,16 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> * have to do anything here.
>> */
>> if (handle->event && (mode & PERF_EF_UPDATE)) {
>> - if (WARN_ON_ONCE(handle->event != event))
>> + if (WARN_ON_ONCE(handle->event != event)) {
>> + kfree(sink_data);
>> return;
>> + }
>> /* update trace information */
>> - if (!sink_ops(sink)->update_buffer)
>> + if (!sink_ops(sink)->update_buffer) {
>> + kfree(sink_data);
>> return;
>> + }
>> size = sink_ops(sink)->update_buffer(sink, handle,
>> event_data->snk_config);
>> @@ -642,8 +665,12 @@ static void etm_event_stop(struct perf_event
>> *event, int mode)
>> WARN_ON(size);
>> }
>> + sink_data->sink = sink;
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_PERF,
>> + &sink->perf_sink_id_map);
>> /* Disabling the path make its elements available to other
>> sessions */
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> + kfree(sink_data);
>> }
>> static int etm_event_add(struct perf_event *event, int mode)
>> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/
>> drivers/hwtracing/coresight/coresight-etm3x-core.c
>> index c103f4c70f5d..0f095fab7e0a 100644
>> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
>> @@ -697,10 +697,40 @@ static void etm_disable(struct coresight_device
>> *csdev,
>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>> }
>> +static int etm_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct etm_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + switch (mode) {
>> + case CS_MODE_SYSFS:
>> + trace_id = etm_read_alloc_trace_id(drvdata);
>> + break;
>> + case CS_MODE_PERF:
>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>> id_map);
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->traceid = (u8)trace_id;
>> + break;
>> + default:
>> + trace_id = -EINVAL;
>> + break;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> +
>> static const struct coresight_ops_source etm_source_ops = {
>> .cpu_id = etm_cpu_id,
>> .enable = etm_enable,
>> .disable = etm_disable,
>> + .trace_id = etm_trace_id,
>> };
>> static const struct coresight_ops etm_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/
>> drivers/hwtracing/coresight/coresight-etm4x-core.c
>> index dd8c74f893db..bac9ea371688 100644
>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> @@ -1025,10 +1025,39 @@ static void etm4_disable(struct
>> coresight_device *csdev,
>> coresight_set_mode(csdev, CS_MODE_DISABLED);
>> }
>> +static int etm4_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct etmv4_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + switch (mode) {
>> + case CS_MODE_SYSFS:
>> + trace_id = etm4_read_alloc_trace_id(drvdata);
>> + break;
>> + case CS_MODE_PERF:
>> + trace_id = coresight_trace_id_read_cpu_id_map(drvdata->cpu,
>> id_map);
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->trcid = (u8)trace_id;
>> + break;
>> + default:
>> + trace_id = -EINVAL;
>> + break;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> static const struct coresight_ops_source etm4_source_ops = {
>> .cpu_id = etm4_cpu_id,
>> .enable = etm4_enable,
>> .disable = etm4_disable,
>> + .trace_id = etm4_trace_id,
>> };
>> static const struct coresight_ops etm4_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/
>> hwtracing/coresight/coresight-priv.h
>> index 05f891ca6b5c..6a95a3ba9339 100644
>> --- a/drivers/hwtracing/coresight/coresight-priv.h
>> +++ b/drivers/hwtracing/coresight/coresight-priv.h
>> @@ -105,6 +105,15 @@ struct cs_buffers {
>> void **data_pages;
>> };
>> +/**
>> + * struct cs_sink_data - data used by coresight_enable_path/
>> coresight_disable_path
>> + */
>> +struct cs_sink_data {
>> + struct perf_output_handle *handle;
>> + struct coresight_device *sink;
>> + u8 traceid;
>> +};
>> +
>> static inline void coresight_insert_barrier_packet(void *buf)
>> {
>> if (buf)
>> @@ -129,9 +138,11 @@ static inline void CS_UNLOCK(void __iomem *addr)
>> } while (0);
>> }
>> -void coresight_disable_path(struct list_head *path);
>> +void coresight_disable_path(struct list_head *path, void *sink_data);
>> int coresight_enable_path(struct list_head *path, enum cs_mode mode,
>> void *sink_data);
>> +int coresight_read_traceid(struct list_head *path, enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map);
>> struct coresight_device *coresight_get_sink(struct list_head *path);
>> struct coresight_device *coresight_get_sink_by_id(u32 id);
>> struct coresight_device *
>> diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/
>> hwtracing/coresight/coresight-stm.c
>> index b581a30a1cd9..5709eda77d9b 100644
>> --- a/drivers/hwtracing/coresight/coresight-stm.c
>> +++ b/drivers/hwtracing/coresight/coresight-stm.c
>> @@ -281,9 +281,31 @@ static void stm_disable(struct coresight_device
>> *csdev,
>> }
>> }
>> +static int stm_trace_id(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map)
>> +{
>> + int trace_id;
>> + struct stm_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + trace_id = drvdata->traceid;
>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>
> Trace ID is static and always set for STM so this isn't necessary, just
> return drvdata->traceid which would already be valid otherwise the
> device wouldn't be registered.
>
>> + trace_id = coresight_trace_id_get_system_id();
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->traceid = (u8)trace_id;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> static const struct coresight_ops_source stm_source_ops = {
>> .enable = stm_enable,
>> .disable = stm_disable,
>> + .trace_id = stm_trace_id,
>> };
>> static const struct coresight_ops stm_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/
>> hwtracing/coresight/coresight-sysfs.c
>> index a01c9e54e2ed..8816bccba374 100644
>> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
>> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
>> @@ -168,6 +168,7 @@ int coresight_enable_sysfs(struct coresight_device
>> *csdev)
>> int cpu, ret = 0;
>> struct coresight_device *sink;
>> struct list_head *path;
>> + struct cs_sink_data *sink_data;
>> enum coresight_dev_subtype_source subtype;
>> u32 hash;
>> @@ -209,7 +210,14 @@ int coresight_enable_sysfs(struct
>> coresight_device *csdev)
>> goto out;
>> }
>> - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>> + if (!sink_data) {
>> + ret = -ENOMEM;
>> + goto out;
>> + }
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>> NULL);
>> + sink_data->sink = sink;
>> + ret = coresight_enable_path(path, CS_MODE_SYSFS, sink_data);
>> if (ret)
>> goto err_path;
>> @@ -246,15 +254,17 @@ int coresight_enable_sysfs(struct
>> coresight_device *csdev)
>> break;
>> }
>> + kfree(sink_data);
>> out:
>> mutex_unlock(&coresight_mutex);
>> return ret;
>> err_source:
>> - coresight_disable_path(path);
>> + coresight_disable_path(path, sink_data);
>> err_path:
>> coresight_release_path(path);
>> + kfree(sink_data);
>> goto out;
>> }
>> EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
>> @@ -263,6 +273,7 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> {
>> int cpu, ret;
>> struct list_head *path = NULL;
>> + struct cs_sink_data *sink_data = NULL;
>> u32 hash;
>> mutex_lock(&coresight_mutex);
>> @@ -274,6 +285,10 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> if (!coresight_disable_source_sysfs(csdev, NULL))
>> goto out;
>> + sink_data = kzalloc(sizeof(*sink_data), GFP_KERNEL);
>> + if (!sink_data)
>> + goto out;
>> +
>> switch (csdev->subtype.source_subtype) {
>> case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
>> cpu = source_ops(csdev)->cpu_id(csdev);
>> @@ -297,8 +312,11 @@ void coresight_disable_sysfs(struct
>> coresight_device *csdev)
>> break;
>> }
>> - coresight_disable_path(path);
>> + sink_data->sink = coresight_find_activated_sysfs_sink(csdev);
>> + sink_data->traceid = coresight_read_traceid(path, CS_MODE_SYSFS,
>> NULL);
>> + coresight_disable_path(path, sink_data);
>> coresight_release_path(path);
>> + kfree(sink_data);
>> out:
>> mutex_unlock(&coresight_mutex);
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index d4f641cd9de6..7dc536eba3e2 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -250,7 +250,8 @@ static int tmc_enable_etf_sink_perf(struct
>> coresight_device *csdev, void *data)
>> pid_t pid;
>> unsigned long flags;
>> struct tmc_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-tmc-etr.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index a48bb85d0e7f..90a4058c9959 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -1254,7 +1254,8 @@ static int tmc_enable_etr_sink_sysfs(struct
>> coresight_device *csdev)
>> struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
>> enum cs_mode mode, void *data)
>> {
>> - 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 etr_perf_buffer *etr_perf;
>> switch (mode) {
>> @@ -1648,7 +1649,8 @@ static int tmc_enable_etr_sink_perf(struct
>> coresight_device *csdev, void *data)
>> pid_t pid;
>> unsigned long flags;
>> struct tmc_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 etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
>> spin_lock_irqsave(&drvdata->spinlock, flags);
>> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/
>> hwtracing/coresight/coresight-tpda.c
>> index 189a4abc2561..05622333f2d2 100644
>> --- a/drivers/hwtracing/coresight/coresight-tpda.c
>> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
>> @@ -241,9 +241,29 @@ static void tpda_disable(struct coresight_device
>> *csdev,
>> dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
>> }
>> +static int tpda_trace_id(struct coresight_device *csdev)
>> +{
>> + int trace_id;
>> + struct tpda_drvdata *drvdata;
>> +
>> + if (csdev == NULL)
>> + return -EINVAL;
>> +
>> + drvdata = dev_get_drvdata(csdev->dev.parent);
>> + trace_id = drvdata->atid;
>> + if (!IS_VALID_CS_TRACE_ID(trace_id)) {
>
> Same comment as STM. This is always set so no ned to try to assign
> another one.
>
>> + trace_id = coresight_trace_id_get_system_id();
>> + if (IS_VALID_CS_TRACE_ID(trace_id))
>> + drvdata->atid = (u8)trace_id;
>> + }
>> +
>> + return trace_id;
>> +}
>> +
>> static const struct coresight_ops_link tpda_link_ops = {
>> .enable = tpda_enable,
>> .disable = tpda_disable,
>> + .trace_id = tpda_trace_id,
>> };
>> static const struct coresight_ops tpda_cs_ops = {
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/
>> hwtracing/coresight/coresight-trbe.c
>> index 919804b12a67..6680d3c69906 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.c
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
>> @@ -21,6 +21,7 @@
>> #include "coresight-self-hosted-trace.h"
>> #include "coresight-trbe.h"
>> +#include "coresight-priv.h"
>> #define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages <<
>> PAGE_SHIFT))
>> @@ -1012,7 +1013,8 @@ static int arm_trbe_enable(struct
>> coresight_device *csdev, enum cs_mode mode,
>> {
>> struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>> struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
>> - 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 trbe_buf *buf = etm_perf_sink_config(handle);
>> WARN_ON(cpudata->cpu != smp_processor_id());
>> diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/
>> hwtracing/coresight/ultrasoc-smb.c
>> index dc3c9504dd7c..99e0eb33c01f 100644
>> --- a/drivers/hwtracing/coresight/ultrasoc-smb.c
>> +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
>> @@ -216,7 +216,8 @@ static void smb_enable_sysfs(struct
>> coresight_device *csdev)
>> static int smb_enable_perf(struct coresight_device *csdev, void *data)
>> {
>> struct smb_drv_data *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);
>> pid_t pid;
>> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
>> index 157c4bd009a1..1929f0088c0f 100644
>> --- a/include/linux/coresight.h
>> +++ b/include/linux/coresight.h
>> @@ -368,6 +368,7 @@ struct coresight_ops_sink {
>> * Operations available for links.
>> * @enable: enables flow between iport and oport.
>> * @disable: disables flow between iport and oport.
>> + * @trace_id: Collect the traceid.
>> */
>> struct coresight_ops_link {
>> int (*enable)(struct coresight_device *csdev,
>> @@ -376,6 +377,7 @@ struct coresight_ops_link {
>> void (*disable)(struct coresight_device *csdev,
>> struct coresight_connection *in,
>> struct coresight_connection *out);
>> + int (*trace_id)(struct coresight_device *csdev);
>> };
>> /**
>> @@ -385,6 +387,7 @@ struct coresight_ops_link {
>> * is associated to.
>> * @enable: enables tracing for a source.
>> * @disable: disables tracing for a source.
>> + * @trace_id: collect the traceid.
>> */
>> struct coresight_ops_source {
>> int (*cpu_id)(struct coresight_device *csdev);
>> @@ -392,6 +395,9 @@ struct coresight_ops_source {
>> enum cs_mode mode, struct coresight_trace_id_map
>> *id_map);
>> void (*disable)(struct coresight_device *csdev,
>> struct perf_event *event);
>> + int (*trace_id)(struct coresight_device *csdev,
>> + enum cs_mode mode,
>> + struct coresight_trace_id_map *id_map);
>> };
>> /**
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-23 6:28 ` Jie Gan
@ 2025-01-23 9:47 ` James Clark
2025-01-23 10:03 ` Jie Gan
0 siblings, 1 reply; 21+ messages in thread
From: James Clark @ 2025-01-23 9:47 UTC (permalink / raw)
To: Jie Gan
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
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@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.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID
2025-01-23 9:47 ` James Clark
@ 2025-01-23 10:03 ` Jie Gan
0 siblings, 0 replies; 21+ messages in thread
From: Jie Gan @ 2025-01-23 10:03 UTC (permalink / raw)
To: James Clark
Cc: Jinlong Mao, coresight, linux-arm-kernel, linux-kernel,
devicetree, Tingwei Zhang, linux-arm-msm, linux-stm32,
Suzuki K Poulose, Mike Leach, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio
On 1/23/2025 5:47 PM, James Clark wrote:
>
>
> 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@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.
>
Sure, wiill check the issue again.
>> 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.
>
Suppose we have two etr devices enabled, TPDM0 with trace_id 3(trace_id
of TPDA0) with etr0 and TPDM1 with trace_id 3(trace_id of TPDA0) with
etr1 have been enabled. So the current refcnt for TPDA device is 2, but
actually, the refcnt for each sink should be 1, right? So I cannot check
the refcnt from TPDA's coresight_device. That's why I implemented a hash
table, use trace_id as key. We can check the refcnt for each trace_id
for each sink with the solution.
Here is the code snippet:
Entry for hash table:
struct ctcu_traceid_entry {
struct hlist_node hlist;
atomic_t refcnt[ATID_MAX_NUM];
u8 trace_id;
};
Usage of hash table:
static struct ctcu_traceid_entry *ctcu_search_traceid_entry(struct
coresight_device *csdev,
u8 trace_id)
{
struct ctcu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct ctcu_traceid_entry *entry, *new_entry;
int i;
new_entry = kzalloc(sizeof(struct ctcu_traceid_entry), GFP_KERNEL);
if (!new_entry)
return NULL;
new_entry->trace_id = trace_id;
for (i = 0; i < ATID_MAX_NUM; i++)
atomic_set(&new_entry->refcnt[i], 0);
guard(raw_spinlock_irqsave)(&drvdata->spin_lock);
hash_for_each_possible(drvdata->traceid_htable, entry, hlist,
trace_id) {
if (entry->trace_id == trace_id) {
kfree(new_entry);
return entry;
}
}
hash_add(drvdata->traceid_htable, &new_entry->hlist, trace_id);
return new_entry;
}
/*
* 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 ctcu_traceid_entry *entry;
struct coresight_device *sink = coresight_get_sink(cs_path->path);
int port_num;
entry = ctcu_search_traceid_entry(csdev, cs_path->trace_id);
if ((sink == NULL) || !IS_VALID_CS_TRACE_ID(cs_path->trace_id)
|| (entry == NULL)) {
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(&entry->refcnt[port_num]);
else {
if (atomic_dec_return(&entry->refcnt[port_num]) > 0) {
dev_dbg(&csdev->dev, "Skip the disable session\n");
return 0;
}
ctcu_rm_traceid_entry(csdev, cs_path->trace_id);
}
dev_dbg(&csdev->dev, "traceid is %d\n", cs_path->trace_id);
return __ctcu_set_etr_traceid(csdev, cs_path->trace_id,
port_num, enable);
}
Or, I also have another solution, create an multi-element atomic array
like refcnt[MAX_ETR_NUM][CORESIGHT_TRACE_ID_RES_TOP]. So we can allocate
memory for the array in CTCU's probe function. It will cost like almost
1k byte.
Thanks,
Jie
>> 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.
>
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-01-23 10:03 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-26 1:10 [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
2024-12-26 1:10 ` [PATCH v8 1/5] Coresight: Add support for new APB clock name Jie Gan
2025-01-13 11:33 ` James Clark
2024-12-26 1:10 ` [PATCH v8 2/5] Coresight: Add trace_id function to retrieving the trace ID Jie Gan
2025-01-13 12:02 ` James Clark
2025-01-14 2:51 ` Jie Gan
2025-01-14 10:07 ` James Clark
2025-01-15 1:44 ` Jie Gan
2025-01-15 12:29 ` James Clark
2025-01-16 3:01 ` Jie Gan
2025-01-16 10:17 ` James Clark
2025-01-17 2:31 ` Jie Gan
2025-01-23 6:28 ` Jie Gan
2025-01-23 9:47 ` James Clark
2025-01-23 10:03 ` Jie Gan
2024-12-26 1:10 ` [PATCH v8 3/5] dt-bindings: arm: Add Coresight TMC Control Unit hardware Jie Gan
2024-12-26 1:10 ` [PATCH v8 4/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
2025-01-13 12:05 ` James Clark
2025-01-14 1:50 ` Jie Gan
2024-12-26 1:10 ` [PATCH v8 5/5] arm64: dts: qcom: sa8775p: Add CTCU and ETR nodes Jie Gan
2025-01-09 7:22 ` [PATCH v8 0/5] Coresight: Add Coresight TMC Control Unit driver Jie Gan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox