remap.c (1614B)
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 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 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, 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 */ 38void *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 */ 60void 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 vunmap(cpu_addr); 70}