Skip to content

Commit

Permalink
[media] omap3isp: Mark next captured frame as faulty when an SBL over…
Browse files Browse the repository at this point in the history
…flow occurs

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>
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Dec 20, 2011
1 parent c3cd257 commit 875e2e3
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 82 deletions.
53 changes: 29 additions & 24 deletions drivers/media/video/omap3isp/isp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
9 changes: 5 additions & 4 deletions drivers/media/video/omap3isp/ispccdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down Expand Up @@ -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;
Expand All @@ -1517,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
ISP_PIPELINE_STREAM_SINGLESHOT);

done:
ccdc->error = 0;
return restart;
}

Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 0 additions & 2 deletions drivers/media/video/omap3isp/ispccdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
22 changes: 7 additions & 15 deletions drivers/media/video/omap3isp/ispccp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -567,22 +567,18 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
omap3isp_pipeline_set_stream(pipe,
ISP_PIPELINE_STREAM_SINGLESHOT);
}

ccp2->error = 0;
}

/*
* omap3isp_ccp2_isr - Handle ISP CCP2 interrupts
* @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 |
Expand All @@ -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) {
Expand All @@ -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;
}

/* -----------------------------------------------------------------------------
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 1 addition & 2 deletions drivers/media/video/omap3isp/ispccp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
18 changes: 7 additions & 11 deletions drivers/media/video/omap3isp/ispcsi2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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 |
Expand All @@ -775,20 +773,18 @@ 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))
csi2_isr_ctx(csi2, &csi2->contexts[0]);

if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
dev_dbg(isp->dev, "CSI2: ECC correction done\n");

return retval;
}

/* -----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion drivers/media/video/omap3isp/ispcsi2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 2 additions & 7 deletions drivers/media/video/omap3isp/isppreview.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
default:
return;
}

prev->error = 0;
}

/*
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 0 additions & 2 deletions drivers/media/video/omap3isp/isppreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
7 changes: 2 additions & 5 deletions drivers/media/video/omap3isp/ispresizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res)
if (restart)
resizer_enable_oneshot(res);
}

res->error = 0;
}

/*
Expand Down Expand Up @@ -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);
}

Expand Down
1 change: 0 additions & 1 deletion drivers/media/video/omap3isp/ispresizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 875e2e3

Please sign in to comment.