* [PATCH 0/1] coresight: tmc-etr: Sync the trace buffer for the device @ 2026-09-15 13:05 NoNine 2026-09-15 13:05 ` [PATCH 1/1] " NoNine 0 siblings, 1 reply; 3+ messages in thread From: NoNine @ 2026-09-15 13:05 UTC (permalink / raw) To: suzuki.poulose Cc: mike.leach, james.clark, alexander.shishkin, coresight, linux-arm-kernel, linux-kernel, Min Chen From: Min Chen <min.chen@siengine.com> The flat ETR trace buffer is allocated with dma_alloc_noncoherent(), which reaches dma_alloc_pages(). That API zeroes the buffer with CPU stores and requires the caller to sync the memory for the device before the device writes into it. The TMC driver only ever syncs for the CPU afterwards, so a non-coherent sink is handed a buffer whose zero fill is still dirty in cache. On an AD1000 EVB this shows up as 64-byte-aligned runs of all-zero formatter frames in the first window of a freshly allocated buffer (1,100-2,400 runs in the leading ~4 MiB; later windows and reused buffers are clean). Writing a known pattern over the buffer before the arm and cleaning it removes every run, which pins the loss to the buffer hand-over. The ETR node is not marked dma-coherent. The patch adds a sync_for_device() buffer operation, implemented by the flat buffer, and calls it from __tmc_etr_enable_hw() before the TMC is enabled. It is intentionally flat-only: the ETR_SG and CATU data pages are allocated and immediately dma_map_page()d, so the map performs the architecture's for-device maintenance for the first hand-over. Their one remaining corner case - a barrier packet written into a full buffer before a live drain re-arms the same buffer - has no reproducer here and is left out. Tested on the AD1000 EVB: five first windows on freshly allocated buffers, including the first capture of a boot, carry no all-zero-frame runs and show the ordinary clean-stream profile (2.851% zero bytes), against 1,141-2,360 runs for the same measurement without the change. The patch was rebased onto the Coresight for-next/queue tip 5442d22da7db and builds with arm64 defconfig (Image and modules, no warnings or errors). The hardware run used the vendor 6.6.87 tree; the rebase carries the same change. Min Chen (1): coresight: tmc-etr: Sync the trace buffer for the device .../hwtracing/coresight/coresight-tmc-etr.c | 29 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tmc.h | 1 + 2 files changed, 30 insertions(+) -- 2.34.1 ^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/1] coresight: tmc-etr: Sync the trace buffer for the device 2026-09-15 13:05 [PATCH 0/1] coresight: tmc-etr: Sync the trace buffer for the device NoNine @ 2026-09-15 13:05 ` NoNine 2026-09-16 3:04 ` Jie Gan 0 siblings, 1 reply; 3+ messages in thread From: NoNine @ 2026-09-15 13:05 UTC (permalink / raw) To: suzuki.poulose Cc: mike.leach, james.clark, alexander.shishkin, coresight, linux-arm-kernel, linux-kernel, Min Chen From: Min Chen <min.chen@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. 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@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); 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); -- 2.34.1 ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 1/1] coresight: tmc-etr: Sync the trace buffer for the device 2026-09-15 13:05 ` [PATCH 1/1] " NoNine @ 2026-09-16 3:04 ` Jie Gan 0 siblings, 0 replies; 3+ messages in thread From: Jie Gan @ 2026-09-16 3:04 UTC (permalink / raw) To: NoNine, suzuki.poulose Cc: mike.leach, james.clark, alexander.shishkin, coresight, linux-arm-kernel, linux-kernel, Min Chen Hi, On 9/15/2026 9:05 PM, NoNine wrote: > From: Min Chen <min.chen@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@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); ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-16 3:04 UTC | newest] Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-15 13:05 [PATCH 0/1] coresight: tmc-etr: Sync the trace buffer for the device NoNine 2026-09-15 13:05 ` [PATCH 1/1] " NoNine 2026-09-16 3:04 ` Jie Gan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®