[media] omap3isp: Move buffer irqlist to isp_buffer structure
[sfrench/cifs-2.6.git] / drivers / media / platform / omap3isp / ispvideo.c
index 85b4036ba5e43296ce647c4f857e8484b430846c..e1f998366ba410203a96919c7d8341679295626e 100644 (file)
@@ -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>
@@ -325,55 +324,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
        return ret;
 }
 
-/* -----------------------------------------------------------------------------
- * 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,19 +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;
-       }
-
-       buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
-       buffer->isp_addr = addr;
+       buffer->isp_addr = buf->dma;
        return 0;
 }
 
@@ -456,14 +381,19 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf)
        unsigned int empty;
        unsigned int start;
 
+       spin_lock_irqsave(&video->irqlock, flags);
+
        if (unlikely(video->error)) {
                buf->state = ISP_BUF_STATE_ERROR;
                wake_up(&buf->wait);
+               spin_unlock_irqrestore(&video->irqlock, flags);
                return;
        }
 
        empty = list_empty(&video->dmaqueue);
-       list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
+       list_add_tail(&buffer->irqlist, &video->dmaqueue);
+
+       spin_unlock_irqrestore(&video->irqlock, flags);
 
        if (empty) {
                if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -491,7 +421,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,
 };
 
 /*
@@ -514,25 +443,29 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
 {
        struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
        struct isp_video_queue *queue = video->queue;
+       struct isp_video_fh *vfh =
+               container_of(queue, struct isp_video_fh, queue);
        enum isp_pipeline_state state;
-       struct isp_video_buffer *buf;
+       struct isp_buffer *buf;
        unsigned long flags;
        struct timespec ts;
 
-       spin_lock_irqsave(&queue->irqlock, flags);
+       spin_lock_irqsave(&video->irqlock, flags);
        if (WARN_ON(list_empty(&video->dmaqueue))) {
-               spin_unlock_irqrestore(&queue->irqlock, flags);
+               spin_unlock_irqrestore(&video->irqlock, flags);
                return NULL;
        }
 
-       buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+       buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
                               irqlist);
        list_del(&buf->irqlist);
-       spin_unlock_irqrestore(&queue->irqlock, flags);
+       spin_unlock_irqrestore(&video->irqlock, flags);
+
+       buf->buffer.vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
 
        ktime_get_ts(&ts);
-       buf->vbuf.timestamp.tv_sec = ts.tv_sec;
-       buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+       buf->buffer.vbuf.timestamp.tv_sec = ts.tv_sec;
+       buf->buffer.vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 
        /* Do frame number propagation only if this is the output video node.
         * Frame number either comes from the CSI receivers or it gets
@@ -541,19 +474,20 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
         * first, so the input number might lag behind by 1 in some cases.
         */
        if (video == pipe->output && !pipe->do_propagation)
-               buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
+               buf->buffer.vbuf.sequence =
+                       atomic_inc_return(&pipe->frame_number);
        else
-               buf->vbuf.sequence = atomic_read(&pipe->frame_number);
+               buf->buffer.vbuf.sequence = atomic_read(&pipe->frame_number);
 
        /* Report pipeline errors to userspace on the capture device side. */
        if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
-               buf->state = ISP_BUF_STATE_ERROR;
+               buf->buffer.state = ISP_BUF_STATE_ERROR;
                pipe->error = false;
        } else {
-               buf->state = ISP_BUF_STATE_DONE;
+               buf->buffer.state = ISP_BUF_STATE_DONE;
        }
 
-       wake_up(&buf->wait);
+       wake_up(&buf->buffer.wait);
 
        if (list_empty(&video->dmaqueue)) {
                if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -577,10 +511,10 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
                spin_unlock_irqrestore(&pipe->lock, flags);
        }
 
-       buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+       buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
                               irqlist);
-       buf->state = ISP_BUF_STATE_ACTIVE;
-       return to_isp_buffer(buf);
+       buf->buffer.state = ISP_BUF_STATE_ACTIVE;
+       return buf;
 }
 
 /*
@@ -592,25 +526,24 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
  */
 void omap3isp_video_cancel_stream(struct isp_video *video)
 {
-       struct isp_video_queue *queue = video->queue;
        unsigned long flags;
 
-       spin_lock_irqsave(&queue->irqlock, flags);
+       spin_lock_irqsave(&video->irqlock, flags);
 
        while (!list_empty(&video->dmaqueue)) {
-               struct isp_video_buffer *buf;
+               struct isp_buffer *buf;
 
                buf = list_first_entry(&video->dmaqueue,
-                                      struct isp_video_buffer, irqlist);
+                                      struct isp_buffer, irqlist);
                list_del(&buf->irqlist);
 
-               buf->state = ISP_BUF_STATE_ERROR;
-               wake_up(&buf->wait);
+               buf->buffer.state = ISP_BUF_STATE_ERROR;
+               wake_up(&buf->buffer.wait);
        }
 
        video->error = true;
 
