Skip to content

Commit 474e2a6

Browse files
committed
drivers: media: cfe: Add more robust ISR handlers
Update the ISR logic to be more robust to sensors in problematic states where interrupts may start arriving overlapped and/or missing. 1) Test for cur_frame in the FE handler, and if present, dequeue it in an error state so that it does not get orphaned. 2) Move the sequence counter and timestamp variables to the node structures. This allows the ISR to track channels running ahead when interrupts arrive unordered. 3) Add a test to ensure we don't have a spurios (but harmlesS) call to the FE handler in some circumstances. Signed-off-by: Naushir Patuck <[email protected]>
1 parent 490efd8 commit 474e2a6

File tree

1 file changed

+49
-43
lines changed
  • drivers/media/platform/raspberrypi/rp1_cfe

1 file changed

+49
-43
lines changed

drivers/media/platform/raspberrypi/rp1_cfe/cfe.c

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ struct cfe_node {
272272
/* Pointer to the parent handle */
273273
struct cfe_device *cfe;
274274
struct media_pad pad;
275+
unsigned int fs_count;
276+
u64 ts;
275277
};
276278

277279
struct cfe_device {
@@ -311,9 +313,6 @@ struct cfe_device {
311313
struct pisp_fe_device fe;
312314

313315
int fe_csi2_channel;
314-
315-
unsigned int sequence;
316-
u64 ts;
317316
};
318317

319318
static inline bool is_fe_enabled(struct cfe_device *cfe)
@@ -393,17 +392,6 @@ static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond,
393392
return true;
394393
}
395394

396-
static void clear_all_nodes(struct cfe_device *cfe, unsigned long precond,
397-
unsigned long state)
398-
{
399-
unsigned int i;
400-
401-
for (i = 0; i < NUM_NODES; i++) {
402-
if (check_state(cfe, precond, i))
403-
clear_state(cfe, state, i);
404-
}
405-
}
406-
407395
static int mipi_cfg_regs_show(struct seq_file *s, void *data)
408396
{
409397
struct cfe_device *cfe = s->private;
@@ -656,22 +644,22 @@ static void cfe_prepare_next_job(struct cfe_device *cfe)
656644
}
657645

658646
static void cfe_process_buffer_complete(struct cfe_node *node,
659-
unsigned int sequence)
647+
enum vb2_buffer_state state)
660648
{
661649
struct cfe_device *cfe = node->cfe;
662650

663651
cfe_dbg_verbose("%s: [%s] buffer:%p\n", __func__,
664652
node_desc[node->id].name, &node->cur_frm->vb.vb2_buf);
665653

666-
node->cur_frm->vb.sequence = sequence;
667-
vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
654+
node->cur_frm->vb.sequence = node->fs_count - 1;
655+
vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state);
668656
}
669657

670658
static void cfe_queue_event_sof(struct cfe_node *node)
671659
{
672660
struct v4l2_event event = {
673661
.type = V4L2_EVENT_FRAME_SYNC,
674-
.u.frame_sync.frame_sequence = node->cfe->sequence,
662+
.u.frame_sync.frame_sequence = node->fs_count - 1,
675663
};
676664

677665
v4l2_event_queue(&node->video_dev, &event);
@@ -680,28 +668,53 @@ static void cfe_queue_event_sof(struct cfe_node *node)
680668
static void cfe_sof_isr_handler(struct cfe_node *node)
681669
{
682670
struct cfe_device *cfe = node->cfe;
671+
bool matching_fs = true;
672+
unsigned int i;
683673

684674
cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name,
685-
cfe->sequence);
686-
687-
node->cur_frm = node->next_frm;
688-
node->next_frm = NULL;
675+
node->fs_count);
689676

690677
/*
691-
* If this is the first node to see a frame start, sample the
692-
* timestamp to use for all frames across all channels.
678+
* If the sensor is producing unexpected frame event ordering over a
679+
* sustained period of time, guard against the possibility of coming
680+
* here and orphaning the cur_frm if it's not been dequeued already.
681+
* Unfortunately, there is not enough hardware state to tell if this
682+
* may have occurred.
693683
*/
694-
if (!test_any_node(cfe, NODE_STREAMING | FS_INT))
695-
cfe->ts = ktime_get_ns();
684+
if (WARN(node->cur_frm, "%s: [%s] Orphanded frame at seq %u\n",
685+
__func__, node_desc[node->id].name, node->fs_count))
686+
cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR);
696687

