blob: e02353e340dd78d07d0750b05af0533ffad35dae [file] [log] [blame]
Magnus Damm2cc45cf2008-07-16 21:33:39 -03001/*
2 * helper functions for physically contiguous capture buffers
3 *
4 * The functions support hardware lacking scatter gather support
5 * (i.e. the buffers must be linear in physical memory)
6 *
7 * Copyright (c) 2008 Magnus Damm
8 *
9 * Based on videobuf-vmalloc.c,
10 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
Hans Verkuilf19ad392008-07-18 02:02:50 -030019#include <linux/mm.h>
Magnus Damm720b17e2009-06-16 15:32:36 -070020#include <linux/pagemap.h>
Magnus Damm2cc45cf2008-07-16 21:33:39 -030021#include <linux/dma-mapping.h>
Guennadi Liakhovetskif39c1ab2009-11-09 16:11:34 -030022#include <linux/sched.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Magnus Damm2cc45cf2008-07-16 21:33:39 -030024#include <media/videobuf-dma-contig.h>
25
26struct videobuf_dma_contig_memory {
27 u32 magic;
28 void *vaddr;
29 dma_addr_t dma_handle;
30 unsigned long size;
31};
32
33#define MAGIC_DC_MEM 0x0733ac61
Guennadi Liakhovetskic60f2b52008-07-17 17:30:47 -030034#define MAGIC_CHECK(is, should) \
35 if (unlikely((is) != (should))) { \
36 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
37 BUG(); \
Magnus Damm2cc45cf2008-07-16 21:33:39 -030038 }
39
Federico Vagaa8f3c202012-04-12 12:39:37 -030040static int __videobuf_dc_alloc(struct device *dev,
41 struct videobuf_dma_contig_memory *mem,
Dan Carpenter50fbe322012-05-24 11:56:41 -030042 unsigned long size, gfp_t flags)
Federico Vagaa8f3c202012-04-12 12:39:37 -030043{
44 mem->size = size;
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -030045 mem->vaddr = dma_alloc_coherent(dev, mem->size,
46 &mem->dma_handle, flags);
Federico Vagaa8f3c202012-04-12 12:39:37 -030047
48 if (!mem->vaddr) {
49 dev_err(dev, "memory alloc size %ld failed\n", mem->size);
50 return -ENOMEM;
51 }
52
53 dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
54
55 return 0;
56}
57
58static void __videobuf_dc_free(struct device *dev,
59 struct videobuf_dma_contig_memory *mem)
60{
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -030061 dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
Federico Vagaa8f3c202012-04-12 12:39:37 -030062
63 mem->vaddr = NULL;
64}
65
66static void videobuf_vm_open(struct vm_area_struct *vma)
Magnus Damm2cc45cf2008-07-16 21:33:39 -030067{
68 struct videobuf_mapping *map = vma->vm_private_data;
69
Hans Verkuilcca36e22014-01-03 08:10:49 -030070 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030071 map, map->count, vma->vm_start, vma->vm_end);
72
73 map->count++;
74}
75
76static void videobuf_vm_close(struct vm_area_struct *vma)
77{
78 struct videobuf_mapping *map = vma->vm_private_data;
79 struct videobuf_queue *q = map->q;
80 int i;
81
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030082 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030083 map, map->count, vma->vm_start, vma->vm_end);
84
Hans Verkuilcca36e22014-01-03 08:10:49 -030085 map->count--;
86 if (0 == map->count) {
Magnus Damm2cc45cf2008-07-16 21:33:39 -030087 struct videobuf_dma_contig_memory *mem;
88
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030089 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
Hans Verkuilcca36e22014-01-03 08:10:49 -030090 videobuf_queue_lock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -030091
92 /* We need first to cancel streams, before unmapping */
93 if (q->streaming)
94 videobuf_queue_cancel(q);
95
96 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
97 if (NULL == q->bufs[i])
98 continue;
99
100 if (q->bufs[i]->map != map)
101 continue;
102
103 mem = q->bufs[i]->priv;
104 if (mem) {
105 /* This callback is called only if kernel has
106 allocated memory and this memory is mmapped.
107 In this case, memory should be freed,
108 in order to do memory unmap.
109 */
110
111 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
112
113 /* vfree is not atomic - can't be
114 called with IRQ's disabled
115 */
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -0300116 dev_dbg(q->dev, "buf[%d] freeing %p\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300117 i, mem->vaddr);
118
Federico Vagaa8f3c202012-04-12 12:39:37 -0300119 __videobuf_dc_free(q->dev, mem);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300120 mem->vaddr = NULL;
121 }
122
Federico Vagaa8f3c202012-04-12 12:39:37 -0300123 q->bufs[i]->map = NULL;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300124 q->bufs[i]->baddr = 0;
125 }
126
127 kfree(map);
128
Hans Verkuilcca36e22014-01-03 08:10:49 -0300129 videobuf_queue_unlock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300130 }
131}
132
Alexey Dobriyanf0f37e22009-09-27 22:29:37 +0400133static const struct vm_operations_struct videobuf_vm_ops = {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300134 .open = videobuf_vm_open,
135 .close = videobuf_vm_close,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300136};
137
Magnus Damm720b17e2009-06-16 15:32:36 -0700138/**
139 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
140 * @mem: per-buffer private videobuf-dma-contig data
141 *
142 * This function resets the user space pointer
143 */
144static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
145{
Magnus Damm720b17e2009-06-16 15:32:36 -0700146 mem->dma_handle = 0;
147 mem->size = 0;
148}
149
150/**
151 * videobuf_dma_contig_user_get() - setup user space memory pointer
152 * @mem: per-buffer private videobuf-dma-contig data
153 * @vb: video buffer to map
154 *
155 * This function validates and sets up a pointer to user space memory.
156 * Only physically contiguous pfn-mapped memory is accepted.
157 *
158 * Returns 0 if successful.
159 */
160static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
161 struct videobuf_buffer *vb)
162{
163 struct mm_struct *mm = current->mm;
164 struct vm_area_struct *vma;
165 unsigned long prev_pfn, this_pfn;
166 unsigned long pages_done, user_address;
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300167 unsigned int offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700168 int ret;
169
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300170 offset = vb->baddr & ~PAGE_MASK;
171 mem->size = PAGE_ALIGN(vb->size + offset);
Magnus Damm720b17e2009-06-16 15:32:36 -0700172 ret = -EINVAL;
173
174 down_read(&mm->mmap_sem);
175
176 vma = find_vma(mm, vb->baddr);
177 if (!vma)
178 goto out_up;
179
180 if ((vb->baddr + mem->size) > vma->vm_end)
181 goto out_up;
182
183 pages_done = 0;
184 prev_pfn = 0; /* kill warning */
185 user_address = vb->baddr;
186
187 while (pages_done < (mem->size >> PAGE_SHIFT)) {
188 ret = follow_pfn(vma, user_address, &this_pfn);
189 if (ret)
190 break;
191
192 if (pages_done == 0)
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300193 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700194 else if (this_pfn != (prev_pfn + 1))
195 ret = -EFAULT;
196
197 if (ret)
198 break;
199
200 prev_pfn = this_pfn;
201 user_address += PAGE_SIZE;
202 pages_done++;
203 }
204
Federico Vagaa8f3c202012-04-12 12:39:37 -0300205out_up:
Magnus Damm720b17e2009-06-16 15:32:36 -0700206 up_read(&current->mm->mmap_sem);
207
208 return ret;
209}
210
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -0300211static struct videobuf_buffer *__videobuf_alloc(size_t size)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300212{
213 struct videobuf_dma_contig_memory *mem;
214 struct videobuf_buffer *vb;
215
216 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
217 if (vb) {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300218 vb->priv = ((char *)vb) + size;
219 mem = vb->priv;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300220 mem->magic = MAGIC_DC_MEM;
221 }
222
223 return vb;
224}
225
Hans Verkuil037c75e2010-03-28 08:18:37 -0300226static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300227{
228 struct videobuf_dma_contig_memory *mem = buf->priv;
229
230 BUG_ON(!mem);
231 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
232
233 return mem->vaddr;
234}
235
236static int __videobuf_iolock(struct videobuf_queue *q,
237 struct videobuf_buffer *vb,
238 struct v4l2_framebuffer *fbuf)
239{
240 struct videobuf_dma_contig_memory *mem = vb->priv;
241
242 BUG_ON(!mem);
243 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
244
245 switch (vb->memory) {
246 case V4L2_MEMORY_MMAP:
247 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
248
249 /* All handling should be done by __videobuf_mmap_mapper() */
250 if (!mem->vaddr) {
251 dev_err(q->dev, "memory is not alloced/mmapped.\n");
252 return -EINVAL;
253 }
254 break;
255 case V4L2_MEMORY_USERPTR:
256 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
257
Magnus Damm720b17e2009-06-16 15:32:36 -0700258 /* handle pointer from user space */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300259 if (vb->baddr)
Magnus Damm720b17e2009-06-16 15:32:36 -0700260 return videobuf_dma_contig_user_get(mem, vb);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300261
Magnus Damm720b17e2009-06-16 15:32:36 -0700262 /* allocate memory for the read() method */
Federico Vagaa8f3c202012-04-12 12:39:37 -0300263 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
264 GFP_KERNEL))
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300265 return -ENOMEM;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300266 break;
267 case V4L2_MEMORY_OVERLAY:
268 default:
Federico Vagaa8f3c202012-04-12 12:39:37 -0300269 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300270 return -EINVAL;
271 }
272
273 return 0;
274}
275
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300276static int __videobuf_mmap_mapper(struct videobuf_queue *q,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300277 struct videobuf_buffer *buf,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300278 struct vm_area_struct *vma)
279{
280 struct videobuf_dma_contig_memory *mem;
281 struct videobuf_mapping *map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300282 int retval;
Hans Verkuil0b62b732010-03-28 09:09:05 -0300283 unsigned long size;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300284
285 dev_dbg(q->dev, "%s\n", __func__);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300286
287 /* create mapping + update buffer list */
288 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
289 if (!map)
290 return -ENOMEM;
291
Hans Verkuil0b62b732010-03-28 09:09:05 -0300292 buf->map = map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300293 map->q = q;
294
Hans Verkuil0b62b732010-03-28 09:09:05 -0300295 buf->baddr = vma->vm_start;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300296
Hans Verkuil0b62b732010-03-28 09:09:05 -0300297 mem = buf->priv;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300298 BUG_ON(!mem);
299 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
300
Federico Vagaa8f3c202012-04-12 12:39:37 -0300301 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
302 GFP_KERNEL | __GFP_COMP))
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300303 goto error;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300304
305 /* Try to remap memory */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300306 size = vma->vm_end - vma->vm_start;
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -0300307 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
Fancy Fang8a6a5472014-10-09 23:21:22 -0300308
309 /* the "vm_pgoff" is just used in v4l2 to find the
310 * corresponding buffer data structure which is allocated
311 * earlier and it does not mean the offset from the physical
312 * buffer start address as usual. So set it to 0 to pass
313 * the sanity check in vm_iomap_memory().
314 */
315 vma->vm_pgoff = 0;
316
Ma Haijun29f1cdb2014-03-27 08:07:06 -0300317 retval = vm_iomap_memory(vma, mem->dma_handle, size);
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -0300318 if (retval) {
319 dev_err(q->dev, "mmap: remap failed with error %d. ",
320 retval);
321 dma_free_coherent(q->dev, mem->size,
322 mem->vaddr, mem->dma_handle);
323 goto error;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300324 }
325
Federico Vagaa8f3c202012-04-12 12:39:37 -0300326 vma->vm_ops = &videobuf_vm_ops;
327 vma->vm_flags |= VM_DONTEXPAND;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300328 vma->vm_private_data = map;
329
330 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
331 map, q, vma->vm_start, vma->vm_end,
Federico Vagaa8f3c202012-04-12 12:39:37 -0300332 (long int)buf->bsize, vma->vm_pgoff, buf->i);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300333
334 videobuf_vm_open(vma);
335
336 return 0;
337
338error:
339 kfree(map);
340 return -ENOMEM;
341}
342
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300343static struct videobuf_qtype_ops qops = {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300344 .magic = MAGIC_QTYPE_OPS,
Mauro Carvalho Chehabcb132cd52013-04-17 08:22:15 -0300345 .alloc_vb = __videobuf_alloc,
Federico Vagaa8f3c202012-04-12 12:39:37 -0300346 .iolock = __videobuf_iolock,
347 .mmap_mapper = __videobuf_mmap_mapper,
348 .vaddr = __videobuf_to_vaddr,
349};
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300350
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300351void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300352 const struct videobuf_queue_ops *ops,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300353 struct device *dev,
354 spinlock_t *irqlock,
355 enum v4l2_buf_type type,
356 enum v4l2_field field,
357 unsigned int msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300358 void *priv,
359 struct mutex *ext_lock)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300360{
361 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300362 priv, &qops, ext_lock);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300363}
364EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
365
366dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
367{
368 struct videobuf_dma_contig_memory *mem = buf->priv;
369
370 BUG_ON(!mem);
371 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
372
373 return mem->dma_handle;
374}
375EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
376
377void videobuf_dma_contig_free(struct videobuf_queue *q,
378 struct videobuf_buffer *buf)
379{
380 struct videobuf_dma_contig_memory *mem = buf->priv;
381
382 /* mmapped memory can't be freed here, otherwise mmapped region
383 would be released, while still needed. In this case, the memory
384 release should happen inside videobuf_vm_close().
385 So, it should free memory only if the memory were allocated for
386 read() operation.
387 */
Magnus Damm720b17e2009-06-16 15:32:36 -0700388 if (buf->memory != V4L2_MEMORY_USERPTR)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300389 return;
390
391 if (!mem)
392 return;
393
394 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
395
Magnus Damm720b17e2009-06-16 15:32:36 -0700396 /* handle user space pointer case */
397 if (buf->baddr) {
398 videobuf_dma_contig_user_put(mem);
399 return;
400 }
401
402 /* read() method */
Pawel Osciakb2b476f2010-07-20 13:49:16 -0300403 if (mem->vaddr) {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300404 __videobuf_dc_free(q->dev, mem);
Pawel Osciakb2b476f2010-07-20 13:49:16 -0300405 mem->vaddr = NULL;
406 }
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300407}
408EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
409
410MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
411MODULE_AUTHOR("Magnus Damm");
412MODULE_LICENSE("GPL");