ump_kernel_memory_backend_dedicated.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright (C) 2010-2011 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. /* needed to detect kernel version specific code */
  11. #include <linux/version.h>
  12. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
  13. #include <linux/semaphore.h>
  14. #else /* pre 2.6.26 the file was in the arch specific location */
  15. #include <asm/semaphore.h>
  16. #endif
  17. #include <linux/mm.h>
  18. #include <linux/slab.h>
  19. #include <asm/atomic.h>
  20. #include <linux/vmalloc.h>
  21. #include "ump_kernel_common.h"
  22. #include "ump_kernel_memory_backend.h"
  23. #define UMP_BLOCK_SIZE (256UL * 1024UL) /* 256kB, remember to keep the ()s */
  24. typedef struct block_info
  25. {
  26. struct block_info * next;
  27. } block_info;
  28. typedef struct block_allocator
  29. {
  30. struct semaphore mutex;
  31. block_info * all_blocks;
  32. block_info * first_free;
  33. u32 base;
  34. u32 num_blocks;
  35. u32 num_free;
  36. } block_allocator;
  37. static void block_allocator_shutdown(ump_memory_backend * backend);
  38. static int block_allocator_allocate(void* ctx, ump_dd_mem * mem);
  39. static void block_allocator_release(void * ctx, ump_dd_mem * handle);
  40. static inline u32 get_phys(block_allocator * allocator, block_info * block);
  41. static u32 block_allocator_stat(struct ump_memory_backend *backend);
  42. /*
  43. * Create dedicated memory backend
  44. */
  45. ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size)
  46. {
  47. ump_memory_backend * backend;
  48. block_allocator * allocator;
  49. u32 usable_size;
  50. u32 num_blocks;
  51. usable_size = (size + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1);
  52. num_blocks = usable_size / UMP_BLOCK_SIZE;
  53. if (0 == usable_size)
  54. {
  55. DBG_MSG(1, ("Memory block of size %u is unusable\n", size));
  56. return NULL;
  57. }
  58. DBG_MSG(5, ("Creating dedicated UMP memory backend. Base address: 0x%08x, size: 0x%08x\n", base_address, size));
  59. DBG_MSG(6, ("%u usable bytes which becomes %u blocks\n", usable_size, num_blocks));
  60. backend = kzalloc(sizeof(ump_memory_backend), GFP_KERNEL);
  61. if (NULL != backend)
  62. {
  63. allocator = kmalloc(sizeof(block_allocator), GFP_KERNEL);
  64. if (NULL != allocator)
  65. {
  66. allocator->all_blocks = kmalloc(sizeof(block_allocator) * num_blocks, GFP_KERNEL);
  67. if (NULL != allocator->all_blocks)
  68. {
  69. int i;
  70. allocator->first_free = NULL;
  71. allocator->num_blocks = num_blocks;
  72. allocator->num_free = num_blocks;
  73. allocator->base = base_address;
  74. sema_init(&allocator->mutex, 1);
  75. for (i = 0; i < num_blocks; i++)
  76. {
  77. allocator->all_blocks[i].next = allocator->first_free;
  78. allocator->first_free = &allocator->all_blocks[i];
  79. }
  80. backend->ctx = allocator;
  81. backend->allocate = block_allocator_allocate;
  82. backend->release = block_allocator_release;
  83. backend->shutdown = block_allocator_shutdown;
  84. backend->stat = block_allocator_stat;
  85. backend->pre_allocate_physical_check = NULL;
  86. backend->adjust_to_mali_phys = NULL;
  87. return backend;
  88. }
  89. kfree(allocator);
  90. }
  91. kfree(backend);
  92. }
  93. return NULL;
  94. }
  95. /*
  96. * Destroy specified dedicated memory backend
  97. */
  98. static void block_allocator_shutdown(ump_memory_backend * backend)
  99. {
  100. block_allocator * allocator;
  101. BUG_ON(!backend);
  102. BUG_ON(!backend->ctx);
  103. allocator = (block_allocator*)backend->ctx;
  104. DBG_MSG_IF(1, allocator->num_free != allocator->num_blocks, ("%u blocks still in use during shutdown\n", allocator->num_blocks - allocator->num_free));
  105. kfree(allocator->all_blocks);
  106. kfree(allocator);
  107. kfree(backend);
  108. }
  109. static int block_allocator_allocate(void* ctx, ump_dd_mem * mem)
  110. {
  111. block_allocator * allocator;
  112. u32 left;
  113. block_info * last_allocated = NULL;
  114. int i = 0;
  115. BUG_ON(!ctx);
  116. BUG_ON(!mem);
  117. allocator = (block_allocator*)ctx;
  118. left = mem->size_bytes;
  119. BUG_ON(!left);
  120. BUG_ON(!&allocator->mutex);
  121. mem->nr_blocks = ((left + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1)) / UMP_BLOCK_SIZE;
  122. mem->block_array = (ump_dd_physical_block*)vmalloc(sizeof(ump_dd_physical_block) * mem->nr_blocks);
  123. if (NULL == mem->block_array)
  124. {
  125. MSG_ERR(("Failed to allocate block array\n"));
  126. return 0;
  127. }
  128. if (down_interruptible(&allocator->mutex))
  129. {
  130. MSG_ERR(("Could not get mutex to do block_allocate\n"));
  131. return 0;
  132. }
  133. mem->size_bytes = 0;
  134. while ((left > 0) && (allocator->first_free))
  135. {
  136. block_info * block;
  137. block = allocator->first_free;
  138. allocator->first_free = allocator->first_free->next;
  139. block->next = last_allocated;
  140. last_allocated = block;
  141. allocator->num_free--;
  142. mem->block_array[i].addr = get_phys(allocator, block);
  143. mem->block_array[i].size = UMP_BLOCK_SIZE;
  144. mem->size_bytes += UMP_BLOCK_SIZE;
  145. i++;
  146. if (left < UMP_BLOCK_SIZE) left = 0;
  147. else left -= UMP_BLOCK_SIZE;
  148. }
  149. if (left)
  150. {
  151. block_info * block;
  152. /* release all memory back to the pool */
  153. while (last_allocated)
  154. {
  155. block = last_allocated->next;
  156. last_allocated->next = allocator->first_free;
  157. allocator->first_free = last_allocated;
  158. last_allocated = block;
  159. allocator->num_free++;
  160. }
  161. vfree(mem->block_array);
  162. mem->backend_info = NULL;
  163. mem->block_array = NULL;
  164. DBG_MSG(4, ("Could not find a mem-block for the allocation.\n"));
  165. up(&allocator->mutex);
  166. return 0;
  167. }
  168. mem->backend_info = last_allocated;
  169. up(&allocator->mutex);
  170. mem->is_cached=0;
  171. return 1;
  172. }
  173. static void block_allocator_release(void * ctx, ump_dd_mem * handle)
  174. {
  175. block_allocator * allocator;
  176. block_info * block, * next;
  177. BUG_ON(!ctx);
  178. BUG_ON(!handle);
  179. allocator = (block_allocator*)ctx;
  180. block = (block_info*)handle->backend_info;
  181. BUG_ON(!block);
  182. if (down_interruptible(&allocator->mutex))
  183. {
  184. MSG_ERR(("Allocator release: Failed to get mutex - memory leak\n"));
  185. return;
  186. }
  187. while (block)
  188. {
  189. next = block->next;
  190. BUG_ON( (block < allocator->all_blocks) || (block > (allocator->all_blocks + allocator->num_blocks)));
  191. block->next = allocator->first_free;
  192. allocator->first_free = block;
  193. allocator->num_free++;
  194. block = next;
  195. }
  196. DBG_MSG(3, ("%d blocks free after release call\n", allocator->num_free));
  197. up(&allocator->mutex);
  198. vfree(handle->block_array);
  199. handle->block_array = NULL;
  200. }
  201. /*
  202. * Helper function for calculating the physical base adderss of a memory block
  203. */
  204. static inline u32 get_phys(block_allocator * allocator, block_info * block)
  205. {
  206. return allocator->base + ((block - allocator->all_blocks) * UMP_BLOCK_SIZE);
  207. }
  208. static u32 block_allocator_stat(struct ump_memory_backend *backend)
  209. {
  210. block_allocator *allocator;
  211. BUG_ON(!backend);
  212. allocator = (block_allocator*)backend->ctx;
  213. BUG_ON(!allocator);
  214. return (allocator->num_blocks - allocator->num_free)* UMP_BLOCK_SIZE;
  215. }