697-
set_state(cfe, FS_INT, node->id);
688+
node->cur_frm = node->next_frm;
689+
node->next_frm = NULL;
690+
node->fs_count++;
698691

699-
/* If all nodes have seen a frame start, we can queue another job. */
700-
if (test_all_nodes(cfe, NODE_STREAMING, FS_INT))
692+
node->ts = ktime_get_ns();
693+
for (i = 0; i < NUM_NODES; i++) {
694+
if (!check_state(cfe, NODE_STREAMING, i) || i == node->id)
695+
continue;
696+
/*
697+
* This checks if any other node has seen a FS. If yes, use the
698+
* same timestamp, eventually across all node buffers.
699+
*/
700+
if (cfe->node[i].fs_count >= node->fs_count)
701+
node->ts = cfe->node[i].ts;
702+
/*
703+
* This checks if all other node have seen a matching FS. If
704+
* yes, we can flag another job to be queued.
705+
*/
706+
if (matching_fs && cfe->node[i].fs_count != node->fs_count)
707+
matching_fs = false;
708+
}
709+
710+
if (matching_fs)
701711
cfe->job_queued = false;
702712

703713
if (node->cur_frm)
704-
node->cur_frm->vb.vb2_buf.timestamp = cfe->ts;
714+
node->cur_frm->vb.vb2_buf.timestamp = node->ts;
715+
716+
set_state(cfe, FS_INT, node->id);
717+
clear_state(cfe, FE_INT, node->id);
705718

706719
if (is_image_output_node(node))
707720
cfe_queue_event_sof(node);
@@ -712,22 +725,14 @@ static void cfe_eof_isr_handler(struct cfe_node *node)
712725
struct cfe_device *cfe = node->cfe;
713726

714727
cfe_dbg_verbose("%s: [%s] seq %u\n", __func__, node_desc[node->id].name,
715-
cfe->sequence);
728+
node->fs_count - 1);
716729

717730
if (node->cur_frm)
718-
cfe_process_buffer_complete(node, cfe->sequence);
731+
cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE);
719732

720733
node->cur_frm = NULL;
721734
set_state(cfe, FE_INT, node->id);
722-
723-
/*
724-
* If all nodes have seen a frame end, we can increment
725-
* the sequence counter now.
726-
*/
727-
if (test_all_nodes(cfe, NODE_STREAMING, FE_INT)) {
728-
cfe->sequence++;
729-
clear_all_nodes(cfe, NODE_STREAMING, FE_INT | FS_INT);
730-
}
735+
clear_state(cfe, FS_INT, node->id);
731736
}
732737

733738
static irqreturn_t cfe_isr(int irq, void *dev)
@@ -794,7 +799,8 @@ static irqreturn_t cfe_isr(int irq, void *dev)
794799
* frame first before the FS handler for the current
795800
* frame.
796801
*/
797-
if (check_state(cfe, FS_INT, node->id)) {
802+
if (check_state(cfe, FS_INT, node->id) &&
803+
!check_state(cfe, FE_INT, node->id)) {
798804
cfe_dbg("%s: [%s] Handling missing previous FE interrupt\n",
799805
__func__, node_desc[node->id].name);
800806
cfe_eof_isr_handler(node);
@@ -1131,6 +1137,7 @@ static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count)
11311137

11321138
clear_state(cfe, FS_INT | FE_INT, node->id);
11331139
set_state(cfe, NODE_STREAMING, node->id);
1140+
node->fs_count = 0;
11341141
cfe_start_channel(node);
11351142

11361143
if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) {
@@ -1166,7 +1173,6 @@ static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count)
11661173
csi2_open_rx(&cfe->csi2);
11671174

11681175
cfe_dbg("Starting sensor streaming\n");
1169-
cfe->sequence = 0;
11701176
ret = v4l2_subdev_call(cfe->sensor, video, s_stream, 1);
11711177
if (ret < 0) {
11721178
cfe_err("stream on failed in subdev\n");

0 commit comments

Comments
 (0)