b9ea88f910ccbd1dee852d624550123224d00c94
[openwrt/staging/neocturne.git] /
1 From a7f335da17a96f0d54101f68d3c7e5baf3324b2c Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 4 Feb 2022 16:12:35 +0000
4 Subject: [PATCH] media: bcm2835-unicam: Handle a repeated frame start
5 with no end
6
7 In the case of 2 frame starts being received with no frame end
8 between, the queued buffer held in next_frm was lost as the
9 pointer was overwritten with the dummy buffer.
10
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12 ---
13 .../media/platform/bcm2835/bcm2835-unicam.c | 29 +++++++++++++++----
14 1 file changed, 24 insertions(+), 5 deletions(-)
15
16 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
17 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
18 @@ -931,10 +931,14 @@ static irqreturn_t unicam_isr(int irq, v
19 * as complete, as the HW will reuse that buffer.
20 */
21 if (unicam->node[i].cur_frm &&
22 - unicam->node[i].cur_frm != unicam->node[i].next_frm)
23 + unicam->node[i].cur_frm != unicam->node[i].next_frm) {
24 unicam_process_buffer_complete(&unicam->node[i],
25 sequence);
26 - unicam->node[i].cur_frm = unicam->node[i].next_frm;
27 + unicam->node[i].cur_frm = unicam->node[i].next_frm;
28 + unicam->node[i].next_frm = NULL;
29 + } else {
30 + unicam->node[i].cur_frm = unicam->node[i].next_frm;
31 + }
32 }
33 unicam->sequence++;
34 }
35 @@ -957,10 +961,25 @@ static irqreturn_t unicam_isr(int irq, v
36 i);
37 /*
38 * Set the next frame output to go to a dummy frame
39 - * if we have not managed to obtain another frame
40 - * from the queue.
41 + * if no buffer currently queued.
42 */
43 - unicam_schedule_dummy_buffer(&unicam->node[i]);
44 + if (!unicam->node[i].next_frm ||
45 + unicam->node[i].next_frm == unicam->node[i].cur_frm) {
46 + unicam_schedule_dummy_buffer(&unicam->node[i]);
47 + } else if (unicam->node[i].cur_frm) {
48 + /*
49 + * Repeated FS without FE. Hardware will have
50 + * swapped buffers, but the cur_frm doesn't
51 + * contain valid data. Return cur_frm to the
52 + * queue.
53 + */
54 + spin_lock(&unicam->node[i].dma_queue_lock);
55 + list_add_tail(&unicam->node[i].cur_frm->list,
56 + &unicam->node[i].dma_queue);
57 + spin_unlock(&unicam->node[i].dma_queue_lock);
58 + unicam->node[i].cur_frm = unicam->node[i].next_frm;
59 + unicam->node[i].next_frm = NULL;
60 + }
61 }
62
63 unicam_queue_event_sof(unicam);