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

Commit 9df4af06 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "arm: dma-mapping: Add dma_remap functions"

parents d5f60c07 1beb770c
Loading
Loading
Loading
Loading
+72 −13
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);

@@ -526,12 +543,28 @@ static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
	return 0;
}

static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr,
			    void *data)
{
	pte_clear(&init_mm, addr, pte);
	return 0;
}

static void __dma_remap(struct page *page, size_t size, pgprot_t prot,
			bool want_vaddr)
{
	unsigned long start = (unsigned long) page_address(page);
	unsigned end = start + size;
	int (*func)(pte_t *pte, pgtable_t token, unsigned long addr,
			    void *data);

	if (!want_vaddr)
		func = __dma_clear_pte;
	else
		func = __dma_update_pte;

	apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot);
	apply_to_page_range(&init_mm, start, size, func, &prot);
	mb(); /*Ensure pte's are updated */
	flush_tlb_kernel_range(start, end);
}

@@ -614,9 +647,6 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,

	__dma_clear_buffer(page, size, coherent_flag);

	if (!want_vaddr)
		goto out;

	if (PageHighMem(page)) {
		ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
		if (!ptr) {
@@ -624,11 +654,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
			return NULL;
		}
	} else {
		__dma_remap(page, size, prot);
		__dma_remap(page, size, prot, want_vaddr);
		ptr = page_address(page);
	}

 out:
	*ret_page = page;
	return ptr;
}
@@ -636,12 +665,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
static void __free_from_contiguous(struct device *dev, struct page *page,
				   void *cpu_addr, size_t size, bool want_vaddr)
{
	if (want_vaddr) {
	if (PageHighMem(page))
		__dma_free_remap(cpu_addr, size, true);
	else
			__dma_remap(page, size, PAGE_KERNEL);
	}
		__dma_remap(page, size, PAGE_KERNEL, true);
	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}

@@ -868,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.
 */