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, size >> PAGE_SHIFT, VM_DMA_COHERENT, prot); 28 if (vaddr) 29 find_vm_area(vaddr)->pages = pages; 30 return vaddr; 31 } 32 33 /* 34 * Remaps an allocated contiguous region into another vm_area. 35 * Cannot be used in non-sleeping contexts 36 */ 37 void *dma_common_contiguous_remap(struct page *page, size_t size, 38 pgprot_t prot, const void *caller) 39 { 40 int count = size >> PAGE_SHIFT; 41 struct page **pages; 42 void *vaddr; 43 int i; 44 45 pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL); 46 if (!pages) 47 return NULL; 48 for (i = 0; i < count; i++) 49 pages[i] = nth_page(page, i); 50 vaddr = vmap(pages, count, VM_DMA_COHERENT, prot); 51 kfree(pages); 52 53 return vaddr; 54 } 55 56 /* 57 * Unmaps a range previously mapped by dma_common_*_remap 58 */ 59 void dma_common_free_remap(void *cpu_addr, size_t size) 60 { 61 struct vm_struct *area = find_vm_area(cpu_addr); 62 63 if (!area || area->flags != VM_DMA_COHERENT) { 64 WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); 65 return; 66 } 67 68 unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size)); 69 vunmap(cpu_addr); 70 } 71