videobuf2-msm-mem.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* Copyright (c) 2011-2012, 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/videobuf2-msm-mem.h>
  28. #include <media/msm_camera.h>
  29. #include <mach/memory.h>
  30. #include <media/videobuf2-core.h>
  31. #include <mach/iommu_domains.h>
  32. #define MAGIC_PMEM 0x0733ac64
  33. #define MAGIC_CHECK(is, should) \
  34. if (unlikely((is) != (should))) { \
  35. pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
  36. BUG(); \
  37. }
  38. #ifdef CONFIG_MSM_CAMERA_DEBUG
  39. #define D(fmt, args...) pr_debug("videobuf-msm-mem: " fmt, ##args)
  40. #else
  41. #define D(fmt, args...) do {} while (0)
  42. #endif
  43. static unsigned long msm_mem_allocate(struct videobuf2_contig_pmem *mem)
  44. {
  45. unsigned long phyaddr;
  46. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
  47. int rc, len;
  48. mem->client = msm_ion_client_create(-1, "camera");
  49. if (IS_ERR((void *)mem->client)) {
  50. pr_err("%s Could not create client\n", __func__);
  51. goto client_failed;
  52. }
  53. mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K,
  54. (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID), 0);
  55. if (IS_ERR((void *)mem->ion_handle)) {
  56. pr_err("%s Could not allocate\n", __func__);
  57. goto alloc_failed;
  58. }
  59. rc = ion_map_iommu(mem->client, mem->ion_handle,
  60. -1, 0, SZ_4K, 0,
  61. (unsigned long *)&phyaddr,
  62. (unsigned long *)&len, 0, 0);
  63. if (rc < 0) {
  64. pr_err("%s Could not get physical address\n", __func__);
  65. goto phys_failed;
  66. }
  67. #else
  68. phyaddr = allocate_contiguous_ebi_nomap(mem->size, SZ_4K);
  69. #endif
  70. return phyaddr;
  71. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
  72. phys_failed:
  73. ion_free(mem->client, mem->ion_handle);
  74. alloc_failed:
  75. ion_client_destroy(mem->client);
  76. client_failed:
  77. return 0;
  78. #endif
  79. }
  80. static int32_t msm_mem_free(struct videobuf2_contig_pmem *mem)
  81. {
  82. int32_t rc = 0;
  83. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
  84. ion_unmap_iommu(mem->client, mem->ion_handle, -1, 0);
  85. ion_free(mem->client, mem->ion_handle);
  86. ion_client_destroy(mem->client);
  87. #else
  88. free_contiguous_memory_by_paddr(mem->phyaddr);
  89. #endif
  90. return rc;
  91. }
  92. static void videobuf2_vm_close(struct vm_area_struct *vma)
  93. {
  94. struct videobuf2_contig_pmem *mem = vma->vm_private_data;
  95. D("vm_close %p [count=%u,vma=%08lx-%08lx]\n",
  96. mem, mem->count, vma->vm_start, vma->vm_end);
  97. mem->count--;
  98. }
  99. static void videobuf2_vm_open(struct vm_area_struct *vma)
  100. {
  101. struct videobuf2_contig_pmem *mem = vma->vm_private_data;
  102. D("vm_open %p [count=%u,vma=%08lx-%08lx]\n",
  103. mem, mem->count, vma->vm_start, vma->vm_end);
  104. mem->count++;
  105. }
  106. static const struct vm_operations_struct videobuf2_vm_ops = {
  107. .open = videobuf2_vm_open,
  108. .close = videobuf2_vm_close,
  109. };
  110. static void *msm_vb2_mem_ops_alloc(void *alloc_ctx, unsigned long size)
  111. {
  112. struct videobuf2_contig_pmem *mem;
  113. mem = kzalloc(sizeof(*mem), GFP_KERNEL);
  114. if (!mem)
  115. return ERR_PTR(-ENOMEM);
  116. mem->magic = MAGIC_PMEM;
  117. mem->size = PAGE_ALIGN(size);
  118. mem->alloc_ctx = alloc_ctx;
  119. mem->is_userptr = 0;
  120. mem->phyaddr = msm_mem_allocate(mem);
  121. if (!mem->phyaddr) {
  122. pr_err("%s : pmem memory allocation failed\n", __func__);
  123. kfree(mem);
  124. return ERR_PTR(-ENOMEM);
  125. }
  126. mem->mapped_phyaddr = mem->phyaddr;
  127. return mem;
  128. }
  129. static void msm_vb2_mem_ops_put(void *buf_priv)
  130. {
  131. struct videobuf2_contig_pmem *mem = buf_priv;
  132. if (!mem->is_userptr) {
  133. D("%s Freeing memory ", __func__);
  134. msm_mem_free(mem);
  135. }
  136. kfree(mem);
  137. }
  138. int videobuf2_pmem_contig_mmap_get(struct videobuf2_contig_pmem *mem,
  139. struct videobuf2_msm_offset *offset,
  140. enum videobuf2_buffer_type buffer_type,
  141. int path)
  142. {
  143. if (offset)
  144. mem->offset = *offset;
  145. else
  146. memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
  147. mem->buffer_type = buffer_type;
  148. mem->path = path;
  149. return 0;
  150. }
  151. EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_mmap_get);
  152. /**
  153. * videobuf_pmem_contig_user_get() - setup user space memory pointer
  154. * @mem: per-buffer private videobuf-contig-pmem data
  155. * @vb: video buffer to map
  156. *
  157. * This function validates and sets up a pointer to user space memory.
  158. * Only physically contiguous pfn-mapped memory is accepted.
  159. *
  160. * Returns 0 if successful.
  161. */
  162. int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
  163. struct videobuf2_msm_offset *offset,
  164. enum videobuf2_buffer_type buffer_type,
  165. uint32_t addr_offset, int path,
  166. struct ion_client *client,
  167. int domain_num)
  168. {
  169. int rc = 0;
  170. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
  171. unsigned long len;
  172. #endif
  173. unsigned long paddr = 0;
  174. if (mem->phyaddr != 0)
  175. return 0;
  176. #if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
  177. mem->ion_handle = ion_import_dma_buf(client, (int)mem->vaddr);
  178. if (IS_ERR_OR_NULL(mem->ion_handle)) {
  179. pr_err("%s ION import failed\n", __func__);
  180. return PTR_ERR(mem->ion_handle);
  181. }
  182. rc = ion_map_iommu(client, mem->ion_handle, domain_num, 0,
  183. SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0);
  184. if (rc < 0)
  185. ion_free(client, mem->ion_handle);
  186. #else
  187. paddr = 0;
  188. #endif
  189. if (offset)
  190. mem->offset = *offset;
  191. else
  192. memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
  193. mem->path = path;
  194. mem->buffer_type = buffer_type;
  195. paddr = mem->phyaddr;
  196. mem->mapped_phyaddr = paddr + addr_offset;
  197. mem->addr_offset = addr_offset;
  198. return rc;
  199. }
  200. EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_get);
  201. void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
  202. struct ion_client *client, int domain_num)
  203. {
  204. if (mem->is_userptr) {
  205. #if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
  206. ion_unmap_iommu(client, mem->ion_handle,
  207. domain_num, 0);
  208. ion_free(client, mem->ion_handle);
  209. #endif
  210. }
  211. mem->is_userptr = 0;
  212. mem->phyaddr = 0;
  213. mem->size = 0;
  214. mem->mapped_phyaddr = 0;
  215. }
  216. EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_put);
  217. static void *msm_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
  218. unsigned long size, int write)
  219. {
  220. struct videobuf2_contig_pmem *mem;
  221. mem = kzalloc(sizeof(*mem), GFP_KERNEL);
  222. if (!mem)
  223. return ERR_PTR(-ENOMEM);
  224. mem->magic = MAGIC_PMEM;
  225. mem->is_userptr = 1;
  226. mem->vaddr = (void *)vaddr;
  227. mem->size = size;
  228. mem->alloc_ctx = alloc_ctx;
  229. return mem;
  230. }
  231. static void msm_vb2_mem_ops_put_userptr(void *buf_priv)
  232. {
  233. kfree(buf_priv);
  234. }
  235. static void *msm_vb2_mem_ops_vaddr(void *buf_priv)
  236. {
  237. struct videobuf2_contig_pmem *mem = buf_priv;
  238. return mem->vaddr;
  239. }
  240. static void *msm_vb2_mem_ops_cookie(void *buf_priv)
  241. {
  242. return buf_priv;
  243. }
  244. static unsigned int msm_vb2_mem_ops_num_users(void *buf_priv)
  245. {
  246. struct videobuf2_contig_pmem *mem = buf_priv;
  247. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  248. return mem->count;
  249. }
  250. static int msm_vb2_mem_ops_mmap(void *buf_priv, struct vm_area_struct *vma)
  251. {
  252. struct videobuf2_contig_pmem *mem;
  253. int retval;
  254. unsigned long size;
  255. D("%s\n", __func__);
  256. mem = buf_priv;
  257. D("mem = 0x%x\n", (u32)mem);
  258. BUG_ON(!mem);
  259. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  260. /* Try to remap memory */
  261. size = vma->vm_end - vma->vm_start;
  262. size = (size < mem->size) ? size : mem->size;
  263. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  264. retval = remap_pfn_range(vma, vma->vm_start,
  265. mem->phyaddr >> PAGE_SHIFT,
  266. size, vma->vm_page_prot);
  267. if (retval) {
  268. pr_err("mmap: remap failed with error %d. ", retval);
  269. goto error;
  270. }
  271. mem->vaddr = (void *)vma->vm_start;
  272. vma->vm_ops = &videobuf2_vm_ops;
  273. vma->vm_flags |= VM_DONTEXPAND;
  274. vma->vm_private_data = mem;
  275. D("mmap %p: %08lx-%08lx (%lx) pgoff %08lx\n",
  276. map, vma->vm_start, vma->vm_end,
  277. (long int)mem->bsize, vma->vm_pgoff);
  278. videobuf2_vm_open(vma);
  279. return 0;
  280. error:
  281. return -ENOMEM;
  282. }
  283. static struct vb2_mem_ops msm_vb2_mem_ops = {
  284. .alloc = msm_vb2_mem_ops_alloc,
  285. .put = msm_vb2_mem_ops_put,
  286. .get_userptr = msm_vb2_mem_ops_get_userptr,
  287. .put_userptr = msm_vb2_mem_ops_put_userptr,
  288. .vaddr = msm_vb2_mem_ops_vaddr,
  289. .cookie = msm_vb2_mem_ops_cookie,
  290. .num_users = msm_vb2_mem_ops_num_users,
  291. .mmap = msm_vb2_mem_ops_mmap
  292. };
  293. void videobuf2_queue_pmem_contig_init(struct vb2_queue *q,
  294. enum v4l2_buf_type type,
  295. const struct vb2_ops *ops,
  296. unsigned int size,
  297. void *priv)
  298. {
  299. memset(q, 0, sizeof(struct vb2_queue));
  300. q->mem_ops = &msm_vb2_mem_ops;
  301. q->ops = ops;
  302. q->drv_priv = priv;
  303. q->type = type;
  304. q->io_modes = VB2_MMAP | VB2_USERPTR;
  305. q->io_flags = 0;
  306. q->buf_struct_size = size;
  307. vb2_queue_init(q);
  308. }
  309. EXPORT_SYMBOL_GPL(videobuf2_queue_pmem_contig_init);
  310. unsigned long videobuf2_to_pmem_contig(struct vb2_buffer *vb,
  311. unsigned int plane_no)
  312. {
  313. struct videobuf2_contig_pmem *mem;
  314. mem = vb2_plane_cookie(vb, plane_no);
  315. BUG_ON(!mem);
  316. MAGIC_CHECK(mem->magic, MAGIC_PMEM);
  317. return mem->mapped_phyaddr;
  318. }
  319. EXPORT_SYMBOL_GPL(videobuf2_to_pmem_contig);
  320. MODULE_DESCRIPTION("helper module to manage video4linux PMEM contig buffers");
  321. MODULE_LICENSE("GPL v2");