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_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.
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