Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b97c6044 authored by Vivek Kumar's avatar Vivek Kumar Committed by Zhiqiang Tu
Browse files

staging: ion: Add support for ion CMA heap to allocate from carveouts



Because of an XPU errata we need to temporarily have the ION CMA heap
support allocating from a careveout which isn't mapped into the kernel.
Once the errata is fixed this change can be reverted. This patch is
written with reference from commit "a568a844adc" in msm-4.14.

Change-Id: Id2bbb81644be514bdb90e743a028e65a05ebd55e
Signed-off-by: default avatarLiam Mark <lmark@codeaurora.org>
Signed-off-by: default avatarVivek Kumar <vivekuma@codeaurora.org>
Signed-off-by: default avatarZhiqiang Tu <ztu@codeaurora.org>
parent 317d25c7
Loading
Loading
Loading
Loading
+91 −49
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/scatterlist.h>
#include <soc/qcom/secure_buffer.h>
#include <linux/highmem.h>
#include <linux/of.h>
#include "msm_ion_priv.h"
#include "ion_secure_util.h"

@@ -25,6 +26,12 @@ struct ion_cma_heap {
	struct cma *cma;
};

struct ion_cma_buffer_info {
	struct msm_ion_buf_lock_state lock_state;
	void *cpu_addr;
	dma_addr_t handle;
};

#define to_cma_heap(x) \
	container_of(to_msm_ion_heap(x), struct ion_cma_heap, heap)

@@ -34,34 +41,61 @@ static bool ion_heap_is_cma_heap_type(enum ion_heap_type type)
	return type == ION_HEAP_TYPE_DMA;
}

static bool ion_cma_has_kernel_mapping(struct ion_cma_heap *cma_heap)
{
	struct device *dev = cma_heap->heap.dev;
	struct device_node *mem_region;

	mem_region = of_parse_phandle(dev->of_node, "memory-region", 0);
	if (!mem_region)
		return false;

	return !of_property_read_bool(mem_region, "no-map");
}

static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
			    unsigned long len,
			    unsigned long flags)
{
	struct ion_cma_heap *cma_heap = to_cma_heap(heap);
	struct sg_table *table;
	struct msm_ion_buf_lock_state *lock_state;
	struct page *pages;
	struct ion_cma_buffer_info *info;
	struct page *pages = NULL;
	unsigned long size = PAGE_ALIGN(len);
	unsigned long nr_pages = size >> PAGE_SHIFT;
	unsigned long align = get_order(size);
	int ret;
	struct device *dev = cma_heap->heap.dev;

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	if (ion_heap_is_cma_heap_type(buffer->heap->type) &&
	    is_secure_allocation(buffer->flags)) {
		pr_err("%s: CMA heap doesn't support secure allocations\n",
		       __func__);
		return -EINVAL;
		goto free_info;
	}

	if (align > CONFIG_CMA_ALIGNMENT)
		align = CONFIG_CMA_ALIGNMENT;

	if (!ion_cma_has_kernel_mapping(cma_heap)) {
		flags &= ~((unsigned long)ION_FLAG_CACHED);
		buffer->flags = flags;

		info->cpu_addr = dma_alloc_wc(dev, size, &info->handle,
					      GFP_KERNEL);
		if (!info->cpu_addr) {
			dev_err(dev, "failed to allocate buffer\n");
			goto free_info;
		}
		pages = pfn_to_page(PFN_DOWN(info->handle));
	} else {
		pages = cma_alloc(cma_heap->cma, nr_pages, align, false);
		if (!pages)
		return -ENOMEM;

			goto free_info;
		if (hlos_accessible_buffer(buffer)) {
			if (PageHighMem(pages)) {
				unsigned long nr_clear_pages = nr_pages;
@@ -85,46 +119,60 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
		    (!ion_buffer_cached(buffer)))
			ion_pages_sync_for_device(dev, pages, size,
						  DMA_BIDIRECTIONAL);
	}

	table = kmalloc(sizeof(*table), GFP_KERNEL);
	if (!table)
		goto err;
		goto err_alloc;

	ret = sg_alloc_table(table, 1, GFP_KERNEL);
	if (ret)
		goto free_mem;
		goto free_table;

	sg_set_page(table->sgl, pages, size, 0);
;
	buffer->sg_table = table;

	lock_state = kzalloc(sizeof(*lock_state), GFP_KERNEL);
	if (!lock_state)
		goto free_mem;
	buffer->priv_virt = lock_state;
	buffer->sg_table = table;
	buffer->priv_virt = &info->lock_state;

	ion_prepare_sgl_for_force_dma_sync(buffer->sg_table);
	return 0;

free_mem:
free_table:
	kfree(table);
err:
err_alloc:
	if (info->cpu_addr)
		dma_free_attrs(dev, size, info->cpu_addr, info->handle, 0);
	else
		cma_release(cma_heap->cma, pages, nr_pages);
free_info:
	kfree(info);
	return -ENOMEM;
}

static void ion_cma_free(struct ion_buffer *buffer)
{
	struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap);
	struct msm_ion_buf_lock_state *lock_state =
			(struct msm_ion_buf_lock_state *)buffer->priv_virt;
	struct ion_cma_buffer_info *info = container_of(lock_state,
			struct ion_cma_buffer_info, lock_state);

	if (info->cpu_addr) {
		struct device *dev = cma_heap->heap.dev;

		dma_free_attrs(dev, PAGE_ALIGN(buffer->size), info->cpu_addr,
			       info->handle, 0);
	} else {
		struct page *pages = sg_page(buffer->sg_table->sgl);
	unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;

		unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT;
		/* release memory */
		cma_release(cma_heap->cma, pages, nr_pages);
	}
	/* release sg table */
	sg_free_table(buffer->sg_table);
	kfree(buffer->sg_table);
	kfree(buffer->priv_virt);
	kfree(info);
}

static struct ion_heap_ops ion_cma_ops = {
@@ -137,9 +185,6 @@ struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)
	struct ion_cma_heap *cma_heap;
	struct device *dev = (struct device *)data->priv;

	if (!dev->cma_area)
		return ERR_PTR(-EINVAL);

	cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL);

	if (!cma_heap)
@@ -210,9 +255,6 @@ struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *data)
	struct ion_cma_heap *cma_heap;
	struct device *dev = (struct device *)data->priv;

	if (!dev->cma_area)
		return ERR_PTR(-EINVAL);

	cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL);

	if (!cma_heap)