[media] omap3isp: Mark next captured frame as faulty when an SBL overflow occurs
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Wed, 7 Dec 2011 11:34:50 +0000 (08:34 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 20 Dec 2011 11:53:43 +0000 (09:53 -0200)
Instead of trying to propagate errors down the pipeline manually (and
failing to do so properly in all cases), flag SBL errors in the pipeline
to which the entity that triggered the error belongs, and use pipeline
error flags to mark buffers as faulty when completing them.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
13 files changed:
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccdc.h
drivers/media/video/omap3isp/ispccp2.c
drivers/media/video/omap3isp/ispccp2.h
drivers/media/video/omap3isp/ispcsi2.c
drivers/media/video/omap3isp/ispcsi2.h
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/omap3isp/isppreview.h
drivers/media/video/omap3isp/ispresizer.c
drivers/media/video/omap3isp/ispresizer.h
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h

index b818cac..5cc15ba 100644 (file)
@@ -410,6 +410,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
 static void isp_isr_sbl(struct isp_device *isp)
 {
        struct device *dev = isp->dev;
+       struct isp_pipeline *pipe;
        u32 sbl_pcr;
 
        /*
@@ -423,27 +424,38 @@ static void isp_isr_sbl(struct isp_device *isp)
        if (sbl_pcr)
                dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
 
-       if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
-                    | ISPSBL_PCR_CSIB_WBL_OVF)) {
-               isp->isp_ccdc.error = 1;
-               if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
-                       isp->isp_prev.error = 1;
-               if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
-                       isp->isp_res.error = 1;
+       if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
+
+       if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
+
+       if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
        }
 
        if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
-               isp->isp_prev.error = 1;
-               if (isp->isp_res.input == RESIZER_INPUT_VP &&
-                   !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
-                       isp->isp_res.error = 1;
+               pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
        }
 
        if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
                       | ISPSBL_PCR_RSZ2_WBL_OVF
                       | ISPSBL_PCR_RSZ3_WBL_OVF
-                      | ISPSBL_PCR_RSZ4_WBL_OVF))
-               isp->isp_res.error = 1;
+                      | ISPSBL_PCR_RSZ4_WBL_OVF)) {
+               pipe = to_isp_pipeline(&isp->isp_res.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
 
        if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
                omap3isp_stat_sbl_overflow(&isp->isp_af);
@@ -471,24 +483,17 @@ static irqreturn_t isp_isr(int irq, void *_isp)
                                       IRQ0STATUS_HS_VS_IRQ;
        struct isp_device *isp = _isp;
        u32 irqstatus;
-       int ret;
 
        irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
        isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
 
        isp_isr_sbl(isp);
 
-       if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
-               ret = omap3isp_csi2_isr(&isp->isp_csi2a);
-               if (ret)
-                       isp->isp_ccdc.error = 1;
-       }
+       if (irqstatus & IRQ0STATUS_CSIA_IRQ)
+               omap3isp_csi2_isr(&isp->isp_csi2a);
 
-       if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
-               ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
-               if (ret)
-                       isp->isp_ccdc.error = 1;
-       }
+       if (irqstatus & IRQ0STATUS_CSIB_IRQ)
+               omap3isp_ccp2_isr(&isp->isp_ccp2);
 
        if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
                if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
index 9012b57..3663834 100644 (file)
@@ -1427,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
        unsigned long flags;
 
        if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
+               struct isp_pipeline *pipe =
+                       to_isp_pipeline(&ccdc->subdev.entity);
+
                ccdc_lsc_error_handler(ccdc);
-               ccdc->error = 1;
+               pipe->error = true;
                dev_dbg(to_device(ccdc), "lsc prefetch error\n");
        }
 
@@ -1503,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                goto done;
        }
 
-       buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
+       buffer = omap3isp_video_buffer_next(&ccdc->video_out);
        if (buffer != NULL) {
                ccdc_set_outaddr(ccdc, buffer->isp_addr);
                restart = 1;
@@ -1517,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                                        ISP_PIPELINE_STREAM_SINGLESHOT);
 
 done:
-       ccdc->error = 0;
        return restart;
 }
 
@@ -1743,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
                 */
                ccdc_config_vp(ccdc);
                ccdc_enable_vp(ccdc, 1);
-               ccdc->error = 0;
                ccdc_print_status(ccdc);
        }
 
index 483a19c..6d0264b 100644 (file)
@@ -150,7 +150,6 @@ struct ispccdc_lsc {
  * @input: Active input
  * @output: Active outputs
  * @video_out: Output video node
- * @error: A hardware error occurred during capture
  * @alaw: A-law compression enabled (1) or disabled (0)
  * @lpf: Low pass filter enabled (1) or disabled (0)
  * @obclamp: Optical-black clamp enabled (1) or disabled (0)
@@ -178,7 +177,6 @@ struct isp_ccdc_device {
        enum ccdc_input_entity input;
        unsigned int output;
        struct isp_video video_out;
-       unsigned int error;
 
        unsigned int alaw:1,
                     lpf:1,
index 904ca8c..70ddbf3 100644 (file)
@@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        struct isp_buffer *buffer;
 
-       buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
+       buffer = omap3isp_video_buffer_next(&ccp2->video_in);
        if (buffer != NULL)
                ccp2_set_inaddr(ccp2, buffer->isp_addr);
 
@@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
                        omap3isp_pipeline_set_stream(pipe,
                                                ISP_PIPELINE_STREAM_SINGLESHOT);
        }
-
-       ccp2->error = 0;
 }
 
 /*
@@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
  * @ccp2: Pointer to ISP CCP2 device
  *
  * This will handle the CCP2 interrupts
- *
- * Returns -EIO in case of error, or 0 on success.
  */
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
 {
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        struct isp_device *isp = to_isp_device(ccp2);
-       int ret = 0;
        static const u32 ISPCCP2_LC01_ERROR =
                ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
                ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
@@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
                       ISPCCP2_LCM_IRQSTATUS);
        /* Errors */
        if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
-               ccp2->error = 1;
+               pipe->error = true;
                dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
-               return -EIO;
+               return;
        }
 
        if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
