mali_memory.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * This confidential and proprietary software may be used only as
  3. * authorised by a licensing agreement from ARM Limited
  4. * (C) COPYRIGHT 2013 ARM Limited
  5. * ALL RIGHTS RESERVED
  6. * The entire notice above must be reproduced on all authorised
  7. * copies and copies may only be made to the extent permitted
  8. * by a licensing agreement from ARM Limited.
  9. */
  10. #include <linux/list.h>
  11. #include <linux/mm.h>
  12. #include <linux/mm_types.h>
  13. #include <linux/fs.h>
  14. #include <linux/dma-mapping.h>
  15. #include <linux/slab.h>
  16. #include <linux/version.h>
  17. #include <linux/platform_device.h>
  18. #include "mali_osk.h"
  19. #include "mali_osk_mali.h"
  20. #include "mali_kernel_linux.h"
  21. #include "mali_scheduler.h"
  22. #include "mali_kernel_descriptor_mapping.h"
  23. #include "mali_memory.h"
  24. #include "mali_memory_dma_buf.h"
  25. #include "mali_memory_os_alloc.h"
  26. #include "mali_memory_block_alloc.h"
  27. /* session->memory_lock must be held when calling this function */
  28. static void mali_mem_release(mali_mem_allocation *descriptor)
  29. {
  30. MALI_DEBUG_ASSERT_POINTER(descriptor);
  31. MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
  32. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  33. switch (descriptor->type) {
  34. case MALI_MEM_OS:
  35. mali_mem_os_release(descriptor);
  36. break;
  37. case MALI_MEM_DMA_BUF:
  38. #if defined(CONFIG_DMA_SHARED_BUFFER)
  39. mali_mem_dma_buf_release(descriptor);
  40. #endif
  41. break;
  42. case MALI_MEM_UMP:
  43. #if defined(CONFIG_MALI400_UMP)
  44. mali_mem_ump_release(descriptor);
  45. #endif
  46. break;
  47. case MALI_MEM_EXTERNAL:
  48. mali_mem_external_release(descriptor);
  49. break;
  50. case MALI_MEM_BLOCK:
  51. mali_mem_block_release(descriptor);
  52. break;
  53. }
  54. }
  55. static void mali_mem_vma_open(struct vm_area_struct * vma)
  56. {
  57. mali_mem_allocation *descriptor = (mali_mem_allocation*)vma->vm_private_data;
  58. MALI_DEBUG_PRINT(4, ("Open called on vma %p\n", vma));
  59. descriptor->cpu_mapping.ref++;
  60. return;
  61. }
  62. static void mali_mem_vma_close(struct vm_area_struct *vma)
  63. {
  64. mali_mem_allocation *descriptor;
  65. struct mali_session_data *session;
  66. mali_mem_virt_cpu_mapping *mapping;
  67. MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma));
  68. descriptor = (mali_mem_allocation*)vma->vm_private_data;
  69. BUG_ON(!descriptor);
  70. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  71. mapping = &descriptor->cpu_mapping;
  72. BUG_ON(0 == mapping->ref);
  73. mapping->ref--;
  74. if (0 != mapping->ref) {
  75. MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", mapping->ref));
  76. return;
  77. }
  78. session = descriptor->session;
  79. mali_descriptor_mapping_free(session->descriptor_mapping, descriptor->id);
  80. _mali_osk_mutex_wait(session->memory_lock);
  81. mali_mem_release(descriptor);
  82. _mali_osk_mutex_signal(session->memory_lock);
  83. mali_mem_descriptor_destroy(descriptor);
  84. }
  85. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
  86. static int mali_kernel_memory_cpu_page_fault_handler(struct vm_fault *vmf)
  87. #else
  88. static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf)
  89. #endif
  90. {
  91. mali_mem_allocation *descriptor;
  92. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
  93. struct vm_area_struct *vma = vmf->vma;
  94. #endif
  95. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
  96. unsigned long address = (unsigned long)vmf->address;
  97. #else
  98. unsigned long address = (unsigned long)vmf->virtual_address;
  99. #endif
  100. descriptor = (mali_mem_allocation *)vma->vm_private_data;
  101. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  102. /*
  103. * We always fail the call since all memory is pre-faulted when assigned to the process.
  104. * Only the Mali cores can use page faults to extend buffers.
  105. */
  106. MALI_DEBUG_PRINT(1, ("Page-fault in Mali memory region caused by the CPU.\n"));
  107. MALI_DEBUG_PRINT(1, ("Tried to access %p (process local virtual address) which is not currently mapped to any Mali memory.\n", (void*)address));
  108. MALI_IGNORE(address);
  109. MALI_IGNORE(descriptor);
  110. return VM_FAULT_SIGBUS;
  111. }
  112. struct vm_operations_struct mali_kernel_vm_ops = {
  113. .open = mali_mem_vma_open,
  114. .close = mali_mem_vma_close,
  115. .fault = mali_kernel_memory_cpu_page_fault_handler
  116. };
  117. /** @note munmap handler is done by vma close handler */
  118. int mali_mmap(struct file *filp, struct vm_area_struct *vma)
  119. {
  120. struct mali_session_data *session;
  121. mali_mem_allocation *descriptor;
  122. u32 size = vma->vm_end - vma->vm_start;
  123. u32 mali_addr = vma->vm_pgoff << PAGE_SHIFT;
  124. session = (struct mali_session_data *)filp->private_data;
  125. if (NULL == session) {
  126. MALI_PRINT_ERROR(("mmap called without any session data available\n"));
  127. return -EFAULT;
  128. }
  129. MALI_DEBUG_PRINT(4, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X vma->flags 0x%08x\n",
  130. (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT),
  131. (unsigned int)(vma->vm_end - vma->vm_start), vma->vm_flags));
  132. /* Set some bits which indicate that, the memory is IO memory, meaning
  133. * that no paging is to be performed and the memory should not be
  134. * included in crash dumps. And that the memory is reserved, meaning
  135. * that it's present and can never be paged out (see also previous
  136. * entry)
  137. */
  138. vma->vm_flags |= VM_IO;
  139. vma->vm_flags |= VM_DONTCOPY;
  140. vma->vm_flags |= VM_PFNMAP;
  141. #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
  142. vma->vm_flags |= VM_RESERVED;
  143. #else
  144. vma->vm_flags |= VM_DONTDUMP;
  145. vma->vm_flags |= VM_DONTEXPAND;
  146. #endif
  147. vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
  148. vma->vm_ops = &mali_kernel_vm_ops; /* Operations used on any memory system */
  149. descriptor = mali_mem_block_alloc(mali_addr, size, vma, session);
  150. if (NULL == descriptor) {
  151. descriptor = mali_mem_os_alloc(mali_addr, size, vma, session);
  152. if (NULL == descriptor) {
  153. MALI_DEBUG_PRINT(3, ("MMAP failed\n"));
  154. return -ENOMEM;
  155. }
  156. }
  157. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  158. vma->vm_private_data = (void*)descriptor;
  159. /* Put on descriptor map */
  160. if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &descriptor->id)) {
  161. _mali_osk_mutex_wait(session->memory_lock);
  162. mali_mem_os_release(descriptor);
  163. _mali_osk_mutex_signal(session->memory_lock);
  164. return -EFAULT;
  165. }
  166. return 0;
  167. }
  168. /* Prepare memory descriptor */
  169. mali_mem_allocation *mali_mem_descriptor_create(struct mali_session_data *session, mali_mem_type type)
  170. {
  171. mali_mem_allocation *descriptor;
  172. descriptor = (mali_mem_allocation*)kzalloc(sizeof(mali_mem_allocation), GFP_KERNEL);
  173. if (NULL == descriptor) {
  174. MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n"));
  175. return NULL;
  176. }
  177. MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_VALID_MAGIC);
  178. descriptor->flags = 0;
  179. descriptor->type = type;
  180. descriptor->session = session;
  181. return descriptor;
  182. }
  183. void mali_mem_descriptor_destroy(mali_mem_allocation *descriptor)
  184. {
  185. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  186. MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_FREED_MAGIC);
  187. kfree(descriptor);
  188. }
  189. _mali_osk_errcode_t mali_mem_mali_map_prepare(mali_mem_allocation *descriptor)
  190. {
  191. u32 size = descriptor->size;
  192. struct mali_session_data *session = descriptor->session;
  193. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  194. /* Map dma-buf into this session's page tables */
  195. if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
  196. size += MALI_MMU_PAGE_SIZE;
  197. }
  198. return mali_mmu_pagedir_map(session->page_directory, descriptor->mali_mapping.addr, size);
  199. }
  200. void mali_mem_mali_map_free(mali_mem_allocation *descriptor)
  201. {
  202. u32 size = descriptor->size;
  203. struct mali_session_data *session = descriptor->session;
  204. MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
  205. if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
  206. size += MALI_MMU_PAGE_SIZE;
  207. }
  208. /* Umap and flush L2 */
  209. mali_mmu_pagedir_unmap(session->page_directory, descriptor->mali_mapping.addr, descriptor->size);
  210. mali_scheduler_zap_all_active(session);
  211. }
  212. u32 _mali_ukk_report_memory_usage(void)
  213. {
  214. u32 sum = 0;
  215. sum += mali_mem_block_allocator_stat();
  216. sum += mali_mem_os_stat();
  217. return sum;
  218. }
  219. /**
  220. * Per-session memory descriptor mapping table sizes
  221. */
  222. #define MALI_MEM_DESCRIPTORS_INIT 64
  223. #define MALI_MEM_DESCRIPTORS_MAX 65536
  224. _mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data)
  225. {
  226. MALI_DEBUG_PRINT(5, ("Memory session begin\n"));
  227. /* Create descriptor mapping table */
  228. session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX);
  229. if (NULL == session_data->descriptor_mapping) {
  230. MALI_ERROR(_MALI_OSK_ERR_NOMEM);
  231. }
  232. session_data->memory_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
  233. _MALI_OSK_LOCK_ORDER_MEM_SESSION);
  234. if (NULL == session_data->memory_lock) {
  235. mali_descriptor_mapping_destroy(session_data->descriptor_mapping);
  236. _mali_osk_free(session_data);
  237. MALI_ERROR(_MALI_OSK_ERR_FAULT);
  238. }
  239. MALI_DEBUG_PRINT(5, ("MMU session begin: success\n"));
  240. MALI_SUCCESS;
  241. }
  242. /** @brief Callback function that releases memory
  243. *
  244. * session->memory_lock must be held when calling this function.
  245. */
  246. static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target)
  247. {
  248. mali_mem_allocation *descriptor;
  249. descriptor = (mali_mem_allocation*)map_target;
  250. MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
  251. MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target));
  252. MALI_DEBUG_ASSERT(descriptor);
  253. mali_mem_release(descriptor);
  254. mali_mem_descriptor_destroy(descriptor);
  255. }
  256. void mali_memory_session_end(struct mali_session_data *session)
  257. {
  258. MALI_DEBUG_PRINT(3, ("MMU session end\n"));
  259. if (NULL == session) {
  260. MALI_DEBUG_PRINT(1, ("No session data found during session end\n"));
  261. return;
  262. }
  263. /* Lock the session so we can modify the memory list */
  264. _mali_osk_mutex_wait(session->memory_lock);
  265. /* Free all allocations still in the descriptor map, and terminate the map */
  266. if (NULL != session->descriptor_mapping) {
  267. mali_descriptor_mapping_call_for_each(session->descriptor_mapping, descriptor_table_cleanup_callback);
  268. mali_descriptor_mapping_destroy(session->descriptor_mapping);
  269. session->descriptor_mapping = NULL;
  270. }
  271. _mali_osk_mutex_signal(session->memory_lock);
  272. /* Free the lock */
  273. _mali_osk_mutex_term(session->memory_lock);
  274. return;
  275. }
  276. _mali_osk_errcode_t mali_memory_initialize(void)
  277. {
  278. return mali_mem_os_init();
  279. }
  280. void mali_memory_terminate(void)
  281. {
  282. mali_mem_os_term();
  283. mali_mem_block_allocator_destroy(NULL);
  284. }