[PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Fix conditional in start_streaming

Sasha Levin
2026-02-14T01:02:55Z

From: Brandon Brnich <b-brnich@ti.com>

[ Upstream commit b4e26c6fc1b3c225caf80d4a95c6f9fcbe959e17 ]

When STREAMON(CAP) is called after STREAMON(OUT), the driver was failing to
switch states from VPU_INST_STATE_OPEN to VPU_INST_STATE_INIT_SEQ and
VPU_INST_STATE_PIC_RUN because the capture queue streaming boolean had not
yet been set to true. This led to a hang in the encoder since the state
was stuck in VPU_INST_STATE_OPEN. During the second call to
start_streaming, the sequence initialization and frame buffer allocation
should occur.

Signed-off-by: Brandon Brnich <b-brnich@ti.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

This confirms the key finding. Now I have all the information needed for
a comprehensive analysis.

## Detailed Analysis

### 1. COMMIT MESSAGE ANALYSIS

The subject "Fix conditional in start_streaming" clearly indicates a
**bug fix**. The commit message explains:
- **Trigger**: When `STREAMON(CAPTURE)` is called after
`STREAMON(OUTPUT)`, the encoder hangs.
- **Root cause**: The capture queue's `streaming` boolean hasn't been
set to `true` yet at the time the condition is checked.
- **Symptom**: The VPU instance state gets stuck at
`VPU_INST_STATE_OPEN`, never advancing to `VPU_INST_STATE_INIT_SEQ` or
`VPU_INST_STATE_PIC_RUN`, causing the encoder to **hang**.

The commit has "Reviewed-by: Nicolas Dufresne" (Collabora engineer,
active V4L2 contributor) and was merged by Hans Verkuil (the V4L2
subsystem maintainer), indicating proper review.

### 2. CODE CHANGE ANALYSIS

The fix is a **one-line conditional change** (technically a 2-line
reformatting of a single condition):

**Before:**
```c
if (inst->state == VPU_INST_STATE_OPEN &&
m2m_ctx->cap_q_ctx.q.streaming) {
```

**After:**
```c
if (inst->state == VPU_INST_STATE_OPEN &&
(m2m_ctx->cap_q_ctx.q.streaming || q->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
```

The logic bug is clear and verified by examining `vb2_core_streamon()`:

```2347:2353:drivers/media/common/videobuf2/videobuf2-core.c
if (q->queued_count >= q->min_queued_buffers) {
ret = vb2_start_streaming(q);
if (ret)
goto unprepare;
}

q->streaming = 1;
```

The `q->streaming = 1` is set **AFTER** the driver's `start_streaming()`
callback returns. So inside `wave5_vpu_enc_start_streaming()`, when
called for the capture queue, `m2m_ctx->cap_q_ctx.q.streaming` is still
`0` because vb2 hasn't set it yet. This means the second `if` block (the
state transition from OPEN -> INIT_SEQ -> PIC_RUN) is **never entered**
when streaming is started in the normal OUT-then-CAP order.

The fix adds `q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE` as an
alternative condition: if we're currently inside `start_streaming` for
the capture queue, we know that capture streaming is about to become
active, so proceed with the state transition.

This is **identical** to how the decoder handles it — the decoder uses
`q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE` directly (line 1346 of
wave5-vpu-dec.c) rather than checking the streaming flag.

### 3. CLASSIFICATION

This is a clear **bug fix** that resolves a **system hang**. The encoder
gets stuck because its state machine never advances past
`VPU_INST_STATE_OPEN`. This is not a feature addition, refactoring, or
optimization.

### 4. SCOPE AND RISK ASSESSMENT

- **Lines changed**: 2 lines (one condition modified)
- **Files touched**: 1 file (`wave5-vpu-enc.c`)
- **Complexity**: Extremely low — a simple boolean condition expansion
- **Risk**: Very low. The added condition (`q->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE`) only evaluates to true when
`start_streaming` is called for the capture queue, which is precisely
when the streaming flag would be about to be set. This is logically
sound and matches the decoder's approach.
- **Regression potential**: Near zero. The fix only adds a case that was
previously unreachable (the dead path that caused the hang).

### 5. USER IMPACT

- **Who is affected**: Any user of the Wave5 VPU encoder (Chips&Media IP
used in TI processors and other SoCs)
- **Severity**: **HIGH** — the encoder **hangs completely**. This isn't
a minor issue; the hardware cannot encode video at all when STREAMON
is called in the standard OUT-then-CAP order.
- **Real-world impact**: This affects all V4L2 applications using the
standard video encoding flow (which is the normal way to use a V4L2
M2M encoder).

### 6. STABILITY INDICATORS

- Reviewed by Nicolas Dufresne (Collabora V4L2 expert)
- Merged by Hans Verkuil (V4L2 subsystem maintainer)
- The fix follows the same pattern already used by the decoder
(wave5-vpu-dec.c), so it's a well-understood pattern

### 7. DEPENDENCY CHECK

- **Self-contained**: Yes. The fix modifies a single condition with no
dependencies on other commits.
- **Exists in stable**: The driver was added in v6.8 via commit
`9707a6254a8a6`. It exists in stable trees 6.8.y through 6.18.y (plus
the active LTS tree 6.12.y).
- **The bug has existed since the driver was added** (commit
`9707a6254a8a6`), meaning all stable trees with this driver have the
bug.
- **Clean apply**: The surrounding code is essentially identical in
6.12.y, 6.15.y, and 6.16.y (minor differences in pm_runtime calls that
don't affect the patch context).

### 8. SUMMARY

This is a textbook stable backport candidate:
- **Fixes a real, user-visible bug**: encoder hangs completely
- **Small, surgical fix**: 2-line conditional change in one file
- **Obviously correct**: matches the decoder's existing pattern,
reviewed by V4L2 experts
- **No new features**: just fixes the broken state machine transition
- **Low regression risk**: only enables a previously dead code path that
was always supposed to be reachable
- **Affects real users**: anyone using the Wave5 encoder for video
encoding on TI SoCs
- **Self-contained**: no dependencies on other commits

**YES**

drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
index 9bfaa9fb3ceb3..bca881a0a1617 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -1367,7 +1367,8 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto return_buffers;
}
- if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) {
+ if (inst->state == VPU_INST_STATE_OPEN &&
+ (m2m_ctx->cap_q_ctx.q.streaming || q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
ret = initialize_sequence(inst);
if (ret) {
dev_warn(inst->dev->dev, "Sequence not found: %d\n", ret);
--
2.51.0