^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2014 The Linux Foundation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/dma-map-ops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) struct page **dma_common_find_pages(void *cpu_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct vm_struct *area = find_vm_area(cpu_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) if (!area || area->flags != VM_DMA_COHERENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) return area->pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Remaps an array of PAGE_SIZE pages into another vm_area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Cannot be used in non-sleeping contexts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) void *dma_common_pages_remap(struct page **pages, size_t size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) pgprot_t prot, const void *caller)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) void *vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) VM_DMA_COHERENT, prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) find_vm_area(vaddr)->pages = pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Remaps an allocated contiguous region into another vm_area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Cannot be used in non-sleeping contexts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void *dma_common_contiguous_remap(struct page *page, size_t size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) pgprot_t prot, const void *caller)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct page **pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) void *vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (!pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) for (i = 0; i < count; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) pages[i] = nth_page(page, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) kfree(pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Unmaps a range previously mapped by dma_common_*_remap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) void dma_common_free_remap(void *cpu_addr, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct vm_struct *area = find_vm_area(cpu_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!area || area->flags != VM_DMA_COHERENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) vunmap(cpu_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }