From: "Maíra Canal" <mcanal@igalia.com>
To: 이재훈 <dlwognsdc6100@gmail.com>, "Melissa Wen" <mwen@igalia.com>
Cc: Iago Toral Quiroga <itoral@igalia.com>,
dri-devel@lists.freedesktop.org, linux-api@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v2] drm/v3d: add write-back BO mappings and cache sync
Date: Wed, 28 Oct 2026 11:23:08 -0300 [thread overview]
Message-ID: <25e3d341-91d9-4080-8975-a5622b84726f@igalia.com> (raw)
In-Reply-To: <CAE5fF3jr6A=UiC6vMv1q=JM4Fjm1n+eX4xCsRBQycxybk2oWAg@mail.gmail.com>
Hi JaeHoon,
Thanks for your patch. See my comments below:
On 25/10/26 09:09, 이재훈 wrote:
> From: JaeHoon Lee <dlwognsdc610@gmail.com>
>
> Add V3D_BO_WB_MMAP to request WB CPU mappings. Keep WC as the default.
This needs to cover dma-buf export. v3d doesn't implement .export, so a
WB BO gets exported with the generic drm_gem_prime_dmabuf_ops. Those
have no begin_cpu_access/end_cpu_access, so DMA_BUF_IOCTL_SYNC does
nothing and an importer has no way to keep the CPU view coherent.
For example, Panfrost has a custom dma-buf implementation, implemented
in commit 3ae6637378e6 ("drm/panfrost: Provide a custom dma_buf
implementation").
I'm not sure if you tested this implementation, but at the moment, cache
maintaince won't work.
I believe we should invest in a more generic approach that both V3D and
Panfrost can make use of. I just worked on a draft of this
implementation and I'll share the result here in the next few days. Then
you can base your userspace implementation on it.
Best regards,
- Maíra
> Set map_wc before getting the BO pages, and use WB for the kernel mapping
> only when the BO is native and uses WB.
>
> Add V3D_SYNC_BO, based on Panfrost's BO sync API. It takes a list of BO
> ranges and supports cache flush or flush and invalidate. Reject imported
> BOs and invalid ranges or sync types.
>
> Indirect CSD uses a CPU job to read three 32-bit workgroup counts. Sync
> this 12-byte input range before the CPU reads it from a WB BO.
>
> Signed-off-by: JaeHoon Lee <dlwognsdc610@gmail.com>
> Assisted-by: LLM
> ---
> Sorry, the wrong version of the email was sent without my Signed-off-by
> trailer. I also forgot to Cc Iago Toral.
> Please use this version instead.
>
> This is an RFC for the V3DV host-cached memory work. The Mesa changes are
> on this branch:
> https://gitlab.freedesktop.org/yserrr/mesa/-/commits/v3dv-host-cached
>
> V3DV uses WB for native HOST_CACHED memory. Internal BOs, including the
> uniform BO, still use WC. Shared allocations, images and TRANSFER_DST
> buffers also use WC. TRANSFER_DST needs cache sync in the CPU jobs that
> copy query results.
>
> Hardware tests were run on a Raspberry Pi 5 with a backport to
> 6.18.34 and a rebuilt V3DV driver. Native BO creation and
> mapping, sync batches, and checks for invalid inputs passed.
>
> If I have missed anything, please let me know so I can fix it.
>
> Base: drm-misc-next cf61bef3801c3c9d0d8c39026b7b2fb242898a3a
>
>
> drivers/gpu/drm/v3d/v3d_bo.c | 127 ++++++++++++++++++++++++++++++++++++++--
> drivers/gpu/drm/v3d/v3d_drv.c | 1 +
> drivers/gpu/drm/v3d/v3d_drv.h | 3 +
> drivers/gpu/drm/v3d/v3d_sched.c | 16 +++++
> include/uapi/drm/v3d_drm.h | 52 +++++++++++++++-
> 5 files changed, 192 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
> index db95a2fac..1eaa57c64 100644
> --- a/drivers/gpu/drm/v3d/v3d_bo.c
> +++ b/drivers/gpu/drm/v3d/v3d_bo.c
> @@ -16,6 +16,8 @@
> */
>
> #include <linux/dma-buf.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/uaccess.h>
> #include <linux/vmalloc.h>
>
> #include <drm/drm_print.h>
> @@ -147,8 +149,8 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
> return 0;
> }
>
> -struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file
> *file_priv,
> - size_t unaligned_size)
> +static struct v3d_bo *v3d_bo_create_flags(struct drm_device *dev,
> + size_t unaligned_size, u32 flags)
> {
> struct drm_gem_shmem_object *shmem_obj;
> struct v3d_bo *bo;
> @@ -159,6 +161,12 @@ struct v3d_bo *v3d_bo_create(struct drm_device
> *dev, struct drm_file *file_priv,
> return ERR_CAST(shmem_obj);
> bo = to_v3d_bo(&shmem_obj->base);
> bo->vaddr = NULL;
> + /*
> + * Use map_wc=true for WC by default.
> + * V3D_BO_WB_MMAP sets map_wc=false for WB.
> + * WB memory needs explicit cache sync.
> + */
> + bo->base.map_wc = !(flags & V3D_BO_WB_MMAP);
>
> ret = v3d_bo_create_finish(&shmem_obj->base);
> if (ret)
> @@ -171,6 +179,12 @@ struct v3d_bo *v3d_bo_create(struct drm_device
> *dev, struct drm_file *file_priv,
> return ERR_PTR(ret);
> }
>
> +struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file
> *file_priv,
> + size_t unaligned_size)
> +{
> + return v3d_bo_create_flags(dev, unaligned_size, 0);
> +}
> +
> struct drm_gem_object *
> v3d_prime_import_sg_table(struct drm_device *dev,
> struct dma_buf_attachment *attach,
> @@ -195,9 +209,13 @@ v3d_prime_import_sg_table(struct drm_device *dev,
> void v3d_get_bo_vaddr(struct v3d_bo *bo)
> {
> struct drm_gem_shmem_object *obj = &bo->base;
> + pgprot_t prot = pgprot_writecombine(PAGE_KERNEL);
> +
> + if (!drm_gem_is_imported(&obj->base) && !obj->map_wc)
> + prot = PAGE_KERNEL;
>
> bo->vaddr = vmap(obj->pages, obj->base.size >> PAGE_SHIFT, VM_MAP,
> - pgprot_writecombine(PAGE_KERNEL));
> + prot);
> }
>
> void v3d_put_bo_vaddr(struct v3d_bo *bo)
> @@ -213,12 +231,12 @@ int v3d_create_bo_ioctl(struct drm_device *dev,
> void *data,
> struct v3d_bo *bo = NULL;
> int ret;
>
> - if (args->flags != 0) {
> + if (args->flags & ~V3D_BO_WB_MMAP) {
> drm_dbg(dev, "unknown create_bo flags: %d\n", args->flags);
> return -EINVAL;
> }
>
> - bo = v3d_bo_create(dev, file_priv, PAGE_ALIGN(args->size));
> + bo = v3d_bo_create_flags(dev, PAGE_ALIGN(args->size), args->flags);
> if (IS_ERR(bo))
> return PTR_ERR(bo);
>
> @@ -230,6 +248,105 @@ int v3d_create_bo_ioctl(struct drm_device *dev,
> void *data,
> return ret;
> }
>
> +int v3d_bo_sync(struct drm_gem_object *obj, u32 type, u32 offset, u32 size)
> +{
> + struct drm_gem_shmem_object *shmem = &to_v3d_bo(obj)->base;
> + struct sg_table *sgt;
> + struct scatterlist *sg;
> + unsigned int i;
> +
> + if (offset + size < offset)
> + return -EINVAL;
> +
> + if (offset + size > obj->size)
> + return -EINVAL;
> +
> + if (drm_gem_is_imported(obj))
> + return -EINVAL;
> +
> + if (type != V3D_BO_SYNC_CPU_CACHE_FLUSH &&
> + type != V3D_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
> + return -EINVAL;
> +
> + if (shmem->map_wc)
> + return 0;
> +
> + if (!size)
> + return 0;
> +
> + sgt = drm_gem_shmem_get_pages_sgt(shmem);
> + if (IS_ERR(sgt))
> + return PTR_ERR(sgt);
> +
> + for_each_sgtable_dma_sg(sgt, sg, i) {
> + dma_addr_t addr = sg_dma_address(sg);
> + size_t len = sg_dma_len(sg);
> +
> + if (!size)
> + break;
> +
> + if (offset >= len) {
> + offset -= len;
> + continue;
> + }
> +
> + addr += offset;
> + len -= offset;
> + len = min_t(size_t, len, size);
> + size -= len;
> + offset = 0;
> +
> + dma_sync_single_for_device(obj->dev->dev, addr, len,
> DMA_TO_DEVICE);
> + if (type == V3D_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
> + dma_sync_single_for_cpu(obj->dev->dev, addr,
> len, DMA_FROM_DEVICE);
> + }
> +
> + return 0;
> +}
> +
> +int v3d_sync_bo_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct drm_v3d_sync_bo *args = data;
> + struct drm_v3d_bo_sync_op *ops;
> + struct drm_gem_object *obj;
> + unsigned int i;
> + int ret = 0;
> +
> + if (args->pad)
> + return -EINVAL;
> +
> + if (!args->op_count)
> + return 0;
> +
> + ops = kvmalloc_objs(*ops, args->op_count);
> + if (!ops)
> + return -ENOMEM;
> +
> + if (copy_from_user(ops, u64_to_user_ptr(args->ops),
> + args->op_count * sizeof(*ops))) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + for (i = 0; i < args->op_count; i++) {
> + obj = drm_gem_object_lookup(file_priv, ops[i].handle);
> + if (!obj) {
> + ret = -ENOENT;
> + goto out;
> + }
> +
> + ret = v3d_bo_sync(obj, ops[i].type, ops[i].offset, ops[i].size);
> + drm_gem_object_put(obj);
> + if (ret)
> + goto out;
> + }
> +
> +out:
> + kvfree(ops);
> + return ret;
> +}
> +
> int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv)
> {
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
> index 8d914dbc3..0fcf6ceed 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.c
> +++ b/drivers/gpu/drm/v3d/v3d_drv.c
> @@ -264,6 +264,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
> DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl,
> DRM_RENDER_ALLOW | DRM_AUTH),
> DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_COUNTER,
> v3d_perfmon_get_counter_ioctl, DRM_RENDER_ALLOW),
> DRM_IOCTL_DEF_DRV(V3D_PERFMON_SET_GLOBAL,
> v3d_perfmon_set_global_ioctl, DRM_RENDER_ALLOW),
> + DRM_IOCTL_DEF_DRV(V3D_SYNC_BO, v3d_sync_bo_ioctl, DRM_RENDER_ALLOW),
> };
>
> static const struct drm_driver v3d_drm_driver = {
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> index 7c7bdf6e5..d5db64bf5 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> @@ -595,10 +595,13 @@ struct v3d_bo *v3d_bo_create(struct drm_device
> *dev, struct drm_file *file_priv,
> size_t size);
> void v3d_get_bo_vaddr(struct v3d_bo *bo);
> void v3d_put_bo_vaddr(struct v3d_bo *bo);
> +int v3d_bo_sync(struct drm_gem_object *obj, u32 type, u32 offset, u32 size);
> int v3d_create_bo_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv);
> int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv);
> +int v3d_sync_bo_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv);
> int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv);
> int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
> index 1924e3440..17648a913 100644
> --- a/drivers/gpu/drm/v3d/v3d_sched.c
> +++ b/drivers/gpu/drm/v3d/v3d_sched.c
> @@ -396,6 +396,22 @@
> v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
> struct drm_v3d_submit_csd *args = &indirect_csd->job->args;
> struct v3d_dev *v3d = job->base.v3d;
> u32 num_batches, *wg_counts;
> + int ret;
> +
> + /*
> + * WB memory needs cache sync before the CPU reads the three counts.
> + * The GPU job that wrote them must finish first.
> + */
> + if (!drm_gem_is_imported(&bo->base.base)) {
> + ret = v3d_bo_sync(&bo->base.base,
> + V3D_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE,
> + indirect_csd->offset, 3 * sizeof(*wg_counts));
> + if (ret) {
> + dma_fence_set_error(job->base.done_fence, ret);
> +
> dma_fence_set_error(indirect_csd->job->base.done_fence, ret);
> + return;
> + }
> + }
>
> v3d_get_bo_vaddr(bo);
> v3d_get_bo_vaddr(indirect);
> diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h
> index d9b01f4c3..ca7352e96 100644
> --- a/include/uapi/drm/v3d_drm.h
> +++ b/include/uapi/drm/v3d_drm.h
> @@ -44,6 +44,7 @@ extern "C" {
> #define DRM_V3D_SUBMIT_CPU 0x0b
> #define DRM_V3D_PERFMON_GET_COUNTER 0x0c
> #define DRM_V3D_PERFMON_SET_GLOBAL 0x0d
> +#define DRM_V3D_SYNC_BO 0x0e
>
> #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE +
> DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
> #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE +
> DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
> @@ -64,6 +65,8 @@ extern "C" {
> struct
> drm_v3d_perfmon_get_counter)
> #define DRM_IOCTL_V3D_PERFMON_SET_GLOBAL DRM_IOW(DRM_COMMAND_BASE +
> DRM_V3D_PERFMON_SET_GLOBAL, \
> struct
> drm_v3d_perfmon_set_global)
> +#define DRM_IOCTL_V3D_SYNC_BO DRM_IOWR(DRM_COMMAND_BASE +
> DRM_V3D_SYNC_BO, \
> + struct drm_v3d_sync_bo)
>
> #define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
> #define DRM_V3D_SUBMIT_EXTENSION 0x02
> @@ -237,11 +240,13 @@ struct drm_v3d_wait_bo {
> __u64 timeout_ns;
> };
>
> +/* WB BOs require explicit cache sync. */
> +#define V3D_BO_WB_MMAP 4
> +
> /**
> * struct drm_v3d_create_bo - ioctl argument for creating V3D BOs.
> *
> - * There are currently no values for the flags argument, but it may be
> - * used in a future extension.
> + * The flags argument may request V3D_BO_WB_MMAP for a write-back CPU mapping.
> */
> struct drm_v3d_create_bo {
> __u32 size;
> @@ -278,6 +283,49 @@ struct drm_v3d_mmap_bo {
> __u64 offset;
> };
>
> +/* Valid flags to pass to drm_v3d_bo_sync_op */
> +#define V3D_BO_SYNC_CPU_CACHE_FLUSH 0
> +#define V3D_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE 1
> +
> +/**
> + * struct drm_v3d_bo_sync_op - BO map sync op
> + */
> +struct drm_v3d_bo_sync_op {
> + /** Handle of the buffer object to sync. */
> + __u32 handle;
> +
> + /** Type of sync operation. */
> + __u32 type;
> +
> + /**
> + * Offset into the BO at which the sync range starts.
> + *
> + * This will be rounded down to the nearest cache line as needed.
> + */
> + __u32 offset;
> +
> + /**
> + * Size of the range to sync
> + *
> + * size + offset will be rounded up to the nearest cache line as
> + * needed.
> + */
> + __u32 size;
> +};
> +
> +/**
> + * struct drm_v3d_sync_bo - ioctl argument for syncing BO maps
> + */
> +struct drm_v3d_sync_bo {
> + /** Array of struct drm_v3d_bo_sync_op */
> + __u64 ops;
> +
> + /** Number of BO sync ops */
> + __u32 op_count;
> +
> + __u32 pad;
> +};
> +
> enum drm_v3d_param {
> DRM_V3D_PARAM_V3D_UIFCFG,
> DRM_V3D_PARAM_V3D_HUB_IDENT1,
prev parent reply other threads:[~2026-10-28 14:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-25 12:09 이재훈
2026-10-28 14:23 ` Maíra Canal [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=25e3d341-91d9-4080-8975-a5622b84726f@igalia.com \
--to=mcanal@igalia.com \
--cc=dlwognsdc6100@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=itoral@igalia.com \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mwen@igalia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®