1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2014 The Linux Foundation 4 */ 5 #include <linux/dma-mapping.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 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(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 = kmalloc_array(count, 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 kfree(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(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 unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size)); 70 vunmap(cpu_addr); 71 } 72