This adds a CMA pool, which allows userspace to allocate a dma-buf of contiguous memory out of a CMA region.
Cc: Laura Abbott <labb...@redhat.com> Cc: Benjamin Gaignard <benjamin.gaign...@linaro.org> Cc: Sumit Semwal <sumit.sem...@linaro.org> Cc: Liam Mark <lm...@codeaurora.org> Cc: Brian Starkey <brian.star...@arm.com> Cc: Andrew F. Davis <a...@ti.com> Cc: Chenbo Feng <fe...@google.com> Cc: Alistair Strachan <astrac...@google.com> Cc: dri-devel@lists.freedesktop.org Signed-off-by: John Stultz <john.stu...@linaro.org> --- drivers/dma-buf/pools/Kconfig | 8 +++ drivers/dma-buf/pools/Makefile | 1 + drivers/dma-buf/pools/cma_pool.c | 143 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/dma-buf/pools/cma_pool.c diff --git a/drivers/dma-buf/pools/Kconfig b/drivers/dma-buf/pools/Kconfig index 787b2a6..e984304 100644 --- a/drivers/dma-buf/pools/Kconfig +++ b/drivers/dma-buf/pools/Kconfig @@ -15,3 +15,11 @@ config DMABUF_POOLS_SYSTEM help Choose this option to enable the system dmabuf pool. The system pool is backed by pages from the buddy allocator. If in doubt, say Y. + +config DMABUF_POOLS_CMA + bool "DMA-BUF CMA Pool" + depends on DMABUF_POOLS && DMA_CMA + help + Choose this option to enable dma-buf CMA pools. This pool is backed + by the Contiguous Memory Allocator (CMA). If your system has these + regions, you should say Y here. diff --git a/drivers/dma-buf/pools/Makefile b/drivers/dma-buf/pools/Makefile index 2ccf2a1..ac8aa28 100644 --- a/drivers/dma-buf/pools/Makefile +++ b/drivers/dma-buf/pools/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DMABUF_POOLS) += dmabuf-pools.o pool-ioctl.o pool-helpers.o page_pool.o obj-$(CONFIG_DMABUF_POOLS_SYSTEM) += system_pool.o +obj-$(CONFIG_DMABUF_POOLS_CMA) += cma_pool.o diff --git a/drivers/dma-buf/pools/cma_pool.c b/drivers/dma-buf/pools/cma_pool.c new file mode 100644 index 0000000..0bd783f --- /dev/null +++ b/drivers/dma-buf/pools/cma_pool.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/dma-buf/pools/cma_pool.c + * + * Copyright (C) 2012, 2019 Linaro Ltd. + * Author: <benjamin.gaign...@linaro.org> for ST-Ericsson. + */ + +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/cma.h> +#include <linux/scatterlist.h> +#include <linux/highmem.h> + +#include "dmabuf-pools.h" + +struct cma_pool { + struct dmabuf_pool pool; + struct cma *cma; +}; + +#define to_cma_pool(x) container_of(x, struct cma_pool, pool) + +/* dmabuf pool CMA operations functions */ +static int cma_pool_allocate(struct dmabuf_pool *pool, + struct dmabuf_pool_buffer *buffer, + unsigned long len, + unsigned long flags) +{ + struct cma_pool *cma_pool = to_cma_pool(pool); + struct sg_table *table; + struct page *pages; + unsigned long size = PAGE_ALIGN(len); + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long align = get_order(size); + int ret; + + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + + pages = cma_alloc(cma_pool->cma, nr_pages, align, false); + if (!pages) + return -ENOMEM; + + if (PageHighMem(pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + page++; + nr_clear_pages--; + } + } else { + memset(page_address(pages), 0, size); + } + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + goto err; + + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto free_mem; + + sg_set_page(table->sgl, pages, size, 0); + + buffer->priv_virt = pages; + buffer->sg_table = table; + return 0; + +free_mem: + kfree(table); +err: + cma_release(cma_pool->cma, pages, nr_pages); + return -ENOMEM; +} + +static void cma_pool_free(struct dmabuf_pool_buffer *buffer) +{ + struct cma_pool *cma_pool = to_cma_pool(buffer->pool); + struct page *pages = buffer->priv_virt; + unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + + /* release memory */ + cma_release(cma_pool->cma, pages, nr_pages); + /* release sg table */ + sg_free_table(buffer->sg_table); + kfree(buffer->sg_table); +} + +static struct dmabuf_pool_ops cma_pool_ops = { + .allocate = cma_pool_allocate, + .free = cma_pool_free, + .map_user = dmabuf_pool_map_user, + .map_kernel = dmabuf_pool_map_kernel, + .unmap_kernel = dmabuf_pool_unmap_kernel, +}; + +static struct dmabuf_pool *__cma_pool_create(struct cma *cma) +{ + struct cma_pool *cma_pool; + + cma_pool = kzalloc(sizeof(*cma_pool), GFP_KERNEL); + + if (!cma_pool) + return ERR_PTR(-ENOMEM); + + cma_pool->pool.ops = &cma_pool_ops; + /* + * get device from private pools data, later it will be + * used to make the link with reserved CMA memory + */ + cma_pool->cma = cma; + return &cma_pool->pool; +} + +static int __add_cma_pools(struct cma *cma, void *data) +{ + struct dmabuf_pool *pool; + + pool = __cma_pool_create(cma); + if (IS_ERR(pool)) + return PTR_ERR(pool); + + pool->name = cma_get_name(cma); + + dmabuf_pool_add(pool); + + return 0; +} + +static int add_cma_pools(void) +{ + cma_for_each_area(__add_cma_pools, NULL); + return 0; +} +device_initcall(add_cma_pools); -- 2.7.4 _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel