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(cpu_addr); 12 13 if (!area || !(area->flags & VM_DMA_COHERENT)) 14 return NULL; 15 WARN(area->flags != VM_DMA_COHERENT, 16 "unexpected flags in area: %p\n", cpu_addr); 17 return area->pages; 18 } 19 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, 25 pgprot_t prot, const void *caller) 26 { 27 void *vaddr; 28 29 vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT, 30 VM_DMA_COHERENT, prot); 31 if (vaddr) 32 find_vm_area(vaddr)->pages = pages; 33 return vaddr; 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, 41 pgprot_t prot, const void *caller) 42 { 43 int count = PAGE_ALIGN(size) >> PAGE_SHIFT; 44 struct page **pages; 45 void *vaddr; 46 int i; 47 48 pages = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL); 49 if (!pages) 50 return NULL; 51 for (i = 0; i < count; i++) 52 pages[i] = nth_page(page, i); 53 vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); 54 kvfree(pages); 55 56 return vaddr; 57 } 58 59 /* 60 * Unmaps a range previously mapped by dma_common_*_remap 61 */ 62 void dma_common_free_remap(void *cpu_addr, size_t size) 63 { 64 struct vm_struct *area = find_vm_area(cpu_addr); 65 66 if (!area || !(area->flags & VM_DMA_COHERENT)) { 67 WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); 68 return; 69 } 70 71 vunmap(cpu_addr); 72 } 73