cma.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /****************************************************************************
  2. *
  3. * The MIT License (MIT)
  4. *
  5. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  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
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. *
  25. *****************************************************************************
  26. *
  27. * The GPL License (GPL)
  28. *
  29. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  30. *
  31. * This program is free software; you can redistribute it and/or
  32. * modify it under the terms of the GNU General Public License
  33. * as published by the Free Software Foundation; either version 2
  34. * of the License, or (at your option) any later version.
  35. *
  36. * This program is distributed in the hope that it will be useful,
  37. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. * GNU General Public License for more details.
  40. *
  41. * You should have received a copy of the GNU General Public License
  42. * along with this program;
  43. *
  44. *****************************************************************************
  45. *
  46. * Note: This software is released under dual MIT and GPL licenses. A
  47. * recipient may use this file under the terms of either the MIT license or
  48. * GPL License. If you wish to use only one license not the other, you can
  49. * indicate your decision by deleting one of the above license notices in your
  50. * version of this file.
  51. *
  52. *****************************************************************************/
  53. #include "cma.h"
  54. #ifdef __KERNEL__
  55. struct block_list {
  56. struct block_list *next;
  57. u64 base_addr;
  58. u64 size;
  59. };
  60. struct cma_mem_context {
  61. u64 base;
  62. u64 size;
  63. u64 align;
  64. struct block_list free_blocks;
  65. struct block_list used_blocks;
  66. };
  67. static struct cma_mem_context *g_cma_mem_ctx;
  68. static inline void add_free_blocks(struct block_list *free_item);
  69. static inline void add_used_blocks(struct block_list *used_item);
  70. struct mutex viv_cma_mutex;
  71. int vsi_cma_init(u64 base, u64 size, u64 align)
  72. {
  73. struct block_list *item = NULL;
  74. pr_debug("enter %s\n", __func__);
  75. if (!size || (size <= align))
  76. return -EINVAL;
  77. g_cma_mem_ctx = kzalloc(sizeof(struct cma_mem_context), GFP_KERNEL);
  78. memset(g_cma_mem_ctx, 0, sizeof(*g_cma_mem_ctx));
  79. g_cma_mem_ctx->base = (base + align - 1) & ~(align - 1);
  80. g_cma_mem_ctx->size = size - (g_cma_mem_ctx->base - base);
  81. g_cma_mem_ctx->align = align;
  82. pr_debug("addr:0x%llx, size:0x%llx, alignment:0x%llx.\n",
  83. g_cma_mem_ctx->base, g_cma_mem_ctx->size,
  84. g_cma_mem_ctx->align);
  85. item = kzalloc(sizeof(struct block_list), GFP_KERNEL);
  86. if (!item) {
  87. kzfree(g_cma_mem_ctx);
  88. g_cma_mem_ctx = NULL;
  89. return -ENOMEM;
  90. }
  91. item->next = NULL;
  92. item->base_addr = g_cma_mem_ctx->base;
  93. item->size = g_cma_mem_ctx->size;
  94. g_cma_mem_ctx->free_blocks.next = item;
  95. g_cma_mem_ctx->used_blocks.next = NULL;
  96. mutex_init(&viv_cma_mutex);
  97. return 0;
  98. }
  99. int vsi_cma_release(void)
  100. {
  101. int result = 0;
  102. struct block_list *item, *pFree;
  103. if (!g_cma_mem_ctx->free_blocks.next
  104. || g_cma_mem_ctx->free_blocks.next->next
  105. || g_cma_mem_ctx->used_blocks.next) {
  106. pr_err("Warning memory is not free.\n");
  107. }
  108. item = g_cma_mem_ctx->free_blocks.next;
  109. while (item) {
  110. pFree = item;
  111. item = item->next;
  112. /* kzfree(pFree); */
  113. }
  114. kzfree(g_cma_mem_ctx);
  115. g_cma_mem_ctx = NULL;
  116. mutex_destroy(&viv_cma_mutex);
  117. return result;
  118. }
  119. u64 vsi_cma_alloc(u64 size)
  120. {
  121. u64 addr = ~0U;
  122. struct block_list *item;
  123. struct block_list *found;
  124. mutex_lock(&viv_cma_mutex);
  125. if (!size || (size > g_cma_mem_ctx->size)) {
  126. mutex_unlock(&viv_cma_mutex);
  127. return ~0U;
  128. }
  129. pr_debug("enter %s\n", __func__);
  130. pr_debug
  131. ("addr:0x%llx, size:0x%llx, alignment:0x%llx, reqsize:0x%llx.\n",
  132. g_cma_mem_ctx->base, g_cma_mem_ctx->size, g_cma_mem_ctx->align,
  133. size);
  134. size += g_cma_mem_ctx->align - 1;
  135. size &= ~(g_cma_mem_ctx->align - 1);
  136. /*TODO: need to lock this block */
  137. item = &g_cma_mem_ctx->free_blocks;
  138. while (item->next && (item->next->size < size))
  139. item = item->next;
  140. found = item->next;
  141. if (found) {
  142. item->next = found->next;
  143. if ((found->size - size) >= g_cma_mem_ctx->align) {
  144. item = kzalloc(sizeof(struct block_list), GFP_KERNEL);
  145. if (item) {
  146. item->base_addr = found->base_addr + size;
  147. item->size = found->size - size;
  148. found->size = size;
  149. pr_debug("new free block: base_addr=0x%llx,\n",
  150. item->base_addr);
  151. add_free_blocks(item);
  152. }
  153. }
  154. pr_debug("new used block: base_addr=0x%llx, size=0x%llx \n",
  155. found->base_addr, found->size);
  156. add_used_blocks(found);
  157. addr = found->base_addr;
  158. }
  159. pr_debug("block allocated: base_addr=0x%llx\n", addr);
  160. mutex_unlock(&viv_cma_mutex);
  161. return addr;
  162. }
  163. void vsi_cma_free(u64 addr)
  164. {
  165. pr_debug("enter %s\n", __func__);
  166. pr_debug("block to free: base_addr=0x%llx\n", addr);
  167. mutex_lock(&viv_cma_mutex);
  168. if (addr) {
  169. /*TODO: need to lock this block */
  170. struct block_list *item, *free_item;
  171. item = &g_cma_mem_ctx->used_blocks;
  172. while (item->next && (item->next->base_addr != addr))
  173. item = item->next;
  174. free_item = item->next;
  175. item->next = free_item->next;
  176. if (((item->base_addr + item->size) != free_item->base_addr) ||
  177. ((free_item->base_addr + item->size) != ((free_item->next) ?
  178. free_item->next->base_addr :
  179. (g_cma_mem_ctx->base
  180. +
  181. g_cma_mem_ctx->size)))) {
  182. struct block_list *loc_item;
  183. struct block_list *pre_item = NULL;
  184. struct block_list *success_item = NULL;
  185. loc_item = &g_cma_mem_ctx->free_blocks;
  186. while (loc_item->next) {
  187. if ((loc_item->next->base_addr +
  188. loc_item->next->size) ==
  189. free_item->base_addr) {
  190. pre_item = loc_item;
  191. }
  192. if ((free_item->base_addr + free_item->size) ==
  193. loc_item->next->base_addr) {
  194. success_item = loc_item;
  195. }
  196. loc_item = loc_item->next;
  197. }
  198. if (success_item) {
  199. loc_item = success_item->next;
  200. free_item->size += loc_item->size;
  201. success_item->next = loc_item->next;
  202. kzfree(loc_item);
  203. }
  204. if (pre_item) {
  205. loc_item = pre_item->next;
  206. free_item->base_addr = loc_item->base_addr;
  207. free_item->size += loc_item->size;
  208. pre_item->next = loc_item->next;
  209. kzfree(loc_item);
  210. }
  211. } else {
  212. pr_err("no adjacent block free\n");
  213. }
  214. add_free_blocks(free_item);
  215. }
  216. mutex_unlock(&viv_cma_mutex);
  217. }
  218. static inline void add_free_blocks(struct block_list *free_item)
  219. {
  220. struct block_list *item;
  221. item = &g_cma_mem_ctx->free_blocks;
  222. while (item->next && (item->next->size < free_item->size))
  223. item = item->next;
  224. free_item->next = item->next;
  225. item->next = free_item;
  226. item = &g_cma_mem_ctx->free_blocks;
  227. while (item->next)
  228. item = item->next;
  229. }
  230. static inline void add_used_blocks(struct block_list *used_item)
  231. {
  232. struct block_list *item;
  233. item = &g_cma_mem_ctx->used_blocks;
  234. while (item->next && (item->next->base_addr < used_item->base_addr))
  235. item = item->next;
  236. used_item->next = item->next;
  237. item->next = used_item;
  238. item = &g_cma_mem_ctx->used_blocks;
  239. while (item->next)
  240. item = item->next;
  241. }
  242. #endif