blob: c9691115f2d26787fa9d85ae98382539d78a8a98 [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
40static void
41videobuf_vm_open(struct vm_area_struct *vma)
42{
43 struct videobuf_mapping *map = vma->vm_private_data;
44
45 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
46 map, map->count, vma->vm_start, vma->vm_end);
47
48 map->count++;
49}
50
51static void videobuf_vm_close(struct vm_area_struct *vma)
52{
53 struct videobuf_mapping *map = vma->vm_private_data;
54 struct videobuf_queue *q = map->q;
55 int i;
56
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030057 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030058 map, map->count, vma->vm_start, vma->vm_end);
59
60 map->count--;
61 if (0 == map->count) {
62 struct videobuf_dma_contig_memory *mem;
63
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030064 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
Hans Verkuil97397682010-09-20 17:24:30 -030065 videobuf_queue_lock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -030066
67 /* We need first to cancel streams, before unmapping */
68 if (q->streaming)
69 videobuf_queue_cancel(q);
70
71 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
72 if (NULL == q->bufs[i])
73 continue;
74
75 if (q->bufs[i]->map != map)
76 continue;
77
78 mem = q->bufs[i]->priv;
79 if (mem) {
80 /* This callback is called only if kernel has
81 allocated memory and this memory is mmapped.
82 In this case, memory should be freed,
83 in order to do memory unmap.
84 */
85
86 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
87
88 /* vfree is not atomic - can't be
89 called with IRQ's disabled
90 */
Guennadi Liakhovetskif35f1bb2010-03-23 11:52:11 -030091 dev_dbg(q->dev, "buf[%d] freeing %p\n",
Magnus Damm2cc45cf2008-07-16 21:33:39 -030092 i, mem->vaddr);
93
94 dma_free_coherent(q->dev, mem->size,
95 mem->vaddr, mem->dma_handle);
96 mem->vaddr = NULL;
97 }
98
99 q->bufs[i]->map = NULL;
100 q->bufs[i]->baddr = 0;
101 }
102
103 kfree(map);
104
Hans Verkuil97397682010-09-20 17:24:30 -0300105 videobuf_queue_unlock(q);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300106 }
107}
108
Alexey Dobriyanf0f37e22009-09-27 22:29:37 +0400109static const struct vm_operations_struct videobuf_vm_ops = {
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300110 .open = videobuf_vm_open,
111 .close = videobuf_vm_close,
112};
113
Magnus Damm720b17e2009-06-16 15:32:36 -0700114/**
115 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
116 * @mem: per-buffer private videobuf-dma-contig data
117 *
118 * This function resets the user space pointer
119 */
120static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
121{
Magnus Damm720b17e2009-06-16 15:32:36 -0700122 mem->dma_handle = 0;
123 mem->size = 0;
124}
125
126/**
127 * videobuf_dma_contig_user_get() - setup user space memory pointer
128 * @mem: per-buffer private videobuf-dma-contig data
129 * @vb: video buffer to map
130 *
131 * This function validates and sets up a pointer to user space memory.
132 * Only physically contiguous pfn-mapped memory is accepted.
133 *
134 * Returns 0 if successful.
135 */
136static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
137 struct videobuf_buffer *vb)
138{
139 struct mm_struct *mm = current->mm;
140 struct vm_area_struct *vma;
141 unsigned long prev_pfn, this_pfn;
142 unsigned long pages_done, user_address;
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300143 unsigned int offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700144 int ret;
145
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300146 offset = vb->baddr & ~PAGE_MASK;
147 mem->size = PAGE_ALIGN(vb->size + offset);
Magnus Damm720b17e2009-06-16 15:32:36 -0700148 ret = -EINVAL;
149
150 down_read(&mm->mmap_sem);
151
152 vma = find_vma(mm, vb->baddr);
153 if (!vma)
154 goto out_up;
155
156 if ((vb->baddr + mem->size) > vma->vm_end)
157 goto out_up;
158
159 pages_done = 0;
160 prev_pfn = 0; /* kill warning */
161 user_address = vb->baddr;
162
163 while (pages_done < (mem->size >> PAGE_SHIFT)) {
164 ret = follow_pfn(vma, user_address, &this_pfn);
165 if (ret)
166 break;
167
168 if (pages_done == 0)
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300169 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700170 else if (this_pfn != (prev_pfn + 1))
171 ret = -EFAULT;
172
173 if (ret)
174 break;
175
176 prev_pfn = this_pfn;
177 user_address += PAGE_SIZE;
178 pages_done++;
179 }
180
Magnus Damm720b17e2009-06-16 15:32:36 -0700181 out_up:
182 up_read(&current->mm->mmap_sem);
183
184 return ret;
185}
186
Pawel Osciak33c38282010-05-11 10:36:28 -0300187static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300188{
189 struct videobuf_dma_contig_memory *mem;
190 struct videobuf_buffer *vb;
191
192 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
193 if (vb) {
194 mem = vb->priv = ((char *)vb) + size;
195 mem->magic = MAGIC_DC_MEM;
196 }
197
198 return vb;
199}
200
Hans Verkuil037c75e2010-03-28 08:18:37 -0300201static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300202{
203 struct videobuf_dma_contig_memory *mem = buf->priv;
204
205 BUG_ON(!mem);
206 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
207
208 return mem->vaddr;
209}
210
211static int __videobuf_iolock(struct videobuf_queue *q,
212 struct videobuf_buffer *vb,
213 struct v4l2_framebuffer *fbuf)
214{
215 struct videobuf_dma_contig_memory *mem = vb->priv;
216
217 BUG_ON(!mem);
218 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
219
220 switch (vb->memory) {
221 case V4L2_MEMORY_MMAP:
222 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
223
224 /* All handling should be done by __videobuf_mmap_mapper() */
225 if (!mem->vaddr) {
226 dev_err(q->dev, "memory is not alloced/mmapped.\n");
227 return -EINVAL;
228 }
229 break;
230 case V4L2_MEMORY_USERPTR:
231 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
232
Magnus Damm720b17e2009-06-16 15:32:36 -0700233 /* handle pointer from user space */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300234 if (vb->baddr)
Magnus Damm720b17e2009-06-16 15:32:36 -0700235 return videobuf_dma_contig_user_get(mem, vb);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300236
Magnus Damm720b17e2009-06-16 15:32:36 -0700237 /* allocate memory for the read() method */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300238 mem->size = PAGE_ALIGN(vb->size);
239 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
240 &mem->dma_handle, GFP_KERNEL);
241 if (!mem->vaddr) {
242 dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
243 mem->size);
244 return -ENOMEM;
245 }
246
247 dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
248 mem->vaddr, mem->size);
249 break;
250 case V4L2_MEMORY_OVERLAY:
251 default:
252 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
253 __func__);
254 return -EINVAL;
255 }
256
257 return 0;
258}
259
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300260static int __videobuf_mmap_mapper(struct videobuf_queue *q,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300261 struct videobuf_buffer *buf,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300262 struct vm_area_struct *vma)
263{
264 struct videobuf_dma_contig_memory *mem;
265 struct videobuf_mapping *map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300266 int retval;
Hans Verkuil0b62b732010-03-28 09:09:05 -0300267 unsigned long size;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300268
269 dev_dbg(q->dev, "%s\n", __func__);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300270
271 /* create mapping + update buffer list */
272 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
273 if (!map)
274 return -ENOMEM;
275
Hans Verkuil0b62b732010-03-28 09:09:05 -0300276 buf->map = map;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300277 map->q = q;
278
Hans Verkuil0b62b732010-03-28 09:09:05 -0300279 buf->baddr = vma->vm_start;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300280
Hans Verkuil0b62b732010-03-28 09:09:05 -0300281 mem = buf->priv;
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300282 BUG_ON(!mem);
283 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
284
Hans Verkuil0b62b732010-03-28 09:09:05 -0300285 mem->size = PAGE_ALIGN(buf->bsize);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300286 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
287 &mem->dma_handle, GFP_KERNEL);
288 if (!mem->vaddr) {
289 dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
290 mem->size);
291 goto error;
292 }
293 dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
294 mem->vaddr, mem->size);
295
296 /* Try to remap memory */
297
298 size = vma->vm_end - vma->vm_start;
299 size = (size < mem->size) ? size : mem->size;
300
301 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
302 retval = remap_pfn_range(vma, vma->vm_start,
Linus Torvalds71460af2011-04-19 10:54:44 -0700303 mem->dma_handle >> PAGE_SHIFT,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300304 size, vma->vm_page_prot);
305 if (retval) {
306 dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
307 dma_free_coherent(q->dev, mem->size,
308 mem->vaddr, mem->dma_handle);
309 goto error;
310 }
311
312 vma->vm_ops = &videobuf_vm_ops;
313 vma->vm_flags |= VM_DONTEXPAND;
314 vma->vm_private_data = map;
315
316 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
317 map, q, vma->vm_start, vma->vm_end,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300318 (long int)buf->bsize,
319 vma->vm_pgoff, buf->i);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300320
321 videobuf_vm_open(vma);
322
323 return 0;
324
325error:
326 kfree(map);
327 return -ENOMEM;
328}
329
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300330static struct videobuf_qtype_ops qops = {
331 .magic = MAGIC_QTYPE_OPS,
332
Pawel Osciak33c38282010-05-11 10:36:28 -0300333 .alloc_vb = __videobuf_alloc_vb,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300334 .iolock = __videobuf_iolock,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300335 .mmap_mapper = __videobuf_mmap_mapper,
Hans Verkuil037c75e2010-03-28 08:18:37 -0300336 .vaddr = __videobuf_to_vaddr,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300337};
338
339void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300340 const struct videobuf_queue_ops *ops,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300341 struct device *dev,
342 spinlock_t *irqlock,
343 enum v4l2_buf_type type,
344 enum v4l2_field field,
345 unsigned int msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300346 void *priv,
347 struct mutex *ext_lock)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300348{
349 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300350 priv, &qops, ext_lock);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300351}
352EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
353
354dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
355{
356 struct videobuf_dma_contig_memory *mem = buf->priv;
357
358 BUG_ON(!mem);
359 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
360
361 return mem->dma_handle;
362}
363EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
364
365void videobuf_dma_contig_free(struct videobuf_queue *q,
366 struct videobuf_buffer *buf)
367{
368 struct videobuf_dma_contig_memory *mem = buf->priv;
369
370 /* mmapped memory can't be freed here, otherwise mmapped region
371 would be released, while still needed. In this case, the memory
372 release should happen inside videobuf_vm_close().
373 So, it should free memory only if the memory were allocated for
374 read() operation.
375 */
Magnus Damm720b17e2009-06-16 15:32:36 -0700376 if (buf->memory != V4L2_MEMORY_USERPTR)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300377 return;
378
379 if (!mem)
380 return;
381
382 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
383
Magnus Damm720b17e2009-06-16 15:32:36 -0700384 /* handle user space pointer case */
385 if (buf->baddr) {
386 videobuf_dma_contig_user_put(mem);
387 return;
388 }
389
390 /* read() method */
Pawel Osciakb2b476f2010-07-20 13:49:16 -0300391 if (mem->vaddr) {
392 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
393 mem->vaddr = NULL;
394 }
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300395}
396EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
397
398MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
399MODULE_AUTHOR("Magnus Damm");
400MODULE_LICENSE("GPL");