memalloc.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. * Physically contiguous memory allocator
  3. *
  4. * Copyright (C) 2009 Hantro Products Oy.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #define DEBUG
  20. #include <linux/module.h>
  21. #include <linux/dma-mapping.h> /* dma_zalloc_coherent, dma_free_coherent */
  22. #include <linux/fs.h>
  23. #include <linux/list.h>
  24. #include <linux/slab.h>
  25. #include <linux/uaccess.h>
  26. #include <linux/of.h>
  27. #include <linux/of_device.h>
  28. #include <linux/of_reserved_mem.h>
  29. #include <asm/cacheflush.h>
  30. #include "memalloc.h"
  31. struct memalloc_drv {
  32. struct class *class;
  33. struct device *dev;
  34. int major;
  35. struct list_head opened; /* list of opened files (memalloc_file_context) */
  36. spinlock_t lock;
  37. };
  38. struct memalloc_file_context {
  39. struct list_head n;
  40. struct memalloc_drv *parent;
  41. struct list_head blocks; /* list of allocated blocks (mem_block) */
  42. spinlock_t lock;
  43. //unsigned int num_blocks;
  44. };
  45. struct memalloc_block {
  46. struct list_head n;
  47. dma_addr_t dma_handle;
  48. void *virt_addr;
  49. size_t size; /* page aligned */
  50. int method;
  51. };
  52. static struct memalloc_drv memalloc_ing = {
  53. .opened = LIST_HEAD_INIT(memalloc_ing.opened),
  54. .lock = __SPIN_LOCK_UNLOCKED(memalloc_ing.lock),
  55. };
  56. /**
  57. * allocate_large_block - Allocate a physically contiguous memory area
  58. *
  59. * @param dev driver device node
  60. * @param pp_block Result block struct address
  61. * @param p_size Wished size. Output is rounded up to page size (often something like 4k)
  62. *
  63. * @return 0 on success, negative value on error
  64. */
  65. static int allocate_large_block(struct device *dev, struct memalloc_block **pp_block, size_t *p_size)
  66. {
  67. struct memalloc_block *p;
  68. p = kmalloc(sizeof(struct memalloc_block), GFP_KERNEL);
  69. if (p == NULL) {
  70. dev_info(dev, "unable to alloc block struct.\n");
  71. return -ENOMEM;
  72. }
  73. p->size = PAGE_ALIGN(*p_size);
  74. /* Multiple of PAGE_SIZE */
  75. p->virt_addr = dma_zalloc_coherent(dev, p->size, &p->dma_handle, GFP_KERNEL);
  76. if (!p->virt_addr) {
  77. dev_err(dev, "large alloc failed (%d)\n", p->size);
  78. kfree(p);
  79. return -ENOMEM;
  80. }
  81. dev_dbg(dev, "large alloc ok: VA=%p PA=0x%llx SZ=%d (requested %d)\n",
  82. p->virt_addr, (unsigned long long)p->dma_handle, p->size, *p_size);
  83. *p_size = p->size;
  84. *pp_block = p;
  85. return 0;
  86. }
  87. static int free_large_block(struct device *dev, struct memalloc_block *p)
  88. {
  89. dev_dbg(dev, "large free: VA=%p\n", p->virt_addr);
  90. dma_free_coherent(dev, p->size, p->virt_addr, p->dma_handle);
  91. kfree(p);
  92. return 0;
  93. }
  94. static long memalloc_ioctl(struct file *filp, unsigned int cmd,
  95. unsigned long arg)
  96. {
  97. struct memalloc_file_context *fc = filp->private_data;
  98. struct memalloc_drv *m = fc->parent;
  99. int ret = -EFAULT;
  100. MemallocParams mem_params;
  101. struct memalloc_block *p;
  102. size_t sz;
  103. if (!filp || arg == 0)
  104. return ret;
  105. switch (cmd) {
  106. case MEMALLOC_IOCXGETBUFFER:
  107. spin_lock(&fc->lock);
  108. if (copy_from_user(&mem_params, (MemallocParams *)arg, sizeof(mem_params)))
  109. dev_dbg(m->dev, "copy_from_user failed\n");
  110. sz = mem_params.size;
  111. ret = allocate_large_block(m->dev, &p, &sz);
  112. if (!ret) {
  113. mem_params.busAddress = (unsigned long)p->dma_handle; /* should be 64-bit! */
  114. mem_params.size = sz;
  115. if (copy_to_user((MemallocParams *)arg, &mem_params, sizeof(mem_params)))
  116. dev_dbg(m->dev, "copy_to_user failed\n");
  117. list_add(&p->n, &fc->blocks);
  118. }
  119. spin_unlock(&fc->lock);
  120. break;
  121. case MEMALLOC_IOCSFREEBUFFER:
  122. ret = -EINVAL;
  123. spin_lock(&fc->lock);
  124. __get_user(mem_params.busAddress, (unsigned long *)arg);
  125. /* find memalloc_block */
  126. list_for_each_entry(p, &fc->blocks, n) {
  127. if ((unsigned long)p->dma_handle == mem_params.busAddress) {
  128. list_del(&p->n);
  129. free_large_block(m->dev, p);
  130. ret = 0;
  131. break;
  132. }
  133. }
  134. spin_unlock(&fc->lock);
  135. break;
  136. case MEMALLOC_IOCSFLUSHRAMBUFFER:
  137. spin_lock(&fc->lock);
  138. if(__copy_from_user(&mem_params, (const void *) arg, sizeof(mem_params)))
  139. return -EFAULT;
  140. if (mem_params.busAddress && mem_params.size) {
  141. outer_flush_range(mem_params.busAddress, mem_params.busAddress + mem_params.size);
  142. ret = 0;
  143. }
  144. spin_unlock(&fc->lock);
  145. //printk(KERN_ALERT "memalloc flush buffer: busAddress=0x%8x, size=0x%0x.\n",mem_params.busAddress, mem_params.size);
  146. break;
  147. default:
  148. ret = -ENOIOCTLCMD;
  149. }
  150. return ret;
  151. }
  152. static int memalloc_open(struct inode *inode, struct file *filp)
  153. {
  154. struct memalloc_file_context *fc;
  155. struct memalloc_drv *m = &memalloc_ing;
  156. int dev = iminor(inode);
  157. if (dev != 0) {
  158. dev_warn(m->dev, "unsupported minor (%d).\n", dev);
  159. return -EINVAL;
  160. }
  161. fc = kmalloc(sizeof(struct memalloc_file_context), GFP_KERNEL);
  162. if (fc == NULL) {
  163. dev_err(m->dev, "unable to alloc struct.\n");
  164. return -ENOMEM;
  165. }
  166. INIT_LIST_HEAD(&fc->blocks);
  167. spin_lock_init(&fc->lock);
  168. fc->parent = m;
  169. filp->private_data = fc;
  170. spin_lock(&m->lock);
  171. list_add_tail(&fc->n, &m->opened);
  172. spin_unlock(&m->lock);
  173. dev_dbg(m->dev, "file open (%p)\n", fc);
  174. return 0;
  175. }
  176. static int memalloc_release(struct inode *inode, struct file *filp)
  177. {
  178. struct memalloc_file_context *fc = filp->private_data;
  179. struct memalloc_drv *m = fc->parent;
  180. struct memalloc_block *p, *tmp;
  181. list_for_each_entry_safe(p, tmp, &fc->blocks, n) {
  182. list_del(&p->n);
  183. free_large_block(m->dev, p);
  184. }
  185. spin_lock(&m->lock);
  186. list_del(&fc->n);
  187. spin_unlock(&m->lock);
  188. kfree(fc);
  189. dev_dbg(m->dev, "file release (%p)\n", fc);
  190. return 0;
  191. }
  192. static const struct vm_operations_struct mmap_mem_ops = {
  193. #ifdef CONFIG_HAVE_IOREMAP_PROT
  194. .access = generic_access_phys
  195. #endif
  196. };
  197. /* This function is based on mmap_mem (drivers/char/mem.c) */
  198. static int memalloc_mmap (struct file *filp, struct vm_area_struct *vma)
  199. {
  200. struct memalloc_file_context *fc = filp->private_data;
  201. struct memalloc_block *p;
  202. int found = 0;
  203. size_t size = vma->vm_end - vma->vm_start;
  204. /* Is this a memory chunk provided by our driver ? */
  205. spin_lock(&fc->lock);
  206. list_for_each_entry(p, &fc->blocks, n) {
  207. if (((u64)p->dma_handle == ((u64)vma->vm_pgoff << PAGE_SHIFT)) &&
  208. (size <= p->size)) {
  209. found = 1;
  210. break;
  211. }
  212. }
  213. spin_unlock(&fc->lock);
  214. if (!found)
  215. return -EPERM;
  216. vma->vm_page_prot = phys_mem_access_prot(filp, vma->vm_pgoff,
  217. size,
  218. vma->vm_page_prot);
  219. vma->vm_ops = &mmap_mem_ops;
  220. /* Remap-pfn-range will mark the range VM_IO */
  221. if (remap_pfn_range(vma,
  222. vma->vm_start,
  223. vma->vm_pgoff,
  224. size,
  225. vma->vm_page_prot)) {
  226. return -EAGAIN;
  227. }
  228. return 0;
  229. }
  230. static struct file_operations memalloc_fops = {
  231. .owner = THIS_MODULE,
  232. .open = memalloc_open,
  233. .release = memalloc_release,
  234. .unlocked_ioctl = memalloc_ioctl,
  235. .llseek = noop_llseek,
  236. .mmap = memalloc_mmap,
  237. };
  238. static int memalloc_init(void)
  239. {
  240. struct memalloc_drv *m = &memalloc_ing;
  241. int ret;
  242. m->major = register_chrdev(0, "memalloc", &memalloc_fops);
  243. if (m->major < 0) {
  244. pr_err("failed to register character device\n");
  245. return m->major;
  246. }
  247. /* create /dev/memalloc */
  248. m->class = class_create(THIS_MODULE, "memalloc-cls");
  249. if (IS_ERR(m->class)) {
  250. ret = PTR_ERR(m->class);
  251. goto err;
  252. }
  253. m->dev = device_create(m->class, NULL, MKDEV(m->major, 0), NULL, "memalloc");
  254. if (IS_ERR(m->dev)) {
  255. ret = PTR_ERR(m->dev);
  256. class_destroy(m->class);
  257. goto err;
  258. }
  259. m->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  260. dev_dbg(m->dev, "allocator with major = %d\n", m->major);
  261. return 0;
  262. err:
  263. unregister_chrdev(m->major, "memalloc");
  264. return ret;
  265. }
  266. module_init(memalloc_init);
  267. static void memalloc_exit(void)
  268. {
  269. struct memalloc_drv *m = &memalloc_ing;
  270. device_destroy(m->class, MKDEV(m->major, 0));
  271. class_destroy(m->class);
  272. unregister_chrdev(m->major, "memalloc");
  273. }
  274. module_exit(memalloc_exit);
  275. MODULE_AUTHOR("Hantro Products Oy");
  276. MODULE_DESCRIPTION("Memory allocator for VDEC");
  277. MODULE_LICENSE("GPL");
  278. MODULE_VERSION("0.5");