Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: Add support for GEM buffers backed by non-coherent memory

Having GEM buffers backed by non-coherent memory is interesting in the
particular case where it is faster to render to a non-coherent buffer
then sync the data cache, than to render to a write-combine buffer, and
(by extension) much faster than using a shadow buffer. This is true for
instance on some Ingenic SoCs, where even simple blits (e.g. memcpy)
are about three times faster using this method.

Add a 'map_noncoherent' flag to the drm_gem_cma_object structure, which
can be set by the drivers when they create the dumb buffer.

Since this really only applies to software rendering, disable this flag
as soon as the CMA objects are exported via PRIME.

v3: New patch. Now uses a simple 'map_noncoherent' flag to control how
the objects are mapped, and use the new dma_mmap_pages function.

v4: Make sure map_noncoherent is always disabled when creating GEM
objects meant to be used with dma-buf.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210523170415.90410-2-paul@crapouillou.net

+32 -9
+29 -9
drivers/gpu/drm/drm_gem_cma_helper.c
··· 46 46 * __drm_gem_cma_create - Create a GEM CMA object without allocating memory 47 47 * @drm: DRM device 48 48 * @size: size of the object to allocate 49 + * @private: true if used for internal purposes 49 50 * 50 51 * This function creates and initializes a GEM CMA object of the given size, 51 52 * but doesn't allocate any memory to back the object. ··· 56 55 * error code on failure. 57 56 */ 58 57 static struct drm_gem_cma_object * 59 - __drm_gem_cma_create(struct drm_device *drm, size_t size) 58 + __drm_gem_cma_create(struct drm_device *drm, size_t size, bool private) 60 59 { 61 60 struct drm_gem_cma_object *cma_obj; 62 61 struct drm_gem_object *gem_obj; 63 - int ret; 62 + int ret = 0; 64 63 65 64 if (drm->driver->gem_create_object) 66 65 gem_obj = drm->driver->gem_create_object(drm, size); ··· 74 73 75 74 cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base); 76 75 77 - ret = drm_gem_object_init(drm, gem_obj, size); 76 + if (private) { 77 + drm_gem_private_object_init(drm, gem_obj, size); 78 + 79 + /* Always use writecombine for dma-buf mappings */ 80 + cma_obj->map_noncoherent = false; 81 + } else { 82 + ret = drm_gem_object_init(drm, gem_obj, size); 83 + } 78 84 if (ret) 79 85 goto error; 80 86 ··· 119 111 120 112 size = round_up(size, PAGE_SIZE); 121 113 122 - cma_obj = __drm_gem_cma_create(drm, size); 114 + cma_obj = __drm_gem_cma_create(drm, size, false); 123 115 if (IS_ERR(cma_obj)) 124 116 return cma_obj; 125 117 126 - cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr, 127 - GFP_KERNEL | __GFP_NOWARN); 118 + if (cma_obj->map_noncoherent) { 119 + cma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size, 120 + &cma_obj->paddr, 121 + DMA_TO_DEVICE, 122 + GFP_KERNEL | __GFP_NOWARN); 123 + } else { 124 + cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr, 125 + GFP_KERNEL | __GFP_NOWARN); 126 + } 128 127 if (!cma_obj->vaddr) { 129 128 drm_dbg(drm, "failed to allocate buffer with size %zu\n", 130 129 size); ··· 447 432 return ERR_PTR(-EINVAL); 448 433 449 434 /* Create a CMA GEM buffer. */ 450 - cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size); 435 + cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size, true); 451 436 if (IS_ERR(cma_obj)) 452 437 return ERR_CAST(cma_obj); 453 438 ··· 514 499 515 500 cma_obj = to_drm_gem_cma_obj(obj); 516 501 517 - ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr, 518 - cma_obj->paddr, vma->vm_end - vma->vm_start); 502 + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 503 + if (!cma_obj->map_noncoherent) 504 + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 505 + 506 + ret = dma_mmap_pages(cma_obj->base.dev->dev, 507 + vma, vma->vm_end - vma->vm_start, 508 + virt_to_page(cma_obj->vaddr)); 519 509 if (ret) 520 510 drm_gem_vm_close(vma); 521 511
+3
include/drm/drm_gem_cma_helper.h
··· 16 16 * more than one entry but they are guaranteed to have contiguous 17 17 * DMA addresses. 18 18 * @vaddr: kernel virtual address of the backing memory 19 + * @map_noncoherent: if true, the GEM object is backed by non-coherent memory 19 20 */ 20 21 struct drm_gem_cma_object { 21 22 struct drm_gem_object base; ··· 25 24 26 25 /* For objects with DMA memory allocated by GEM CMA */ 27 26 void *vaddr; 27 + 28 + bool map_noncoherent; 28 29 }; 29 30 30 31 #define to_drm_gem_cma_obj(gem_obj) \