openwrt/target/linux/bcm27xx/patches-5.15/950-0702-media-bcm2835-unic...

64 lines
2.3 KiB
Diff

From a7f335da17a96f0d54101f68d3c7e5baf3324b2c Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
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 <dave.stevenson@raspberrypi.com>
---
.../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);