-               ccp2->error = 1;
+               pipe->error = true;
                dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
-               ret = -EIO;
        }
 
        if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
-               return 0;
+               return;
 
        /* Frame number propagation */
        if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
@@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
        /* Handle queued buffers on frame end interrupts */
        if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
                ccp2_isr_buffer(ccp2);
-
-       return ret;
 }
 
 /* -----------------------------------------------------------------------------
@@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
                if (enable == ISP_PIPELINE_STREAM_STOPPED)
                        return 0;
                atomic_set(&ccp2->stopping, 0);
-               ccp2->error = 0;
        }
 
        switch (enable) {
index 6674e9d..76d65f4 100644 (file)
@@ -82,7 +82,6 @@ struct isp_ccp2_device {
        struct isp_video video_in;
        struct isp_csiphy *phy;
        struct regulator *vdds_csib;
-       unsigned int error;
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
        atomic_t stopping;
@@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp);
 int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
                        struct v4l2_device *vdev);
 void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
 
 #endif /* OMAP3_ISP_CCP2_H */
index 0c5f1cb..fcb5168 100644 (file)
@@ -667,7 +667,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2)
 
        csi2_ctx_enable(isp, csi2, 0, 0);
 
-       buffer = omap3isp_video_buffer_next(&csi2->video_out, 0);
+       buffer = omap3isp_video_buffer_next(&csi2->video_out);
 
        /*
         * Let video queue operation restart engine if there is an underrun
@@ -727,17 +727,15 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2,
 
 /*
  * omap3isp_csi2_isr - CSI2 interrupt handling.
- *
- * Return -EIO on Transmission error
  */
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2)
 {
+       struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
        u32 csi2_irqstatus, cpxio1_irqstatus;
        struct isp_device *isp = csi2->isp;
-       int retval = 0;
 
        if (!csi2->available)
-               return -ENODEV;
+               return;
 
        csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
        isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
@@ -750,7 +748,7 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
                               csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
                dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
                        "%x\n", cpxio1_irqstatus);
-               retval = -EIO;
+               pipe->error = true;
        }
 
        if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
@@ -775,11 +773,11 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
                         ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
                        (csi2_irqstatus &
                         ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
-               retval = -EIO;
+               pipe->error = true;
        }
 
        if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
-               return 0;
+               return;
 
        /* Successful cases */
        if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
@@ -787,8 +785,6 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
 
        if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
                dev_dbg(isp->dev, "CSI2: ECC correction done\n");
