memalloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*------------------------------------------------------------------------------
  2. -- --
  3. -- This software is confidential and proprietary and may be used --
  4. -- only as expressly authorized by a licensing agreement from --
  5. -- --
  6. -- Hantro Products Oy. --
  7. -- --
  8. -- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
  9. -- ALL RIGHTS RESERVED --
  10. -- --
  11. -- The entire notice above must be reproduced --
  12. -- on all copies and should not be removed. --
  13. -- --
  14. --------------------------------------------------------------------------------
  15. --
  16. -- Abstract : Allocate memory blocks
  17. --
  18. ------------------------------------------------------------------------------*/
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. /* needed for __init,__exit directives */
  22. #include <linux/init.h>
  23. /* needed for remap_page_range */
  24. #include <linux/mm.h>
  25. /* obviously, for kmalloc */
  26. #include <linux/slab.h>
  27. /* for struct file_operations, register_chrdev() */
  28. #include <linux/fs.h>
  29. /* standard error codes */
  30. #include <linux/errno.h>
  31. /* this header files wraps some common module-space operations ...
  32. here we use mem_map_reserve() macro */
  33. #include <asm/io.h>
  34. #include <asm/uaccess.h>
  35. #include <linux/ioport.h>
  36. #include <linux/list.h>
  37. /* for current pid */
  38. #include <linux/sched.h>
  39. /* Our header */
  40. #include "memalloc.h"
  41. /* module description */
  42. MODULE_LICENSE("Proprietary");
  43. MODULE_AUTHOR("Hantro Products Oy");
  44. MODULE_DESCRIPTION("RAM allocation");
  45. /* start of reserved linear memory area */
  46. #ifndef HLINA_START_ADDRESS
  47. #define HLINA_START_ADDRESS 0x02000000 /* 32MB */
  48. #endif
  49. /* end of reserved linear memory area */
  50. #ifndef HLINA_END_ADDRESS
  51. #define HLINA_END_ADDRESS 0x08000000 /* 128MB */
  52. #endif
  53. #define MEMALLOC_SW_MINOR 9
  54. #define MEMALLOC_SW_MAJOR 0
  55. #define MEMALLOC_SW_BUILD ((MEMALLOC_SW_MAJOR * 1000) + MEMALLOC_SW_MINOR)
  56. #define MAX_OPEN 32
  57. #define ID_UNUSED 0xFF
  58. #define MEMALLOC_BASIC 0
  59. #define MEMALLOC_MAX_OUTPUT 1
  60. /* selects the memory allocation method, i.e. which allocation scheme table is used */
  61. unsigned int alloc_method = MEMALLOC_BASIC;
  62. static int memalloc_major = 0; /* dynamic */
  63. int id[MAX_OPEN] = { ID_UNUSED };
  64. /* module_param(name, type, perm) */
  65. module_param(alloc_method, uint, 0);
  66. /* here's all the must remember stuff */
  67. struct allocation
  68. {
  69. struct list_head list;
  70. void *buffer;
  71. unsigned int order;
  72. int fid;
  73. };
  74. struct list_head heap_list;
  75. static spinlock_t mem_lock = SPIN_LOCK_UNLOCKED;
  76. typedef struct hlinc
  77. {
  78. unsigned int bus_address;
  79. unsigned int used;
  80. unsigned int size;
  81. int file_id;
  82. } hlina_chunk;
  83. unsigned int *size_table;
  84. unsigned int size_table_0[] = {
  85. 1, 1, 1, 1, 1, 1, 1, 1, 1,
  86. 4, 4, 4, 4, 4, 4, 4, 4,
  87. 10, 10, 10, 10,
  88. 22, 22, 22, 22,
  89. 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
  90. 50, 50, 50, 50, 50, 50, 50,
  91. 75, 75, 75, 75, 75,
  92. 86, 86, 86, 86, 86,
  93. 113, 113,
  94. 152, 152,
  95. 162, 162, 162,
  96. 270, 270, 270,
  97. 399, 399,
  98. 450, 450,
  99. 769, 769,
  100. 1999,
  101. 3072,
  102. 8192
  103. };
  104. /* MEMALLOC_MAX_OUTPUT */
  105. unsigned int size_table_1[] = {
  106. 1, 1,
  107. 16, 16, 16, 16,
  108. 64, 64, 64, 64,
  109. 2675,
  110. 21575,
  111. 40960
  112. };
  113. /* x280 */
  114. unsigned int size_table_2[] = {
  115. 1, 1,
  116. 16, 16,
  117. 64, 64,
  118. 1024,
  119. 2048, 2048, 2048,
  120. 4096, 4096,
  121. 8192,
  122. /* 96MB used so far, if more is available we can allocate big chunk for
  123. * maximum input resolution */
  124. 24500, 4096, 4096
  125. };
  126. unsigned int size_table_3[] = {
  127. 1, 1,
  128. 57, 57, 57, 57, 57,
  129. 225, 225, 225, 225, 225,
  130. 384, 384,
  131. 1013, 1013, 1013, 1013, 1013, 1013,
  132. 16000
  133. };
  134. static int max_chunks;
  135. #define HLINA_NUMBER_OF_CHUNKS max_chunks
  136. hlina_chunk hlina_chunks[256];
  137. static int AllocMemory(unsigned *busaddr, unsigned int size, struct file *filp);
  138. static int FreeMemory(unsigned long busaddr);
  139. static void ResetMems(void);
  140. static int memalloc_ioctl(struct inode *inode, struct file *filp,
  141. unsigned int cmd, unsigned long arg)
  142. {
  143. int err = 0;
  144. int ret;
  145. PDEBUG("ioctl cmd 0x%08x\n", cmd);
  146. if(inode == NULL || filp == NULL || arg == 0)
  147. {
  148. return -EFAULT;
  149. }
  150. /*
  151. * extract the type and number bitfields, and don't decode
  152. * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
  153. */
  154. if(_IOC_TYPE(cmd) != MEMALLOC_IOC_MAGIC)
  155. return -ENOTTY;
  156. if(_IOC_NR(cmd) > MEMALLOC_IOC_MAXNR)
  157. return -ENOTTY;
  158. if(_IOC_DIR(cmd) & _IOC_READ)
  159. err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
  160. else if(_IOC_DIR(cmd) & _IOC_WRITE)
  161. err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
  162. if(err)
  163. return -EFAULT;
  164. switch (cmd)
  165. {
  166. case MEMALLOC_IOCHARDRESET:
  167. PDEBUG("HARDRESET\n");
  168. ResetMems();
  169. break;
  170. case MEMALLOC_IOCXGETBUFFER:
  171. {
  172. int result;
  173. MemallocParams memparams;
  174. PDEBUG("GETBUFFER\n");
  175. spin_lock(&mem_lock);
  176. if(__copy_from_user
  177. (&memparams, (const void *) arg, sizeof(memparams)))
  178. {
  179. result = -EFAULT;
  180. }
  181. else
  182. {
  183. result =
  184. AllocMemory(&memparams.busAddress, memparams.size, filp);
  185. if(__copy_to_user((void *) arg, &memparams, sizeof(memparams)))
  186. {
  187. result = -EFAULT;
  188. }
  189. }
  190. spin_unlock(&mem_lock);
  191. return result;
  192. }
  193. case MEMALLOC_IOCSFREEBUFFER:
  194. {
  195. unsigned long busaddr;
  196. PDEBUG("FREEBUFFER\n");
  197. spin_lock(&mem_lock);
  198. __get_user(busaddr, (unsigned long *) arg);
  199. ret = FreeMemory(busaddr);
  200. spin_unlock(&mem_lock);
  201. return ret;
  202. }
  203. }
  204. return 0;
  205. }
  206. static int memalloc_open(struct inode *inode, struct file *filp)
  207. {
  208. int i = 0;
  209. for(i = 0; i < MAX_OPEN + 1; i++)
  210. {
  211. if(i == MAX_OPEN)
  212. return -1;
  213. if(id[i] == ID_UNUSED)
  214. {
  215. id[i] = i;
  216. filp->private_data = id + i;
  217. break;
  218. }
  219. }
  220. PDEBUG("dev opened\n");
  221. return 0;
  222. }
  223. static int memalloc_release(struct inode *inode, struct file *filp)
  224. {
  225. int i = 0;
  226. for(i = 0; i < HLINA_NUMBER_OF_CHUNKS; i++)
  227. {
  228. if(hlina_chunks[i].file_id == *((int *) (filp->private_data)))
  229. {
  230. hlina_chunks[i].used = 0;
  231. hlina_chunks[i].file_id = ID_UNUSED;
  232. }
  233. }
  234. *((int *) filp->private_data) = ID_UNUSED;
  235. PDEBUG("dev closed\n");
  236. return 0;
  237. }
  238. /* VFS methods */
  239. static struct file_operations memalloc_fops = {
  240. open:memalloc_open,
  241. release:memalloc_release,
  242. ioctl:memalloc_ioctl,
  243. };
  244. int __init memalloc_init(void)
  245. {
  246. int result;
  247. int i = 0;
  248. #if (HLINA_END_ADDRESS <= HLINA_START_ADDRESS)
  249. #error HLINA_END_ADDRESS and/or HLINA_START_ADDRESS not valid!
  250. #endif
  251. PDEBUG("module init\n");
  252. printk("memalloc: 8290 build %d \n", MEMALLOC_SW_BUILD);
  253. printk("memalloc: linear memory base = 0x%08x \n", HLINA_START_ADDRESS);
  254. printk("memalloc: linear memory end = 0x%08x \n", HLINA_END_ADDRESS);
  255. printk("memalloc: linear memory size = %8d KB \n",
  256. (HLINA_END_ADDRESS - HLINA_START_ADDRESS) / 1024);
  257. switch (alloc_method)
  258. {
  259. case MEMALLOC_MAX_OUTPUT:
  260. size_table = size_table_1;
  261. max_chunks = (sizeof(size_table_1) / sizeof(*size_table_1));
  262. printk(KERN_INFO "memalloc: allocation method: MEMALLOC_MAX_OUTPUT\n");
  263. break;
  264. case 2:
  265. size_table = size_table_2;
  266. max_chunks = (sizeof(size_table_2) / sizeof(*size_table_2));
  267. printk(KERN_INFO "memalloc: allocation method: x280's\n");
  268. break;
  269. case 3:
  270. size_table = size_table_3;
  271. max_chunks = (sizeof(size_table_3) / sizeof(*size_table_3));
  272. printk(KERN_INFO "memalloc: allocation method: PC PCI test\n");
  273. break;
  274. default:
  275. size_table = size_table_0;
  276. max_chunks = (sizeof(size_table_0) / sizeof(*size_table_0));
  277. printk(KERN_INFO "memalloc: allocation method: MEMALLOC_BASIC\n");
  278. break;
  279. }
  280. result = register_chrdev(memalloc_major, "memalloc", &memalloc_fops);
  281. if(result < 0)
  282. {
  283. PDEBUG("memalloc: unable to get major %d\n", memalloc_major);
  284. goto err;
  285. }
  286. else if(result != 0) /* this is for dynamic major */
  287. {
  288. memalloc_major = result;
  289. }
  290. ResetMems();
  291. /* We keep a register of out customers, reset it */
  292. for(i = 0; i < MAX_OPEN; i++)
  293. {
  294. id[i] = ID_UNUSED;
  295. }
  296. return 0;
  297. err:
  298. PDEBUG("memalloc: module not inserted\n");
  299. unregister_chrdev(memalloc_major, "memalloc");
  300. return result;
  301. }
  302. void __exit memalloc_cleanup(void)
  303. {
  304. PDEBUG("clenup called\n");
  305. unregister_chrdev(memalloc_major, "memalloc");
  306. printk(KERN_INFO "memalloc: module removed\n");
  307. return;
  308. }
  309. module_init(memalloc_init);
  310. module_exit(memalloc_cleanup);
  311. /* Cycle through the buffers we have, give the first free one */
  312. static int AllocMemory(unsigned *busaddr, unsigned int size, struct file *filp)
  313. {
  314. int i = 0;
  315. *busaddr = 0;
  316. for(i = 0; i < HLINA_NUMBER_OF_CHUNKS; i++)
  317. {
  318. if(!hlina_chunks[i].used && (hlina_chunks[i].size >= size))
  319. {
  320. *busaddr = hlina_chunks[i].bus_address;
  321. hlina_chunks[i].used = 1;
  322. hlina_chunks[i].file_id = *((int *) (filp->private_data));
  323. break;
  324. }
  325. }
  326. if((*busaddr + hlina_chunks[i].size) > HLINA_END_ADDRESS)
  327. {
  328. printk("memalloc: FAILED allocation, linear memory overflow\n");
  329. *busaddr = 0;
  330. }
  331. else if(*busaddr == 0)
  332. {
  333. printk("memalloc: FAILED allocation, no free chunck of size = %d\n",
  334. size);
  335. }
  336. else
  337. {
  338. PDEBUG("memalloc: Allocated chunck; size requested %d, reserved: %d\n",
  339. size, hlina_chunks[i].size);
  340. }
  341. return 0;
  342. }
  343. /* Free a buffer based on bus address */
  344. static int FreeMemory(unsigned long busaddr)
  345. {
  346. int i = 0;
  347. for(i = 0; i < HLINA_NUMBER_OF_CHUNKS; i++)
  348. {
  349. if(hlina_chunks[i].bus_address == busaddr)
  350. {
  351. hlina_chunks[i].used = 0;
  352. hlina_chunks[i].file_id = ID_UNUSED;
  353. }
  354. }
  355. return 0;
  356. }
  357. /* Reset "used" status */
  358. void ResetMems(void)
  359. {
  360. int i = 0;
  361. unsigned int ba = HLINA_START_ADDRESS;
  362. for(i = 0; i < HLINA_NUMBER_OF_CHUNKS; i++)
  363. {
  364. hlina_chunks[i].bus_address = ba;
  365. hlina_chunks[i].used = 0;
  366. hlina_chunks[i].file_id = ID_UNUSED;
  367. hlina_chunks[i].size = 4096 * size_table[i];
  368. ba += hlina_chunks[i].size;
  369. }
  370. printk("memalloc: %d bytes (%d KB) configured\n",
  371. ba - HLINA_START_ADDRESS, (ba - HLINA_START_ADDRESS) / 1024);
  372. if(ba > HLINA_END_ADDRESS)
  373. {
  374. printk("memalloc: WARNING! Linear memory top limit exceeded!\n");
  375. }
  376. }