mali_kernel_mem_os.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
  3. *
  4. * This program is free software and is provided to you under the terms of the GNU General Public License version 2
  5. * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
  6. *
  7. * A copy of the licence is included with the program, and can also be obtained from Free Software
  8. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  9. */
  10. #include "mali_kernel_common.h"
  11. #include "mali_kernel_core.h"
  12. #include "mali_kernel_memory_engine.h"
  13. #include "mali_osk.h"
  14. typedef struct os_allocation
  15. {
  16. u32 num_pages;
  17. u32 offset_start;
  18. mali_allocation_engine * engine;
  19. mali_memory_allocation * descriptor;
  20. } os_allocation;
  21. typedef struct os_allocator
  22. {
  23. _mali_osk_lock_t *mutex;
  24. /**
  25. * Maximum number of pages to allocate from the OS
  26. */
  27. u32 num_pages_max;
  28. /**
  29. * Number of pages allocated from the OS
  30. */
  31. u32 num_pages_allocated;
  32. /** CPU Usage adjustment (add to mali physical address to get cpu physical address) */
  33. u32 cpu_usage_adjust;
  34. } os_allocator;
  35. static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
  36. static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block);
  37. static void os_allocator_release(void * ctx, void * handle);
  38. static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block );
  39. static void os_allocator_destroy(mali_physical_memory_allocator * allocator);
  40. static u32 os_allocator_stat(mali_physical_memory_allocator * allocator);
  41. mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u32 cpu_usage_adjust, const char *name)
  42. {
  43. mali_physical_memory_allocator * allocator;
  44. os_allocator * info;
  45. max_allocation = (max_allocation + _MALI_OSK_CPU_PAGE_SIZE-1) & ~(_MALI_OSK_CPU_PAGE_SIZE-1);
  46. MALI_DEBUG_PRINT(2, ("Mali OS memory allocator created with max allocation size of 0x%X bytes, cpu_usage_adjust 0x%08X\n", max_allocation, cpu_usage_adjust));
  47. allocator = _mali_osk_malloc(sizeof(mali_physical_memory_allocator));
  48. if (NULL != allocator)
  49. {
  50. info = _mali_osk_malloc(sizeof(os_allocator));
  51. if (NULL != info)
  52. {
  53. info->num_pages_max = max_allocation / _MALI_OSK_CPU_PAGE_SIZE;
  54. info->num_pages_allocated = 0;
  55. info->cpu_usage_adjust = cpu_usage_adjust;
  56. info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_MEM_INFO);
  57. if (NULL != info->mutex)
  58. {
  59. allocator->allocate = os_allocator_allocate;
  60. allocator->allocate_page_table_block = os_allocator_allocate_page_table_block;
  61. allocator->destroy = os_allocator_destroy;
  62. allocator->stat = os_allocator_stat;
  63. allocator->ctx = info;
  64. allocator->name = name;
  65. return allocator;
  66. }
  67. _mali_osk_free(info);
  68. }
  69. _mali_osk_free(allocator);
  70. }
  71. return NULL;
  72. }
  73. static u32 os_allocator_stat(mali_physical_memory_allocator * allocator)
  74. {
  75. os_allocator * info;
  76. info = (os_allocator*)allocator->ctx;
  77. return info->num_pages_allocated * _MALI_OSK_MALI_PAGE_SIZE;
  78. }
  79. static void os_allocator_destroy(mali_physical_memory_allocator * allocator)
  80. {
  81. os_allocator * info;
  82. MALI_DEBUG_ASSERT_POINTER(allocator);
  83. MALI_DEBUG_ASSERT_POINTER(allocator->ctx);
  84. info = (os_allocator*)allocator->ctx;
  85. _mali_osk_lock_term(info->mutex);
  86. _mali_osk_free(info);
  87. _mali_osk_free(allocator);
  88. }
  89. static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
  90. {
  91. mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_NONE;
  92. u32 left;
  93. os_allocator * info;
  94. os_allocation * allocation;
  95. int pages_allocated = 0;
  96. _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
  97. MALI_DEBUG_ASSERT_POINTER(ctx);
  98. MALI_DEBUG_ASSERT_POINTER(engine);
  99. MALI_DEBUG_ASSERT_POINTER(descriptor);
  100. MALI_DEBUG_ASSERT_POINTER(offset);
  101. MALI_DEBUG_ASSERT_POINTER(alloc_info);
  102. info = (os_allocator*)ctx;
  103. left = descriptor->size - *offset;
  104. if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
  105. /** @note this code may not work on Linux, or may require a more complex Linux implementation */
  106. allocation = _mali_osk_malloc(sizeof(os_allocation));
  107. if (NULL != allocation)
  108. {
  109. u32 os_mem_max_usage = info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE;
  110. allocation->offset_start = *offset;
  111. allocation->num_pages = ((left + _MALI_OSK_CPU_PAGE_SIZE - 1) & ~(_MALI_OSK_CPU_PAGE_SIZE - 1)) >> _MALI_OSK_CPU_PAGE_ORDER;
  112. MALI_DEBUG_PRINT(6, ("Allocating page array of size %d bytes\n", allocation->num_pages * sizeof(struct page*)));
  113. while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max) && _mali_osk_mem_check_allocated(os_mem_max_usage))
  114. {
  115. err = mali_allocation_engine_map_physical(engine, descriptor, *offset, MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, info->cpu_usage_adjust, _MALI_OSK_CPU_PAGE_SIZE);
  116. if ( _MALI_OSK_ERR_OK != err)
  117. {
  118. if ( _MALI_OSK_ERR_NOMEM == err)
  119. {
  120. /* 'Partial' allocation (or, out-of-memory on first page) */
  121. break;
  122. }
  123. MALI_DEBUG_PRINT(1, ("Mapping of physical memory failed\n"));
  124. /* Fatal error, cleanup any previous pages allocated. */
  125. if ( pages_allocated > 0 )
  126. {
  127. mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*pages_allocated, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
  128. /* (*offset) doesn't need to be restored; it will not be used by the caller on failure */
  129. }
  130. pages_allocated = 0;
  131. result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
  132. break;
  133. }
  134. /* Loop iteration */
  135. if (left < _MALI_OSK_CPU_PAGE_SIZE) left = 0;
  136. else left -= _MALI_OSK_CPU_PAGE_SIZE;
  137. pages_allocated++;
  138. *offset += _MALI_OSK_CPU_PAGE_SIZE;
  139. }
  140. if (left) MALI_PRINT(("Out of memory. Mali memory allocated: %d kB Configured maximum OS memory usage: %d kB\n",
  141. (info->num_pages_allocated * _MALI_OSK_CPU_PAGE_SIZE)/1024, (info->num_pages_max* _MALI_OSK_CPU_PAGE_SIZE)/1024));
  142. /* Loop termination; decide on result */
  143. if (pages_allocated)
  144. {
  145. MALI_DEBUG_PRINT(6, ("Allocated %d pages\n", pages_allocated));
  146. if (left) result = MALI_MEM_ALLOC_PARTIAL;
  147. else result = MALI_MEM_ALLOC_FINISHED;
  148. /* Some OS do not perform a full cache flush (including all outer caches) for uncached mapped memory.
  149. * They zero the memory through a cached mapping, then flush the inner caches but not the outer caches.
  150. * This is required for MALI to have the correct view of the memory.
  151. */
  152. _mali_osk_cache_ensure_uncached_range_flushed( (void *)descriptor, allocation->offset_start, pages_allocated *_MALI_OSK_CPU_PAGE_SIZE );
  153. allocation->num_pages = pages_allocated;
  154. allocation->engine = engine; /* Necessary to make the engine's unmap call */
  155. allocation->descriptor = descriptor; /* Necessary to make the engine's unmap call */
  156. info->num_pages_allocated += pages_allocated;
  157. MALI_DEBUG_PRINT(6, ("%d out of %d pages now allocated\n", info->num_pages_allocated, info->num_pages_max));
  158. alloc_info->ctx = info;
  159. alloc_info->handle = allocation;
  160. alloc_info->release = os_allocator_release;
  161. }
  162. else
  163. {
  164. MALI_DEBUG_PRINT(6, ("Releasing pages array due to no pages allocated\n"));
  165. _mali_osk_free( allocation );
  166. }
  167. }
  168. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  169. return result;
  170. }
  171. static void os_allocator_release(void * ctx, void * handle)
  172. {
  173. os_allocator * info;
  174. os_allocation * allocation;
  175. mali_allocation_engine * engine;
  176. mali_memory_allocation * descriptor;
  177. MALI_DEBUG_ASSERT_POINTER(ctx);
  178. MALI_DEBUG_ASSERT_POINTER(handle);
  179. info = (os_allocator*)ctx;
  180. allocation = (os_allocation*)handle;
  181. engine = allocation->engine;
  182. descriptor = allocation->descriptor;
  183. MALI_DEBUG_ASSERT_POINTER( engine );
  184. MALI_DEBUG_ASSERT_POINTER( descriptor );
  185. if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
  186. {
  187. MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
  188. return;
  189. }
  190. MALI_DEBUG_PRINT(6, ("Releasing %d os pages\n", allocation->num_pages));
  191. MALI_DEBUG_ASSERT( allocation->num_pages <= info->num_pages_allocated);
  192. info->num_pages_allocated -= allocation->num_pages;
  193. mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*allocation->num_pages, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
  194. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  195. _mali_osk_free(allocation);
  196. }
  197. static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block)
  198. {
  199. int allocation_order = 6; /* _MALI_OSK_CPU_PAGE_SIZE << 6 */
  200. void *virt = NULL;
  201. u32 size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order;
  202. os_allocator * info;
  203. u32 cpu_phys_base;
  204. MALI_DEBUG_ASSERT_POINTER(ctx);
  205. info = (os_allocator*)ctx;
  206. /* Ensure we don't allocate more than we're supposed to from the ctx */
  207. if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
  208. /* if the number of pages to be requested lead to exceeding the memory
  209. * limit in info->num_pages_max, reduce the size that is to be requested. */
  210. while ( (info->num_pages_allocated + (1 << allocation_order) > info->num_pages_max)
  211. && _mali_osk_mem_check_allocated(info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE) )
  212. {
  213. if ( allocation_order > 0 ) {
  214. --allocation_order;
  215. } else {
  216. /* return OOM */
  217. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  218. return MALI_MEM_ALLOC_NONE;
  219. }
  220. }
  221. /* try to allocate 2^(allocation_order) pages, if that fails, try
  222. * allocation_order-1 to allocation_order 0 (inclusive) */
  223. while ( allocation_order >= 0 )
  224. {
  225. size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order;
  226. virt = _mali_osk_mem_allocioregion( &cpu_phys_base, size );
  227. if (NULL != virt) break;
  228. --allocation_order;
  229. }
  230. if ( NULL == virt )
  231. {
  232. MALI_DEBUG_PRINT(1, ("Failed to allocate consistent memory. Is CONSISTENT_DMA_SIZE set too low?\n"));
  233. /* return OOM */
  234. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  235. return MALI_MEM_ALLOC_NONE;
  236. }
  237. MALI_DEBUG_PRINT(5, ("os_allocator_allocate_page_table_block: Allocation of order %i succeeded\n",
  238. allocation_order));
  239. /* we now know the size of the allocation since we know for what
  240. * allocation_order the allocation succeeded */
  241. size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order;
  242. block->release = os_allocator_page_table_block_release;
  243. block->ctx = ctx;
  244. block->handle = (void*)allocation_order;
  245. block->size = size;
  246. block->phys_base = cpu_phys_base - info->cpu_usage_adjust;
  247. block->mapping = virt;
  248. info->num_pages_allocated += (1 << allocation_order);
  249. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  250. return MALI_MEM_ALLOC_FINISHED;
  251. }
  252. static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block )
  253. {
  254. os_allocator * info;
  255. u32 allocation_order;
  256. u32 pages_allocated;
  257. MALI_DEBUG_ASSERT_POINTER( page_table_block );
  258. info = (os_allocator*)page_table_block->ctx;
  259. MALI_DEBUG_ASSERT_POINTER( info );
  260. allocation_order = (u32)page_table_block->handle;
  261. pages_allocated = 1 << allocation_order;
  262. MALI_DEBUG_ASSERT( pages_allocated * _MALI_OSK_CPU_PAGE_SIZE == page_table_block->size );
  263. if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
  264. {
  265. MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
  266. return;
  267. }
  268. MALI_DEBUG_ASSERT( pages_allocated <= info->num_pages_allocated);
  269. info->num_pages_allocated -= pages_allocated;
  270. /* Adjust phys_base from mali physical address to CPU physical address */
  271. _mali_osk_mem_freeioregion( page_table_block->phys_base + info->cpu_usage_adjust, page_table_block->size, page_table_block->mapping );
  272. _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
  273. }