[PATCH 3/3] drm/ingenic: Alloc cached GEM buffers with dma_alloc_noncoherent

From: Paul Cercueil
Date: Wed Sep 30 2020 - 13:17:25 EST


It turns out that if you want to mmap GEM buffers fully cached, then
they should be allocated as such as well. Who would have known?

Introduce a custom .dumb_create callback, that will behave just like
drm_gem_cma_dumb_create(), except that it will allocate the GEM buffer
using dma_alloc_noncoherent() if non-coherent memory is what we want.

Signed-off-by: Paul Cercueil <paul@xxxxxxxxxxxxxxx>
---
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 48 ++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 07a1da7266e4..8ece269c040f 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -794,6 +794,52 @@ static int ingenic_drm_gem_cma_mmap(struct file *filp,
return ingenic_drm_gem_mmap(vma->vm_private_data, vma);
}

+static int ingenic_drm_gem_cma_dumb_create(struct drm_file *file_priv,
+ struct drm_device *drm,
+ struct drm_mode_create_dumb *args)
+{
+ /*
+ * This is basically a copy of drm_gem_cma_dumb_create, which supports
+ * creating fully cached GEM buffers.
+ */
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
+ size_t size;
+ int ret;
+
+ args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+ args->size = args->pitch * args->height;
+
+ size = PAGE_ALIGN(args->size);
+
+ cma_obj = drm_gem_cma_create_noalloc(drm, size);
+ if (IS_ERR(cma_obj))
+ return PTR_ERR(cma_obj);
+
+ if (ingenic_drm_cached_gem_buf) {
+ cma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size,
+ &cma_obj->paddr,
+ DMA_TO_DEVICE,
+ GFP_KERNEL | __GFP_NOWARN);
+ } else {
+ cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
+ GFP_KERNEL | __GFP_NOWARN);
+ }
+ if (!cma_obj->vaddr) {
+ dev_err(drm->dev, "Failed to allocate buffer with size %zu\n", size);
+ ret = -ENOMEM;
+ goto out_gem_object_put;
+ }
+
+ gem_obj = &cma_obj->base;
+
+ ret = drm_gem_handle_create(file_priv, gem_obj, &args->handle);
+
+out_gem_object_put:
+ drm_gem_object_put(gem_obj);
+ return ret;
+}
+
static const struct file_operations ingenic_drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@@ -816,7 +862,7 @@ static struct drm_driver ingenic_drm_driver_data = {
.patchlevel = 0,

.fops = &ingenic_drm_fops,
- DRM_GEM_CMA_DRIVER_OPS,
+ DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(ingenic_drm_gem_cma_dumb_create),

.irq_handler = ingenic_drm_irq_handler,
};
--
2.28.0