1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2014 The Linux Foundation |
4 | */ |
5 | #include <linux/dma-map-ops.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(addr: 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, PAGE_ALIGN(size) >> PAGE_SHIFT, |
28 | VM_DMA_COHERENT, prot); |
29 | if (vaddr) |
30 | find_vm_area(addr: vaddr)->pages = pages; |
31 | return vaddr; |
32 | } |
33 | |
34 | /* |
35 | * Remaps an allocated contiguous region into another vm_area. |
36 | * Cannot be used in non-sleeping contexts |
37 | */ |
38 | void *dma_common_contiguous_remap(struct page *page, size_t size, |
39 | pgprot_t prot, const void *caller) |
40 | { |
41 | int count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
42 | struct page **pages; |
43 | void *vaddr; |
44 | int i; |
45 | |
46 | pages = kvmalloc_array(n: count, size: sizeof(struct page *), GFP_KERNEL); |
47 | if (!pages) |
48 | return NULL; |
49 | for (i = 0; i < count; i++) |
50 | pages[i] = nth_page(page, i); |
51 | vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); |
52 | kvfree(addr: pages); |
53 | |
54 | return vaddr; |
55 | } |
56 | |
57 | /* |
58 | * Unmaps a range previously mapped by dma_common_*_remap |
59 | */ |
60 | void dma_common_free_remap(void *cpu_addr, size_t size) |
61 | { |
62 | struct vm_struct *area = find_vm_area(addr: cpu_addr); |
63 | |
64 | if (!area || area->flags != VM_DMA_COHERENT) { |
65 | WARN(1, "trying to free invalid coherent area: %p\n" , cpu_addr); |
66 | return; |
67 | } |
68 | |
69 | vunmap(addr: cpu_addr); |
70 | } |
71 | |