From 410f4716ea61c91b5731d2e18b4830f22585f8e8 Mon Sep 17 00:00:00 2001 From: Robby Cai Date: Thu, 29 Nov 2012 17:58:43 +0800 Subject: [PATCH] ENGR00229855 mx6sl: csi: can not support two camera instances run two unit test instances as follows fails (sometimes kernel dump). /unit_tests/csi_v4l2_capture.out & /unit_tests/csi_v4l2_capture.out Fix by improving the resource lock. - We get busy_lock semaphore before we get a dqueue event, so, when user is blocked at DQBUF ioctrl, the user will also be blocked at QBUF ioctrl, then the video performance will drop. This patch changes to get busy_lock semaphore to protect DQBUF ioctrl until we successfully get a dqueue event. - Use queue_int_lock spinlock to protect cam->ping_pong_csi, since it can be modified either in irq handler or in queue event. - linked list should be protected by the lock: -- Use queue_int_lock and dqueue_int_lock spinlocks to protect working_q/ ready_q/done_q in the end of frame interrupt handler camera_callback(), in case, the handler and VIDIOC_QBUF/VIDIOC_DQBUF ioctrls are called on different threads at same time. -- Protect ready_q with queue_int_lock spinlock in streamon(), in case, VIDIOC_STREAMON and VIDIOC_QBUF ioctrls are called on different threads at same time. Signed-off-by: Robby Cai --- .../video/mxc/capture/csi_v4l2_capture.c | 31 +++++++++++++------ drivers/media/video/mxc/capture/fsl_csi.c | 4 +++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index 54b073e6970b..6cf06c47f996 100644 --- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c @@ -272,9 +272,13 @@ static void camera_callback(u32 mask, void *dev) if (cam == NULL) return; + spin_lock(&cam->queue_int_lock); + spin_lock(&cam->dqueue_int_lock); if (list_empty(&cam->working_q)) { pr_debug("v4l2 capture: %s: " "working queue empty\n", __func__); + spin_unlock(&cam->dqueue_int_lock); + spin_unlock(&cam->queue_int_lock); return; } @@ -309,6 +313,8 @@ static void camera_callback(u32 mask, void *dev) pr_err("ERROR: v4l2 capture: %s: " "buffer not queued\n", __func__); } + spin_unlock(&cam->dqueue_int_lock); + spin_unlock(&cam->queue_int_lock); return; } @@ -502,6 +508,7 @@ static inline int valid_mode(u32 palette) static int csi_streamon(cam_data *cam) { struct mxc_v4l_frame *frame; + unsigned long lock_flags; pr_debug("In MVC: %s\n", __func__); @@ -511,10 +518,12 @@ static int csi_streamon(cam_data *cam) return -1; } + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); /* move the frame from readyq to workingq */ if (list_empty(&cam->ready_q)) { pr_err("ERROR: v4l2 capture: %s: " "ready_q queue empty\n", __func__); + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); return -1; } frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); @@ -525,12 +534,14 @@ static int csi_streamon(cam_data *cam) if (list_empty(&cam->ready_q)) { pr_err("ERROR: v4l2 capture: %s: " "ready_q queue empty\n", __func__); + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); return -1; } frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); __raw_writel(cam->frame[frame->index].paddress, CSI_CSIDMASA_FB2); + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); cam->capture_pid = current->pid; cam->capture_on = true; @@ -862,6 +873,9 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) return -ERESTARTSYS; } + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; + spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); cam->enc_counter--; @@ -905,6 +919,7 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) } pxp_complete_update(cam); } + up(&cam->busy_lock); return retval; } @@ -1091,8 +1106,9 @@ static long csi_v4l_do_ioctl(struct file *file, pr_debug("In MVC: %s, %x\n", __func__, ioctlnr); wait_event_interruptible(cam->power_queue, cam->low_power == false); /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EBUSY; + if (ioctlnr != VIDIOC_DQBUF) + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; switch (ioctlnr) { /*! @@ -1202,14 +1218,10 @@ static long csi_v4l_do_ioctl(struct file *file, } csi_streamoff(cam); - if (req->memory & V4L2_MEMORY_MMAP) + if (req->memory & V4L2_MEMORY_MMAP) { csi_free_frame_buf(cam); - cam->skip_frame = 0; - INIT_LIST_HEAD(&cam->ready_q); - INIT_LIST_HEAD(&cam->working_q); - INIT_LIST_HEAD(&cam->done_q); - if (req->memory & V4L2_MEMORY_MMAP) retval = csi_allocate_frame_buf(cam, req->count); + } break; } @@ -1375,7 +1387,8 @@ static long csi_v4l_do_ioctl(struct file *file, break; } - up(&cam->busy_lock); + if (ioctlnr != VIDIOC_DQBUF) + up(&cam->busy_lock); return retval; } diff --git a/drivers/media/video/mxc/capture/fsl_csi.c b/drivers/media/video/mxc/capture/fsl_csi.c index f5677e473e87..cd59b8e3cb1b 100644 --- a/drivers/media/video/mxc/capture/fsl_csi.c +++ b/drivers/media/video/mxc/capture/fsl_csi.c @@ -58,7 +58,9 @@ static irqreturn_t csi_irq_handler(int irq, void *data) if (status & BIT_DMA_TSF_DONE_FB1) { if (cam->capture_on) { + spin_lock(&cam->queue_int_lock); cam->ping_pong_csi = 1; + spin_unlock(&cam->queue_int_lock); cam->enc_callback(0, cam); } else { cam->still_counter++; @@ -68,7 +70,9 @@ static irqreturn_t csi_irq_handler(int irq, void *data) if (status & BIT_DMA_TSF_DONE_FB2) { if (cam->capture_on) { + spin_lock(&cam->queue_int_lock); cam->ping_pong_csi = 2; + spin_unlock(&cam->queue_int_lock); cam->enc_callback(0, cam); } else { cam->still_counter++; -- 2.39.5