From: Benjamin Gaignard benjamin.gaignard@linaro.org
New heap, allocation is done with dma_alloc_coherent API. device dma_mask and coherent_dma_mask fields must be set to DMA_BIT_MASK(32) CMA heap use ion_heap private field to store the device pointer
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/ion/Kconfig | 6 ++ drivers/gpu/ion/Makefile | 1 + drivers/gpu/ion/cma/Makefile | 1 + drivers/gpu/ion/cma/ion_cma_heap.c | 126 ++++++++++++++++++++++++++++++++++++ drivers/gpu/ion/cma/ion_cma_heap.h | 11 +++ 5 files changed, 145 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/ion/cma/Makefile create mode 100644 drivers/gpu/ion/cma/ion_cma_heap.c create mode 100644 drivers/gpu/ion/cma/ion_cma_heap.h
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig index 0e87dab..231dbb1 100644 --- a/drivers/gpu/ion/Kconfig +++ b/drivers/gpu/ion/Kconfig @@ -9,3 +9,9 @@ config ION_TEGRA depends on ARCH_TEGRA && ION help Choose this option if you wish to use ion on an nVidia Tegra. + +config ION_CMA + tristate "Ion CMA heap" + depends on ION && CMA + help + Choose this option to enable ION CMA heap. diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile index 73fe3fa..05f174a 100644 --- a/drivers/gpu/ion/Makefile +++ b/drivers/gpu/ion/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_CMA) += cma/ diff --git a/drivers/gpu/ion/cma/Makefile b/drivers/gpu/ion/cma/Makefile new file mode 100644 index 0000000..673508d --- /dev/null +++ b/drivers/gpu/ion/cma/Makefile @@ -0,0 +1 @@ +obj-y += ion_cma_heap.o diff --git a/drivers/gpu/ion/cma/ion_cma_heap.c b/drivers/gpu/ion/cma/ion_cma_heap.c new file mode 100644 index 0000000..53d59fc --- /dev/null +++ b/drivers/gpu/ion/cma/ion_cma_heap.c @@ -0,0 +1,126 @@ +/* + * drivers/gpu/ion/ion_cma_heap.c + * + * Copyright (C) Linaro 2012 + * Author: benjamin.gaignard@linaro.org for ST-Ericsson. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/ion.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/miscdevice.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> + +/* for ion_heap_ops structure */ +#include "../ion_priv.h" + +#define ION_CMA_ALLOCATE_FAILED -1 + +struct ion_cma_buffer_info { + void *cpu_addr; + dma_addr_t handle; +}; + +/* ION CMA heap operations functions */ +static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, + unsigned long len, unsigned long align, + unsigned long flags) +{ + struct device *dev = heap->priv; + struct ion_cma_buffer_info *info; + + dev_dbg(dev, "Request buffer allocation len %ld\n", len); + + info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL); + if (!info) { + dev_err(dev, "Can't allocate buffer info\n"); + return ION_CMA_ALLOCATE_FAILED; + } + + info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0); + + if (!info->cpu_addr) { + dev_err(dev, "Fail to allocate buffer\n"); + kfree(info); + return ION_CMA_ALLOCATE_FAILED; + } + + /* keep this for memory release */ + buffer->priv_virt = info; + dev_dbg(dev, "Allocate buffer %p\n", buffer); + return 0; +} + +static void ion_cma_free(struct ion_buffer *buffer) +{ + struct device *dev = buffer->heap->priv; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + dev_dbg(dev, "Release buffer %p\n", buffer); + dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); + kfree(info); +} + +/* return physical address in addr */ +static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, + ion_phys_addr_t *addr, size_t *len) +{ + struct device *dev = heap->priv; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer, + virt_to_phys(info->cpu_addr)); + + *addr = virt_to_phys(info->cpu_addr); + *len = buffer->size; + + return 0; +} + +static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + struct device *dev = buffer->heap->priv; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle, + buffer->size); +} + +static struct ion_heap_ops ion_cma_ops = { + .allocate = ion_cma_allocate, + .free = ion_cma_free, + .phys = ion_cma_phys, + .map_user = ion_cma_mmap, +}; + +struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data, + struct device *dev) +{ + struct ion_heap *heap; + + heap = ion_heap_create(data); + + if (heap) { + heap->ops = &ion_cma_ops; + /* set device as private heaps data, later it will be + * used to make the link with reserved CMA memory */ + heap->priv = dev; + } + return heap; +} +EXPORT_SYMBOL(ion_cma_heap_create); diff --git a/drivers/gpu/ion/cma/ion_cma_heap.h b/drivers/gpu/ion/cma/ion_cma_heap.h new file mode 100644 index 0000000..267e654 --- /dev/null +++ b/drivers/gpu/ion/cma/ion_cma_heap.h @@ -0,0 +1,11 @@ +/* + * ion_cma_heap.h + * + * Copyright (C) Linaro 2012 + * + * Author: benjamin.gaignard@linaro.org for ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2 + */ + +struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data, + struct device *dev);