On 01/16/2017 01:47 AM, Benjamin Gaignard wrote:
2017-01-13 20:30 GMT+01:00 Laura Abbott labbott@redhat.com:
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_ALLOCATORdepends 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.
cma_areas array is static in cma.c and I need it content to call cma_alloc. The problem is the same with cma_area_count.
I will have a look into cma.c to see if I can remove those constraints
This has happened in the powerpc kvm stuff, see arch/powerpc/kvm/book3s_hv_builtin.c The most difficult part is going to be figuring out how to hook up to do the early reservations.
Benjamin
Thanks, Laura