On 01/12/2017 06:01 AM, Benjamin Gaignard wrote:
This patch add allocator for CMA default region
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org
drivers/simpleallocator/Kconfig | 7 ++ drivers/simpleallocator/Makefile | 1 + drivers/simpleallocator/simple-allocator-cma.c | 163 +++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/simpleallocator/simple-allocator-cma.c
diff --git a/drivers/simpleallocator/Kconfig b/drivers/simpleallocator/Kconfig index c6fc2e3..788fb0b 100644 --- a/drivers/simpleallocator/Kconfig +++ b/drivers/simpleallocator/Kconfig @@ -7,4 +7,11 @@ config SIMPLE_ALLOCATOR The Simple Allocator Framework adds an API to allocate and share memory in userland. +config SIMPLE_ALLOCATOR_CMA
- tristate "Simple Allocator CMA"
- select SIMPLE_ALLOCATOR
- depends on DMA_CMA
- ---help---
Select this option to enable Simple Allocator on CMA area.
endmenu diff --git a/drivers/simpleallocator/Makefile b/drivers/simpleallocator/Makefile index e27c6ad..4e11611 100644 --- a/drivers/simpleallocator/Makefile +++ b/drivers/simpleallocator/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_SIMPLE_ALLOCATOR) += simple-allocator.o +obj-$(CONFIG_SIMPLE_ALLOCATOR_CMA) += simple-allocator-cma.o diff --git a/drivers/simpleallocator/simple-allocator-cma.c b/drivers/simpleallocator/simple-allocator-cma.c new file mode 100644 index 0000000..c4f5767 --- /dev/null +++ b/drivers/simpleallocator/simple-allocator-cma.c @@ -0,0 +1,163 @@ +/*
- Copyright (C) Linaro 2016
- Author: Benjamin Gaignard benjamin.gaignard@linaro.org
- License terms: GNU General Public License (GPL)
- */
+#include <linux/module.h> +#include <linux/slab.h>
+#include "simple-allocator-priv.h"
+static struct sa_device *default_cma;
+struct sa_cma_buffer_info {
- void *vaddr;
- dma_addr_t handle;
- size_t size;
- struct device *dev;
+};
+static struct sg_table *sa_cma_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction direction)
+{
- struct dma_buf *dmabuf = attach->dmabuf;
- struct sa_cma_buffer_info *info = dmabuf->priv;
- struct sg_table *sgt;
- int ret;
- sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
- if (!sgt)
return NULL;
- ret = dma_get_sgtable(info->dev, sgt, info->vaddr, info->handle,
info->size);
- if (ret < 0)
goto out;
- return sgt;
+out:
- kfree(sgt);
- return NULL;
+}
+static void sa_cma_unmap_dma_buf(struct dma_buf_attachment *attach,
struct sg_table *sgt,
enum dma_data_direction dir)
+{
- kfree(sgt);
+}
+static int sa_cma_mmap_dma_buf(struct dma_buf *dmabuf,
struct vm_area_struct *vma)
+{
- struct sa_cma_buffer_info *info = dmabuf->priv;
- int ret;
- ret = dma_mmap_wc(info->dev, vma, info->vaddr, info->handle,
vma->vm_end - vma->vm_start);
- return ret;
+}
+static void sa_cma_release_dma_buf(struct dma_buf *dmabuf) +{
- struct sa_cma_buffer_info *info = dmabuf->priv;
- dma_free_wc(info->dev, info->size, info->vaddr, info->handle);
- kfree(info);
+}
+static void *sa_cma_kmap_dma_buf(struct dma_buf *dmabuf, unsigned long offset) +{
- struct sa_cma_buffer_info *info = dmabuf->priv;
- return info->vaddr + offset * PAGE_SIZE;
+}
+static struct dma_buf_ops sa_dma_buf_ops = {
- .map_dma_buf = sa_cma_map_dma_buf,
- .unmap_dma_buf = sa_cma_unmap_dma_buf,
- .mmap = sa_cma_mmap_dma_buf,
- .release = sa_cma_release_dma_buf,
- .kmap_atomic = sa_cma_kmap_dma_buf,
- .kmap = sa_cma_kmap_dma_buf,
+};
+static struct dma_buf *sa_cma_allocate(struct sa_device *sadev,
u64 length, u32 flags)
+{
- DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
- struct sa_cma_buffer_info *info;
- struct dma_buf *dmabuf;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
return NULL;
- info->dev = sadev->dev.parent;
- info->size = round_up(length, PAGE_SIZE);
- info->vaddr = dma_alloc_wc(info->dev, info->size, &info->handle,
GFP_KERNEL | __GFP_NOWARN);
- if (!info->vaddr)
goto cleanup;
- exp_info.ops = &sa_dma_buf_ops;
- exp_info.size = info->size;
- exp_info.flags = flags;
- exp_info.priv = info;
- dmabuf = dma_buf_export(&exp_info);
- if (IS_ERR(dmabuf))
goto export_failed;
- return dmabuf;
+export_failed:
- dma_free_wc(info->dev, info->size, info->vaddr, info->handle);
+cleanup:
- kfree(info);
- return NULL;
+}
+struct sa_device *simple_allocator_register_cma(struct device *dev) +{
- struct sa_device *sadev;
- int ret;
- sadev = kzalloc(sizeof(*sadev), GFP_KERNEL);
- if (!sadev)
return NULL;
- sadev->dev.parent = dev;
- sadev->owner = THIS_MODULE;
- sadev->name = "cma";
- sadev->allocate = sa_cma_allocate;
- ret = simple_allocator_register(sadev);
- if (ret) {
kfree(sadev);
return NULL;
- }
- return sadev;
+}
+static int __init sa_cma_init(void) +{
- default_cma = simple_allocator_register_cma(NULL);
- return 0;
+}
+static void __exit sa_cma_exit(void) +{
- simple_allocator_unregister(default_cma);
+}
+module_init(sa_cma_init); +module_exit(sa_cma_exit);
I really don't like having to force the CMA allocation through the device structure. This ends up resulting in the need to create a dummy device just to allocate CMA memory. I'd rather see this code reworked to not require calling dma_alloc and just call cma_alloc directly. This memory can latter be mapped with dma_map.
Thanks, Laura