videobuf-msm-mem.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* Copyright (c) 2011, The Linux Foundation. All rights reserved.
  2. *
  3. * Based on videobuf-dma-contig.c,
  4. * (c) 2008 Magnus Damm
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 and
  8. * only version 2 as published by the Free Software Foundation.
  9. *
  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. * helper functions for physically contiguous pmem capture buffers
  16. * The functions support contiguous memory allocations using pmem
  17. * kernel API.
  18. */
  19. #include <linux/init.h>
  20. #include <linux/module.h>
  21. #include <linux/mm.h>
  22. #include <linux/slab.h>
  23. #include <linux/pagemap.h>
  24. #include <linux/sched.h>
  25. #include <linux/io.h>
  26. #include <linux/memory_alloc.h>
  27. #include <media/videobuf-msm-mem.h>
  28. #include <media/msm_camera.h>
  29. #include <mach/memory.h>
  30. #define MAGIC_PMEM 0x0733ac64
  31. #define MAGIC_CHECK(is, should) \
  32. if (unlikely((is) != (should))) { \
  33. pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
  34. BUG(); \
  35. }
  36. #ifdef CONFIG_MSM_CAMERA_DEBUG
  37. #define D(fmt, args...) printk(KERN_DEBUG "videobuf-msm-mem: " fmt, ##args)
  38. #else
  39. #define D(fmt, args...) do {} while (0)
  40. #endif
  41. static int32_t msm_mem_allocate(const size_t size)
  42. {
  43. int32_t phyaddr;
  44. phyaddr = allocate_contiguous_ebi_nomap(size, SZ_4K);
  45. return phyaddr;
  46. }
  47. static int32_t msm_mem_free(const int32_t phyaddr)
  48. {
  49. int32_t rc = 0;
  50. free_contiguous_memory_by_paddr(phyaddr);
  51. return rc;
  52. }
  53. static void
  54. videobuf_vm_open(struct vm_area_struct *vma)
  55. {
  56. struct videobuf_mapping *map = vma->vm_private_data;
  57. D("vm_open %p [count=%u,vma=%08lx-%08lx]\n",
  58. map, map->count, vma->vm_start, vma->vm_end);
  59. map->count++;
  60. }
  61. static void videobuf_vm_close(struct vm_area_struct *vma)
  62. {
  63. struct videobuf_mapping *map = vma->vm_private_data;
  64. struct videobuf_queue *q = map->q;
  65. int i, rc;
  66. D("vm_close %p [count=%u,vma=%08lx-%08lx]\n",
  67. map, map->count, vma->vm_start, vma->vm_end);
  68. map->count--;
  69. if (0 == map->count) {
  70. struct videobuf_contig_pmem *mem;
  71. D("munmap %p q=%p\n", map, q);
  72. mutex_lock(&q->vb_lock);
  73. /* We need first to cancel streams, before unmapping */
  74. if (q->streaming)
  75. videobuf_queue_cancel(q);
  76. for (i = 0; i < VIDEO_MAX_FRAME; i++) {
  77. if (NULL == q->bufs[i])
  78. continue;
  79. if (q->bufs[i]->map != map)
  80. continue;
  81. mem = q->bufs[i]->priv;
  82. if (mem) {
  83. /* This callback is called only if kernel has
  84. * allocated memory and this memory is mmapped.
  85. * In this case, memory should be freed,
  86. * in order to do memory unmap.
  87. */
  88. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  89. /* vfree is not atomic - can't be
  90. called with IRQ's disabled
  91. */
  92. D("buf[%d] freeing physical %d\n",
  93. i, mem->phyaddr);
  94. rc = msm_mem_free(mem->phyaddr);
  95. if (rc < 0)
  96. D("%s: Invalid memory location\n",
  97. __func__);
  98. else {
  99. mem->phyaddr = 0;
  100. }
  101. }
  102. q->bufs[i]->map = NULL;
  103. q->bufs[i]->baddr = 0;
  104. }
  105. kfree(map);
  106. mutex_unlock(&q->vb_lock);
  107. /* deallocate the q->bufs[i] structure not a good solution
  108. as it will result in unnecessary iterations but right now
  109. this looks like the only cleaner way */
  110. videobuf_mmap_free(q);
  111. }
  112. }
  113. static const struct vm_operations_struct videobuf_vm_ops = {
  114. .open = videobuf_vm_open,
  115. .close = videobuf_vm_close,
  116. };
  117. static struct videobuf_buffer *__videobuf_alloc(size_t size)
  118. {
  119. struct videobuf_contig_pmem *mem;
  120. struct videobuf_buffer *vb;
  121. vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
  122. if (vb) {
  123. mem = vb->priv = ((char *)vb) + size;
  124. mem->magic = MAGIC_PMEM;
  125. }
  126. return vb;
  127. }
  128. static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
  129. {
  130. struct videobuf_contig_pmem *mem = buf->priv;
  131. BUG_ON(!mem);
  132. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  133. return mem->vaddr;
  134. }
  135. static int __videobuf_iolock(struct videobuf_queue *q,
  136. struct videobuf_buffer *vb,
  137. struct v4l2_framebuffer *fbuf)
  138. {
  139. int rc = 0;
  140. struct videobuf_contig_pmem *mem = vb->priv;
  141. BUG_ON(!mem);
  142. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  143. switch (vb->memory) {
  144. case V4L2_MEMORY_MMAP:
  145. D("%s memory method MMAP\n", __func__);
  146. /* All handling should be done by __videobuf_mmap_mapper() */
  147. break;
  148. case V4L2_MEMORY_OVERLAY:
  149. default:
  150. pr_err("%s memory method OVERLAY/unknown\n", __func__);
  151. rc = -EINVAL;
  152. }
  153. return rc;
  154. }
  155. static int __videobuf_mmap_mapper(struct videobuf_queue *q,
  156. struct videobuf_buffer *buf,
  157. struct vm_area_struct *vma)
  158. {
  159. struct videobuf_contig_pmem *mem;
  160. struct videobuf_mapping *map;
  161. int retval;
  162. unsigned long size;
  163. D("%s\n", __func__);
  164. /* create mapping + update buffer list */
  165. map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
  166. if (!map) {
  167. pr_err("%s: kzalloc failed.\n", __func__);
  168. return -ENOMEM;
  169. }
  170. buf->map = map;
  171. map->q = q;
  172. buf->baddr = vma->vm_start;
  173. mem = buf->priv;
  174. D("mem = 0x%x\n", (u32)mem);
  175. D("buf = 0x%x\n", (u32)buf);
  176. BUG_ON(!mem);
  177. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  178. mem->size = PAGE_ALIGN(buf->bsize);
  179. mem->y_off = 0;
  180. mem->cbcr_off = (buf->bsize)*2/3;
  181. if (buf->i >= 0 && buf->i <= 3)
  182. mem->buffer_type = OUTPUT_TYPE_P;
  183. else
  184. mem->buffer_type = OUTPUT_TYPE_V;
  185. buf->bsize = mem->size;
  186. mem->phyaddr = msm_mem_allocate(mem->size);
  187. if (!mem->phyaddr) {
  188. pr_err("%s : pmem memory allocation failed\n", __func__);
  189. goto error;
  190. }
  191. /* Try to remap memory */
  192. size = vma->vm_end - vma->vm_start;
  193. size = (size < mem->size) ? size : mem->size;
  194. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  195. retval = remap_pfn_range(vma, vma->vm_start,
  196. mem->phyaddr >> PAGE_SHIFT,
  197. size, vma->vm_page_prot);
  198. if (retval) {
  199. pr_err("mmap: remap failed with error %d. ", retval);
  200. retval = msm_mem_free(mem->phyaddr);
  201. if (retval < 0)
  202. printk(KERN_ERR "%s: Invalid memory location\n",
  203. __func__);
  204. else {
  205. mem->phyaddr = 0;
  206. }
  207. goto error;
  208. }
  209. vma->vm_ops = &videobuf_vm_ops;
  210. vma->vm_flags |= VM_DONTEXPAND;
  211. vma->vm_private_data = map;
  212. D("mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
  213. map, q, vma->vm_start, vma->vm_end,
  214. (long int)buf->bsize,
  215. vma->vm_pgoff, buf->i);
  216. videobuf_vm_open(vma);
  217. return 0;
  218. error:
  219. kfree(map);
  220. return -ENOMEM;
  221. }
  222. static struct videobuf_qtype_ops qops = {
  223. .magic = MAGIC_QTYPE_OPS,
  224. .alloc_vb = __videobuf_alloc,
  225. .iolock = __videobuf_iolock,
  226. .mmap_mapper = __videobuf_mmap_mapper,
  227. .vaddr = __videobuf_to_vaddr,
  228. };
  229. void videobuf_queue_pmem_contig_init(struct videobuf_queue *q,
  230. const struct videobuf_queue_ops *ops,
  231. struct device *dev,
  232. spinlock_t *irqlock,
  233. enum v4l2_buf_type type,
  234. enum v4l2_field field,
  235. unsigned int msize,
  236. void *priv,
  237. struct mutex *ext_lock)
  238. {
  239. videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
  240. priv, &qops, ext_lock);
  241. }
  242. EXPORT_SYMBOL_GPL(videobuf_queue_pmem_contig_init);
  243. int videobuf_to_pmem_contig(struct videobuf_buffer *buf)
  244. {
  245. struct videobuf_contig_pmem *mem = buf->priv;
  246. BUG_ON(!mem);
  247. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  248. return mem->phyaddr;
  249. }
  250. EXPORT_SYMBOL_GPL(videobuf_to_pmem_contig);
  251. int videobuf_pmem_contig_free(struct videobuf_queue *q,
  252. struct videobuf_buffer *buf)
  253. {
  254. struct videobuf_contig_pmem *mem = buf->priv;
  255. /* mmapped memory can't be freed here, otherwise mmapped region
  256. would be released, while still needed. In this case, the memory
  257. release should happen inside videobuf_vm_close().
  258. So, it should free memory only if the memory were allocated for
  259. read() operation.
  260. */
  261. if (buf->memory != V4L2_MEMORY_USERPTR)
  262. return -EINVAL;
  263. if (!mem)
  264. return -ENOMEM;
  265. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  266. /* handle user space pointer case */
  267. if (buf->baddr) {
  268. return 0;
  269. } else {
  270. /* don't support read() method */
  271. return -EINVAL;
  272. }
  273. }
  274. EXPORT_SYMBOL_GPL(videobuf_pmem_contig_free);
  275. MODULE_DESCRIPTION("helper module to manage video4linux PMEM contig buffers");
  276. MODULE_LICENSE("GPL v2");