linux/kernel/dma/remap.c
<<
>>
Prefs
   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
   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        unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
  70        vunmap(cpu_addr);
  71}
  72