-
-       return retval;
 }
 
 /* -----------------------------------------------------------------------------
index 456fb7f..885ad79 100644 (file)
@@ -156,7 +156,7 @@ struct isp_csi2_device {
        atomic_t stopping;
 };
 
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2);
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2);
 int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
 int omap3isp_csi2_init(struct isp_device *isp);
 void omap3isp_csi2_cleanup(struct isp_device *isp);
index 28a1232..6d0fb2c 100644 (file)
@@ -1404,16 +1404,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
        int restart = 0;
 
        if (prev->input == PREVIEW_INPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&prev->video_in,
-                                                   prev->error);
+               buffer = omap3isp_video_buffer_next(&prev->video_in);
                if (buffer != NULL)
                        preview_set_inaddr(prev, buffer->isp_addr);
                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
        }
 
        if (prev->output & PREVIEW_OUTPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&prev->video_out,
-                                                   prev->error);
+               buffer = omap3isp_video_buffer_next(&prev->video_out);
                if (buffer != NULL) {
                        preview_set_outaddr(prev, buffer->isp_addr);
                        restart = 1;
@@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
        default:
                return;
        }
-
-       prev->error = 0;
 }
 
 /*
@@ -1565,7 +1561,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
                preview_configure(prev);
                atomic_set(&prev->stopping, 0);
-               prev->error = 0;
                preview_print_status(prev);
        }
 
index f54e775..0968660 100644 (file)
@@ -157,7 +157,6 @@ struct isptables_update {
  * @output: Bitmask of the active output
  * @video_in: Input video entity
  * @video_out: Output video entity
- * @error: A hardware error occurred during capture
  * @params: Module configuration data
  * @shadow_update: If set, update the hardware configured in the next interrupt
  * @underrun: Whether the preview entity has queued buffers on the output
@@ -179,7 +178,6 @@ struct isp_prev_device {
        unsigned int output;
        struct isp_video video_in;
        struct isp_video video_out;
-       unsigned int error;
 
        struct prev_params params;
        unsigned int shadow_update:1;
index 50e593b..6958a9e 100644 (file)
@@ -1038,7 +1038,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
        /* Complete the output buffer and, if reading from memory, the input
         * buffer.
         */
-       buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
+       buffer = omap3isp_video_buffer_next(&res->video_out);
        if (buffer != NULL) {
                resizer_set_outaddr(res, buffer->isp_addr);
                restart = 1;
@@ -1047,7 +1047,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
        pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
 
        if (res->input == RESIZER_INPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&res->video_in, 0);
+               buffer = omap3isp_video_buffer_next(&res->video_in);
                if (buffer != NULL)
                        resizer_set_inaddr(res, buffer->isp_addr);
                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
@@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res)
                if (restart)
                        resizer_enable_oneshot(res);
        }
-
-       res->error = 0;
 }
 
 /*
@@ -1154,7 +1152,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
 
                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
                resizer_configure(res);
-               res->error = 0;
                resizer_print_status(res);
        }
 
index 76abc2e..70c1c0e 100644 (file)
@@ -107,7 +107,6 @@ struct isp_res_device {
        enum resizer_input_entity input;
        struct isp_video video_in;
        struct isp_video video_out;
-       unsigned int error;
 
        u32 addr_base;   /* stored source buffer address in memory mode */
        u32 crop_offset; /* additional offset for crop in memory mode */
index ffe7ce9..ffb9f00 100644 (file)
@@ -580,21 +580,20 @@ static const struct isp_video_queue_operations isp_video_queue_ops = {
 /*
  * omap3isp_video_buffer_next - Complete the current buffer and return the next
  * @video: ISP video object
- * @error: Whether an error occurred during capture
  *
  * Remove the current video buffer from the DMA queue and fill its timestamp,
  * field count and state fields before waking up its completion handler.
  *
- * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0)
- * or VIDEOBUF_ERROR otherwise (@error is non-zero).
+ * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no
+ * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise.
+ * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE.
  *
  * The DMA queue is expected to contain at least one buffer.
  *
  * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
  * empty.
  */
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
-                                             unsigned int error)
+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;
@@ -629,7 +628,13 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
        else
                buf->vbuf.sequence = atomic_read(&pipe->frame_number);
 
-       buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;
+       /* 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;
+               pipe->error = false;
+       } else {
+               buf->state = ISP_BUF_STATE_DONE;
+       }
 
        wake_up(&buf->wait);
 
@@ -1015,6 +1020,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto error;
 
+       pipe->error = false;
+
        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state &= ~ISP_PIPELINE_STREAM;
        pipe->state |= state;
index 08cbfa1..d91bdb9 100644 (file)
@@ -85,6 +85,10 @@ enum isp_pipeline_state {
        ISP_PIPELINE_STREAM = 64,
 };
 
+/*
+ * struct isp_pipeline - An ISP hardware pipeline
+ * @error: A hardware error occurred during capture
+ */
 struct isp_pipeline {
        struct media_pipeline pipe;
        spinlock_t lock;                /* Pipeline state and queue flags */
@@ -96,6 +100,7 @@ struct isp_pipeline {
        unsigned int max_rate;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
+       bool error;
        struct v4l2_fract max_timeperframe;
 };
 
@@ -194,8 +199,7 @@ void omap3isp_video_cleanup(struct isp_video *video);
 int omap3isp_video_register(struct isp_video *video,
                            struct v4l2_device *vdev);
 void omap3isp_video_unregister(struct isp_video *video);
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
-                                             unsigned int error);
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
 void omap3isp_video_resume(struct isp_video *video, int continuous);
 struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);