remap.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. struct page **dma_common_find_pages(void *cpu_addr)
  9. {
  10. struct vm_struct *area = find_vm_area(cpu_addr);
  11. if (!area || !(area->flags & VM_DMA_COHERENT))
  12. return NULL;
  13. WARN(area->flags != VM_DMA_COHERENT,
  14. "unexpected flags in area: %p\n", cpu_addr);
  15. return area->pages;
  16. }
  17. /*
  18. * Remaps an array of PAGE_SIZE pages into another vm_area.
  19. * Cannot be used in non-sleeping contexts
  20. */
  21. void *dma_common_pages_remap(struct page **pages, size_t size,
  22. pgprot_t prot, const void *caller)
  23. {
  24. void *vaddr;
  25. vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT,
  26. VM_DMA_COHERENT, prot);
  27. if (vaddr)
  28. find_vm_area(vaddr)->pages = pages;
  29. return vaddr;
  30. }
  31. /*
  32. * Remaps an allocated contiguous region into another vm_area.
  33. * Cannot be used in non-sleeping contexts
  34. */
  35. void *dma_common_contiguous_remap(struct page *page, size_t size,
  36. pgprot_t prot, const void *caller)
  37. {
  38. int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
  39. struct page **pages;
  40. void *vaddr;
  41. int i;
  42. pages = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
  43. if (!pages)
  44. return NULL;
  45. for (i = 0; i < count; i++)
  46. pages[i] = nth_page(page, i);
  47. vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
  48. kvfree(pages);
  49. return vaddr;
  50. }
  51. /*
  52. * Unmaps a range previously mapped by dma_common_*_remap
  53. */
  54. void dma_common_free_remap(void *cpu_addr, size_t size)
  55. {
  56. struct vm_struct *area = find_vm_area(cpu_addr);
  57. if (!area || !(area->flags & VM_DMA_COHERENT)) {
  58. WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
  59. return;
  60. }
  61. vunmap(cpu_addr);
  62. }