From: Dave Stevenson Date: Fri, 4 Feb 2022 16:12:35 +0000 (+0000) Subject: media: bcm2835-unicam: Handle a repeated frame start with no end X-Git-Tag: accepted/tizen/unified/20240422.153132~631 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d9094146e7aad5c33b7fa1e47c040c9153b0ba71;p=platform%2Fkernel%2Flinux-rpi.git 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 --- diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c index 228d771..7b7de97 100644 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -930,10 +930,14 @@ static irqreturn_t unicam_isr(int irq, void *dev) * 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++; } @@ -956,10 +960,25 @@ static irqreturn_t unicam_isr(int irq, void *dev) 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);