[PATCH v3 07/10] coresight: tmc: add prepare/unprepare functions for byte-cntr
From: Jie Gan <hidden>
Date: 2025-06-24 06:05:24
Also in:
linux-arm-msm, linux-devicetree, lkml
Subsystem:
arm/coresight framework and drivers, hardware tracing facilities, the rest · Maintainers:
Suzuki K Poulose, Alexander Shishkin, Linus Torvalds
Prepare for byte-cntr reading. An additional sysfs_buf is required to receive trace data, as byte-cntr always reads from the deactivated and filled sysfs_buf. The unprepare function releases the additional deactivated sysfs_buf allocated during the prepare phase. Signed-off-by: Jie Gan <redacted> --- .../hwtracing/coresight/coresight-tmc-core.c | 38 ++++++++- .../hwtracing/coresight/coresight-tmc-etr.c | 79 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tmc.h | 8 ++ 3 files changed, 121 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 8531bac79211..40605310240d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c@@ -229,7 +229,11 @@ static int tmc_prepare_crashdata(struct tmc_drvdata *drvdata) static int tmc_read_prepare(struct tmc_drvdata *drvdata) { - int ret = 0; + struct coresight_device *helper = coresight_get_helper(drvdata->csdev, + CORESIGHT_DEV_SUBTYPE_HELPER_CTCU); + struct ctcu_byte_cntr *byte_cntr_data = NULL; + struct ctcu_drvdata *ctcu_drvdata = NULL; + int port, ret = 0; switch (drvdata->config_type) { case TMC_CONFIG_TYPE_ETB:
@@ -237,7 +241,18 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) ret = tmc_read_prepare_etb(drvdata); break; case TMC_CONFIG_TYPE_ETR: - ret = tmc_read_prepare_etr(drvdata); + if (helper) { + port = coresight_get_port_helper(drvdata->csdev, helper); + if (port >= 0) { + ctcu_drvdata = dev_get_drvdata(helper->dev.parent); + byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port]; + } + } + + if (byte_cntr_data && byte_cntr_data->thresh_val) + ret = tmc_read_prepare_byte_cntr(drvdata, byte_cntr_data); + else + ret = tmc_read_prepare_etr(drvdata); break; default: ret = -EINVAL;
@@ -251,7 +266,11 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) static int tmc_read_unprepare(struct tmc_drvdata *drvdata) { - int ret = 0; + struct coresight_device *helper = coresight_get_helper(drvdata->csdev, + CORESIGHT_DEV_SUBTYPE_HELPER_CTCU); + struct ctcu_byte_cntr *byte_cntr_data = NULL; + struct ctcu_drvdata *ctcu_drvdata = NULL; + int port, ret = 0; switch (drvdata->config_type) { case TMC_CONFIG_TYPE_ETB:
@@ -259,7 +278,18 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata) ret = tmc_read_unprepare_etb(drvdata); break; case TMC_CONFIG_TYPE_ETR: - ret = tmc_read_unprepare_etr(drvdata); + if (helper) { + port = coresight_get_port_helper(drvdata->csdev, helper); + if (port >= 0) { + ctcu_drvdata = dev_get_drvdata(helper->dev.parent); + byte_cntr_data = &ctcu_drvdata->byte_cntr_data[port]; + } + } + + if (byte_cntr_data && byte_cntr_data->thresh_val) + ret = tmc_read_unprepare_byte_cntr(drvdata, byte_cntr_data); + else + ret = tmc_read_unprepare_etr(drvdata); break; default: ret = -EINVAL;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 4609df80ae38..2b73bd8074bb 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c@@ -2032,6 +2032,85 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) return 0; } +int tmc_read_prepare_byte_cntr(struct tmc_drvdata *drvdata, + struct ctcu_byte_cntr *byte_cntr_data) +{ + unsigned long flags; + int ret = 0; + + /* config types are set a boot time and never change */ + if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) + return -EINVAL; + + if (coresight_get_mode(drvdata->csdev) != CS_MODE_SYSFS) + return -EINVAL; + + /* + * The threshold value must not exceed the buffer size. + * A margin should be maintained between the two values to account + * for the time gap between the interrupt and buffer switching. + */ + if (byte_cntr_data->thresh_val + SZ_16K >= drvdata->size) { + dev_err(&drvdata->csdev->dev, "The threshold value is too large\n"); + return -EINVAL; + } + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + if (byte_cntr_data->reading) { + ret = -EBUSY; + goto out_unlock; + } + + byte_cntr_data->reading = true; + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + /* Insert current sysfs_buf into the list */ + ret = tmc_create_etr_buf_node(drvdata, drvdata->sysfs_buf); + if (!ret) { + /* + * Add one more sysfs_buf for byte-cntr function, byte-cntr always reads + * the data from the buffer which has been synced. Switch the buffer when + * the used buffer is nearly full. The used buffer will be synced and made + * available for reading before switch. + */ + ret = tmc_create_etr_buf_node(drvdata, NULL); + if (ret) { + dev_err(&drvdata->csdev->dev, "Failed to create etr_buf_node\n"); + tmc_delete_etr_buf_node(drvdata); + byte_cntr_data->reading = false; + goto out; + } + } + + raw_spin_lock_irqsave(&drvdata->spinlock, flags); + atomic_set(&byte_cntr_data->irq_cnt, 0); + enable_irq(byte_cntr_data->byte_cntr_irq); + enable_irq_wake(byte_cntr_data->byte_cntr_irq); + byte_cntr_data->total_size = 0; + byte_cntr_data->irq_num = 0; + +out_unlock: + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); + +out: + return ret; +} + +int tmc_read_unprepare_byte_cntr(struct tmc_drvdata *drvdata, + struct ctcu_byte_cntr *byte_cntr_data) +{ + struct device *dev = &drvdata->csdev->dev; + + guard(raw_spinlock_irqsave)(&byte_cntr_data->spin_lock); + disable_irq_wake(byte_cntr_data->byte_cntr_irq); + disable_irq(byte_cntr_data->byte_cntr_irq); + byte_cntr_data->reading = false; + tmc_delete_etr_buf_node(drvdata); + dev_dbg(dev, "send data total size:%llu bytes, irq_cnt:%d\n", + byte_cntr_data->total_size, byte_cntr_data->irq_num); + + return 0; +} + static const char *const buf_modes_str[] = { [ETR_MODE_FLAT] = "flat", [ETR_MODE_ETR_SG] = "tmc-sg",
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index f6b05639aeca..f95df0a34ad6 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h@@ -14,6 +14,8 @@ #include <linux/refcount.h> #include <linux/crc32.h> +#include "coresight-ctcu.h" + #define TMC_RSZ 0x004 #define TMC_STS 0x00c #define TMC_RRD 0x010
@@ -357,6 +359,12 @@ extern const struct coresight_ops tmc_etr_cs_ops; ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len, char **bufpp); +/* Byte-cntr functions */ +int tmc_read_prepare_byte_cntr(struct tmc_drvdata *drvdata, + struct ctcu_byte_cntr *byte_cntr_data); +int tmc_read_unprepare_byte_cntr(struct tmc_drvdata *drvdata, + struct ctcu_byte_cntr *byte_cntr_data); + #define TMC_REG_PAIR(name, lo_off, hi_off) \ static inline u64 \
--
2.34.1