-       spin_unlock_irqrestore(&queue->irqlock, flags);
+       spin_unlock_irqrestore(&video->irqlock, flags);
 }
 
 /*
@@ -627,12 +560,15 @@ void omap3isp_video_resume(struct isp_video *video, int continuous)
 {
        struct isp_buffer *buf = NULL;
 
-       if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               mutex_lock(&video->queue_lock);
                omap3isp_video_queue_discard_done(video->queue);
+               mutex_unlock(&video->queue_lock);
+       }
 
        if (!list_empty(&video->dmaqueue)) {
                buf = list_first_entry(&video->dmaqueue,
-                                      struct isp_buffer, buffer.irqlist);
+                                      struct isp_buffer, irqlist);
                video->ops->queue(video, buf);
                video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
        } else {
@@ -840,33 +776,57 @@ static int
 isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       int ret;
+
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_reqbufs(&vfh->queue, rb);
+       mutex_unlock(&video->queue_lock);
 
-       return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
+       return ret;
 }
 
 static int
 isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       int ret;
+
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_querybuf(&vfh->queue, b);
+       mutex_unlock(&video->queue_lock);
 
-       return omap3isp_video_queue_querybuf(&vfh->queue, b);
+       return ret;
 }
 
 static int
 isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       int ret;
 
-       return omap3isp_video_queue_qbuf(&vfh->queue, b);
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_qbuf(&vfh->queue, b);
+       mutex_unlock(&video->queue_lock);
+
+       return ret;
 }
 
 static int
 isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       int ret;
 
-       return omap3isp_video_queue_dqbuf(&vfh->queue, b,
-                                         file->f_flags & O_NONBLOCK);
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_dqbuf(&vfh->queue, b,
+                                        file->f_flags & O_NONBLOCK);
+       mutex_unlock(&video->queue_lock);
+
+       return ret;
 }
 
 static int isp_video_check_external_subdevs(struct isp_video *video,
@@ -1069,7 +1029,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        INIT_LIST_HEAD(&video->dmaqueue);
        atomic_set(&pipe->frame_number, -1);
 
+       mutex_lock(&video->queue_lock);
        ret = omap3isp_video_queue_streamon(&vfh->queue);
+       mutex_unlock(&video->queue_lock);
        if (ret < 0)
                goto err_check_format;
 
@@ -1082,10 +1044,10 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
                                              ISP_PIPELINE_STREAM_CONTINUOUS);
                if (ret < 0)
                        goto err_set_stream;
-               spin_lock_irqsave(&video->queue->irqlock, flags);
+               spin_lock_irqsave(&video->irqlock, flags);
                if (list_empty(&video->dmaqueue))
                        video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
-               spin_unlock_irqrestore(&video->queue->irqlock, flags);
+               spin_unlock_irqrestore(&video->irqlock, flags);
        }
 
        video->streaming = 1;
@@ -1094,7 +1056,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        return 0;
 
 err_set_stream:
+       mutex_lock(&video->queue_lock);
        omap3isp_video_queue_streamoff(&vfh->queue);
+       mutex_unlock(&video->queue_lock);
 err_check_format:
        media_entity_pipeline_stop(&video->video.entity);
 err_pipeline_start:
@@ -1130,9 +1094,9 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
        mutex_lock(&video->stream_lock);
 
        /* Make sure we're not streaming yet. */
-       mutex_lock(&vfh->queue.lock);
+       mutex_lock(&video->queue_lock);
        streaming = vfh->queue.streaming;
-       mutex_unlock(&vfh->queue.lock);
+       mutex_unlock(&video->queue_lock);
 
        if (!streaming)
                goto done;
@@ -1151,7 +1115,9 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 
        /* Stop the stream. */
        omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
+       mutex_lock(&video->queue_lock);
        omap3isp_video_queue_streamoff(&vfh->queue);
+       mutex_unlock(&video->queue_lock);
        video->queue = NULL;
        video->streaming = 0;
        video->error = false;
@@ -1273,9 +1239,9 @@ static int isp_video_release(struct file *file)
        /* Disable streaming and free the buffers queue resources. */
        isp_video_streamoff(file, vfh, video->type);
 
-       mutex_lock(&handle->queue.lock);
+       mutex_lock(&video->queue_lock);
        omap3isp_video_queue_cleanup(&handle->queue);
-       mutex_unlock(&handle->queue.lock);
+       mutex_unlock(&video->queue_lock);
 
        omap3isp_pipeline_pm_use(&video->video.entity, 0);
 
@@ -1292,16 +1258,27 @@ static int isp_video_release(struct file *file)
 static unsigned int isp_video_poll(struct file *file, poll_table *wait)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
-       struct isp_video_queue *queue = &vfh->queue;
+       struct isp_video *video = video_drvdata(file);
+       int ret;
 
-       return omap3isp_video_queue_poll(queue, file, wait);
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_poll(&vfh->queue, file, wait);
+       mutex_unlock(&video->queue_lock);
+
+       return ret;
 }
 
 static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+       struct isp_video *video = video_drvdata(file);
+       int ret;
 
-       return omap3isp_video_queue_mmap(&vfh->queue, vma);
+       mutex_lock(&video->queue_lock);
+       ret = omap3isp_video_queue_mmap(&vfh->queue, vma);
+       mutex_unlock(&video->queue_lock);
+
+       return ret;
 }
 
 static struct v4l2_file_operations isp_video_fops = {
@@ -1351,6 +1328,8 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
 
        spin_lock_init(&video->pipe.lock);
        mutex_init(&video->stream_lock);
+       mutex_init(&video->queue_lock);
+       spin_lock_init(&video->irqlock);
 
        /* Initialize the video device. */
        if (video->ops == NULL)
@@ -1372,6 +1351,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
 void omap3isp_video_cleanup(struct isp_video *video)
 {
        media_entity_cleanup(&video->video.entity);
+       mutex_destroy(&video->queue_lock);
        mutex_destroy(&video->stream_lock);
        mutex_destroy(&video->mutex);
 }