diff options
author | Sumit Semwal <sumit.semwal@ti.com> | 2012-06-14 09:37:45 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-11-25 14:18:44 -0500 |
commit | 8c417d03a840f6c0b15e141e6e721b16a5f5d81d (patch) | |
tree | 41c2412a804b8fe335341836756784ccccf344be /drivers/media/v4l2-core/videobuf2-dma-contig.c | |
parent | 199d101efdbae654ab86c5251e35a175f11ddaac (diff) |
[media] v4l: vb2-dma-contig: add support for dma_buf importing
This patch makes changes for adding dma-contig as a dma_buf user. It provides
function implementations for the {attach, detach, map, unmap}_dmabuf()
mem_ops of DMABUF memory type.
[author of the original patch]
[integration with refactored dma-contig allocator]
Signed-off-by: Sumit Semwal <sumit.semwal@ti.com>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-dma-contig.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dma-contig.c | 120 |
1 files changed, 118 insertions, 2 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 494a824f57c4..a5804cf12c7c 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * the Free Software Foundation. | 10 | * the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/dma-buf.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/scatterlist.h> | 15 | #include <linux/scatterlist.h> |
15 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
@@ -38,6 +39,9 @@ struct vb2_dc_buf { | |||
38 | 39 | ||
39 | /* USERPTR related */ | 40 | /* USERPTR related */ |
40 | struct vm_area_struct *vma; | 41 | struct vm_area_struct *vma; |
42 | |||
43 | /* DMABUF related */ | ||
44 | struct dma_buf_attachment *db_attach; | ||
41 | }; | 45 | }; |
42 | 46 | ||
43 | /*********************************************/ | 47 | /*********************************************/ |
@@ -108,7 +112,8 @@ static void vb2_dc_prepare(void *buf_priv) | |||
108 | struct vb2_dc_buf *buf = buf_priv; | 112 | struct vb2_dc_buf *buf = buf_priv; |
109 | struct sg_table *sgt = buf->dma_sgt; | 113 | struct sg_table *sgt = buf->dma_sgt; |
110 | 114 | ||
111 | if (!sgt) | 115 | /* DMABUF exporter will flush the cache for us */ |
116 | if (!sgt || buf->db_attach) | ||
112 | return; | 117 | return; |
113 | 118 | ||
114 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | 119 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); |
@@ -119,7 +124,8 @@ static void vb2_dc_finish(void *buf_priv) | |||
119 | struct vb2_dc_buf *buf = buf_priv; | 124 | struct vb2_dc_buf *buf = buf_priv; |
120 | struct sg_table *sgt = buf->dma_sgt; | 125 | struct sg_table *sgt = buf->dma_sgt; |
121 | 126 | ||
122 | if (!sgt) | 127 | /* DMABUF exporter will flush the cache for us */ |
128 | if (!sgt || buf->db_attach) | ||
123 | return; | 129 | return; |
124 | 130 | ||
125 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | 131 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); |
@@ -377,6 +383,112 @@ fail_buf: | |||
377 | } | 383 | } |
378 | 384 | ||
379 | /*********************************************/ | 385 | /*********************************************/ |
386 | /* callbacks for DMABUF buffers */ | ||
387 | /*********************************************/ | ||
388 | |||
389 | static int vb2_dc_map_dmabuf(void *mem_priv) | ||
390 | { | ||
391 | struct vb2_dc_buf *buf = mem_priv; | ||
392 | struct sg_table *sgt; | ||
393 | unsigned long contig_size; | ||
394 | |||
395 | if (WARN_ON(!buf->db_attach)) { | ||
396 | pr_err("trying to pin a non attached buffer\n"); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | if (WARN_ON(buf->dma_sgt)) { | ||
401 | pr_err("dmabuf buffer is already pinned\n"); | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* get the associated scatterlist for this buffer */ | ||
406 | sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); | ||
407 | if (IS_ERR_OR_NULL(sgt)) { | ||
408 | pr_err("Error getting dmabuf scatterlist\n"); | ||
409 | return -EINVAL; | ||
410 | } | ||
411 | |||
412 | /* checking if dmabuf is big enough to store contiguous chunk */ | ||
413 | contig_size = vb2_dc_get_contiguous_size(sgt); | ||
414 | if (contig_size < buf->size) { | ||
415 | pr_err("contiguous chunk is too small %lu/%lu b\n", | ||
416 | contig_size, buf->size); | ||
417 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); | ||
418 | return -EFAULT; | ||
419 | } | ||
420 | |||
421 | buf->dma_addr = sg_dma_address(sgt->sgl); | ||
422 | buf->dma_sgt = sgt; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static void vb2_dc_unmap_dmabuf(void *mem_priv) | ||
428 | { | ||
429 | struct vb2_dc_buf *buf = mem_priv; | ||
430 | struct sg_table *sgt = buf->dma_sgt; | ||
431 | |||
432 | if (WARN_ON(!buf->db_attach)) { | ||
433 | pr_err("trying to unpin a not attached buffer\n"); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | if (WARN_ON(!sgt)) { | ||
438 | pr_err("dmabuf buffer is already unpinned\n"); | ||
439 | return; | ||
440 | } | ||
441 | |||
442 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); | ||
443 | |||
444 | buf->dma_addr = 0; | ||
445 | buf->dma_sgt = NULL; | ||
446 | } | ||
447 | |||
448 | static void vb2_dc_detach_dmabuf(void *mem_priv) | ||
449 | { | ||
450 | struct vb2_dc_buf *buf = mem_priv; | ||
451 | |||
452 | /* if vb2 works correctly you should never detach mapped buffer */ | ||
453 | if (WARN_ON(buf->dma_addr)) | ||
454 | vb2_dc_unmap_dmabuf(buf); | ||
455 | |||
456 | /* detach this attachment */ | ||
457 | dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach); | ||
458 | kfree(buf); | ||
459 | } | ||
460 | |||
461 | static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, | ||
462 | unsigned long size, int write) | ||
463 | { | ||
464 | struct vb2_dc_conf *conf = alloc_ctx; | ||
465 | struct vb2_dc_buf *buf; | ||
466 | struct dma_buf_attachment *dba; | ||
467 | |||
468 | if (dbuf->size < size) | ||
469 | return ERR_PTR(-EFAULT); | ||
470 | |||
471 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
472 | if (!buf) | ||
473 | return ERR_PTR(-ENOMEM); | ||
474 | |||
475 | buf->dev = conf->dev; | ||
476 | /* create attachment for the dmabuf with the user device */ | ||
477 | dba = dma_buf_attach(dbuf, buf->dev); | ||
478 | if (IS_ERR(dba)) { | ||
479 | pr_err("failed to attach dmabuf\n"); | ||
480 | kfree(buf); | ||
481 | return dba; | ||
482 | } | ||
483 | |||
484 | buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | ||
485 | buf->size = size; | ||
486 | buf->db_attach = dba; | ||
487 | |||
488 | return buf; | ||
489 | } | ||
490 | |||
491 | /*********************************************/ | ||
380 | /* DMA CONTIG exported functions */ | 492 | /* DMA CONTIG exported functions */ |
381 | /*********************************************/ | 493 | /*********************************************/ |
382 | 494 | ||
@@ -390,6 +502,10 @@ const struct vb2_mem_ops vb2_dma_contig_memops = { | |||
390 | .put_userptr = vb2_dc_put_userptr, | 502 | .put_userptr = vb2_dc_put_userptr, |
391 | .prepare = vb2_dc_prepare, | 503 | .prepare = vb2_dc_prepare, |
392 | .finish = vb2_dc_finish, | 504 | .finish = vb2_dc_finish, |
505 | .map_dmabuf = vb2_dc_map_dmabuf, | ||
506 | .unmap_dmabuf = vb2_dc_unmap_dmabuf, | ||
507 | .attach_dmabuf = vb2_dc_attach_dmabuf, | ||
508 | .detach_dmabuf = vb2_dc_detach_dmabuf, | ||
393 | .num_users = vb2_dc_num_users, | 509 | .num_users = vb2_dc_num_users, |
394 | }; | 510 | }; |
395 | EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); | 511 | EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); |