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

Commit 1beb770c authored by Laura Abbott's avatar Laura Abbott Committed by Gerrit - the friendly Code Review server
Browse files

arm: dma-mapping: Add dma_remap functions



After getting an allocation from dma_alloc_coherent, there
may be cases where it is necessary to remap the handle
into the CPU's address space (e.g. no CPU side mapping was
requested at allocation time but now one is needed). Add
APIs to bring a handle into the CPU address space again.

Change-Id: Ia954c603743ea5f6fbe24e79e4f0c00b94532675
Signed-off-by: default avatarLaura Abbott <lauraa@codeaurora.org>
Signed-off-by: default avatarIan Maund <imaund@codeaurora.org>
Signed-off-by: default avatarVijayanand Jitta <vjitta@codeaurora.org>
Signed-off-by: default avatarCharan Teja Reddy <charante@codeaurora.org>
Signed-off-by: default avatarQingqing Zhou <qqzhou@codeaurora.org>
parent e0c84257
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -112,6 +112,21 @@ static void __dma_page_cpu_to_dev(struct page *, unsigned long,
static void __dma_page_dev_to_cpu(struct page *, unsigned long,
		size_t, enum dma_data_direction);

static void *
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
		const void *caller);

static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn);

static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot);

static void *arm_dma_remap(struct device *dev, void *cpu_addr,
			dma_addr_t handle, size_t size,
			unsigned long attrs);

static void arm_dma_unremap(struct device *dev, void *remapped_addr,
				size_t size);

/**
 * arm_dma_map_page - map a portion of a page for streaming DMA
 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -200,6 +215,8 @@ const struct dma_map_ops arm_dma_ops = {
	.sync_sg_for_device	= arm_dma_sync_sg_for_device,
	.mapping_error		= arm_dma_mapping_error,
	.dma_supported		= arm_dma_supported,
	.remap			= arm_dma_remap,
	.unremap		= arm_dma_unremap,
};
EXPORT_SYMBOL(arm_dma_ops);

@@ -878,6 +895,38 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
	return ret;
}

static void *arm_dma_remap(struct device *dev, void *cpu_addr,
			dma_addr_t handle, size_t size,
			unsigned long attrs)
{
	void *ptr;
	struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
	unsigned long offset = handle & ~PAGE_MASK;

	size = PAGE_ALIGN(size + offset);
	ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot,
			__builtin_return_address(0));
	return ptr ? ptr + offset : ptr;
}

static void arm_dma_unremap(struct device *dev, void *remapped_addr,
				size_t size)
{
	unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
	struct vm_struct *area;

	remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK);

	area = find_vm_area(remapped_addr);
	if (!area || (area->flags & flags) != flags) {
		WARN(1, "trying to free invalid coherent area: %pK\n",
			remapped_addr);
		return;
	}

	vunmap(remapped_addr);
}
/*
 * Create userspace mapping for the DMA-coherent memory.
 */