img_mem_coherent.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*!
  2. *****************************************************************************
  3. * Copyright (c) Imagination Technologies Ltd.
  4. *
  5. * The contents of this file are subject to the MIT license as set out below.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of the
  26. * GNU General Public License Version 2 ("GPL")in which case the provisions of
  27. * GPL are applicable instead of those above.
  28. *
  29. * If you wish to allow use of your version of this file only under the terms
  30. * of GPL, and not to allow others to use your version of this file under the
  31. * terms of the MIT license, indicate your decision by deleting the provisions
  32. * above and replace them with the notice and other provisions required by GPL
  33. * as set out in the file called "GPLHEADER" included in this distribution. If
  34. * you do not delete the provisions above, a recipient may use your version of
  35. * this file under the terms of either the MIT license or GPL.
  36. *
  37. * This License is also included in this distribution in the file called
  38. * "MIT_COPYING".
  39. *
  40. *****************************************************************************/
  41. #include <linux/module.h>
  42. #include <linux/mm.h>
  43. #include <linux/slab.h>
  44. #include <linux/scatterlist.h>
  45. #include <linux/gfp.h>
  46. #include <linux/vmalloc.h>
  47. #include <linux/dma-mapping.h>
  48. #include <img_mem_man.h>
  49. #include "img_mem_man_priv.h"
  50. struct buffer_data {
  51. void *kptr;
  52. dma_addr_t dma_handle; /* addr returned by dma_alloc_coherent */
  53. uint64_t *addrs; /* array of physical addresses, upcast to 64-bit */
  54. struct device *dev;
  55. size_t size;
  56. };
  57. static int trace_physical_pages;
  58. static int coherent_heap_alloc(struct device *device, struct heap *heap,
  59. size_t size, enum img_mem_attr attr,
  60. struct buffer *buffer)
  61. {
  62. struct buffer_data *buffer_data;
  63. phys_addr_t phys_addr;
  64. size_t pages, page;
  65. pr_debug("%s:%d buffer %d (0x%p)\n", __func__, __LINE__,
  66. buffer->id, buffer);
  67. buffer_data = kmalloc(sizeof(struct buffer_data), GFP_KERNEL);
  68. if (!buffer_data)
  69. return -ENOMEM;
  70. pages = size / PAGE_SIZE;
  71. buffer_data->addrs = kmalloc_array(pages, sizeof(uint64_t), GFP_KERNEL);
  72. if (!buffer_data->addrs) {
  73. kfree(buffer_data);
  74. return -ENOMEM;
  75. }
  76. buffer_data->dev = device;
  77. buffer_data->size = size;
  78. buffer_data->kptr = dma_alloc_coherent(device,
  79. size,
  80. &buffer_data->dma_handle,
  81. heap->options.coherent.gfp_flags);
  82. if (!buffer_data->kptr) {
  83. pr_err("%s dma_alloc_coherent failed!\n", __func__);
  84. kfree(buffer_data->addrs);
  85. kfree(buffer_data);
  86. return -ENOMEM;
  87. }
  88. buffer->kptr = (void *)buffer_data->kptr;
  89. page = 0;
  90. phys_addr = buffer_data->dma_handle;
  91. while (page < pages) {
  92. if (trace_physical_pages)
  93. pr_info("%s phys %llx\n",
  94. __func__, (unsigned long long)phys_addr);
  95. buffer_data->addrs[page++] = phys_addr;
  96. phys_addr += PAGE_SIZE;
  97. };
  98. buffer->priv = buffer_data;
  99. pr_debug("%s buffer %d kptr %p phys %#llx size %zu\n", __func__,
  100. buffer->id, buffer->kptr,
  101. (unsigned long long)buffer_data->addrs[0], size);
  102. return 0;
  103. }
  104. static void coherent_heap_free(struct heap *heap, struct buffer *buffer)
  105. {
  106. struct buffer_data *buffer_data = buffer->priv;
  107. pr_debug("%s:%d buffer %d (0x%p)\n", __func__, __LINE__,
  108. buffer->id, buffer);
  109. dma_free_coherent(buffer_data->dev, buffer_data->size,
  110. buffer_data->kptr, buffer_data->dma_handle);
  111. kfree(buffer_data->addrs);
  112. kfree(buffer_data);
  113. }
  114. static int coherent_heap_map_um(struct heap *heap, struct buffer *buffer,
  115. struct vm_area_struct *vma)
  116. {
  117. struct buffer_data *buffer_data = buffer->priv;
  118. unsigned long pfn = *buffer_data->addrs >> PAGE_SHIFT;
  119. pr_debug("%s:%d buffer %d (0x%p)\n", __func__, __LINE__,
  120. buffer->id, buffer);
  121. pr_debug("%s:%d vm_start %#lx vm_end %#lx size %ld\n",
  122. __func__, __LINE__,
  123. vma->vm_start, vma->vm_end, vma->vm_end - vma->vm_start);
  124. vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
  125. return remap_pfn_range(vma, vma->vm_start, pfn,
  126. vma->vm_end - vma->vm_start, vma->vm_page_prot);
  127. }
  128. static int coherent_heap_map_km(struct heap *heap, struct buffer *buffer)
  129. {
  130. pr_debug("%s:%d buffer %d (0x%p) kptr 0x%p\n", __func__, __LINE__,
  131. buffer->id, buffer, buffer->kptr);
  132. return 0;
  133. }
  134. static int coherent_heap_unmap_km(struct heap *heap, struct buffer *buffer)
  135. {
  136. pr_debug("%s:%d buffer %d (0x%p) kptr 0x%p\n", __func__, __LINE__,
  137. buffer->id, buffer, buffer->kptr);
  138. return 0;
  139. }
  140. static int coherent_heap_get_page_array(struct heap *heap,
  141. struct buffer *buffer,
  142. uint64_t **addrs)
  143. {
  144. struct buffer_data *buffer_data = buffer->priv;
  145. *addrs = buffer_data->addrs;
  146. return 0;
  147. }
  148. static void coherent_heap_destroy(struct heap *heap)
  149. {
  150. pr_debug("%s:%d\n", __func__, __LINE__);
  151. }
  152. static struct heap_ops coherent_heap_ops = {
  153. .alloc = coherent_heap_alloc,
  154. .import = NULL,
  155. .free = coherent_heap_free,
  156. .map_um = coherent_heap_map_um,
  157. .unmap_um = NULL,
  158. .map_km = coherent_heap_map_km,
  159. .unmap_km = coherent_heap_unmap_km,
  160. .get_sg_table = NULL,
  161. .get_page_array = coherent_heap_get_page_array,
  162. .sync_cpu_to_dev = NULL,
  163. .sync_dev_to_cpu = NULL,
  164. .set_offset = NULL,
  165. .destroy = coherent_heap_destroy,
  166. };
  167. int img_mem_coherent_init(const struct heap_config *config, struct heap *heap)
  168. {
  169. pr_debug("%s gfp:%x\n", __func__,
  170. config->options.coherent.gfp_flags);
  171. heap->ops = &coherent_heap_ops;
  172. return 0;
  173. }