Merge tag 'arm-soc-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-block.git] / kernel / dma / remap.c
CommitLineData
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
9struct 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 */
22void *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 */
38void *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 60void 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}