0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/init.h>
0015 #include <linux/module.h>
0016 #include <linux/mm.h>
0017 #include <linux/pagemap.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/sched.h>
0020 #include <linux/slab.h>
0021 #include <media/videobuf-dma-contig.h>
0022
0023 struct videobuf_dma_contig_memory {
0024 u32 magic;
0025 void *vaddr;
0026 dma_addr_t dma_handle;
0027 unsigned long size;
0028 };
0029
0030 #define MAGIC_DC_MEM 0x0733ac61
0031 #define MAGIC_CHECK(is, should) \
0032 if (unlikely((is) != (should))) { \
0033 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
0034 BUG(); \
0035 }
0036
0037 static int __videobuf_dc_alloc(struct device *dev,
0038 struct videobuf_dma_contig_memory *mem,
0039 unsigned long size, gfp_t flags)
0040 {
0041 mem->size = size;
0042 mem->vaddr = dma_alloc_coherent(dev, mem->size,
0043 &mem->dma_handle, flags);
0044
0045 if (!mem->vaddr) {
0046 dev_err(dev, "memory alloc size %ld failed\n", mem->size);
0047 return -ENOMEM;
0048 }
0049
0050 dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
0051
0052 return 0;
0053 }
0054
0055 static void __videobuf_dc_free(struct device *dev,
0056 struct videobuf_dma_contig_memory *mem)
0057 {
0058 dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
0059
0060 mem->vaddr = NULL;
0061 }
0062
0063 static void videobuf_vm_open(struct vm_area_struct *vma)
0064 {
0065 struct videobuf_mapping *map = vma->vm_private_data;
0066
0067 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
0068 map, map->count, vma->vm_start, vma->vm_end);
0069
0070 map->count++;
0071 }
0072
0073 static void videobuf_vm_close(struct vm_area_struct *vma)
0074 {
0075 struct videobuf_mapping *map = vma->vm_private_data;
0076 struct videobuf_queue *q = map->q;
0077 int i;
0078
0079 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
0080 map, map->count, vma->vm_start, vma->vm_end);
0081
0082 map->count--;
0083 if (0 == map->count) {
0084 struct videobuf_dma_contig_memory *mem;
0085
0086 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
0087 videobuf_queue_lock(q);
0088
0089
0090 if (q->streaming)
0091 videobuf_queue_cancel(q);
0092
0093 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
0094 if (NULL == q->bufs[i])
0095 continue;
0096
0097 if (q->bufs[i]->map != map)
0098 continue;
0099
0100 mem = q->bufs[i]->priv;
0101 if (mem) {
0102
0103
0104
0105
0106
0107
0108 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0109
0110
0111
0112
0113 dev_dbg(q->dev, "buf[%d] freeing %p\n",
0114 i, mem->vaddr);
0115
0116 __videobuf_dc_free(q->dev, mem);
0117 mem->vaddr = NULL;
0118 }
0119
0120 q->bufs[i]->map = NULL;
0121 q->bufs[i]->baddr = 0;
0122 }
0123
0124 kfree(map);
0125
0126 videobuf_queue_unlock(q);
0127 }
0128 }
0129
0130 static const struct vm_operations_struct videobuf_vm_ops = {
0131 .open = videobuf_vm_open,
0132 .close = videobuf_vm_close,
0133 };
0134
0135
0136
0137
0138
0139
0140
0141 static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
0142 {
0143 mem->dma_handle = 0;
0144 mem->size = 0;
0145 }
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
0158 struct videobuf_buffer *vb)
0159 {
0160 unsigned long untagged_baddr = untagged_addr(vb->baddr);
0161 struct mm_struct *mm = current->mm;
0162 struct vm_area_struct *vma;
0163 unsigned long prev_pfn, this_pfn;
0164 unsigned long pages_done, user_address;
0165 unsigned int offset;
0166 int ret;
0167
0168 offset = untagged_baddr & ~PAGE_MASK;
0169 mem->size = PAGE_ALIGN(vb->size + offset);
0170 ret = -EINVAL;
0171
0172 mmap_read_lock(mm);
0173
0174 vma = find_vma(mm, untagged_baddr);
0175 if (!vma)
0176 goto out_up;
0177
0178 if ((untagged_baddr + mem->size) > vma->vm_end)
0179 goto out_up;
0180
0181 pages_done = 0;
0182 prev_pfn = 0;
0183 user_address = untagged_baddr;
0184
0185 while (pages_done < (mem->size >> PAGE_SHIFT)) {
0186 ret = follow_pfn(vma, user_address, &this_pfn);
0187 if (ret)
0188 break;
0189
0190 if (pages_done == 0)
0191 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
0192 else if (this_pfn != (prev_pfn + 1))
0193 ret = -EFAULT;
0194
0195 if (ret)
0196 break;
0197
0198 prev_pfn = this_pfn;
0199 user_address += PAGE_SIZE;
0200 pages_done++;
0201 }
0202
0203 out_up:
0204 mmap_read_unlock(current->mm);
0205
0206 return ret;
0207 }
0208
0209 static struct videobuf_buffer *__videobuf_alloc(size_t size)
0210 {
0211 struct videobuf_dma_contig_memory *mem;
0212 struct videobuf_buffer *vb;
0213
0214 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
0215 if (vb) {
0216 vb->priv = ((char *)vb) + size;
0217 mem = vb->priv;
0218 mem->magic = MAGIC_DC_MEM;
0219 }
0220
0221 return vb;
0222 }
0223
0224 static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
0225 {
0226 struct videobuf_dma_contig_memory *mem = buf->priv;
0227
0228 BUG_ON(!mem);
0229 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0230
0231 return mem->vaddr;
0232 }
0233
0234 static int __videobuf_iolock(struct videobuf_queue *q,
0235 struct videobuf_buffer *vb,
0236 struct v4l2_framebuffer *fbuf)
0237 {
0238 struct videobuf_dma_contig_memory *mem = vb->priv;
0239
0240 BUG_ON(!mem);
0241 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0242
0243 switch (vb->memory) {
0244 case V4L2_MEMORY_MMAP:
0245 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
0246
0247
0248 if (!mem->vaddr) {
0249 dev_err(q->dev, "memory is not allocated/mmapped.\n");
0250 return -EINVAL;
0251 }
0252 break;
0253 case V4L2_MEMORY_USERPTR:
0254 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
0255
0256
0257 if (vb->baddr)
0258 return videobuf_dma_contig_user_get(mem, vb);
0259
0260
0261 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
0262 GFP_KERNEL))
0263 return -ENOMEM;
0264 break;
0265 case V4L2_MEMORY_OVERLAY:
0266 default:
0267 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
0268 return -EINVAL;
0269 }
0270
0271 return 0;
0272 }
0273
0274 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
0275 struct videobuf_buffer *buf,
0276 struct vm_area_struct *vma)
0277 {
0278 struct videobuf_dma_contig_memory *mem;
0279 struct videobuf_mapping *map;
0280 int retval;
0281
0282 dev_dbg(q->dev, "%s\n", __func__);
0283
0284
0285 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
0286 if (!map)
0287 return -ENOMEM;
0288
0289 buf->map = map;
0290 map->q = q;
0291
0292 buf->baddr = vma->vm_start;
0293
0294 mem = buf->priv;
0295 BUG_ON(!mem);
0296 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0297
0298 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
0299 GFP_KERNEL | __GFP_COMP))
0300 goto error;
0301
0302
0303 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0304
0305
0306
0307
0308
0309
0310
0311 vma->vm_pgoff = 0;
0312
0313 retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
0314 if (retval) {
0315 dev_err(q->dev, "mmap: remap failed with error %d. ",
0316 retval);
0317 dma_free_coherent(q->dev, mem->size,
0318 mem->vaddr, mem->dma_handle);
0319 goto error;
0320 }
0321
0322 vma->vm_ops = &videobuf_vm_ops;
0323 vma->vm_flags |= VM_DONTEXPAND;
0324 vma->vm_private_data = map;
0325
0326 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
0327 map, q, vma->vm_start, vma->vm_end,
0328 (long int)buf->bsize, vma->vm_pgoff, buf->i);
0329
0330 videobuf_vm_open(vma);
0331
0332 return 0;
0333
0334 error:
0335 kfree(map);
0336 return -ENOMEM;
0337 }
0338
0339 static struct videobuf_qtype_ops qops = {
0340 .magic = MAGIC_QTYPE_OPS,
0341 .alloc_vb = __videobuf_alloc,
0342 .iolock = __videobuf_iolock,
0343 .mmap_mapper = __videobuf_mmap_mapper,
0344 .vaddr = __videobuf_to_vaddr,
0345 };
0346
0347 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
0348 const struct videobuf_queue_ops *ops,
0349 struct device *dev,
0350 spinlock_t *irqlock,
0351 enum v4l2_buf_type type,
0352 enum v4l2_field field,
0353 unsigned int msize,
0354 void *priv,
0355 struct mutex *ext_lock)
0356 {
0357 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
0358 priv, &qops, ext_lock);
0359 }
0360 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
0361
0362 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
0363 {
0364 struct videobuf_dma_contig_memory *mem = buf->priv;
0365
0366 BUG_ON(!mem);
0367 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0368
0369 return mem->dma_handle;
0370 }
0371 EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
0372
0373 void videobuf_dma_contig_free(struct videobuf_queue *q,
0374 struct videobuf_buffer *buf)
0375 {
0376 struct videobuf_dma_contig_memory *mem = buf->priv;
0377
0378
0379
0380
0381
0382
0383
0384 if (buf->memory != V4L2_MEMORY_USERPTR)
0385 return;
0386
0387 if (!mem)
0388 return;
0389
0390 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0391
0392
0393 if (buf->baddr) {
0394 videobuf_dma_contig_user_put(mem);
0395 return;
0396 }
0397
0398
0399 if (mem->vaddr) {
0400 __videobuf_dc_free(q->dev, mem);
0401 mem->vaddr = NULL;
0402 }
0403 }
0404 EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
0405
0406 MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
0407 MODULE_AUTHOR("Magnus Damm");
0408 MODULE_LICENSE("GPL");