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 <p...@crapouillou.net>
---
 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

Reply via email to