[PATCH v3 3/3] drm/gem-dma: Support DRM_MODE_DUMB_KERNEL_MAP flag
Thomas Zimmermann
tzimmermann at suse.de
Fri Mar 27 00:29:05 PDT 2026
Hi
Am 26.03.26 um 11:01 schrieb Chen-Yu Tsai:
> From: Rob Herring <robh at kernel.org>
>
> Add support in DMA helpers to handle callers specifying
> DRM_MODE_DUMB_KERNEL_MAP flag. Existing behavior is maintained with this
> change. drm_gem_dma_dumb_create() always creates a kernel mapping as
> before. drm_gem_dma_dumb_create_internal() lets the caller set the flags
> as desired.
>
> drm_gem_dma_dumb_create_internal() users have DRM_MODE_DUMB_KERNEL_MAP
> added to preserve existing behavior.
>
> A dumb buffer allocated from these devices can be shared (exported) to
> another device. The consuming device may require the kernel mapping to
> scan out the buffer to its own display. Such devices include DisplayLink
> and various MIPI DBI based displays. Therefore altering the behavior
> should be given much consideration.
NAK on this whole thing. Please do not clutter the sources with these
flags and tests. If drivers cannot use the gem-cma helpers, they should
not do so. Maybe these drivers _are_ different. Then give them different
interfaces or even a different memory manager, if necessary.
>
> Signed-off-by: Rob Herring <robh at kernel.org>
> [wenst at chromium.org: Rebase onto renamed GEM DMA helpers]
> [wenst at chromium.org: show "vaddr=(no mapping)" in drm_gem_dma_print_info()]
> [wenst at chromium.org: Add DRM_MODE_DUMB_KERNEL_MAP to new drivers]
> [wenst at chromium.org: Add flags field to drm_gem_dma_create_with_handle()
> kerneldoc]
> Signed-off-by: Chen-Yu Tsai <wenst at chromium.org>
> ---
> Changes since v2:
> - Added back DRM_MODE_DUMB_KERNEL_MAP flag to all drivers calling
> drm_gem_dma_dumb_create_internal()
> - Expanded commit message to cover display drivers needing the kernel
> mapping to do scan out
>
> Changes since v1:
> - Rebased onto renamed GEM DMA helpers
> - Added check in drm_fb_dma_get_scanout_buffer() and drm_gem_dma_vmap().
> - Made drm_gem_dma_print_info() show "vaddr=(no mapping)" for objects
> allocated without kernel mapping
> - Dropped existing DRM_MODE_DUMB_KERNEL_MAP flag addition in various
> drivers
> - Added DRM_MODE_DUMB_KERNEL_MAP flag to adp_drm_gem_dumb_create()
> - Added flags field kerneldoc for drm_gem_dma_create_with_handle()
>
> Cc: Sasha Finkelstein <fnkl.kernel at gmail.com>
> Cc: Janne Grunau <j at jannau.net>
> Cc: Liviu Dudau <liviu.dudau at arm.com>
> Cc: Paul Kocialkowski <paulk at sys-base.io>
> Cc: Neil Armstrong <neil.armstrong at linaro.org>
> Cc: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> Cc: Tomi Valkeinen <tomi.valkeinen+renesas at ideasonboard.com>
> Cc: Kieran Bingham <kieran.bingham+renesas at ideasonboard.com>
> Cc: Biju Das <biju.das.jz at bp.renesas.com>
> Cc: Yannick Fertre <yannick.fertre at foss.st.com>
> Cc: Raphael Gallais-Pou <raphael.gallais-pou at foss.st.com>
> Cc: Philippe Cornu <philippe.cornu at foss.st.com>
> Cc: Jernej Skrabec <jernej.skrabec at gmail.com>
> Cc: Maxime Ripard <mripard at kernel.org>
> Cc: Dave Stevenson <dave.stevenson at raspberrypi.com>
> Cc: "Maíra Canal" <mcanal at igalia.com>
> Cc: Raspberry Pi Kernel Maintenance <kernel-list at raspberrypi.com>
> Cc: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> Cc: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Cc: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> ---
> drivers/gpu/drm/adp/adp_drv.c | 1 +
> .../gpu/drm/arm/display/komeda/komeda_kms.c | 1 +
> drivers/gpu/drm/arm/malidp_drv.c | 1 +
> drivers/gpu/drm/drm_fb_dma_helper.c | 4 ++
> drivers/gpu/drm/drm_gem_dma_helper.c | 67 ++++++++++++-------
> drivers/gpu/drm/logicvc/logicvc_drm.c | 1 +
> drivers/gpu/drm/meson/meson_drv.c | 1 +
> drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c | 2 +
> drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 1 +
> drivers/gpu/drm/stm/drv.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_drv.c | 1 +
> drivers/gpu/drm/vc4/vc4_drv.c | 2 +
> drivers/gpu/drm/verisilicon/vs_drm.c | 2 +
> drivers/gpu/drm/xlnx/zynqmp_kms.c | 2 +
> 14 files changed, 63 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c
> index 4554cf75565e..c549b44b3814 100644
> --- a/drivers/gpu/drm/adp/adp_drv.c
> +++ b/drivers/gpu/drm/adp/adp_drv.c
> @@ -95,6 +95,7 @@ static int adp_drm_gem_dumb_create(struct drm_file *file_priv,
> {
> args->height = ALIGN(args->height, 64);
> args->size = args->pitch * args->height;
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
>
> return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
> }
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> index 6ed504099188..2c096ebaea33 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> @@ -29,6 +29,7 @@ static int komeda_gem_dma_dumb_create(struct drm_file *file,
> struct komeda_dev *mdev = dev->dev_private;
> u32 pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> args->pitch = ALIGN(pitch, mdev->chip.bus_width);
>
> return drm_gem_dma_dumb_create_internal(file, dev, args);
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index b765f6c9eea4..5519f48a27c0 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -464,6 +464,7 @@ static int malidp_dumb_create(struct drm_file *file_priv,
> /* allocate for the worst case scenario, i.e. rotated buffers */
> u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 1);
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), alignment);
>
> return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
> index fd71969d2fb1..12a44accc48c 100644
> --- a/drivers/gpu/drm/drm_fb_dma_helper.c
> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
> @@ -187,6 +187,10 @@ int drm_fb_dma_get_scanout_buffer(struct drm_plane *plane,
> if (!dma_obj->vaddr)
> return -ENODEV;
>
> + /* Buffer was allocated with NO_KERNEL_MAPPING */
> + if (dma_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
> + return -ENODEV;
This is a good example of what I'm talking about. A driver that cannot
provide a scanout buffer should not set the callback in the first place.
Best regards
Thomas
> +
> iosys_map_set_vaddr(&sb->map[0], dma_obj->vaddr);
> sb->format = fb->format;
> sb->height = fb->height;
> diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c
> index 9722c9fc86f3..281fb563f061 100644
> --- a/drivers/gpu/drm/drm_gem_dma_helper.c
> +++ b/drivers/gpu/drm/drm_gem_dma_helper.c
> @@ -116,26 +116,8 @@ __drm_gem_dma_create(struct drm_device *drm, size_t size, bool private)
> return ERR_PTR(ret);
> }
>
> -/**
> - * drm_gem_dma_create - allocate an object with the given size
> - * @drm: DRM device
> - * @size: size of the object to allocate
> - *
> - * This function creates a DMA GEM object and allocates memory as backing store.
> - * The allocated memory will occupy a contiguous chunk of bus address space.
> - *
> - * For devices that are directly connected to the memory bus then the allocated
> - * memory will be physically contiguous. For devices that access through an
> - * IOMMU, then the allocated memory is not expected to be physically contiguous
> - * because having contiguous IOVAs is sufficient to meet a devices DMA
> - * requirements.
> - *
> - * Returns:
> - * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative
> - * error code on failure.
> - */
> -struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm,
> - size_t size)
> +static struct drm_gem_dma_object *
> +drm_gem_dma_create_flags(struct drm_device *drm, size_t size, u32 flags)
> {
> struct drm_gem_dma_object *dma_obj;
> int ret;
> @@ -146,6 +128,9 @@ struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm,
> if (IS_ERR(dma_obj))
> return dma_obj;
>
> + if (!(flags & DRM_MODE_DUMB_KERNEL_MAP))
> + dma_obj->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
> +
> if (dma_obj->map_noncoherent) {
> dma_obj->vaddr = dma_alloc_noncoherent(drm_dev_dma_dev(drm),
> size,
> @@ -171,6 +156,30 @@ struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm,
> drm_gem_object_put(&dma_obj->base);
> return ERR_PTR(ret);
> }
> +
> +/**
> + * drm_gem_dma_create - allocate an object with the given size
> + * @drm: DRM device
> + * @size: size of the object to allocate
> + *
> + * This function creates a DMA GEM object and allocates memory as backing store.
> + * The allocated memory will occupy a contiguous chunk of bus address space.
> + *
> + * For devices that are directly connected to the memory bus then the allocated
> + * memory will be physically contiguous. For devices that access through an
> + * IOMMU, then the allocated memory is not expected to be physically contiguous
> + * because having contiguous IOVAs is sufficient to meet a devices DMA
> + * requirements.
> + *
> + * Returns:
> + * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative
> + * error code on failure.
> + */
> +struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm,
> + size_t size)
> +{
> + return drm_gem_dma_create_flags(drm, size, DRM_MODE_DUMB_KERNEL_MAP);
> +}
> EXPORT_SYMBOL_GPL(drm_gem_dma_create);
>
> /**
> @@ -179,6 +188,7 @@ EXPORT_SYMBOL_GPL(drm_gem_dma_create);
> * @file_priv: DRM file-private structure to register the handle for
> * @drm: DRM device
> * @size: size of the object to allocate
> + * @flags: DRM_MODE_DUMB_* flags if any
> * @handle: return location for the GEM handle
> *
> * This function creates a DMA GEM object, allocating a chunk of memory as
> @@ -194,14 +204,14 @@ EXPORT_SYMBOL_GPL(drm_gem_dma_create);
> */
> static struct drm_gem_dma_object *
> drm_gem_dma_create_with_handle(struct drm_file *file_priv,
> - struct drm_device *drm, size_t size,
> + struct drm_device *drm, size_t size, u32 flags,
> uint32_t *handle)
> {
> struct drm_gem_dma_object *dma_obj;
> struct drm_gem_object *gem_obj;
> int ret;
>
> - dma_obj = drm_gem_dma_create(drm, size);
> + dma_obj = drm_gem_dma_create_flags(drm, size, DRM_MODE_DUMB_KERNEL_MAP);
> if (IS_ERR(dma_obj))
> return dma_obj;
>
> @@ -283,7 +293,7 @@ int drm_gem_dma_dumb_create_internal(struct drm_file *file_priv,
> args->size = args->pitch * args->height;
>
> dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size,
> - &args->handle);
> + args->flags, &args->handle);
> return PTR_ERR_OR_ZERO(dma_obj);
> }
> EXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create_internal);
> @@ -313,12 +323,13 @@ int drm_gem_dma_dumb_create(struct drm_file *file_priv,
> struct drm_gem_dma_object *dma_obj;
> int ret;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> ret = drm_mode_size_dumb(drm, args, 0, 0);
> if (ret)
> return ret;
>
> dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size,
> - &args->handle);
> + args->flags, &args->handle);
> return PTR_ERR_OR_ZERO(dma_obj);
> }
> EXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create);
> @@ -412,7 +423,10 @@ void drm_gem_dma_print_info(const struct drm_gem_dma_object *dma_obj,
> struct drm_printer *p, unsigned int indent)
> {
> drm_printf_indent(p, indent, "dma_addr=%pad\n", &dma_obj->dma_addr);
> - drm_printf_indent(p, indent, "vaddr=%p\n", dma_obj->vaddr);
> + if (dma_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
> + drm_printf_indent(p, indent, "vaddr=(no mapping)\n");
> + else
> + drm_printf_indent(p, indent, "vaddr=%p\n", dma_obj->vaddr);
> }
> EXPORT_SYMBOL(drm_gem_dma_print_info);
>
> @@ -511,6 +525,9 @@ EXPORT_SYMBOL_GPL(drm_gem_dma_prime_import_sg_table);
> int drm_gem_dma_vmap(struct drm_gem_dma_object *dma_obj,
> struct iosys_map *map)
> {
> + if (dma_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
> + return -ENOMEM;
> +
> iosys_map_set_vaddr(map, dma_obj->vaddr);
>
> return 0;
> diff --git a/drivers/gpu/drm/logicvc/logicvc_drm.c b/drivers/gpu/drm/logicvc/logicvc_drm.c
> index bbebf4fc7f51..595a71163cb5 100644
> --- a/drivers/gpu/drm/logicvc/logicvc_drm.c
> +++ b/drivers/gpu/drm/logicvc/logicvc_drm.c
> @@ -39,6 +39,7 @@ static int logicvc_drm_gem_dma_dumb_create(struct drm_file *file_priv,
> {
> struct logicvc_drm *logicvc = logicvc_drm(drm_dev);
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> /* Stride is always fixed to its configuration value. */
> args->pitch = logicvc->config.row_stride * DIV_ROUND_UP(args->bpp, 8);
>
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index 49ff9f1f16d3..9fa339d6e273 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -83,6 +83,7 @@ static irqreturn_t meson_irq(int irq, void *arg)
> static int meson_dumb_create(struct drm_file *file, struct drm_device *dev,
> struct drm_mode_create_dumb *args)
> {
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> /*
> * We need 64bytes aligned stride, and PAGE aligned size
> */
> diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
> index 60e6f43b8ab2..611fe3d4a4d8 100644
> --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
> +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
> @@ -424,6 +424,8 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
> if (ret)
> return ret;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> +
> return drm_gem_dma_dumb_create_internal(file, dev, args);
> }
>
> diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
> index 87f171145a23..359f85bd84eb 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
> @@ -184,6 +184,7 @@ int rzg2l_du_dumb_create(struct drm_file *file, struct drm_device *dev,
> unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
> unsigned int align = 16 * args->bpp / 8;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> args->pitch = roundup(min_pitch, align);
>
> return drm_gem_dma_dumb_create_internal(file, dev, args);
> diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
> index 56d53ac3082d..a0bc2e215adb 100644
> --- a/drivers/gpu/drm/stm/drv.c
> +++ b/drivers/gpu/drm/stm/drv.c
> @@ -51,8 +51,9 @@ static int stm_gem_dma_dumb_create(struct drm_file *file,
> * in order to optimize data transfer, pitch is aligned on
> * 128 bytes, height is aligned on 4 bytes
> */
> - args->pitch = roundup(min_pitch, 128);
> args->height = roundup(args->height, 4);
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> + args->pitch = roundup(min_pitch, 128);
>
> return drm_gem_dma_dumb_create_internal(file, dev, args);
> }
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 8a409eee1dca..d3ff53ce2450 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -36,6 +36,7 @@ static int drm_sun4i_gem_dumb_create(struct drm_file *file_priv,
> struct drm_device *drm,
> struct drm_mode_create_dumb *args)
> {
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> /* The hardware only allows even pitches for YUV buffers. */
> args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2);
>
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index a14ecb769461..7a04cf52f511 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -87,6 +87,8 @@ static int vc5_dumb_create(struct drm_file *file_priv,
> if (ret)
> return ret;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> +
> return drm_gem_dma_dumb_create_internal(file_priv, dev, args);
> }
>
> diff --git a/drivers/gpu/drm/verisilicon/vs_drm.c b/drivers/gpu/drm/verisilicon/vs_drm.c
> index fd259d53f49f..fe3591244d02 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drm.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drm.c
> @@ -44,6 +44,8 @@ static int vs_gem_dumb_create(struct drm_file *file_priv,
> if (ret)
> return ret;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> +
> return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
> }
>
> diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> index 02f3a7d78cf8..aa3822b3cb08 100644
> --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
> +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
> @@ -371,6 +371,8 @@ static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
> if (ret)
> return ret;
>
> + args->flags = DRM_MODE_DUMB_KERNEL_MAP;
> +
> return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
> }
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
More information about the linux-arm-kernel
mailing list