[PATCH 3/3] accel/amdxdna: flush only the requested range in amdxdna_flush_bo

From: Taimuraz Kaitmazov

Date: Tue Aug 11 2026 - 16:49:26 EST


SYNC_BO carries an offset and a size, but amdxdna_flush_bo() honours
them only on the vmap path: an imported BO is tested for first and
flushes its whole scatterlist, and the page-array fallback flushes every
page of the BO. A sync costs what the BO is worth rather than what the
caller asked to maintain.

amdxdna_gem_obj_vmap() maps an imported BO through dma_buf_vmap(), so
try the vmap path first and leave drm_clflush_sg() as the fallback for
an exporter that cannot serve one. Index the page-array fallback from
the requested offset. An imported BO now holds a kernel mapping from its
first sync until it is freed, as a shmem BO already does.

Measured on npu4, 64 MiB BO, pinned, minimum of 50 runs: an imported BO
cost 1056 us to sync at every size from 4 KiB up, and now tracks the
driver-owned BO at 0.7 us for 4 KiB, 17 us for 1 MiB and 1056 us for the
whole BO. The driver-owned column does not move.

An earlier version walked the scatterlist a page at a time instead. It
fixed the range case but cost about 179 ns per page of barrier and call
overhead, taking the whole-BO sync from 1056 to 3989 us, so this one
reuses the mapping instead.

This does not bracket the flush with dma_buf_begin_cpu_access() and
dma_buf_end_cpu_access(). The driver has never called them, here or
anywhere else, so the omission predates this change; what changes is that
the vmap path now serves an imported BO by default, which is where the
exporter's own coherency hook would matter most. Adding the bracket is
follow-up work rather than part of this one: the calls carry a direction
but no range, so pairing them with a ranged flush wants its own reasoning
and its own measurement.

Signed-off-by: Taimuraz Kaitmazov <taimuraz@xxxxxxxxxxxxx>
---
drivers/accel/amdxdna/amdxdna_gem.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
index d0c846b02..4886f7c08 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.c
+++ b/drivers/accel/amdxdna/amdxdna_gem.c
@@ -1234,6 +1234,8 @@ int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm

static int amdxdna_flush_bo(struct amdxdna_gem_obj *abo, u64 offset, u64 size)
{
+ unsigned long first, nr_pages;
+ void *kva;
u64 end;

if (offset >= abo->mem.size)
@@ -1243,12 +1245,16 @@ static int amdxdna_flush_bo(struct amdxdna_gem_obj *abo, u64 offset, u64 size)
return -EINVAL;

size = min(abo->mem.size, end) - offset;
- if (is_import_bo(abo))
+ first = offset >> PAGE_SHIFT;
+ nr_pages = (PAGE_ALIGN(offset + size) >> PAGE_SHIFT) - first;
+
+ kva = __amdxdna_gem_vmap(abo);
+ if (!IS_ERR(kva))
+ drm_clflush_virt_range(kva + offset, size);
+ else if (is_import_bo(abo))
drm_clflush_sg(abo->base.sgt);
- else if (amdxdna_gem_vmap(abo))
- drm_clflush_virt_range(amdxdna_gem_vmap(abo) + offset, size);
else if (abo->base.pages)
- drm_clflush_pages(abo->base.pages, abo->mem.size >> PAGE_SHIFT);
+ drm_clflush_pages(&abo->base.pages[first], nr_pages);
else
return -EINVAL;

--
2.55.0