Commit | Line | Data |
---|---|---|
f0edfea8 CH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2014 The Linux Foundation | |
4 | */ | |
695cebe5 | 5 | #include <linux/dma-map-ops.h> |
f0edfea8 CH |
6 | #include <linux/slab.h> |
7 | #include <linux/vmalloc.h> | |
8 | ||
5cf45379 CH |
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 | ||
f0edfea8 CH |
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, | |
51231740 | 23 | pgprot_t prot, const void *caller) |
f0edfea8 | 24 | { |
515e5b6d | 25 | void *vaddr; |
f0edfea8 | 26 | |
8e36baf9 EA |
27 | vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT, |
28 | VM_DMA_COHERENT, prot); | |
515e5b6d CH |
29 | if (vaddr) |
30 | find_vm_area(vaddr)->pages = pages; | |
31 | return vaddr; | |
f0edfea8 CH |
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, | |
f0edfea8 CH |
39 | pgprot_t prot, const void *caller) |
40 | { | |
8e36baf9 | 41 | int count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
f0edfea8 | 42 | struct page **pages; |
515e5b6d CH |
43 | void *vaddr; |
44 | int i; | |
f0edfea8 | 45 | |
515e5b6d | 46 | pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL); |
f0edfea8 CH |
47 | if (!pages) |
48 | return NULL; | |
515e5b6d | 49 | for (i = 0; i < count; i++) |
f0edfea8 | 50 | pages[i] = nth_page(page, i); |
515e5b6d | 51 | vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); |
f0edfea8 CH |
52 | kfree(pages); |
53 | ||
515e5b6d | 54 | return vaddr; |
f0edfea8 CH |
55 | } |
56 | ||
57 | /* | |
58 | * Unmaps a range previously mapped by dma_common_*_remap | |
59 | */ | |
51231740 | 60 | void dma_common_free_remap(void *cpu_addr, size_t size) |
f0edfea8 | 61 | { |
2cf2aa6a | 62 | struct vm_struct *area = find_vm_area(cpu_addr); |
f0edfea8 | 63 | |
2cf2aa6a | 64 | if (!area || area->flags != VM_DMA_COHERENT) { |
f0edfea8 CH |
65 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
66 | return; | |
67 | } | |
68 | ||
f0edfea8 CH |
69 | vunmap(cpu_addr); |
70 | } |