xref: /openbmc/linux/kernel/dma/remap.c (revision 82df5b73)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2014 The Linux Foundation
4  */
5 #include <linux/dma-mapping.h>
6 #include <linux/slab.h>
7 #include <linux/vmalloc.h>
8 
9 struct page **dma_common_find_pages(void *cpu_addr)
10 {
11 	struct vm_struct *area = find_vm_area(cpu_addr);
12 
13 	if (!area || area->flags != VM_DMA_COHERENT)
14 		return NULL;
15 	return area->pages;
16 }
17 
18 /*
19  * Remaps an array of PAGE_SIZE pages into another vm_area.
20  * Cannot be used in non-sleeping contexts
21  */
22 void *dma_common_pages_remap(struct page **pages, size_t size,
23 			 pgprot_t prot, const void *caller)
24 {
25 	void *vaddr;
26 
27 	vaddr = vmap(pages, size >> PAGE_SHIFT, VM_DMA_COHERENT, prot);
28 	if (vaddr)
29 		find_vm_area(vaddr)->pages = pages;
30 	return vaddr;
31 }
32 
33 /*
34  * Remaps an allocated contiguous region into another vm_area.
35  * Cannot be used in non-sleeping contexts
36  */
37 void *dma_common_contiguous_remap(struct page *page, size_t size,
38 			pgprot_t prot, const void *caller)
39 {
40 	int count = size >> PAGE_SHIFT;
41 	struct page **pages;
42 	void *vaddr;
43 	int i;
44 
45 	pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
46 	if (!pages)
47 		return NULL;
48 	for (i = 0; i < count; i++)
49 		pages[i] = nth_page(page, i);
50 	vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
51 	kfree(pages);
52 
53 	return vaddr;
54 }
55 
56 /*
57  * Unmaps a range previously mapped by dma_common_*_remap
58  */
59 void dma_common_free_remap(void *cpu_addr, size_t size)
60 {
61 	struct vm_struct *area = find_vm_area(cpu_addr);
62 
63 	if (!area || area->flags != VM_DMA_COHERENT) {
64 		WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
65 		return;
66 	}
67 
68 	unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
69 	vunmap(cpu_addr);
70 }
71