[PATCH 1/1] coresight: tmc-etr: Sync the trace buffer for the device

Jie Gan jie.gan at oss.qualcomm.com
Tue Sep 15 20:04:20 PDT 2026


Hi,

On 9/15/2026 9:05 PM, NoNine wrote:
> From: Min Chen <min.chen at siengine.com>
> 
> The flat ETR buffer comes from dma_alloc_noncoherent(), which zeroes it
> with CPU stores.  The DMA API requires the caller to sync the buffer for
> the device before the device writes into it, but the TMC driver only
> ever syncs for the CPU afterwards.  On a non-coherent sink the zero fill
> is therefore still dirty in cache when the ETR starts writing, and its
> write-back lands on top of the trace data.
> 

Agree, without the sync, the dirty data may overwrites the trace data.

> Add a sync_for_device() buffer operation and call it from
> __tmc_etr_enable_hw() just before the TMC is enabled.  Only the flat
> buffer implements it.  The ETR_SG and CATU data pages are synced by
> dma_map_page() when they are allocated; their remaining corner case, a
> barrier packet followed by a live-drain re-arm, is left for a separate
> change.
> 
> Tested on an AD1000 EVB: five first windows on freshly allocated
> buffers, including the first capture of a boot, all without the
> previous all-zero-formatter-frame runs.
> 
> Signed-off-by: Min Chen <min.chen at siengine.com>
> ---
>   .../hwtracing/coresight/coresight-tmc-etr.c   | 29 +++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tmc.h   |  1 +
>   2 files changed, 30 insertions(+)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 76a8cb2..bf1d6c6 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -689,10 +689,29 @@ static ssize_t tmc_etr_get_data_flat_buf(struct etr_buf *etr_buf,
>   	return len;
>   }
>   
> +/*
> + * tmc_etr_sync_flat_buf_for_device: Drop any CPU cache lines over the trace
> + * buffer before the ETR is allowed to write into it.  The buffer is allocated
> + * with dma_alloc_noncoherent(), which zeroes it with CPU stores, and the DMA
> + * API requires a sync for the device before the device writes into the
> + * memory.  Without it a non-coherent sink writes into memory while the zero
> + * fill is still dirty in cache, and the write-back lands on top of the trace
> + * data.
> + */
> +static void tmc_etr_sync_flat_buf_for_device(struct etr_buf *etr_buf)
> +{
> +	struct etr_flat_buf *flat_buf = etr_buf->private;
> +	struct device *real_dev = flat_buf->dev->parent;
> +
> +	dma_sync_single_for_device(real_dev, flat_buf->daddr, etr_buf->size,
> +				   DMA_FROM_DEVICE);
> +}
> +
>   static const struct etr_buf_operations etr_flat_buf_ops = {
>   	.alloc = tmc_etr_alloc_flat_buf,
>   	.free = tmc_etr_free_flat_buf,
>   	.sync = tmc_etr_sync_flat_buf,
> +	.sync_for_device = tmc_etr_sync_flat_buf_for_device,
>   	.get_data = tmc_etr_get_data_flat_buf,
>   };
>   
> @@ -1113,6 +1132,16 @@ static int __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
>   	writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
>   
>   	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
> +
> +	/*
> +	 * Hand the buffer over in a state the device can write into: drop
> +	 * any dirty CPU cache lines first, or they get written back over
> +	 * the trace data the ETR produces.  Only the flat buffer needs
> +	 * this; the ETR_SG and CATU data pages are synced by
> +	 * dma_map_page() when they are allocated.
> +	 */
> +	if (etr_buf->ops->sync_for_device)
> +		etr_buf->ops->sync_for_device(etr_buf);

Can we add a condition to perform the synchronization only when flat_buf 
mode is enabled, instead of introducing a new operation that is required 
only for flat_buf mode?

if (etr_buf->mode == ETR_MODE_FLAT)
	tmc_etr_sync_flat_buf_for_device(etr_buf);

Thanks,
Jie

>   	tmc_enable_hw(drvdata);
>   
>   	CS_LOCK(drvdata->base);
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 6541a27..3dd17da 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -277,6 +277,7 @@ struct etr_buf_operations {
>   	int (*alloc)(struct tmc_drvdata *drvdata, struct etr_buf *etr_buf,
>   		     int node, void **pages);
>   	void (*sync)(struct etr_buf *etr_buf, u64 rrp, u64 rwp);
> +	void (*sync_for_device)(struct etr_buf *etr_buf);
>   	ssize_t (*get_data)(struct etr_buf *etr_buf, u64 offset, size_t len,
>   			    char **bufpp);
>   	void (*free)(struct etr_buf *etr_buf);




More information about the linux-arm-kernel mailing list