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 | ||
fa3c109a | 13 | if (!area || !(area->flags & VM_DMA_COHERENT)) |
5cf45379 | 14 | return NULL; |
fa3c109a YA |
15 | WARN(area->flags != VM_DMA_COHERENT, |
16 | "unexpected flags in area: %p\n", cpu_addr); | |
5cf45379 CH |
17 | return area->pages; |
18 | } | |
19 | ||
f0edfea8 CH |
20 | /* |
21 | * Remaps an array of PAGE_SIZE pages into another vm_area. | |
22 | * Cannot be used in non-sleeping contexts | |
23 | */ | |
24 | void *dma_common_pages_remap(struct page **pages, size_t size, | |
51231740 | 25 | pgprot_t prot, const void *caller) |
f0edfea8 | 26 | { |
515e5b6d | 27 | void *vaddr; |
f0edfea8 | 28 | |
8e36baf9 EA |
29 | vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT, |
30 | VM_DMA_COHERENT, prot); | |
515e5b6d CH |
31 | if (vaddr) |
32 | find_vm_area(vaddr)->pages = pages; | |
33 | return vaddr; | |
f0edfea8 CH |
34 | } |
35 | ||
36 | /* | |
37 | * Remaps an allocated contiguous region into another vm_area. | |
38 | * Cannot be used in non-sleeping contexts | |
39 | */ | |
40 | void *dma_common_contiguous_remap(struct page *page, size_t size, | |
f0edfea8 CH |
41 | pgprot_t prot, const void *caller) |
42 | { | |
8e36baf9 | 43 | int count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
f0edfea8 | 44 | struct page **pages; |
515e5b6d CH |
45 | void *vaddr; |
46 | int i; | |
f0edfea8 | 47 | |
51ff97d5 | 48 | pages = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL); |
f0edfea8 CH |
49 | if (!pages) |
50 | return NULL; | |
515e5b6d | 51 | for (i = 0; i < count; i++) |
f0edfea8 | 52 | pages[i] = nth_page(page, i); |
515e5b6d | 53 | vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); |
51ff97d5 | 54 | kvfree(pages); |
f0edfea8 | 55 | |
515e5b6d | 56 | return vaddr; |
f0edfea8 CH |
57 | } |
58 | ||
59 | /* | |
60 | * Unmaps a range previously mapped by dma_common_*_remap | |
61 | */ | |
51231740 | 62 | void dma_common_free_remap(void *cpu_addr, size_t size) |
f0edfea8 | 63 | { |
2cf2aa6a | 64 | struct vm_struct *area = find_vm_area(cpu_addr); |
f0edfea8 | 65 | |
fa3c109a | 66 | if (!area || !(area->flags & VM_DMA_COHERENT)) { |
f0edfea8 CH |
67 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
68 | return; | |
69 | } | |
70 | ||
f0edfea8 CH |
71 | vunmap(cpu_addr); |
72 | } |