diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2014-01-02 22:12:42 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-05-25 11:13:17 -0300 |
commit | 9000427aec61b2ae3766d0f635bf1d60fcb8c41b (patch) | |
tree | e191e5d12f8158c61c6e205c38cf7d753bc7f8a2 /drivers | |
parent | 2a6dc96b973c8d1defd39bf21e89e6907b1c72f1 (diff) | |
download | op-kernel-dev-9000427aec61b2ae3766d0f635bf1d60fcb8c41b.zip op-kernel-dev-9000427aec61b2ae3766d0f635bf1d60fcb8c41b.tar.gz |
[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')
-rw-r--r-- | drivers/media/platform/omap3isp/ispqueue.c | 78 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/ispqueue.h | 6 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/ispvideo.c | 77 |
3 files changed, 78 insertions, 83 deletions
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c index a5e6585..8623c05 100644 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ b/drivers/media/platform/omap3isp/ispqueue.c @@ -26,6 +26,7 @@ #include <asm/cacheflush.h> #include <linux/dma-mapping.h> #include <linux/mm.h> +#include <linux/omap-iommu.h> #include <linux/pagemap.h> #include <linux/poll.h> #include <linux/scatterlist.h> @@ -33,7 +34,58 @@ #include <linux/slab.h> #include <linux/vmalloc.h> +#include "isp.h" #include "ispqueue.h" +#include "ispvideo.h" + +/* ----------------------------------------------------------------------------- + * IOMMU management + */ + +#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) + +/* + * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list + * @dev: Device pointer specific to the OMAP3 ISP. + * @sglist: Pointer to source Scatter gather list to allocate. + * @sglen: Number of elements of the scatter-gatter list. + * + * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if + * we ran out of memory. + */ +static dma_addr_t +ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) +{ + struct sg_table *sgt; + u32 da; + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (sgt == NULL) + return -ENOMEM; + + sgt->sgl = (struct scatterlist *)sglist; + sgt->nents = sglen; + sgt->orig_nents = sglen; + + da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG); + if (IS_ERR_VALUE(da)) + kfree(sgt); + + return da; +} + +/* + * ispmmu_vunmap - Unmap a device address from the ISP MMU + * @dev: Device pointer specific to the OMAP3 ISP. + * @da: Device address generated from a ispmmu_vmap call. + */ +static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) +{ + struct sg_table *sgt; + + sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da); + kfree(sgt); +} /* ----------------------------------------------------------------------------- * Video buffers management @@ -260,11 +312,15 @@ static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) */ static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) { + struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_video *video = vfh->video; enum dma_data_direction direction; unsigned int i; - if (buf->queue->ops->buffer_cleanup) - buf->queue->ops->buffer_cleanup(buf); + if (buf->dma) { + ispmmu_vunmap(video->isp, buf->dma); + buf->dma = 0; + } if (!(buf->vm_flags & VM_PFNMAP)) { direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE @@ -479,7 +535,10 @@ done: */ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) { + struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_video *video = vfh->video; enum dma_data_direction direction; + unsigned long addr; int ret; switch (buf->vbuf.memory) { @@ -525,6 +584,21 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) } } + addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); + if (IS_ERR_VALUE(addr)) { + ret = -EIO; + goto done; + } + + buf->dma = addr; + + if (!IS_ALIGNED(addr, 32)) { + dev_dbg(video->isp->dev, + "Buffer address must be aligned to 32 bytes boundary.\n"); + ret = -EINVAL; + goto done; + } + if (buf->queue->ops->buffer_prepare) ret = buf->queue->ops->buffer_prepare(buf); diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h index 3e048ad..0899a11 100644 --- a/drivers/media/platform/omap3isp/ispqueue.h +++ b/drivers/media/platform/omap3isp/ispqueue.h @@ -106,6 +106,7 @@ struct isp_video_buffer { struct list_head irqlist; enum isp_video_buffer_state state; wait_queue_head_t wait; + dma_addr_t dma; }; #define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb) @@ -121,17 +122,12 @@ struct isp_video_buffer { * mapping the buffer memory in an IOMMU). This operation is optional. * @buffer_queue: Called when a buffer is being added to the queue with the * queue irqlock spinlock held. - * @buffer_cleanup: Called before freeing buffers, or before changing the - * userspace memory address for a USERPTR buffer, with the queue lock held. - * Drivers must perform cleanup operations required to undo the - * buffer_prepare call. This operation is optional. */ struct isp_video_queue_operations { void (*queue_prepare)(struct isp_video_queue *queue, unsigned int *nbuffers, unsigned int *size); int (*buffer_prepare)(struct isp_video_buffer *buf); void (*buffer_queue)(struct isp_video_buffer *buf); - void (*buffer_cleanup)(struct isp_video_buffer *buf); }; /** diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index e0f594f3..a7ef081 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -27,7 +27,6 @@ #include <linux/clk.h> #include <linux/mm.h> #include <linux/module.h> -#include <linux/omap-iommu.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> @@ -326,55 +325,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) } /* ----------------------------------------------------------------------------- - * IOMMU management - */ - -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - -/* - * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list - * @isp: Device pointer specific to the OMAP3 ISP. - * @sglist: Pointer to source Scatter gather list to allocate. - * @sglen: Number of elements of the scatter-gatter list. - * - * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if - * we ran out of memory. - */ -static dma_addr_t -ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) -{ - struct sg_table *sgt; - u32 da; - - sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); - if (sgt == NULL) - return -ENOMEM; - - sgt->sgl = (struct scatterlist *)sglist; - sgt->nents = sglen; - sgt->orig_nents = sglen; - - da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG); - if (IS_ERR_VALUE(da)) - kfree(sgt); - - return da; -} - -/* - * ispmmu_vunmap - Unmap a device address from the ISP MMU - * @isp: Device pointer specific to the OMAP3 ISP. - * @da: Device address generated from a ispmmu_vmap call. - */ -static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) -{ - struct sg_table *sgt; - - sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da); - kfree(sgt); -} - -/* ----------------------------------------------------------------------------- * Video queue operations */ @@ -392,24 +342,11 @@ static void isp_video_queue_prepare(struct isp_video_queue *queue, *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size)); } -static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) -{ - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); - struct isp_buffer *buffer = to_isp_buffer(buf); - struct isp_video *video = vfh->video; - - if (buffer->isp_addr) { - ispmmu_vunmap(video->isp, buffer->isp_addr); - buffer->isp_addr = 0; - } -} - static int isp_video_buffer_prepare(struct isp_video_buffer *buf) { struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; - unsigned long addr; /* Refuse to prepare the buffer is the video node has registered an * 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) if (unlikely(video->error)) return -EIO; - addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); - if (IS_ERR_VALUE(addr)) - return -EIO; - - if (!IS_ALIGNED(addr, 32)) { - dev_dbg(video->isp->dev, "Buffer address must be " - "aligned to 32 bytes boundary.\n"); - ispmmu_vunmap(video->isp, buffer->isp_addr); - return -EINVAL; - } - - buffer->isp_addr = addr; + buffer->isp_addr = buf->dma; return 0; } @@ -490,7 +416,6 @@ static const struct isp_video_queue_operations isp_video_queue_ops = { .queue_prepare = &isp_video_queue_prepare, .buffer_prepare = &isp_video_buffer_prepare, .buffer_queue = &isp_video_buffer_queue, - .buffer_cleanup = &isp_video_buffer_cleanup, }; /* |