memalloc_freertos.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /****************************************************************************
  2. *
  3. * The MIT License (MIT)
  4. *
  5. * Copyright (c) 2014 - 2021 VERISILICON
  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) 2014 - 2021 VERISILICON
  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; if not, write to the Free Software Foundation,
  43. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  44. *
  45. *****************************************************************************
  46. *
  47. * Note: This software is released under dual MIT and GPL licenses. A
  48. * recipient may use this file under the terms of either the MIT license or
  49. * GPL License. If you wish to use only one license not the other, you can
  50. * indicate your decision by deleting one of the above license notices in your
  51. * version of this file.
  52. *
  53. *****************************************************************************/
  54. #include "osal.h"
  55. #include "memalloc_freertos.h"
  56. /* Dev Memory Map for NETNT */
  57. #define DEV_MEM_BANK_0 (0)
  58. #define MEM_BANK0_SIZE (16*1024*1024*1024LL)
  59. #define DEV_MEM_BANK_1 (1)
  60. #define MEM_BANK1_SIZE (16*1024*1024*1024LL)
  61. #if 1
  62. #define SHARED_MEM_DEV_ADDRESS (0x840000000LL) //TOP 29
  63. #define SHARED_MEM_CPU_ADDRESS (0x40000000)
  64. //#define SHARED_MEM_CPU_ADDRESS (0x30000000)
  65. //#define SHARED_MEM_CPU_ADDRESS (0x30000000)
  66. #define SHARED_MEM_SIZE (2*1024*1024*1024LL)
  67. #define SHARED_MEM_BANK (DEV_MEM_BANK_0)
  68. #else
  69. #define SHARED_MEM_DEV_ADDRESS (0x800000000LL) //TOP24
  70. #define SHARED_MEM_CPU_ADDRESS (0x80000000)
  71. #define SHARED_MEM_SIZE (2*1024*1024*1024LL)
  72. #define SHARED_MEM_BANK (DEV_MEM_BANK_0)
  73. #endif
  74. #define MEM_0_DEV_ADDRESS (SHARED_MEM_DEV_ADDRESS + SHARED_MEM_SIZE)
  75. #define MEM_0_CPU_ADDRESS (0)
  76. #define MEM_0_SIZE (MEM_BANK0_SIZE + MEM_BANK1_SIZE - SHARED_MEM_SIZE)
  77. #define MEM_0_BANK (DEV_MEM_BANK_0)
  78. /*
  79. #define MEM_1_DEV_ADDRESS (0xC00000000LL)
  80. #define MEM_1_CPU_ADDRESS (0)
  81. #define MEM_1_SIZE (16*1024*1024*1024LL)
  82. #define MEM_1_BANK (DEV_MEM_BANK_1)
  83. */
  84. /* the size of chunk in MEMALLOC_DYNAMIC */
  85. #define CHUNK_SIZE (16*1024)
  86. /* DO NOT change below defines, they need to be matched with DWL_MEM_TYPE_xx */
  87. #define _MEM_TYPE_CPU 0U /* CPU RW. non-secure CMA memory */
  88. #define _MEM_TYPE_SLICE 1U /* VPU R, CAAM W */
  89. #define _MEM_TYPE_DPB 2U /* VPU RW, Render R */
  90. #define _MEM_TYPE_VPU_WORKING 3U /* VPU R, CPU W. non-secure memory */
  91. #define _MEM_TYPE_VPU_WORKING_SPECIAL 4U /* VPU R, CPU RW. only for VP9 counter context table */
  92. #define _MEM_TYPE_VPU_ONLY 5U /* VPU RW only. */
  93. /*
  94. memory type enum
  95. */
  96. typedef enum {
  97. MEM_TYPE_SHARED = 0,
  98. MEM_TYPE_DEVICE,
  99. }_mem_type;
  100. /*
  101. memory region id enum, also as index of array "_regions" and array "hlina_mgr"
  102. */
  103. typedef enum {
  104. MEM_ID_SHARED = 0,
  105. MEM_ID_0,
  106. /* MEM_ID_1, */
  107. MAX_MEM_REGION
  108. }_mem_region_id;
  109. /*
  110. memory region properties struct
  111. */
  112. typedef struct __mem_region {
  113. unsigned long long bus_addr; /* Physical address of dev memory region */
  114. char * virt_addr; /* virtual address mapping to CPU, 0 means invisible to CPU */
  115. unsigned long long size; /* size of dev memory region */
  116. unsigned short bank; /* DDR RAM bank id */
  117. _mem_type type;
  118. unsigned long translation_offset; /* user space SW will substract HLINA_TRANSL_OFFSET from the bus address
  119. * and decoder HW will use the result as the address translated base
  120. * address. The SW needs the original host memory bus address for memory
  121. * mapping to virtual address. */
  122. } _mem_region_t;
  123. /*
  124. descriptor for each chunk
  125. */
  126. typedef struct hlinc {
  127. unsigned short chunks_occupied; /* indicate number of occupied chunks which start from current chunk */
  128. int filp; /* Client that allocated this chunk */
  129. } hlina_chunk_t;
  130. /*
  131. memory region management struct
  132. */
  133. typedef struct __hlina_mgr {
  134. hlina_chunk_t *hlina_chunks; /* point to descriptor of each chunks */
  135. unsigned long chunks; /* total chunks in this mem region */
  136. unsigned long reserved_chunks; /* number of reserved chunks in this mem rtegion.
  137. * The reserved chunks is located at the beginning of corresponding mem region, application can't use them */
  138. _mem_region_t *mem_prop;
  139. } _hlina_mgr_t;
  140. /*
  141. memory regions perporties, indexed by _mem_region_id.
  142. */
  143. static _mem_region_t _regions[MAX_MEM_REGION] = {
  144. /*MEM_ID_SHARED*/ { SHARED_MEM_DEV_ADDRESS, (char *)SHARED_MEM_CPU_ADDRESS, SHARED_MEM_SIZE, SHARED_MEM_BANK, MEM_TYPE_SHARED, 0 },
  145. /*MEM_ID_0 */ { MEM_0_DEV_ADDRESS, (char *)MEM_0_CPU_ADDRESS, MEM_0_SIZE, MEM_0_BANK, MEM_TYPE_DEVICE, 0 }
  146. /*MEM_ID_1 { MEM_1_DEV_ADDRESS, (char *)MEM_1_CPU_ADDRESS, MEM_1_SIZE, MEM_1_BANK, MEM_TYPE_DEVICE, 0 } */
  147. };
  148. /*
  149. memory regions hlina manager, indexed by _mem_region_id.
  150. */
  151. static _hlina_mgr_t hlina_mgr[MAX_MEM_REGION];
  152. int memalloc_major = -1;
  153. //static DEFINE_SPINLOCK(mem_lock);
  154. pthread_mutex_t mem_lock = PTHREAD_MUTEX_INITIALIZER;
  155. /*
  156. Functions declaration
  157. */
  158. static int AllocMemory(unsigned long long *busaddr, unsigned int size, unsigned int region, const int filp);
  159. static int FreeMemory(unsigned long long busaddr, const int filp);
  160. //static void * DirectMemoryMap(unsigned long long busaddr, unsigned long map_size);
  161. static void CalculateChunks(_mem_region_id id, unsigned long *chunks, unsigned long *chunks_mgr_size);
  162. static void ResetMems(void);
  163. /*
  164. To specified mem region, calculate total chunks number and aligned buffer size to store chunks' descriptors.
  165. */
  166. static void CalculateChunks(_mem_region_id id, unsigned long *chunks, unsigned long *chunks_mgr_size)
  167. {
  168. *chunks = 0;
  169. *chunks_mgr_size = 0;
  170. if(id < MAX_MEM_REGION) {
  171. *chunks = _regions[id].size / CHUNK_SIZE;
  172. *chunks_mgr_size = (((unsigned int)*chunks) * sizeof(hlina_chunk_t) + CHUNK_SIZE - 1) & (~(CHUNK_SIZE - 1));
  173. }
  174. }
  175. /*
  176. To specified bus address, convert it to virtual (CPU) address according to mem region properties.
  177. */
  178. void * DirectMemoryMap(unsigned long long busaddr, unsigned long map_size) {
  179. int i;
  180. unsigned long long offset;
  181. void *virtaddr = NULL;
  182. u32 busAddrRight = 0;
  183. if(map_size == 0) {
  184. return NULL;
  185. }
  186. for(i=0; i<MAX_MEM_REGION; i++) {
  187. if((busaddr >= _regions[i].bus_addr) && (busaddr <= _regions[i].bus_addr + _regions[i].size)) {
  188. busAddrRight = 1;
  189. if(_regions[i].virt_addr == NULL) {
  190. continue;
  191. }
  192. else {
  193. offset = busaddr - _regions[i].bus_addr;
  194. if ((offset + map_size) <= _regions[i].size) {
  195. virtaddr = (void *)(_regions[i].virt_addr + offset);
  196. break;
  197. }
  198. }
  199. }
  200. }
  201. if((!busAddrRight) && (virtaddr==NULL)) {
  202. return (void *)(unsigned long)busaddr;
  203. }
  204. return virtaddr;
  205. }
  206. /*
  207. ioctl
  208. */
  209. long memalloc_ioctl(int filp, unsigned int cmd, void *arg) {
  210. int ret = 0;
  211. MemallocParams memparams;
  212. addr_t busaddr;
  213. unsigned int region;
  214. PDEBUG("memalloc ioctl cmd 0x%08x\n", cmd);
  215. /*
  216. * extract the type and number bitfields, and don't decode
  217. * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
  218. */
  219. if (_IOC_TYPE(cmd) != MEMALLOC_IOC_MAGIC) return -ENOTTY;
  220. if (_IOC_NR(cmd) > MEMALLOC_IOC_MAXNR) return -ENOTTY;
  221. if (_IOC_DIR(cmd) & _IOC_READ)
  222. ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));
  223. else if (_IOC_DIR(cmd) & _IOC_WRITE)
  224. ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));
  225. if (ret) return -EFAULT;
  226. spin_lock(&mem_lock);
  227. switch (cmd) {
  228. case MEMALLOC_IOCHARDRESET:
  229. PDEBUG("memalloc HARDRESET\n");
  230. ResetMems();
  231. break;
  232. case MEMALLOC_IOCXGETBUFFER:
  233. PDEBUG("memalloc GETBUFFER");
  234. ret = copy_from_user(&memparams, (MemallocParams *)arg,
  235. sizeof(MemallocParams));
  236. if (ret) break;
  237. region = MEM_ID_SHARED;
  238. if(memparams.mem_type == _MEM_TYPE_DPB || memparams.mem_type == _MEM_TYPE_VPU_ONLY)
  239. #ifndef MEM_ONLY_DEV_CHECK
  240. region = MEM_ID_SHARED; //For get output buffer for CPU
  241. #else
  242. region = MEM_ID_0;
  243. #endif
  244. ret = AllocMemory(&memparams.bus_address, memparams.size, region, filp);
  245. memparams.translation_offset = _regions[region].translation_offset;
  246. ret |= copy_to_user((MemallocParams *)arg, &memparams,
  247. sizeof(MemallocParams));
  248. break;
  249. case MEMALLOC_IOCSFREEBUFFER:
  250. PDEBUG("memalloc FREEBUFFER\n");
  251. __get_user(busaddr, (addr_t *)arg);
  252. ret = FreeMemory(busaddr, filp);
  253. break;
  254. }
  255. spin_unlock(&mem_lock);
  256. return ret ? -EFAULT : 0;
  257. }
  258. int memalloc_open(int *inode, int filp) {
  259. PDEBUG("memalloc dev opened\n");
  260. return 0;
  261. }
  262. int memalloc_release(int *inode, int filp) {
  263. int i = 0, j = 0;
  264. hlina_chunk_t *p_hlina;
  265. for (i = 0; i < MAX_MEM_REGION; i++) {
  266. p_hlina = hlina_mgr[i].hlina_chunks;
  267. for (j = hlina_mgr[i].reserved_chunks; j < hlina_mgr[i].chunks; j++) {
  268. spin_lock(&mem_lock);
  269. if (p_hlina[j].filp == filp) {
  270. printk(KERN_WARNING "memalloc: Found unfreed memory at release time!\n");
  271. p_hlina[j].filp = 0;
  272. p_hlina[j].chunks_occupied = 0;
  273. }
  274. spin_unlock(&mem_lock);
  275. }
  276. }
  277. PDEBUG("memalloc dev closed\n");
  278. return 0;
  279. }
  280. int __init memalloc_init(void) {
  281. int result;
  282. int i;
  283. unsigned long chunks, mgr_size, reserved_size;
  284. void *p;
  285. PDEBUG("memalloc module init\n");
  286. printk("memalloc: Linear Memory Allocator\n");
  287. /*
  288. Allocate memory for hlina_mgr
  289. In NETINT platform, there is no big heap memory to store hlina_mgr, so it is put to beginning of shared memory region directly
  290. */
  291. reserved_size = 0;
  292. for (i=0; i<MAX_MEM_REGION; i++) {
  293. CalculateChunks(i, &chunks, &mgr_size);
  294. /* all hlina_chunks are put to SHARED memory region */
  295. p = DirectMemoryMap(_regions[MEM_ID_SHARED].bus_addr + reserved_size, mgr_size);
  296. hlina_mgr[i].hlina_chunks = (hlina_chunk_t *)p;
  297. hlina_mgr[i].chunks = chunks;
  298. hlina_mgr[i].reserved_chunks = 0;
  299. hlina_mgr[i].mem_prop = &_regions[i];
  300. reserved_size += mgr_size;
  301. printk("memalloc: Linear memory base = 0x%08llx\n", _regions[i].bus_addr);
  302. printk(KERN_INFO
  303. "memalloc: Region[%d] size %lu MB; %lu chunks"
  304. " of size %d\n", i,
  305. (unsigned long)(_regions[i].size/(1024*1024)), chunks, CHUNK_SIZE);
  306. }
  307. hlina_mgr[MEM_ID_SHARED].reserved_chunks = reserved_size / CHUNK_SIZE;
  308. result = register_chrdev(memalloc_major, "memalloc", &memalloc_fops);
  309. if (result < 0) {
  310. PDEBUG("memalloc: unable to get major %d\n", memalloc_major);
  311. goto err;
  312. } else if (result != 0) {/* this is for dynamic major */
  313. memalloc_major = result;
  314. }
  315. ResetMems();
  316. printf("memalloc init successful...\n");
  317. return 0;
  318. err:
  319. #if 0
  320. if (hlina_chunks != NULL) vfree(hlina_chunks);
  321. #endif
  322. return result;
  323. }
  324. /*
  325. Cycle through the buffers in specified region, give the first free one.
  326. TBD: need to check if specifying _mem_type is better than region.
  327. */
  328. static int AllocMemory(unsigned long long *busaddr, unsigned int size, unsigned int region, const int filp) {
  329. int i = 0;
  330. int j = 0;
  331. unsigned int skip_chunks = 0;
  332. unsigned long total_chunks;
  333. hlina_chunk_t *p_hlina;
  334. /* calculate how many chunks we need; round up to chunk boundary */
  335. unsigned int alloc_chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
  336. *busaddr = 0;
  337. if(region >= MAX_MEM_REGION) {
  338. printk("memalloc: Allocation FAILED: unknown region = %u\n", region);
  339. return -EFAULT;
  340. }
  341. p_hlina = hlina_mgr[region].hlina_chunks;
  342. total_chunks = hlina_mgr[region].chunks;
  343. /* run through the chunk table */
  344. for (i = hlina_mgr[region].reserved_chunks; i < total_chunks;) {
  345. skip_chunks = 0;
  346. /* if this chunk is available */
  347. if (!p_hlina[i].chunks_occupied) {
  348. /* check that there is enough memory left */
  349. if (i + alloc_chunks > total_chunks) break;
  350. /* check that there is enough consecutive chunks available */
  351. for (j = i; j < i + alloc_chunks; j++) {
  352. if (p_hlina[j].chunks_occupied) {
  353. skip_chunks = 1;
  354. /* skip the used chunks */
  355. i = j + p_hlina[j].chunks_occupied;
  356. break;
  357. }
  358. }
  359. /* if enough free memory found */
  360. if (!skip_chunks) {
  361. *busaddr = hlina_mgr[region].mem_prop->bus_addr + i * CHUNK_SIZE;
  362. p_hlina[i].filp = filp;
  363. p_hlina[i].chunks_occupied = alloc_chunks;
  364. break;
  365. }
  366. } else {
  367. /* skip the used chunks */
  368. i += p_hlina[i].chunks_occupied;
  369. }
  370. }
  371. if (*busaddr == 0) {
  372. printk("memalloc: Allocation FAILED: size = %u\n", size);
  373. return -EFAULT;
  374. } else {
  375. PDEBUG("MEMALLOC OK: size: %d, reserved: %d\n", size,
  376. alloc_chunks * CHUNK_SIZE);
  377. }
  378. return 0;
  379. }
  380. /* Free a buffer based on bus address */
  381. static int FreeMemory(unsigned long long busaddr, const int filp) {
  382. unsigned int i, id;
  383. unsigned long long addr;
  384. hlina_chunk_t *p_hlina;
  385. for(i = 0; i < MAX_MEM_REGION; i++) {
  386. addr = busaddr + _regions[i].translation_offset;
  387. if ((addr >= _regions[i].bus_addr) && (addr < _regions[i].bus_addr + _regions[i].size)) {
  388. id = (addr - _regions[i].bus_addr) / CHUNK_SIZE;
  389. p_hlina = &hlina_mgr[i].hlina_chunks[id];
  390. if ((p_hlina->chunks_occupied) && (p_hlina->filp == filp)) {
  391. p_hlina->filp = 0;
  392. p_hlina->chunks_occupied = 0;
  393. return 0;
  394. }
  395. }
  396. }
  397. printk(KERN_WARNING "memalloc: Owner mismatch while freeing memory!\n");
  398. return -1;
  399. }
  400. /* Reset "used" status */
  401. static void ResetMems(void) {
  402. int i, j = 0;
  403. hlina_chunk_t *p_hlina;
  404. for (i=0; i<MAX_MEM_REGION; i++) {
  405. p_hlina = hlina_mgr[i].hlina_chunks;
  406. for(j=hlina_mgr[i].reserved_chunks; j<hlina_mgr[i].chunks; j++) {
  407. p_hlina[j].filp = 0;
  408. p_hlina[j].chunks_occupied = 0;
  409. }
  410. }
  411. }
  412. //memory type is shared
  413. //return busAddr and virtrulAddr
  414. addr_t GetBusAddrForIODevide(unsigned int size) {
  415. addr_t bus_addr = 0;
  416. AllocMemory(&bus_addr, size, MEM_ID_SHARED , MEM_FD);
  417. return bus_addr;
  418. }