blob: 65411adcd0ea958a3b4c7a5edd6f4f2d57cb32d9 [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 Chehabcb132cd2013-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 Chehabcb132cd2013-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;
Al Viroa242f422013-05-09 15:03:33 -030069 struct videobuf_queue *q = map->q;
Magnus Damm2cc45cf2008-07-16 21:33:39 -030070
Al Viroa242f422013-05-09 15:03:33 -030071 dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030072 map, map->count, vma->vm_start, vma->vm_end);
73
Al Viroa242f422013-05-09 15:03:33 -030074 videobuf_queue_lock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -030075 map->count++;
Al Viroa242f422013-05-09 15:03:33 -030076 videobuf_queue_unlock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -030077}
78
79static void videobuf_vm_close(struct vm_area_struct *vma)
80{
81 struct videobuf_mapping *map = vma->vm_private_data;
82 struct videobuf_queue *q = map->q;
83 int i;
84
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030085 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030086 map, map->count, vma->vm_start, vma->vm_end);
87
Al Viroa242f422013-05-09 15:03:33 -030088 videobuf_queue_lock(q);
89 if (!--map->count) {
Magnus Damm2cc45cf2008-07-16 21:33:39 -030090 struct videobuf_dma_contig_memory *mem;
91
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030092 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -030093
94 /* We need first to cancel streams, before unmapping */
95 if (q->streaming)
96 videobuf_queue_cancel(q);
97
98 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
99 if (NULL == q->bufs[i])
100 continue;
101
102 if (q->bufs[i]->map != map)
103 continue;
104
105 mem = q->bufs[i]->priv;
106 if (mem) {
107 /* This callback is called only if kernel has
108 allocated memory and this memory is mmapped.
109 In this case, memory should be freed,
110 in order to do memory unmap.
111 */
112
113 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
114
115 /* vfree is not atomic - can't be
116 called with IRQ's disabled
117 */
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -0300118 dev_dbg(q->dev, "buf[%d] freeing %p\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300119 i, mem->vaddr);
120
Federico Vagaa8f3c202012-04-12 12:39:37 -0300121 __videobuf_dc_free(q->dev, mem);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300122 mem->vaddr = NULL;
123 }
124
Federico Vagaa8f3c202012-04-12 12:39:37 -0300125 q->bufs[i]->map = NULL;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300126 q->bufs[i]->baddr = 0;
127 }
128
129 kfree(map);
130
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300131 }
Al Viroa242f422013-05-09 15:03:33 -0300132 videobuf_queue_unlock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300133}
134
Alexey Dobriyanf0f37e22009-09-27 22:29:37 +0400135static const struct vm_operations_struct videobuf_vm_ops = {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300136 .open = videobuf_vm_open,
137 .close = videobuf_vm_close,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300138};
139
Magnus Damm720b17e2009-06-16 15:32:36 -0700140/**
141 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
142 * @mem: per-buffer private videobuf-dma-contig data
143 *
144 * This function resets the user space pointer
145 */
146static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
147{
Magnus Damm720b17e2009-06-16 15:32:36 -0700148 mem->dma_handle = 0;
149 mem->size = 0;
150}
151
152/**
153 * videobuf_dma_contig_user_get() - setup user space memory pointer
154 * @mem: per-buffer private videobuf-dma-contig 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 */
162static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
163 struct videobuf_buffer *vb)
164{
165 struct mm_struct *mm = current->mm;
166 struct vm_area_struct *vma;
167 unsigned long prev_pfn, this_pfn;
168 unsigned long pages_done, user_address;
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300169 unsigned int offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700170 int ret;
171
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300172 offset = vb->baddr & ~PAGE_MASK;
173 mem->size = PAGE_ALIGN(vb->size + offset);
Magnus Damm720b17e2009-06-16 15:32:36 -0700174 ret = -EINVAL;
175
176 down_read(&mm->mmap_sem);
177
178 vma = find_vma(mm, vb->baddr);
179 if (!vma)
180 goto out_up;
181
182 if ((vb->baddr + mem->size) > vma->vm_end)
183 goto out_up;
184
185 pages_done = 0;
186 prev_pfn = 0; /* kill warning */
187 user_address = vb->baddr;
188
189 while (pages_done < (mem->size >> PAGE_SHIFT)) {
190 ret = follow_pfn(vma, user_address, &this_pfn);
191 if (ret)
192 break;
193
194 if (pages_done == 0)
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300195 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700196 else if (this_pfn != (prev_pfn + 1))
197 ret = -EFAULT;
198
199 if (ret)
200 break;
201
202 prev_pfn = this_pfn;
203 user_address += PAGE_SIZE;
204 pages_done++;
205 }
206
Federico Vagaa8f3c202012-04-12 12:39:37 -0300207out_up:
Magnus Damm720b17e2009-06-16 15:32:36 -0700208 up_read(&current->mm->mmap_sem);
209
210 return ret;
211}
212
Mauro Carvalho Chehabcb132cd2013-04-17 08:22:15 -0300213static struct videobuf_buffer *__videobuf_alloc(size_t size)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300214{
215 struct videobuf_dma_contig_memory *mem;
216 struct videobuf_buffer *vb;
217
218 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
219 if (vb) {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300220 vb->priv = ((char *)vb) + size;
221 mem = vb->priv;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300222 mem->magic = MAGIC_DC_MEM;
223 }
224
225 return vb;
226}
227
Hans Verkuil037c75e2010-03-28 08:18:37 -0300228static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300229{
230 struct videobuf_dma_contig_memory *mem = buf->priv;
231
232 BUG_ON(!mem);
233 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
234
235 return mem->vaddr;
236}
237
238static int __videobuf_iolock(struct videobuf_queue *q,
239 struct videobuf_buffer *vb,
240 struct v4l2_framebuffer *fbuf)
241{
242 struct videobuf_dma_contig_memory *mem = vb->priv;
243
244 BUG_ON(!mem);
245 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
246
247 switch (vb->memory) {
248 case V4L2_MEMORY_MMAP:
249 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
250
251 /* All handling should be done by __videobuf_mmap_mapper() */
252 if (!mem->vaddr) {
253 dev_err(q->dev, "memory is not alloced/mmapped.\n");
254 return -EINVAL;
255 }
256 break;
257 case V4L2_MEMORY_USERPTR:
258 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
259
Magnus Damm720b17e2009-06-16 15:32:36 -0700260 /* handle pointer from user space */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300261 if (vb->baddr)
Magnus Damm720b17e2009-06-16 15:32:36 -0700262 return videobuf_dma_contig_user_get(mem, vb);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300263
Magnus Damm720b17e2009-06-16 15:32:36 -0700264 /* allocate memory for the read() method */
Federico Vagaa8f3c202012-04-12 12:39:37 -0300265 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
266 GFP_KERNEL))
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300267 return -ENOMEM;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300268 break;
269 case V4L2_MEMORY_OVERLAY:
270 default:
Federico Vagaa8f3c202012-04-12 12:39:37 -0300271 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300272 return -EINVAL;
273 }
274
275 return 0;
276}
277
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300278static int __videobuf_mmap_mapper(struct videobuf_queue *q,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300279 struct videobuf_buffer *buf,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300280 struct vm_area_struct *vma)
281{
282 struct videobuf_dma_contig_memory *mem;
283 struct videobuf_mapping *map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300284 int retval;
Hans Verkuil0b62b732010-03-28 09:09:05 -0300285 unsigned long size;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300286
287 dev_dbg(q->dev, "%s\n", __func__);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300288
289 /* create mapping + update buffer list */
290 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
291 if (!map)
292 return -ENOMEM;
293
Hans Verkuil0b62b732010-03-28 09:09:05 -0300294 buf->map = map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300295 map->q = q;
296
Hans Verkuil0b62b732010-03-28 09:09:05 -0300297 buf->baddr = vma->vm_start;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300298
Hans Verkuil0b62b732010-03-28 09:09:05 -0300299 mem = buf->priv;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300300 BUG_ON(!mem);
301 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
302
Federico Vagaa8f3c202012-04-12 12:39:37 -0300303 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
304 GFP_KERNEL | __GFP_COMP))
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300305 goto error;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300306
307 /* Try to remap memory */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300308 size = vma->vm_end - vma->vm_start;
Mauro Carvalho Chehabcb132cd2013-04-17 08:22:15 -0300309 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
Mauro Carvalho Chehab2a848b22013-04-17 08:22:16 -0300310 retval = vm_iomap_memory(vma, vma->vm_start, size);
Mauro Carvalho Chehabcb132cd2013-04-17 08:22:15 -0300311 if (retval) {
312 dev_err(q->dev, "mmap: remap failed with error %d. ",
313 retval);
314 dma_free_coherent(q->dev, mem->size,
315 mem->vaddr, mem->dma_handle);
316 goto error;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300317 }
318
Federico Vagaa8f3c202012-04-12 12:39:37 -0300319 vma->vm_ops = &videobuf_vm_ops;
320 vma->vm_flags |= VM_DONTEXPAND;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300321 vma->vm_private_data = map;
322
323 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
324 map, q, vma->vm_start, vma->vm_end,
Federico Vagaa8f3c202012-04-12 12:39:37 -0300325 (long int)buf->bsize, vma->vm_pgoff, buf->i);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300326
327 videobuf_vm_open(vma);
328
329 return 0;
330
331error:
332 kfree(map);
333 return -ENOMEM;
334}
335
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300336static struct videobuf_qtype_ops qops = {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300337 .magic = MAGIC_QTYPE_OPS,
Mauro Carvalho Chehabcb132cd2013-04-17 08:22:15 -0300338 .alloc_vb = __videobuf_alloc,
Federico Vagaa8f3c202012-04-12 12:39:37 -0300339 .iolock = __videobuf_iolock,
340 .mmap_mapper = __videobuf_mmap_mapper,
341 .vaddr = __videobuf_to_vaddr,
342};
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300343
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300344void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300345 const struct videobuf_queue_ops *ops,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300346 struct device *dev,
347 spinlock_t *irqlock,
348 enum v4l2_buf_type type,
349 enum v4l2_field field,
350 unsigned int msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300351 void *priv,
352 struct mutex *ext_lock)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300353{
354 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300355 priv, &qops, ext_lock);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300356}
357EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
358
359dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
360{
361 struct videobuf_dma_contig_memory *mem = buf->priv;
362
363 BUG_ON(!mem);
364 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
365
366 return mem->dma_handle;
367}
368EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
369
370void videobuf_dma_contig_free(struct videobuf_queue *q,
371 struct videobuf_buffer *buf)
372{
373 struct videobuf_dma_contig_memory *mem = buf->priv;
374
375 /* mmapped memory can't be freed here, otherwise mmapped region
376 would be released, while still needed. In this case, the memory
377 release should happen inside videobuf_vm_close().
378 So, it should free memory only if the memory were allocated for
379 read() operation.
380 */
Magnus Damm720b17e2009-06-16 15:32:36 -0700381 if (buf->memory != V4L2_MEMORY_USERPTR)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300382 return;
383
384 if (!mem)
385 return;
386
387 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
388
Magnus Damm720b17e2009-06-16 15:32:36 -0700389 /* handle user space pointer case */
390 if (buf->baddr) {
391 videobuf_dma_contig_user_put(mem);
392 return;
393 }
394
395 /* read() method */
Pawel Osciakb2b476f2010-07-20 13:49:16 -0300396 if (mem->vaddr) {
Federico Vagaa8f3c202012-04-12 12:39:37 -0300397 __videobuf_dc_free(q->dev, mem);
Pawel Osciakb2b476f2010-07-20 13:49:16 -0300398 mem->vaddr = NULL;
399 }
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300400}
401EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
402
403MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
404MODULE_AUTHOR("Magnus Damm");
405MODULE_LICENSE("GPL");