Introduce functions for creating and inserting or removing the
etr_buf_node to/from the etr_buf_list.
The byte-cntr functionality requires two etr_buf to receive trace data.
The active etr_buf collects the trace data from source device, while the
byte-cntr reading function accesses the deactivated etr_buf after is
has been filled and synced, transferring data to the userspace.
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: Jie Gan <jie.gan@oss.qualcomm.com>
---
drivers/hwtracing/coresight/coresight-tmc-core.c | 1 +
drivers/hwtracing/coresight/coresight-tmc-etr.c | 108 +++++++++++++++++++++++
drivers/hwtracing/coresight/coresight-tmc.h | 17 ++++
3 files changed, 126 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index c89fe996af23..bac3278ef4dd 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -835,6 +835,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
idr_init(&drvdata->idr);
mutex_init(&drvdata->idr_mutex);
dev_list = "tmc_etr";
+ INIT_LIST_HEAD(&drvdata->etr_buf_list);
break;
case TMC_CONFIG_TYPE_ETF:
desc.groups = coresight_etf_groups;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 4dc1defe27a5..fdf23e1c932f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1918,6 +1918,114 @@ const struct coresight_ops tmc_etr_cs_ops = {
.panic_ops = &tmc_etr_sync_ops,
};
+/**
+ * tmc_clean_etr_buf_list - clean the etr_buf_list.
+ * @drvdata: driver data of the TMC device.
+ *
+ * Remove unused buffers from @drvdata->etr_buf_list and free them.
+ */
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
+{
+ struct etr_buf_node *nd, *next;
+ unsigned long flags;
+
+ lockdep_assert_held(&drvdata->spinlock);
+ list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, link) {
+ if (nd->sysfs_buf == drvdata->sysfs_buf) {
+ if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED) {
+ /*
+ * Dont free the sysfs_buf, just remove it from list.
+ * drvdata->sysfs_buf will hold the buffer and free it later.
+ */
+ nd->sysfs_buf = NULL;
+ list_del(&nd->link);
+ kfree(nd);
+ continue;
+ }
+ }
+ /* Free allocated buffers which are not utilized by ETR */
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ tmc_etr_free_sysfs_buf(nd->sysfs_buf);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ drvdata->sysfs_buf = NULL;
+ nd->sysfs_buf = NULL;
+ list_del(&nd->link);
+ kfree(nd);
+ }
+}
+EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
+
+/**
+ * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
+ * @drvdata: driver data of the TMC device.
+ * @num_nodes: number of nodes want to create with the list.
+ *
+ * Return 0 upon success and return the error number if fail.
+ */
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
+{
+ struct etr_buf_node *new_node;
+ struct etr_buf *sysfs_buf;
+ unsigned long flags;
+ int i = 0, ret = 0;
+
+ lockdep_assert_held(&drvdata->spinlock);
+ /* We dont need a list if there is only one node */
+ if (num_nodes < 2)
+ return -EINVAL;
+
+ /* We expect that sysfs_buf in drvdata has already been allocated. */
+ if (drvdata->sysfs_buf) {
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ /* Directly insert the allocated sysfs_buf into the list first */
+ new_node = kzalloc_obj(*new_node, GFP_KERNEL);
+ if (IS_ERR(new_node))
+ return PTR_ERR(new_node);
+
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ new_node->sysfs_buf = drvdata->sysfs_buf;
+ new_node->is_free = false;
+ list_add(&new_node->link, &drvdata->etr_buf_list);
+ i++;
+ }
+
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ while (i < num_nodes) {
+ new_node = kzalloc_obj(*new_node, GFP_KERNEL);
+ if (IS_ERR(new_node)) {
+ ret = PTR_ERR(new_node);
+ break;
+ }
+
+ sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
+ if (IS_ERR(sysfs_buf)) {
+ kfree(new_node);
+ ret = PTR_ERR(sysfs_buf);
+ break;
+ }
+
+ /* We dont have a available sysfs_buf in drvdata, setup one */
+ if (!drvdata->sysfs_buf) {
+ drvdata->sysfs_buf = sysfs_buf;
+ new_node->is_free = false;
+ } else
+ new_node->is_free = true;
+
+ new_node->sysfs_buf = sysfs_buf;
+ list_add(&new_node->link, &drvdata->etr_buf_list);
+ i++;
+ }
+
+ /* Clean the list if there is an error */
+ if (ret)
+ tmc_clean_etr_buf_list(drvdata);
+
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
+
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
{
int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 319a354ede9f..81237944b986 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -208,6 +208,19 @@ struct tmc_resrv_buf {
s64 len;
};
+/**
+ * @sysfs_buf: Allocated sysfs_buf.
+ * @is_free: Indicates whether the buffer is free to choose.
+ * @pos: Position of the buffer.
+ * @link: list_head of the node.
+ */
+struct etr_buf_node {
+ struct etr_buf *sysfs_buf;
+ bool is_free;
+ loff_t pos;
+ struct list_head link;
+};
+
/**
* struct tmc_drvdata - specifics associated to an TMC component
* @atclk: optional clock for the core parts of the TMC.
@@ -245,6 +258,7 @@ struct tmc_resrv_buf {
* (after crash) by default.
* @crash_mdata: Reserved memory for storing tmc crash metadata.
* Used by ETR/ETF.
+ * @etr_buf_list: List that is used to manage allocated etr_buf.
*/
struct tmc_drvdata {
struct clk *atclk;
@@ -275,6 +289,7 @@ struct tmc_drvdata {
struct etr_buf *perf_buf;
struct tmc_resrv_buf resrv_buf;
struct tmc_resrv_buf crash_mdata;
+ struct list_head etr_buf_list;
};
struct etr_buf_operations {
@@ -447,5 +462,7 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
enum cs_mode mode,
struct coresight_path *path);
extern const struct attribute_group coresight_etr_group;
+void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
+int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
#endif
--
2.34.1
On 13/03/2026 09:02, Jie Gan wrote:
> Introduce functions for creating and inserting or removing the
> etr_buf_node to/from the etr_buf_list.
>
> The byte-cntr functionality requires two etr_buf to receive trace data.
> The active etr_buf collects the trace data from source device, while the
> byte-cntr reading function accesses the deactivated etr_buf after is
> has been filled and synced, transferring data to the userspace.
>
> Reviewed-by: Mike Leach <mike.leach@linaro.org>
> Signed-off-by: Jie Gan <jie.gan@oss.qualcomm.com>
> ---
> drivers/hwtracing/coresight/coresight-tmc-core.c | 1 +
> drivers/hwtracing/coresight/coresight-tmc-etr.c | 108 +++++++++++++++++++++++
> drivers/hwtracing/coresight/coresight-tmc.h | 17 ++++
> 3 files changed, 126 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
> index c89fe996af23..bac3278ef4dd 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-core.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
> @@ -835,6 +835,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
> idr_init(&drvdata->idr);
> mutex_init(&drvdata->idr_mutex);
> dev_list = "tmc_etr";
> + INIT_LIST_HEAD(&drvdata->etr_buf_list);
> break;
> case TMC_CONFIG_TYPE_ETF:
> desc.groups = coresight_etf_groups;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 4dc1defe27a5..fdf23e1c932f 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1918,6 +1918,114 @@ const struct coresight_ops tmc_etr_cs_ops = {
> .panic_ops = &tmc_etr_sync_ops,
> };
>
> +/**
> + * tmc_clean_etr_buf_list - clean the etr_buf_list.
> + * @drvdata: driver data of the TMC device.
> + *
> + * Remove unused buffers from @drvdata->etr_buf_list and free them.
> + */
> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
> +{
> + struct etr_buf_node *nd, *next;
> + unsigned long flags;
> +
> + lockdep_assert_held(&drvdata->spinlock);
> + list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, link) {
> + if (nd->sysfs_buf == drvdata->sysfs_buf) {
> + if (coresight_get_mode(drvdata->csdev) != CS_MODE_DISABLED) {
> + /*
> + * Dont free the sysfs_buf, just remove it from list.
> + * drvdata->sysfs_buf will hold the buffer and free it later.
> + */
> + nd->sysfs_buf = NULL;
> + list_del(&nd->link);
> + kfree(nd);
> + continue;
> + }
> + }
> + /* Free allocated buffers which are not utilized by ETR */
> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
This is dangerous ! Restoring the irqflags to an uninitialised value
from a different function thant where it was locked. Please clean this up
Suzuki
> + tmc_etr_free_sysfs_buf(nd->sysfs_buf);
> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
> + drvdata->sysfs_buf = NULL;
> + nd->sysfs_buf = NULL;
> + list_del(&nd->link);
> + kfree(nd);
> + }
> +}
> +EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
> +
> +/**
> + * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
> + * @drvdata: driver data of the TMC device.
> + * @num_nodes: number of nodes want to create with the list.
> + *
> + * Return 0 upon success and return the error number if fail.
> + */
> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
> +{
> + struct etr_buf_node *new_node;
> + struct etr_buf *sysfs_buf;
> + unsigned long flags;
> + int i = 0, ret = 0;
> +
> + lockdep_assert_held(&drvdata->spinlock);
> + /* We dont need a list if there is only one node */
> + if (num_nodes < 2)
> + return -EINVAL;
> +
> + /* We expect that sysfs_buf in drvdata has already been allocated. */
> + if (drvdata->sysfs_buf) {
> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
> + /* Directly insert the allocated sysfs_buf into the list first */
> + new_node = kzalloc_obj(*new_node, GFP_KERNEL);
> + if (IS_ERR(new_node))
> + return PTR_ERR(new_node);
> +
> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
> + new_node->sysfs_buf = drvdata->sysfs_buf;
> + new_node->is_free = false;
> + list_add(&new_node->link, &drvdata->etr_buf_list);
> + i++;
> + }
> +
> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
> + while (i < num_nodes) {
> + new_node = kzalloc_obj(*new_node, GFP_KERNEL);
> + if (IS_ERR(new_node)) {
> + ret = PTR_ERR(new_node);
> + break;
> + }
> +
> + sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
> + if (IS_ERR(sysfs_buf)) {
> + kfree(new_node);
> + ret = PTR_ERR(sysfs_buf);
> + break;
> + }
> +
> + /* We dont have a available sysfs_buf in drvdata, setup one */
> + if (!drvdata->sysfs_buf) {
> + drvdata->sysfs_buf = sysfs_buf;
> + new_node->is_free = false;
> + } else
> + new_node->is_free = true;
> +
> + new_node->sysfs_buf = sysfs_buf;
> + list_add(&new_node->link, &drvdata->etr_buf_list);
> + i++;
> + }
> +
> + /* Clean the list if there is an error */
> + if (ret)
> + tmc_clean_etr_buf_list(drvdata);
> +
> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
> +
> int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
> {
> int ret = 0;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 319a354ede9f..81237944b986 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -208,6 +208,19 @@ struct tmc_resrv_buf {
> s64 len;
> };
>
> +/**
> + * @sysfs_buf: Allocated sysfs_buf.
> + * @is_free: Indicates whether the buffer is free to choose.
> + * @pos: Position of the buffer.
> + * @link: list_head of the node.
> + */
> +struct etr_buf_node {
> + struct etr_buf *sysfs_buf;
> + bool is_free;
> + loff_t pos;
> + struct list_head link;
> +};
> +
> /**
> * struct tmc_drvdata - specifics associated to an TMC component
> * @atclk: optional clock for the core parts of the TMC.
> @@ -245,6 +258,7 @@ struct tmc_resrv_buf {
> * (after crash) by default.
> * @crash_mdata: Reserved memory for storing tmc crash metadata.
> * Used by ETR/ETF.
> + * @etr_buf_list: List that is used to manage allocated etr_buf.
> */
> struct tmc_drvdata {
> struct clk *atclk;
> @@ -275,6 +289,7 @@ struct tmc_drvdata {
> struct etr_buf *perf_buf;
> struct tmc_resrv_buf resrv_buf;
> struct tmc_resrv_buf crash_mdata;
> + struct list_head etr_buf_list;
> };
>
> struct etr_buf_operations {
> @@ -447,5 +462,7 @@ struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
> enum cs_mode mode,
> struct coresight_path *path);
> extern const struct attribute_group coresight_etr_group;
> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
>
> #endif
>
On 3/17/2026 7:01 PM, Suzuki K Poulose wrote:
> On 13/03/2026 09:02, Jie Gan wrote:
>> Introduce functions for creating and inserting or removing the
>> etr_buf_node to/from the etr_buf_list.
>>
>> The byte-cntr functionality requires two etr_buf to receive trace data.
>> The active etr_buf collects the trace data from source device, while the
>> byte-cntr reading function accesses the deactivated etr_buf after is
>> has been filled and synced, transferring data to the userspace.
>>
>> Reviewed-by: Mike Leach <mike.leach@linaro.org>
>> Signed-off-by: Jie Gan <jie.gan@oss.qualcomm.com>
>> ---
>> drivers/hwtracing/coresight/coresight-tmc-core.c | 1 +
>> drivers/hwtracing/coresight/coresight-tmc-etr.c | 108 +++++++++++++
>> ++++++++++
>> drivers/hwtracing/coresight/coresight-tmc.h | 17 ++++
>> 3 files changed, 126 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/
>> drivers/hwtracing/coresight/coresight-tmc-core.c
>> index c89fe996af23..bac3278ef4dd 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
>> @@ -835,6 +835,7 @@ static int __tmc_probe(struct device *dev, struct
>> resource *res)
>> idr_init(&drvdata->idr);
>> mutex_init(&drvdata->idr_mutex);
>> dev_list = "tmc_etr";
>> + INIT_LIST_HEAD(&drvdata->etr_buf_list);
>> break;
>> case TMC_CONFIG_TYPE_ETF:
>> desc.groups = coresight_etf_groups;
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 4dc1defe27a5..fdf23e1c932f 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -1918,6 +1918,114 @@ const struct coresight_ops tmc_etr_cs_ops = {
>> .panic_ops = &tmc_etr_sync_ops,
>> };
>> +/**
>> + * tmc_clean_etr_buf_list - clean the etr_buf_list.
>> + * @drvdata: driver data of the TMC device.
>> + *
>> + * Remove unused buffers from @drvdata->etr_buf_list and free them.
>> + */
>> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata)
>> +{
>> + struct etr_buf_node *nd, *next;
>> + unsigned long flags;
>> +
>> + lockdep_assert_held(&drvdata->spinlock);
>> + list_for_each_entry_safe(nd, next, &drvdata->etr_buf_list, link) {
>> + if (nd->sysfs_buf == drvdata->sysfs_buf) {
>> + if (coresight_get_mode(drvdata->csdev) !=
>> CS_MODE_DISABLED) {
>> + /*
>> + * Dont free the sysfs_buf, just remove it from list.
>> + * drvdata->sysfs_buf will hold the buffer and free
>> it later.
>> + */
>> + nd->sysfs_buf = NULL;
>> + list_del(&nd->link);
>> + kfree(nd);
>> + continue;
>> + }
>> + }
>> + /* Free allocated buffers which are not utilized by ETR */
>> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> This is dangerous ! Restoring the irqflags to an uninitialised value
> from a different function thant where it was locked. Please clean this up
>
Noted, will take care of it in the future.
Thanks,
Jie
> Suzuki
>
>
>> + tmc_etr_free_sysfs_buf(nd->sysfs_buf);
>> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>> + drvdata->sysfs_buf = NULL;
>> + nd->sysfs_buf = NULL;
>> + list_del(&nd->link);
>> + kfree(nd);
>> + }
>> +}
>> +EXPORT_SYMBOL_GPL(tmc_clean_etr_buf_list);
>> +
>> +/**
>> + * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
>> + * @drvdata: driver data of the TMC device.
>> + * @num_nodes: number of nodes want to create with the list.
>> + *
>> + * Return 0 upon success and return the error number if fail.
>> + */
>> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
>> +{
>> + struct etr_buf_node *new_node;
>> + struct etr_buf *sysfs_buf;
>> + unsigned long flags;
>> + int i = 0, ret = 0;
>> +
>> + lockdep_assert_held(&drvdata->spinlock);
>> + /* We dont need a list if there is only one node */
>> + if (num_nodes < 2)
>> + return -EINVAL;
>> +
>> + /* We expect that sysfs_buf in drvdata has already been
>> allocated. */
>> + if (drvdata->sysfs_buf) {
>> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> + /* Directly insert the allocated sysfs_buf into the list
>> first */
>> + new_node = kzalloc_obj(*new_node, GFP_KERNEL);
>> + if (IS_ERR(new_node))
>> + return PTR_ERR(new_node);
>> +
>> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>> + new_node->sysfs_buf = drvdata->sysfs_buf;
>> + new_node->is_free = false;
>> + list_add(&new_node->link, &drvdata->etr_buf_list);
>> + i++;
>> + }
>> +
>> + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> + while (i < num_nodes) {
>> + new_node = kzalloc_obj(*new_node, GFP_KERNEL);
>> + if (IS_ERR(new_node)) {
>> + ret = PTR_ERR(new_node);
>> + break;
>> + }
>> +
>> + sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0,
>> cpu_to_node(0), NULL);
>> + if (IS_ERR(sysfs_buf)) {
>> + kfree(new_node);
>> + ret = PTR_ERR(sysfs_buf);
>> + break;
>> + }
>> +
>> + /* We dont have a available sysfs_buf in drvdata, setup one */
>> + if (!drvdata->sysfs_buf) {
>> + drvdata->sysfs_buf = sysfs_buf;
>> + new_node->is_free = false;
>> + } else
>> + new_node->is_free = true;
>> +
>> + new_node->sysfs_buf = sysfs_buf;
>> + list_add(&new_node->link, &drvdata->etr_buf_list);
>> + i++;
>> + }
>> +
>> + /* Clean the list if there is an error */
>> + if (ret)
>> + tmc_clean_etr_buf_list(drvdata);
>> +
>> + raw_spin_lock_irqsave(&drvdata->spinlock, flags);
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
>> +
>> int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>> {
>> int ret = 0;
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/
>> hwtracing/coresight/coresight-tmc.h
>> index 319a354ede9f..81237944b986 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>> @@ -208,6 +208,19 @@ struct tmc_resrv_buf {
>> s64 len;
>> };
>> +/**
>> + * @sysfs_buf: Allocated sysfs_buf.
>> + * @is_free: Indicates whether the buffer is free to choose.
>> + * @pos: Position of the buffer.
>> + * @link: list_head of the node.
>> + */
>> +struct etr_buf_node {
>> + struct etr_buf *sysfs_buf;
>> + bool is_free;
>> + loff_t pos;
>> + struct list_head link;
>> +};
>> +
>> /**
>> * struct tmc_drvdata - specifics associated to an TMC component
>> * @atclk: optional clock for the core parts of the TMC.
>> @@ -245,6 +258,7 @@ struct tmc_resrv_buf {
>> * (after crash) by default.
>> * @crash_mdata: Reserved memory for storing tmc crash metadata.
>> * Used by ETR/ETF.
>> + * @etr_buf_list: List that is used to manage allocated etr_buf.
>> */
>> struct tmc_drvdata {
>> struct clk *atclk;
>> @@ -275,6 +289,7 @@ struct tmc_drvdata {
>> struct etr_buf *perf_buf;
>> struct tmc_resrv_buf resrv_buf;
>> struct tmc_resrv_buf crash_mdata;
>> + struct list_head etr_buf_list;
>> };
>> struct etr_buf_operations {
>> @@ -447,5 +462,7 @@ struct etr_buf *tmc_etr_get_buffer(struct
>> coresight_device *csdev,
>> enum cs_mode mode,
>> struct coresight_path *path);
>> extern const struct attribute_group coresight_etr_group;
>> +void tmc_clean_etr_buf_list(struct tmc_drvdata *drvdata);
>> +int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes);
>> #endif
>>
>
>
Hi Jie,
kernel test robot noticed the following build warnings:
[auto build test WARNING on a0ae2a256046c0c5d3778d1a194ff2e171f16e5f]
url: https://github.com/intel-lab-lkp/linux/commits/Jie-Gan/coresight-core-refactor-ctcu_get_active_port-and-make-it-generic/20260315-052703
base: a0ae2a256046c0c5d3778d1a194ff2e171f16e5f
patch link: https://lore.kernel.org/r/20260313-enable-byte-cntr-for-ctcu-v15-2-1777f14ed319%40oss.qualcomm.com
patch subject: [PATCH v15 2/7] coresight: tmc: add create/clean functions for etr_buf_list
config: arm64-allmodconfig (https://download.01.org/0day-ci/archive/20260317/202603171518.XQOgdjNN-lkp@intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260317/202603171518.XQOgdjNN-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603171518.XQOgdjNN-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/hwtracing/coresight/coresight-tmc-etr.c:1979:50: warning: variable 'flags' is uninitialized when used here [-Wuninitialized]
1979 | raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
| ^~~~~
include/linux/spinlock.h:283:37: note: expanded from macro 'raw_spin_unlock_irqrestore'
283 | _raw_spin_unlock_irqrestore(lock, flags); \
| ^~~~~
drivers/hwtracing/coresight/coresight-tmc-etr.c:1969:21: note: initialize the variable 'flags' to silence this warning
1969 | unsigned long flags;
| ^
| = 0
1 warning generated.
vim +/flags +1979 drivers/hwtracing/coresight/coresight-tmc-etr.c
1957
1958 /**
1959 * tmc_create_etr_buf_list - create a list to manage the etr_buf_node.
1960 * @drvdata: driver data of the TMC device.
1961 * @num_nodes: number of nodes want to create with the list.
1962 *
1963 * Return 0 upon success and return the error number if fail.
1964 */
1965 int tmc_create_etr_buf_list(struct tmc_drvdata *drvdata, int num_nodes)
1966 {
1967 struct etr_buf_node *new_node;
1968 struct etr_buf *sysfs_buf;
1969 unsigned long flags;
1970 int i = 0, ret = 0;
1971
1972 lockdep_assert_held(&drvdata->spinlock);
1973 /* We dont need a list if there is only one node */
1974 if (num_nodes < 2)
1975 return -EINVAL;
1976
1977 /* We expect that sysfs_buf in drvdata has already been allocated. */
1978 if (drvdata->sysfs_buf) {
> 1979 raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
1980 /* Directly insert the allocated sysfs_buf into the list first */
1981 new_node = kzalloc_obj(*new_node, GFP_KERNEL);
1982 if (IS_ERR(new_node))
1983 return PTR_ERR(new_node);
1984
1985 raw_spin_lock_irqsave(&drvdata->spinlock, flags);
1986 new_node->sysfs_buf = drvdata->sysfs_buf;
1987 new_node->is_free = false;
1988 list_add(&new_node->link, &drvdata->etr_buf_list);
1989 i++;
1990 }
1991
1992 raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
1993 while (i < num_nodes) {
1994 new_node = kzalloc_obj(*new_node, GFP_KERNEL);
1995 if (IS_ERR(new_node)) {
1996 ret = PTR_ERR(new_node);
1997 break;
1998 }
1999
2000 sysfs_buf = tmc_alloc_etr_buf(drvdata, drvdata->size, 0, cpu_to_node(0), NULL);
2001 if (IS_ERR(sysfs_buf)) {
2002 kfree(new_node);
2003 ret = PTR_ERR(sysfs_buf);
2004 break;
2005 }
2006
2007 /* We dont have a available sysfs_buf in drvdata, setup one */
2008 if (!drvdata->sysfs_buf) {
2009 drvdata->sysfs_buf = sysfs_buf;
2010 new_node->is_free = false;
2011 } else
2012 new_node->is_free = true;
2013
2014 new_node->sysfs_buf = sysfs_buf;
2015 list_add(&new_node->link, &drvdata->etr_buf_list);
2016 i++;
2017 }
2018
2019 /* Clean the list if there is an error */
2020 if (ret)
2021 tmc_clean_etr_buf_list(drvdata);
2022
2023 raw_spin_lock_irqsave(&drvdata->spinlock, flags);
2024
2025 return ret;
2026 }
2027 EXPORT_SYMBOL_GPL(tmc_create_etr_buf_list);
2028
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.