mm: replace vma->vm_flags direct modifications with modifier calls
[linux-block.git] / drivers / media / v4l2-core / videobuf-dma-contig.c
CommitLineData
77512baa 1// SPDX-License-Identifier: GPL-2.0-only
2cc45cf2
MD
2/*
3 * helper functions for physically contiguous capture buffers
4 *
5 * The functions support hardware lacking scatter gather support
6 * (i.e. the buffers must be linear in physical memory)
7 *
8 * Copyright (c) 2008 Magnus Damm
9 *
10 * Based on videobuf-vmalloc.c,
32590819 11 * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
2cc45cf2
MD
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
f19ad390 16#include <linux/mm.h>
720b17e7 17#include <linux/pagemap.h>
2cc45cf2 18#include <linux/dma-mapping.h>
f39c1ab3 19#include <linux/sched.h>
5a0e3ad6 20#include <linux/slab.h>
2cc45cf2
MD
21#include <media/videobuf-dma-contig.h>
22
23struct videobuf_dma_contig_memory {
24 u32 magic;
25 void *vaddr;
26 dma_addr_t dma_handle;
27 unsigned long size;
28};
29
30#define MAGIC_DC_MEM 0x0733ac61
c60f2b5c
GL
31#define MAGIC_CHECK(is, should) \
32 if (unlikely((is) != (should))) { \
33 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
34 BUG(); \
2cc45cf2
MD
35 }
36
a8f3c203
FV
37static int __videobuf_dc_alloc(struct device *dev,
38 struct videobuf_dma_contig_memory *mem,
b3dc3f8e 39 unsigned long size)
a8f3c203
FV
40{
41 mem->size = size;
b3dc3f8e
CH
42 mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle,
43 GFP_KERNEL);
a8f3c203
FV
44 if (!mem->vaddr) {
45 dev_err(dev, "memory alloc size %ld failed\n", mem->size);
46 return -ENOMEM;
47 }
48
49 dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
50
51 return 0;
52}
53
54static void __videobuf_dc_free(struct device *dev,
55 struct videobuf_dma_contig_memory *mem)
56{
cb132cd5 57 dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
a8f3c203
FV
58
59 mem->vaddr = NULL;
60}
61
62static void videobuf_vm_open(struct vm_area_struct *vma)
2cc45cf2
MD
63{
64 struct videobuf_mapping *map = vma->vm_private_data;
65
cca36e2e 66 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
2cc45cf2
MD
67 map, map->count, vma->vm_start, vma->vm_end);
68
69 map->count++;
70}
71
72static void videobuf_vm_close(struct vm_area_struct *vma)
73{
74 struct videobuf_mapping *map = vma->vm_private_data;
75 struct videobuf_queue *q = map->q;
76 int i;
77
f35f1bb8 78 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
2cc45cf2
MD
79 map, map->count, vma->vm_start, vma->vm_end);
80
cca36e2e
HV
81 map->count--;
82 if (0 == map->count) {
2cc45cf2
MD
83 struct videobuf_dma_contig_memory *mem;
84
f35f1bb8 85 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
cca36e2e 86 videobuf_queue_lock(q);
2cc45cf2
MD
87
88 /* We need first to cancel streams, before unmapping */
89 if (q->streaming)
90 videobuf_queue_cancel(q);
91
92 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
93 if (NULL == q->bufs[i])
94 continue;
95
96 if (q->bufs[i]->map != map)
97 continue;
98
99 mem = q->bufs[i]->priv;
100 if (mem) {
101 /* This callback is called only if kernel has
102 allocated memory and this memory is mmapped.
103 In this case, memory should be freed,
104 in order to do memory unmap.
105 */
106
107 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
108
109 /* vfree is not atomic - can't be
110 called with IRQ's disabled
111 */
f35f1bb8 112 dev_dbg(q->dev, "buf[%d] freeing %p\n",
2cc45cf2
MD
113 i, mem->vaddr);
114
a8f3c203 115 __videobuf_dc_free(q->dev, mem);
2cc45cf2
MD
116 mem->vaddr = NULL;
117 }
118
a8f3c203 119 q->bufs[i]->map = NULL;
2cc45cf2
MD
120 q->bufs[i]->baddr = 0;
121 }
122
123 kfree(map);
124
cca36e2e 125 videobuf_queue_unlock(q);
2cc45cf2
MD
126 }
127}
128
f0f37e2f 129static const struct vm_operations_struct videobuf_vm_ops = {
a8f3c203
FV
130 .open = videobuf_vm_open,
131 .close = videobuf_vm_close,
2cc45cf2
MD
132};
133
720b17e7
MD
134/**
135 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
136 * @mem: per-buffer private videobuf-dma-contig data
137 *
138 * This function resets the user space pointer
139 */
140static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
141{
720b17e7
MD
142 mem->dma_handle = 0;
143 mem->size = 0;
144}
145
146/**
147 * videobuf_dma_contig_user_get() - setup user space memory pointer
148 * @mem: per-buffer private videobuf-dma-contig data
149 * @vb: video buffer to map
150 *
151 * This function validates and sets up a pointer to user space memory.
152 * Only physically contiguous pfn-mapped memory is accepted.
153 *
154 * Returns 0 if successful.
155 */
156static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
157 struct videobuf_buffer *vb)
158{
e275faf3 159 unsigned long untagged_baddr = untagged_addr(vb->baddr);
720b17e7
MD
160 struct mm_struct *mm = current->mm;
161 struct vm_area_struct *vma;
162 unsigned long prev_pfn, this_pfn;
163 unsigned long pages_done, user_address;
31bedfa5 164 unsigned int offset;
720b17e7
MD
165 int ret;
166
e275faf3 167 offset = untagged_baddr & ~PAGE_MASK;
31bedfa5 168 mem->size = PAGE_ALIGN(vb->size + offset);
720b17e7
MD
169 ret = -EINVAL;
170
d8ed45c5 171 mmap_read_lock(mm);
720b17e7 172
e275faf3 173 vma = find_vma(mm, untagged_baddr);
720b17e7
MD
174 if (!vma)
175 goto out_up;
176
e275faf3 177 if ((untagged_baddr + mem->size) > vma->vm_end)
720b17e7
MD
178 goto out_up;
179
180 pages_done = 0;
181 prev_pfn = 0; /* kill warning */
e275faf3 182 user_address = untagged_baddr;
720b17e7
MD
183
184 while (pages_done < (mem->size >> PAGE_SHIFT)) {
185 ret = follow_pfn(vma, user_address, &this_pfn);
186 if (ret)
187 break;
188
189 if (pages_done == 0)
31bedfa5 190 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
720b17e7
MD
191 else if (this_pfn != (prev_pfn + 1))
192 ret = -EFAULT;
193
194 if (ret)
195 break;
196
197 prev_pfn = this_pfn;
198 user_address += PAGE_SIZE;
199 pages_done++;
200 }
201
a8f3c203 202out_up:
d8ed45c5 203 mmap_read_unlock(current->mm);
720b17e7
MD
204
205 return ret;
206}
207
cb132cd5 208static struct videobuf_buffer *__videobuf_alloc(size_t size)
2cc45cf2
MD
209{
210 struct videobuf_dma_contig_memory *mem;
211 struct videobuf_buffer *vb;
212
213 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
214 if (vb) {
a8f3c203
FV
215 vb->priv = ((char *)vb) + size;
216 mem = vb->priv;
2cc45cf2
MD
217 mem->magic = MAGIC_DC_MEM;
218 }
219
220 return vb;
221}
222
037c75eb 223static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
2cc45cf2
MD
224{
225 struct videobuf_dma_contig_memory *mem = buf->priv;
226
227 BUG_ON(!mem);
228 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
229
230 return mem->vaddr;
231}
232
233static int __videobuf_iolock(struct videobuf_queue *q,
234 struct videobuf_buffer *vb,
235 struct v4l2_framebuffer *fbuf)
236{
237 struct videobuf_dma_contig_memory *mem = vb->priv;
238
239 BUG_ON(!mem);
240 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
241
242 switch (vb->memory) {
243 case V4L2_MEMORY_MMAP:
244 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
245
246 /* All handling should be done by __videobuf_mmap_mapper() */
247 if (!mem->vaddr) {
4faf7066 248 dev_err(q->dev, "memory is not allocated/mmapped.\n");
2cc45cf2
MD
249 return -EINVAL;
250 }
251 break;
252 case V4L2_MEMORY_USERPTR:
253 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
254
720b17e7 255 /* handle pointer from user space */
2cc45cf2 256 if (vb->baddr)
720b17e7 257 return videobuf_dma_contig_user_get(mem, vb);
2cc45cf2 258
720b17e7 259 /* allocate memory for the read() method */
b3dc3f8e 260 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size)))
2cc45cf2 261 return -ENOMEM;
2cc45cf2
MD
262 break;
263 case V4L2_MEMORY_OVERLAY:
264 default:
a8f3c203 265 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
2cc45cf2
MD
266 return -EINVAL;
267 }
268
269 return 0;
270}
271
2cc45cf2 272static int __videobuf_mmap_mapper(struct videobuf_queue *q,
0b62b737 273 struct videobuf_buffer *buf,
2cc45cf2
MD
274 struct vm_area_struct *vma)
275{
276 struct videobuf_dma_contig_memory *mem;
277 struct videobuf_mapping *map;
2cc45cf2 278 int retval;
2cc45cf2
MD
279
280 dev_dbg(q->dev, "%s\n", __func__);
2cc45cf2
MD
281
282 /* create mapping + update buffer list */
283 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
284 if (!map)
285 return -ENOMEM;
286
0b62b737 287 buf->map = map;
2cc45cf2
MD
288 map->q = q;
289
0b62b737 290 buf->baddr = vma->vm_start;
2cc45cf2 291
0b62b737 292 mem = buf->priv;
2cc45cf2
MD
293 BUG_ON(!mem);
294 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
295
b3dc3f8e 296 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize)))
2cc45cf2 297 goto error;
2cc45cf2 298
8a6a547f
FF
299 /* the "vm_pgoff" is just used in v4l2 to find the
300 * corresponding buffer data structure which is allocated
301 * earlier and it does not mean the offset from the physical
302 * buffer start address as usual. So set it to 0 to pass
b3dc3f8e 303 * the sanity check in dma_mmap_coherent().
8a6a547f
FF
304 */
305 vma->vm_pgoff = 0;
b3dc3f8e
CH
306 retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
307 mem->size);
cb132cd5
MCC
308 if (retval) {
309 dev_err(q->dev, "mmap: remap failed with error %d. ",
310 retval);
311 dma_free_coherent(q->dev, mem->size,
312 mem->vaddr, mem->dma_handle);
313 goto error;
2cc45cf2
MD
314 }
315
a8f3c203 316 vma->vm_ops = &videobuf_vm_ops;
1c71222e 317 vm_flags_set(vma, VM_DONTEXPAND);
2cc45cf2
MD
318 vma->vm_private_data = map;
319
320 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
321 map, q, vma->vm_start, vma->vm_end,
a8f3c203 322 (long int)buf->bsize, vma->vm_pgoff, buf->i);
2cc45cf2
MD
323
324 videobuf_vm_open(vma);
325
326 return 0;
327
328error:
329 kfree(map);
330 return -ENOMEM;
331}
332
2cc45cf2 333static struct videobuf_qtype_ops qops = {
a8f3c203 334 .magic = MAGIC_QTYPE_OPS,
cb132cd5 335 .alloc_vb = __videobuf_alloc,
a8f3c203 336 .iolock = __videobuf_iolock,
a8f3c203
FV
337 .mmap_mapper = __videobuf_mmap_mapper,
338 .vaddr = __videobuf_to_vaddr,
2cc45cf2
MD
339};
340
341void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
38a54f35 342 const struct videobuf_queue_ops *ops,
2cc45cf2
MD
343 struct device *dev,
344 spinlock_t *irqlock,
345 enum v4l2_buf_type type,
346 enum v4l2_field field,
347 unsigned int msize,
08bff03e
HV
348 void *priv,
349 struct mutex *ext_lock)
2cc45cf2
MD
350{
351 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
08bff03e 352 priv, &qops, ext_lock);
2cc45cf2
MD
353}
354EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
355
356dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
357{
358 struct videobuf_dma_contig_memory *mem = buf->priv;
359
360 BUG_ON(!mem);
361 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
362
363 return mem->dma_handle;
364}
365EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
366
367void videobuf_dma_contig_free(struct videobuf_queue *q,
368 struct videobuf_buffer *buf)
369{
370 struct videobuf_dma_contig_memory *mem = buf->priv;
371
372 /* mmapped memory can't be freed here, otherwise mmapped region
373 would be released, while still needed. In this case, the memory
374 release should happen inside videobuf_vm_close().
375 So, it should free memory only if the memory were allocated for
376 read() operation.
377 */
720b17e7 378 if (buf->memory != V4L2_MEMORY_USERPTR)
2cc45cf2
MD
379 return;
380
381 if (!mem)
382 return;
383
384 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
385
720b17e7
MD
386 /* handle user space pointer case */
387 if (buf->baddr) {
388 videobuf_dma_contig_user_put(mem);
389 return;
390 }
391
392 /* read() method */
b2b476f5 393 if (mem->vaddr) {
a8f3c203 394 __videobuf_dc_free(q->dev, mem);
b2b476f5
PO
395 mem->vaddr = NULL;
396 }
2cc45cf2
MD
397}
398EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
399
400MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
401MODULE_AUTHOR("Magnus Damm");
402MODULE_LICENSE("GPL");