1 From 6fb7a0b4c1dd6cf5b12ec2b2c197dcf8e58cd2b9 Mon Sep 17 00:00:00 2001
2 From: Naushir Patuck <naush@raspberrypi.com>
3 Date: Mon, 18 Dec 2023 09:52:45 +0000
4 Subject: [PATCH] drivers: media: cfe: Add more robust ISR handlers
6 Update the ISR logic to be more robust to sensors in problematic states
7 where interrupts may start arriving overlapped and/or missing.
9 1) Test for cur_frame in the FE handler, and if present, dequeue it in
10 an error state so that it does not get orphaned.
12 2) Move the sequence counter and timestamp variables to the node
13 structures. This allows the ISR to track channels running ahead when
14 interrupts arrive unordered.
16 3) Add a test to ensure we don't have a spurios (but harmlesS) call to
17 the FE handler in some circumstances.
19 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
21 .../media/platform/raspberrypi/rp1_cfe/cfe.c | 92 ++++++++++---------
22 1 file changed, 49 insertions(+), 43 deletions(-)
24 --- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c
25 +++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c
26 @@ -272,6 +272,8 @@ struct cfe_node {
27 /* Pointer to the parent handle */
28 struct cfe_device *cfe;
30 + unsigned int fs_count;
35 @@ -311,9 +313,6 @@ struct cfe_device {
36 struct pisp_fe_device fe;
40 - unsigned int sequence;
44 static inline bool is_fe_enabled(struct cfe_device *cfe)
45 @@ -393,17 +392,6 @@ static bool test_all_nodes(struct cfe_de
49 -static void clear_all_nodes(struct cfe_device *cfe, unsigned long precond,
50 - unsigned long state)
54 - for (i = 0; i < NUM_NODES; i++) {
55 - if (check_state(cfe, precond, i))
56 - clear_state(cfe, state, i);
60 static int mipi_cfg_regs_show(struct seq_file *s, void *data)
62 struct cfe_device *cfe = s->private;
63 @@ -656,22 +644,22 @@ static void cfe_prepare_next_job(struct
66 static void cfe_process_buffer_complete(struct cfe_node *node,
67 - unsigned int sequence)
68 + enum vb2_buffer_state state)
70 struct cfe_device *cfe = node->cfe;
72 cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__,
73 node_desc[node->id].name, &node->cur_frm->vb.vb2_buf);
75 - node->cur_frm->vb.sequence = sequence;
76 - vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
77 + node->cur_frm->vb.sequence = node->fs_count - 1;
78 + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state);
81 static void cfe_queue_event_sof(struct cfe_node *node)
83 struct v4l2_event event = {
84 .type = V4L2_EVENT_FRAME_SYNC,
85 - .u.frame_sync.frame_sequence = node->cfe->sequence,
86 + .u.frame_sync.frame_sequence = node->fs_count - 1,
89 v4l2_event_queue(&node->video_dev, &event);
90 @@ -680,28 +668,53 @@ static void cfe_queue_event_sof(struct c
91 static void cfe_sof_isr_handler(struct cfe_node *node)
93 struct cfe_device *cfe = node->cfe;
94 + bool matching_fs = true;
97 cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name,
100 - node->cur_frm = node->next_frm;
101 - node->next_frm = NULL;
105 - * If this is the first node to see a frame start, sample the
106 - * timestamp to use for all frames across all channels.
107 + * If the sensor is producing unexpected frame event ordering over a
108 + * sustained period of time, guard against the possibility of coming
109 + * here and orphaning the cur_frm if it's not been dequeued already.
110 + * Unfortunately, there is not enough hardware state to tell if this
111 + * may have occurred.
113 - if (!test_any_node(cfe, NODE_STREAMING | FS_INT))
114 - cfe->ts = ktime_get_ns();
115 + if (WARN(node->cur_frm, "%s: [%s] Orphanded frame at seq %u\n",
116 + __func__, node_desc[node->id].name, node->fs_count))
117 + cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR);
119 - set_state(cfe, FS_INT, node->id);
120 + node->cur_frm = node->next_frm;
121 + node->next_frm = NULL;
124 - /* If all nodes have seen a frame start, we can queue another job. */
125 - if (test_all_nodes(cfe, NODE_STREAMING, FS_INT))
126 + node->ts = ktime_get_ns();
127 + for (i = 0; i < NUM_NODES; i++) {
128 + if (!check_state(cfe, NODE_STREAMING, i) || i == node->id)
131 + * This checks if any other node has seen a FS. If yes, use the
132 + * same timestamp, eventually across all node buffers.
134 + if (cfe->node[i].fs_count >= node->fs_count)
135 + node->ts = cfe->node[i].ts;
137 + * This checks if all other node have seen a matching FS. If
138 + * yes, we can flag another job to be queued.
140 + if (matching_fs && cfe->node[i].fs_count != node->fs_count)
141 + matching_fs = false;
145 cfe->job_queued = false;
148 - node->cur_frm->vb.vb2_buf.timestamp = cfe->ts;
149 + node->cur_frm->vb.vb2_buf.timestamp = node->ts;
151 + set_state(cfe, FS_INT, node->id);
152 + clear_state(cfe, FE_INT, node->id);
154 if (is_image_output_node(node))
155 cfe_queue_event_sof(node);
156 @@ -712,22 +725,14 @@ static void cfe_eof_isr_handler(struct c
157 struct cfe_device *cfe = node->cfe;
159 cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name,
161 + node->fs_count - 1);
164 - cfe_process_buffer_complete(node, cfe->sequence);
165 + cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE);
167 node->cur_frm = NULL;
168 set_state(cfe, FE_INT, node->id);
171 - * If all nodes have seen a frame end, we can increment
172 - * the sequence counter now.
174 - if (test_all_nodes(cfe, NODE_STREAMING, FE_INT)) {
176 - clear_all_nodes(cfe, NODE_STREAMING, FE_INT | FS_INT);
178 + clear_state(cfe, FS_INT, node->id);
181 static irqreturn_t cfe_isr(int irq, void *dev)
182 @@ -794,7 +799,8 @@ static irqreturn_t cfe_isr(int irq, void
183 * frame first before the FS handler for the current
186 - if (check_state(cfe, FS_INT, node->id)) {
187 + if (check_state(cfe, FS_INT, node->id) &&
188 + !check_state(cfe, FE_INT, node->id)) {
189 cfe_dbg("%s: [%s] Handling missing previous FE interrupt\n",
190 __func__, node_desc[node->id].name);
191 cfe_eof_isr_handler(node);
192 @@ -1131,6 +1137,7 @@ static int cfe_start_streaming(struct vb
194 clear_state(cfe, FS_INT | FE_INT, node->id);
195 set_state(cfe, NODE_STREAMING, node->id);
196 + node->fs_count = 0;
197 cfe_start_channel(node);
199 if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) {
200 @@ -1166,7 +1173,6 @@ static int cfe_start_streaming(struct vb
201 csi2_open_rx(&cfe->csi2);
203 cfe_dbg("Starting sensor streaming\n");
205 ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1);
207 cfe_err("stream on failed in subdev\n");