From a7f335da17a96f0d54101f68d3c7e5baf3324b2c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 4 Feb 2022 16:12:35 +0000 Subject: [PATCH] media: bcm2835-unicam: Handle a repeated frame start with no end In the case of 2 frame starts being received with no frame end between, the queued buffer held in next_frm was lost as the pointer was overwritten with the dummy buffer. Signed-off-by: Dave Stevenson --- .../media/platform/bcm2835/bcm2835-unicam.c | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -931,10 +931,14 @@ static irqreturn_t unicam_isr(int irq, v * as complete, as the HW will reuse that buffer. */ if (unicam->node[i].cur_frm && - unicam->node[i].cur_frm != unicam->node[i].next_frm) + unicam->node[i].cur_frm != unicam->node[i].next_frm) { unicam_process_buffer_complete(&unicam->node[i], sequence); - unicam->node[i].cur_frm = unicam->node[i].next_frm; + unicam->node[i].cur_frm = unicam->node[i].next_frm; + unicam->node[i].next_frm = NULL; + } else { + unicam->node[i].cur_frm = unicam->node[i].next_frm; + } } unicam->sequence++; } @@ -957,10 +961,25 @@ static irqreturn_t unicam_isr(int irq, v i); /* * Set the next frame output to go to a dummy frame - * if we have not managed to obtain another frame - * from the queue. + * if no buffer currently queued. */ - unicam_schedule_dummy_buffer(&unicam->node[i]); + if (!unicam->node[i].next_frm || + unicam->node[i].next_frm == unicam->node[i].cur_frm) { + unicam_schedule_dummy_buffer(&unicam->node[i]); + } else if (unicam->node[i].cur_frm) { + /* + * Repeated FS without FE. Hardware will have + * swapped buffers, but the cur_frm doesn't + * contain valid data. Return cur_frm to the + * queue. + */ + spin_lock(&unicam->node[i].dma_queue_lock); + list_add_tail(&unicam->node[i].cur_frm->list, + &unicam->node[i].dma_queue); + spin_unlock(&unicam->node[i].dma_queue_lock); + unicam->node[i].cur_frm = unicam->node[i].next_frm; + unicam->node[i].next_frm = NULL; + } } unicam_queue_event_sof(unicam);