aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-01-02 20:12:42 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-25 10:13:17 -0400
commit9000427aec61b2ae3766d0f635bf1d60fcb8c41b (patch)
treee191e5d12f8158c61c6e205c38cf7d753bc7f8a2 /drivers/media/platform
parent2a6dc96b973c8d1defd39bf21e89e6907b1c72f1 (diff)
[media] omap3isp: queue: Move IOMMU handling code to the queue
As a preparation for the switch from the OMAP IOMMU API to the DMA API move all IOMMU handling code from the video node implementation to the buffers queue implementation. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Sakari Ailus <sakari.ailus@iki.fi> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c78
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.h6
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c77
3 files changed, 78 insertions, 83 deletions
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
index a5e65858e799..8623c058734e 100644
--- a/drivers/media/platform/omap3isp/ispqueue.c
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -26,6 +26,7 @@
26#include <asm/cacheflush.h> 26#include <asm/cacheflush.h>
27#include <linux/dma-mapping.h> 27#include <linux/dma-mapping.h>
28#include <linux/mm.h> 28#include <linux/mm.h>
29#include <linux/omap-iommu.h>
29#include <linux/pagemap.h> 30#include <linux/pagemap.h>
30#include <linux/poll.h> 31#include <linux/poll.h>
31#include <linux/scatterlist.h> 32#include <linux/scatterlist.h>
@@ -33,7 +34,58 @@
33#include <linux/slab.h> 34#include <linux/slab.h>
34#include <linux/vmalloc.h> 35#include <linux/vmalloc.h>
35 36
37#include "isp.h"
36#include "ispqueue.h" 38#include "ispqueue.h"
39#include "ispvideo.h"
40
41/* -----------------------------------------------------------------------------
42 * IOMMU management
43 */
44
45#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
46
47/*
48 * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
49 * @dev: Device pointer specific to the OMAP3 ISP.
50 * @sglist: Pointer to source Scatter gather list to allocate.
51 * @sglen: Number of elements of the scatter-gatter list.
52 *
53 * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
54 * we ran out of memory.
55 */
56static dma_addr_t
57ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
58{
59 struct sg_table *sgt;
60 u32 da;
61
62 sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
63 if (sgt == NULL)
64 return -ENOMEM;
65
66 sgt->sgl = (struct scatterlist *)sglist;
67 sgt->nents = sglen;
68 sgt->orig_nents = sglen;
69
70 da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG);
71 if (IS_ERR_VALUE(da))
72 kfree(sgt);
73
74 return da;
75}
76
77/*
78 * ispmmu_vunmap - Unmap a device address from the ISP MMU
79 * @dev: Device pointer specific to the OMAP3 ISP.
80 * @da: Device address generated from a ispmmu_vmap call.
81 */
82static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
83{
84 struct sg_table *sgt;
85
86 sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da);
87 kfree(sgt);
88}
37 89
38/* ----------------------------------------------------------------------------- 90/* -----------------------------------------------------------------------------
39 * Video buffers management 91 * Video buffers management
@@ -260,11 +312,15 @@ static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
260 */ 312 */
261static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) 313static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
262{ 314{
315 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
316 struct isp_video *video = vfh->video;
263 enum dma_data_direction direction; 317 enum dma_data_direction direction;
264 unsigned int i; 318 unsigned int i;
265 319
266 if (buf->queue->ops->buffer_cleanup) 320 if (buf->dma) {
267 buf->queue->ops->buffer_cleanup(buf); 321 ispmmu_vunmap(video->isp, buf->dma);
322 buf->dma = 0;
323 }
268 324
269 if (!(buf->vm_flags & VM_PFNMAP)) { 325 if (!(buf->vm_flags & VM_PFNMAP)) {
270 direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE 326 direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
@@ -479,7 +535,10 @@ done:
479 */ 535 */
480static int isp_video_buffer_prepare(struct isp_video_buffer *buf) 536static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
481{ 537{
538 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
539 struct isp_video *video = vfh->video;
482 enum dma_data_direction direction; 540 enum dma_data_direction direction;
541 unsigned long addr;
483 int ret; 542 int ret;
484 543
485 switch (buf->vbuf.memory) { 544 switch (buf->vbuf.memory) {
@@ -525,6 +584,21 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
525 } 584 }
526 } 585 }
527 586
587 addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
588 if (IS_ERR_VALUE(addr)) {
589 ret = -EIO;
590 goto done;
591 }
592
593 buf->dma = addr;
594
595 if (!IS_ALIGNED(addr, 32)) {
596 dev_dbg(video->isp->dev,
597 "Buffer address must be aligned to 32 bytes boundary.\n");
598 ret = -EINVAL;
599 goto done;
600 }
601
528 if (buf->queue->ops->buffer_prepare) 602 if (buf->queue->ops->buffer_prepare)
529 ret = buf->queue->ops->buffer_prepare(buf); 603 ret = buf->queue->ops->buffer_prepare(buf);
530 604
diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h
index 3e048ad65647..0899a116b4d5 100644
--- a/drivers/media/platform/omap3isp/ispqueue.h
+++ b/drivers/media/platform/omap3isp/ispqueue.h
@@ -106,6 +106,7 @@ struct isp_video_buffer {
106 struct list_head irqlist; 106 struct list_head irqlist;
107 enum isp_video_buffer_state state; 107 enum isp_video_buffer_state state;
108 wait_queue_head_t wait; 108 wait_queue_head_t wait;
109 dma_addr_t dma;
109}; 110};
110 111
111#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb) 112#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb)
@@ -121,17 +122,12 @@ struct isp_video_buffer {
121 * mapping the buffer memory in an IOMMU). This operation is optional. 122 * mapping the buffer memory in an IOMMU). This operation is optional.
122 * @buffer_queue: Called when a buffer is being added to the queue with the 123 * @buffer_queue: Called when a buffer is being added to the queue with the
123 * queue irqlock spinlock held. 124 * queue irqlock spinlock held.
124 * @buffer_cleanup: Called before freeing buffers, or before changing the
125 * userspace memory address for a USERPTR buffer, with the queue lock held.
126 * Drivers must perform cleanup operations required to undo the
127 * buffer_prepare call. This operation is optional.
128 */ 125 */
129struct isp_video_queue_operations { 126struct isp_video_queue_operations {
130 void (*queue_prepare)(struct isp_video_queue *queue, 127 void (*queue_prepare)(struct isp_video_queue *queue,
131 unsigned int *nbuffers, unsigned int *size); 128 unsigned int *nbuffers, unsigned int *size);
132 int (*buffer_prepare)(struct isp_video_buffer *buf); 129 int (*buffer_prepare)(struct isp_video_buffer *buf);
133 void (*buffer_queue)(struct isp_video_buffer *buf); 130 void (*buffer_queue)(struct isp_video_buffer *buf);
134 void (*buffer_cleanup)(struct isp_video_buffer *buf);
135}; 131};
136 132
137/** 133/**
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index e0f594f34bec..a7ef0816230a 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -27,7 +27,6 @@
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/mm.h> 28#include <linux/mm.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/omap-iommu.h>
31#include <linux/pagemap.h> 30#include <linux/pagemap.h>
32#include <linux/scatterlist.h> 31#include <linux/scatterlist.h>
33#include <linux/sched.h> 32#include <linux/sched.h>
@@ -326,55 +325,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
326} 325}
327 326
328/* ----------------------------------------------------------------------------- 327/* -----------------------------------------------------------------------------
329 * IOMMU management
330 */
331
332#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
333
334/*
335 * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
336 * @isp: Device pointer specific to the OMAP3 ISP.
337 * @sglist: Pointer to source Scatter gather list to allocate.
338 * @sglen: Number of elements of the scatter-gatter list.
339 *
340 * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
341 * we ran out of memory.
342 */
343static dma_addr_t
344ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
345{
346 struct sg_table *sgt;
347 u32 da;
348
349 sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
350 if (sgt == NULL)
351 return -ENOMEM;
352
353 sgt->sgl = (struct scatterlist *)sglist;
354 sgt->nents = sglen;
355 sgt->orig_nents = sglen;
356
357 da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG);
358 if (IS_ERR_VALUE(da))
359 kfree(sgt);
360
361 return da;
362}
363
364/*
365 * ispmmu_vunmap - Unmap a device address from the ISP MMU
366 * @isp: Device pointer specific to the OMAP3 ISP.
367 * @da: Device address generated from a ispmmu_vmap call.
368 */
369static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
370{
371 struct sg_table *sgt;
372
373 sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da);
374 kfree(sgt);
375}
376
377/* -----------------------------------------------------------------------------
378 * Video queue operations 328 * Video queue operations
379 */ 329 */
380 330
@@ -392,24 +342,11 @@ static void isp_video_queue_prepare(struct isp_video_queue *queue,
392 *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size)); 342 *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
393} 343}
394 344
395static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
396{
397 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
398 struct isp_buffer *buffer = to_isp_buffer(buf);
399 struct isp_video *video = vfh->video;
400
401 if (buffer->isp_addr) {
402 ispmmu_vunmap(video->isp, buffer->isp_addr);
403 buffer->isp_addr = 0;
404 }
405}
406
407static int isp_video_buffer_prepare(struct isp_video_buffer *buf) 345static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
408{ 346{
409 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); 347 struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
410 struct isp_buffer *buffer = to_isp_buffer(buf); 348 struct isp_buffer *buffer = to_isp_buffer(buf);
411 struct isp_video *video = vfh->video; 349 struct isp_video *video = vfh->video;
412 unsigned long addr;
413 350
414 /* Refuse to prepare the buffer is the video node has registered an 351 /* Refuse to prepare the buffer is the video node has registered an
415 * error. We don't need to take any lock here as the operation is 352 * error. We don't need to take any lock here as the operation is
@@ -420,18 +357,7 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
420 if (unlikely(video->error)) 357 if (unlikely(video->error))
421 return -EIO; 358 return -EIO;
422 359
423 addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); 360 buffer->isp_addr = buf->dma;
424 if (IS_ERR_VALUE(addr))
425 return -EIO;
426
427 if (!IS_ALIGNED(addr, 32)) {
428 dev_dbg(video->isp->dev, "Buffer address must be "
429 "aligned to 32 bytes boundary.\n");
430 ispmmu_vunmap(video->isp, buffer->isp_addr);
431 return -EINVAL;
432 }
433
434 buffer->isp_addr = addr;
435 return 0; 361 return 0;
436} 362}
437 363
@@ -490,7 +416,6 @@ static const struct isp_video_queue_operations isp_video_queue_ops = {
490 .queue_prepare = &isp_video_queue_prepare, 416 .queue_prepare = &isp_video_queue_prepare,
491 .buffer_prepare = &isp_video_buffer_prepare, 417 .buffer_prepare = &isp_video_buffer_prepare,
492 .buffer_queue = &isp_video_buffer_queue, 418 .buffer_queue = &isp_video_buffer_queue,
493 .buffer_cleanup = &isp_video_buffer_cleanup,
494}; 419};
495 420
496/* 421/*