diff mbox series

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

Message ID 20200930171644.299363-3-paul@crapouillou.net (mailing list archive)
State New, archived
Headers show
Series [1/3] drm: Add and export function drm_gem_cma_create_noalloc | expand

Commit Message

Paul Cercueil Sept. 30, 2020, 5:16 p.m. UTC
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@crapouillou.net>
---
 drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 48 ++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)
diff mbox series

Patch

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,
 };