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. */
  84. *p_size = p->size;
  85. *pp_block = p;
  86. return 0;
  87. }
  88. static int free_large_block(struct device *dev, struct memalloc_block *p)
  89. {
  90. /* dev_dbg(dev, "large free: VA=%p\n", p->virt_addr); */
  91. dma_free_coherent(dev, p->size, p->virt_addr, p->dma_handle);
  92. kfree(p);
  93. return 0;
  94. }
  95. static long memalloc_ioctl(struct file *filp, unsigned int cmd,
  96. unsigned long arg)
  97. {
  98. struct memalloc_file_context *fc = filp->private_data;
  99. struct memalloc_drv *m = fc->parent;
  100. int ret = -EFAULT;
  101. MemallocParams mem_params;
  102. struct memalloc_block *p;
  103. size_t sz;
  104. if (!filp || arg == 0)
  105. return ret;
  106. switch (cmd) {
  107. case MEMALLOC_IOCXGETBUFFER:
  108. spin_lock(&fc->lock);
  109. if (copy_from_user(&mem_params, (MemallocParams *)arg, sizeof(mem_params)))
  110. dev_dbg(m->dev, "copy_from_user failed\n");
  111. sz = mem_params.size;
  112. ret = allocate_large_block(m->dev, &p, &sz);
  113. if (!ret) {
  114. mem_params.busAddress = (unsigned long)p->dma_handle; /* should be 64-bit! */
  115. mem_params.size = sz;
  116. if (copy_to_user((MemallocParams *)arg, &mem_params, sizeof(mem_params)))
  117. dev_dbg(m->dev, "copy_to_user failed\n");
  118. list_add(&p->n, &fc->blocks);
  119. }
  120. spin_unlock(&fc->lock);
  121. break;
  122. case MEMALLOC_IOCSFREEBUFFER:
  123. ret = -EINVAL;
  124. spin_lock(&fc->lock);
  125. __get_user(mem_params.busAddress, (unsigned long *)arg);
  126. /* find memalloc_block */
  127. list_for_each_entry(p, &fc->blocks, n) {
  128. if ((unsigned long)p->dma_handle == mem_params.busAddress) {
  129. list_del(&p->n);
  130. free_large_block(m->dev, p);
  131. ret = 0;
  132. break;
  133. }
  134. }
  135. spin_unlock(&fc->lock);
  136. break;
  137. case MEMALLOC_IOCSFLUSHRAMBUFFER:
  138. spin_lock(&fc->lock);
  139. if(__copy_from_user(&mem_params, (const void *) arg, sizeof(mem_params)))
  140. return -EFAULT;
  141. if (mem_params.busAddress && mem_params.size) {
  142. outer_flush_range(mem_params.busAddress, mem_params.busAddress + mem_params.size);
  143. ret = 0;
  144. }
  145. spin_unlock(&fc->lock);
  146. //printk(KERN_ALERT "memalloc flush buffer: busAddress=0x%8x, size=0x%0x.\n",mem_params.busAddress, mem_params.size);
  147. break;
  148. default:
  149. ret = -ENOIOCTLCMD;
  150. }
  151. return ret;
  152. }
  153. static int memalloc_open(struct inode *inode, struct file *filp)
  154. {
  155. struct memalloc_file_context *fc;
  156. struct memalloc_drv *m = &memalloc_ing;
  157. int dev = iminor(inode);
  158. if (dev != 0) {
  159. dev_warn(m->dev, "unsupported minor (%d).\n", dev);
  160. return -EINVAL;
  161. }
  162. fc = kmalloc(sizeof(struct memalloc_file_context), GFP_KERNEL);
  163. if (fc == NULL) {
  164. dev_err(m->dev, "unable to alloc struct.\n");
  165. return -ENOMEM;
  166. }
  167. INIT_LIST_HEAD(&fc->blocks);
  168. spin_lock_init(&fc->lock);
  169. fc->parent = m;
  170. filp->private_data = fc;
  171. spin_lock(&m->lock);
  172. list_add_tail(&fc->n, &m->opened);
  173. spin_unlock(&m->lock);
  174. dev_dbg(m->dev, "file open (%p)\n", fc);
  175. return 0;
  176. }
  177. static int memalloc_release(struct inode *inode, struct file *filp)
  178. {
  179. struct memalloc_file_context *fc = filp->private_data;
  180. struct memalloc_drv *m = fc->parent;
  181. struct memalloc_block *p, *tmp;
  182. list_for_each_entry_safe(p, tmp, &fc->blocks, n) {
  183. list_del(&p->n);
  184. free_large_block(m->dev, p);
  185. }
  186. spin_lock(&m->lock);
  187. list_del(&fc->n);
  188. spin_unlock(&m->lock);
  189. kfree(fc);
  190. dev_dbg(m->dev, "file release (%p)\n", fc);
  191. return 0;
  192. }
  193. static const struct vm_operations_struct mmap_mem_ops = {
  194. #ifdef CONFIG_HAVE_IOREMAP_PROT
  195. .access = generic_access_phys
  196. #endif
  197. };
  198. /* This function is based on mmap_mem (drivers/char/mem.c) */
  199. static int memalloc_mmap (struct file *filp, struct vm_area_struct *vma)
  200. {
  201. struct memalloc_file_context *fc = filp->private_data;
  202. struct memalloc_block *p;
  203. int found = 0;
  204. size_t size = vma->vm_end - vma->vm_start;
  205. /* Is this a memory chunk provided by our driver ? */
  206. spin_lock(&fc->lock);
  207. list_for_each_entry(p, &fc->blocks, n) {
  208. if (((u64)p->dma_handle == ((u64)vma->vm_pgoff << PAGE_SHIFT)) &&
  209. (size <= p->size)) {
  210. found = 1;
  211. break;
  212. }
  213. }
  214. spin_unlock(&fc->lock);
  215. if (!found)
  216. return -EPERM;
  217. vma->vm_page_prot = phys_mem_access_prot(filp, vma->vm_pgoff,
  218. size,
  219. vma->vm_page_prot);
  220. vma->vm_ops = &mmap_mem_ops;
  221. /* Remap-pfn-range will mark the range VM_IO */
  222. if (remap_pfn_range(vma,
  223. vma->vm_start,
  224. vma->vm_pgoff,
  225. size,
  226. vma->vm_page_prot)) {
  227. return -EAGAIN;
  228. }
  229. return 0;
  230. }
  231. static struct file_operations memalloc_fops = {
  232. .owner = THIS_MODULE,
  233. .open = memalloc_open,
  234. .release = memalloc_release,
  235. .unlocked_ioctl = memalloc_ioctl,
  236. .llseek = noop_llseek,
  237. .mmap = memalloc_mmap,
  238. };
  239. static int memalloc_init(void)
  240. {
  241. struct memalloc_drv *m = &memalloc_ing;
  242. int ret;
  243. m->major = register_chrdev(0, "memalloc", &memalloc_fops);
  244. if (m->major < 0) {
  245. pr_err("failed to register character device\n");
  246. return m->major;
  247. }
  248. /* create /dev/memalloc */
  249. m->class = class_create(THIS_MODULE, "memalloc-cls");
  250. if (IS_ERR(m->class)) {
  251. ret = PTR_ERR(m->class);
  252. goto err;
  253. }
  254. m->dev = device_create(m->class, NULL, MKDEV(m->major, 0), NULL, "memalloc");
  255. if (IS_ERR(m->dev)) {
  256. ret = PTR_ERR(m->dev);
  257. class_destroy(m->class);
  258. goto err;
  259. }
  260. m->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  261. dev_dbg(m->dev, "allocator with major = %d\n", m->major);
  262. return 0;
  263. err:
  264. unregister_chrdev(m->major, "memalloc");
  265. return ret;
  266. }
  267. module_init(memalloc_init);
  268. static void memalloc_exit(void)
  269. {
  270. struct memalloc_drv *m = &memalloc_ing;
  271. device_destroy(m->class, MKDEV(m->major, 0));
  272. class_destroy(m->class);
  273. unregister_chrdev(m->major, "memalloc");
  274. }
  275. module_exit(memalloc_exit);
  276. MODULE_AUTHOR("Hantro Products Oy");
  277. MODULE_DESCRIPTION("Memory allocator for VDEC");
  278. MODULE_LICENSE("GPL");
  279. MODULE_VERSION("0.5");