* [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes
@ 2026-10-28 3:43 ` Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 1/4] media: iris: Don't flag an empty source change LAST buffer as an error Christian Cortner
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Christian Cortner @ 2026-10-28 3:43 UTC (permalink / raw)
To: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
Four fixes for iris decoder problems at resolution changes, reworked
after Bryan's review of v1 [1]. There is no Signed-off-by from me,
since I'm not a kernel developer and can't vouch for the code; please
take over whatever is useful. An AI assistant wrote the code and the
logs (Assisted-by in each patch). I'm happy to test.
Tested on glymur (Zenbook A16, laptops tree 65f4ae73 with these four
and the iris patches listed in [2]): v4l2-compliance passes, and
GStreamer and a spec-following client decode bit-exact across
resolution changes. ffmpeg's h264_v4l2m2m still stops at the first
source change when it sets up CAPTURE early (problem 1 in [2]).
Build-tested on media-committers next with W=1, sparse and smatch.
Changes in v2:
- 1/4: shorter log, with the traced firmware flags (Bryan)
- 2/4: shorter log (Bryan)
- 3/4: one helper for the EOS check (Bryan)
- 4/4: comment states the 500 ms limit, no domain check, warn on
timeout (Bryan)
- v1 5/5 dropped: too much for stable, and broken (Bryan)
[1] https://lore.kernel.org/linux-media/20261027021934.22113-1-ccortner@gmail.com/
[2] https://lore.kernel.org/linux-media/20261026160952.22082-1-ccortner@gmail.com/
Christian Cortner (4):
media: iris: Don't flag an empty source change LAST buffer as an error
media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT)
media: iris: Signal V4L2_EVENT_EOS only at the end of a drain
media: iris: Let a resolution change drain before stopping CAPTURE
.../media/platform/qcom/iris/iris_buffer.c | 26 +++++---
.../media/platform/qcom/iris/iris_buffer.h | 1 +
.../qcom/iris/iris_hfi_gen2_response.c | 7 ++-
.../media/platform/qcom/iris/iris_instance.h | 3 +
drivers/media/platform/qcom/iris/iris_state.c | 8 ++-
drivers/media/platform/qcom/iris/iris_vb2.c | 26 ++++++--
drivers/media/platform/qcom/iris/iris_vdec.c | 61 ++++++++++---------
drivers/media/platform/qcom/iris/iris_vidc.c | 1 +
8 files changed, 91 insertions(+), 42 deletions(-)
base-commit: d7e7bca7169873b46e857c025c10f3336c1258d8
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC PATCH v2 1/4] media: iris: Don't flag an empty source change LAST buffer as an error
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
@ 2026-10-28 3:43 ` Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 2/4] media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT) Christian Cortner
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Christian Cortner @ 2026-10-28 3:43 UTC (permalink / raw)
To: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
The firmware ends both a drain and a source change with an empty
capture buffer. Traced on glymur, it flags the first
HFI_BUF_FW_FLAG_LAST (0x10000000) and the second
HFI_BUF_FW_FLAG_PSC_LAST (0x20000000). Only LAST is exempt from the
empty buffer check, so the client gets the source change buffer as
LAST|ERROR, and ffmpeg's h264_v4l2m2m reports a decode error.
Exempt HFI_BUF_FW_FLAG_PSC_LAST as well.
Fixes: 7adc11e6abf6 ("media: iris: Send V4L2_BUF_FLAG_ERROR for capture buffers with 0 filled length")
Cc: stable@vger.kernel.org
Assisted-by: LLM sparse smatch
---
drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
index f0782c4b1e6e..b4fe9066fcb8 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
@@ -390,8 +390,13 @@ static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst,
buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags);
+ /*
+ * The empty buffer that ends a drain (LAST) or a source change
+ * (PSC_LAST) is not an error, the client just ignores it.
+ */
if (!buf->data_size && inst->state == IRIS_INST_STREAMING &&
- !(hfi_buffer->flags & HFI_BUF_FW_FLAG_LAST)) {
+ !(hfi_buffer->flags &
+ (HFI_BUF_FW_FLAG_LAST | HFI_BUF_FW_FLAG_PSC_LAST))) {
buf->flags |= V4L2_BUF_FLAG_ERROR;
}
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH v2 2/4] media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT)
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 1/4] media: iris: Don't flag an empty source change LAST buffer as an error Christian Cortner
@ 2026-10-28 3:43 ` Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 3/4] media: iris: Signal V4L2_EVENT_EOS only at the end of a drain Christian Cortner
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Christian Cortner @ 2026-10-28 3:43 UTC (permalink / raw)
To: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
S_FMT(OUTPUT) updates the CAPTURE width and height but not
bytesperline and sizeimage, which keep the values of the previous
format. With a 640x360 stream, REQBUFS(CAPTURE) then allocates buffers
that iris_vb2_buf_prepare() rejects with -EINVAL.
Move the CAPTURE format rules of S_FMT(CAPTURE) into a helper and use
it for S_FMT(OUTPUT) as well.
Fixes: 8aadfd445373 ("media: iris: Update CAPTURE format info based on OUTPUT format")
Cc: stable@vger.kernel.org
Assisted-by: LLM sparse smatch
---
drivers/media/platform/qcom/iris/iris_vdec.c | 61 +++++++++++---------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
index 0dd33ff447bb..472e8e50830d 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -212,6 +212,35 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f)
return 0;
}
+static void iris_vdec_set_capture_size(struct iris_inst *inst, u32 width,
+ u32 height)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &inst->fmt_dst->fmt.pix_mp;
+ struct iris_buffers *bufs = &inst->buffers[BUF_OUTPUT];
+
+ switch (pix_mp->pixelformat) {
+ case V4L2_PIX_FMT_P010:
+ pix_mp->width = ALIGN(width, 128);
+ pix_mp->height = ALIGN(height, 32);
+ pix_mp->plane_fmt[0].bytesperline = ALIGN(width * 2, 256);
+ break;
+ case V4L2_PIX_FMT_QC10C:
+ pix_mp->width = roundup(width, 192);
+ pix_mp->height = ALIGN(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = ALIGN(width * 4 / 3, 256);
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_QC08C:
+ pix_mp->width = ALIGN(width, 128);
+ pix_mp->height = ALIGN(height, 32);
+ pix_mp->plane_fmt[0].bytesperline = ALIGN(width, 128);
+ break;
+ }
+ pix_mp->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT);
+ bufs->min_count = iris_vpu_buf_count(inst, BUF_OUTPUT);
+ bufs->size = pix_mp->plane_fmt[0].sizeimage;
+}
+
int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f)
{
struct v4l2_format *fmt, *output_fmt;
@@ -263,10 +292,8 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f)
output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
/* Update capture format based on new ip w/h */
- output_fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128);
- output_fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32);
- inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT);
- inst->buffers[BUF_OUTPUT].size = iris_get_buffer_size(inst, BUF_OUTPUT);
+ iris_vdec_set_capture_size(inst, f->fmt.pix_mp.width,
+ f->fmt.pix_mp.height);
inst->crop.left = 0;
inst->crop.top = 0;
@@ -281,30 +308,8 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f)
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
fmt->fmt.pix_mp.num_planes = 1;
- switch (f->fmt.pix_mp.pixelformat) {
- case V4L2_PIX_FMT_P010:
- fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128);
- fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32);
- fmt->fmt.pix_mp.plane_fmt[0].bytesperline =
- ALIGN(f->fmt.pix_mp.width * 2, 256);
- break;
- case V4L2_PIX_FMT_QC10C:
- fmt->fmt.pix_mp.width = roundup(f->fmt.pix_mp.width, 192);
- fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
- fmt->fmt.pix_mp.plane_fmt[0].bytesperline =
- ALIGN(f->fmt.pix_mp.width * 4 / 3, 256);
- break;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_QC08C:
- fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128);
- fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32);
- fmt->fmt.pix_mp.plane_fmt[0].bytesperline =
- ALIGN(f->fmt.pix_mp.width, 128);
- break;
- }
- fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT);
- inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT);
- inst->buffers[BUF_OUTPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+ iris_vdec_set_capture_size(inst, f->fmt.pix_mp.width,
+ f->fmt.pix_mp.height);
inst->crop.top = 0;
inst->crop.left = 0;
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH v2 3/4] media: iris: Signal V4L2_EVENT_EOS only at the end of a drain
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 1/4] media: iris: Don't flag an empty source change LAST buffer as an error Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 2/4] media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT) Christian Cortner
@ 2026-10-28 3:43 ` Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 4/4] media: iris: Let a resolution change drain before stopping CAPTURE Christian Cortner
2026-10-28 10:00 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Bryan O'Donoghue
4 siblings, 0 replies; 6+ messages in thread
From: Christian Cortner @ 2026-10-28 3:43 UTC (permalink / raw)
To: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
V4L2_EVENT_EOS is queued, and the m2m context marked stopped, for every
LAST capture buffer, including the one that ends a source change. With
a stream that changes resolution, a client gets EOS at the change and
none at the end, and ffmpeg's h264_v4l2m2m stops decoding there.
Do both only when IRIS_INST_SUB_DRAIN_LAST is set, which both HFI
generations do before they return the LAST buffer of a drain. Use one
helper for iris_vb2_buffer_done() and iris_vb2_buf_queue().
Fixes: 84e17adae3e3 ("media: iris: add support for dynamic resolution change")
Cc: stable@vger.kernel.org
Assisted-by: LLM sparse smatch
---
.../media/platform/qcom/iris/iris_buffer.c | 26 ++++++++++++++-----
.../media/platform/qcom/iris/iris_buffer.h | 1 +
drivers/media/platform/qcom/iris/iris_vb2.c | 6 +----
3 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c
index eb8de60c1177..178e50eadcf7 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_buffer.c
@@ -870,9 +870,26 @@ static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns,
vbuf->timecode = inst->tss[inst->metadata_idx].tc;
}
-int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf)
+/*
+ * Queue V4L2_EVENT_EOS and mark the m2m context stopped, once, when a LAST
+ * capture buffer ends a drain. The LAST buffer of a source change does not
+ * end the stream.
+ */
+void iris_vb2_signal_eos(struct iris_inst *inst)
{
+ static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS };
struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+
+ if (!(inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) ||
+ v4l2_m2m_has_stopped(m2m_ctx))
+ return;
+
+ v4l2_event_queue_fh(&inst->fh, &eos);
+ v4l2_m2m_mark_stopped(m2m_ctx);
+}
+
+int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf)
+{
struct vb2_v4l2_buffer *vbuf;
struct vb2_buffer *vb2;
u32 type, state;
@@ -913,12 +930,7 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf)
}
if (vbuf->flags & V4L2_BUF_FLAG_LAST) {
- if (!v4l2_m2m_has_stopped(m2m_ctx)) {
- const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
-
- v4l2_event_queue_fh(&inst->fh, &ev);
- v4l2_m2m_mark_stopped(m2m_ctx);
- }
+ iris_vb2_signal_eos(inst);
inst->last_buffer_dequeued = true;
}
diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h
index ab8e5d953101..a8d2002e00ee 100644
--- a/drivers/media/platform/qcom/iris/iris_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_buffer.h
@@ -120,6 +120,7 @@ int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst);
int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf);
int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type);
int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf);
+void iris_vb2_signal_eos(struct iris_inst *inst);
void iris_vb2_queue_error(struct iris_inst *inst);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c
index 8faf709c26c1..bb713da20605 100644
--- a/drivers/media/platform/qcom/iris/iris_vb2.c
+++ b/drivers/media/platform/qcom/iris/iris_vb2.c
@@ -290,7 +290,6 @@ int iris_vb2_buf_out_validate(struct vb2_buffer *vb)
void iris_vb2_buf_queue(struct vb2_buffer *vb2)
{
- static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS };
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
struct v4l2_m2m_ctx *m2m_ctx;
struct iris_inst *inst;
@@ -324,10 +323,7 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2)
vbuf->field = V4L2_FIELD_NONE;
vb2_set_plane_payload(vb2, 0, 0);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
- if (!v4l2_m2m_has_stopped(m2m_ctx)) {
- v4l2_event_queue_fh(&inst->fh, &eos);
- v4l2_m2m_mark_stopped(m2m_ctx);
- }
+ iris_vb2_signal_eos(inst);
inst->last_buffer_dequeued = true;
goto exit;
}
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH v2 4/4] media: iris: Let a resolution change drain before stopping CAPTURE
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
` (2 preceding siblings ...)
2026-10-28 3:43 ` [RFC PATCH v2 3/4] media: iris: Signal V4L2_EVENT_EOS only at the end of a drain Christian Cortner
@ 2026-10-28 3:43 ` Christian Cortner
2026-10-28 10:00 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Bryan O'Donoghue
4 siblings, 0 replies; 6+ messages in thread
From: Christian Cortner @ 2026-10-28 3:43 UTC (permalink / raw)
To: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
ffmpeg's h264_v4l2m2m stops CAPTURE about 10 us after it dequeues a
source change event. If the stop reaches the firmware before the
PSC_LAST buffer, that buffer still arrives (1.3 ms later in a trace),
iris_inst_sub_state_change_drc_last() rejects it, and the instance
goes to IRIS_INST_ERROR: no more buffers come back.
Wait up to 500 ms in iris_vb2_stop_streaming() for a pending source
change to drain, and warn when it does not.
Fixes: 84e17adae3e3 ("media: iris: add support for dynamic resolution change")
Assisted-by: LLM sparse smatch
---
.../media/platform/qcom/iris/iris_instance.h | 3 +++
drivers/media/platform/qcom/iris/iris_state.c | 8 +++++++-
drivers/media/platform/qcom/iris/iris_vb2.c | 20 +++++++++++++++++++
drivers/media/platform/qcom/iris/iris_vidc.c | 1 +
4 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h
index 771269e705d9..1013ed2911a1 100644
--- a/drivers/media/platform/qcom/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/iris/iris_instance.h
@@ -7,6 +7,7 @@
#define __IRIS_INSTANCE_H__
#include <linux/kref.h>
+#include <linux/wait.h>
#include <media/v4l2-ctrls.h>
@@ -56,6 +57,7 @@ struct iris_hfi_session_ops;
* @metadata_idx: index for metadata buffer
* @codec: codec type
* @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver
+ * @drc_wq: woken when IRIS_INST_SUB_DRC_LAST is set
* @last_buf_ns: start time of received input buffer for current one second FPS window
* @frame_counter: input buffer counter for current one second FPS window
* @frame_rate: frame rate of current instance
@@ -104,6 +106,7 @@ struct iris_inst {
u32 metadata_idx;
u32 codec;
bool last_buffer_dequeued;
+ wait_queue_head_t drc_wq;
u64 last_buf_ns;
u32 frame_counter;
u32 frame_rate;
diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c
index 5552725c614e..dd8e0093b972 100644
--- a/drivers/media/platform/qcom/iris/iris_state.c
+++ b/drivers/media/platform/qcom/iris/iris_state.c
@@ -209,6 +209,7 @@ int iris_inst_sub_state_change_drain_last(struct iris_inst *inst)
int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
{
enum iris_inst_sub_state set_sub_state;
+ int ret;
if (inst->sub_state & IRIS_INST_SUB_DRC_LAST)
return -EINVAL;
@@ -222,7 +223,12 @@ int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
set_sub_state = IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
- return iris_inst_change_sub_state(inst, 0, set_sub_state);
+ ret = iris_inst_change_sub_state(inst, 0, set_sub_state);
+ /* a CAPTURE STREAMOFF may be waiting, see iris_vb2_stop_streaming() */
+ if (!ret)
+ wake_up_all(&inst->drc_wq);
+
+ return ret;
}
int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane)
diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c
index bb713da20605..2460778c408d 100644
--- a/drivers/media/platform/qcom/iris/iris_vb2.c
+++ b/drivers/media/platform/qcom/iris/iris_vb2.c
@@ -228,6 +228,15 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
return ret;
}
+/* a source change whose drain the firmware has not completed yet */
+static bool iris_drc_draining(struct iris_inst *inst)
+{
+ enum iris_inst_sub_state sub_state = READ_ONCE(inst->sub_state);
+
+ return sub_state & IRIS_INST_SUB_DRC &&
+ !(sub_state & IRIS_INST_SUB_DRC_LAST);
+}
+
void iris_vb2_stop_streaming(struct vb2_queue *q)
{
struct iris_inst *inst;
@@ -238,6 +247,17 @@ void iris_vb2_stop_streaming(struct vb2_queue *q)
if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT)
return;
+ /*
+ * Stopping CAPTURE before the firmware has drained a pending
+ * resolution change leaves the change incomplete, and decoding stalls
+ * after the next STREAMON. Wait up to 500 ms for the drain.
+ */
+ if (V4L2_TYPE_IS_CAPTURE(q->type) &&
+ !wait_event_timeout(inst->drc_wq, !iris_drc_draining(inst),
+ msecs_to_jiffies(500)))
+ dev_warn(inst->core->dev,
+ "resolution change drain timed out, stopping CAPTURE\n");
+
mutex_lock(&inst->lock);
if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index 05aab6e3005d..0df0a5915e16 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -201,6 +201,7 @@ int iris_open(struct file *filp)
INIT_LIST_HEAD(&inst->buffers[BUF_PARTIAL].list);
init_completion(&inst->completion);
init_completion(&inst->flush_completion);
+ init_waitqueue_head(&inst->drc_wq);
iris_v4l2_fh_init(inst, filp);
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
` (3 preceding siblings ...)
2026-10-28 3:43 ` [RFC PATCH v2 4/4] media: iris: Let a resolution change drain before stopping CAPTURE Christian Cortner
@ 2026-10-28 10:00 ` Bryan O'Donoghue
4 siblings, 0 replies; 6+ messages in thread
From: Bryan O'Donoghue @ 2026-10-28 10:00 UTC (permalink / raw)
To: Christian Cortner, Vikash Garodia, Dikshita Agarwal
Cc: Abhinav Kumar, Birk Skyum, linux-media, linux-arm-msm
On 28/10/2026 03:43, Christian Cortner wrote:
> Four fixes for iris decoder problems at resolution changes, reworked
> after Bryan's review of v1 [1]. There is no Signed-off-by from me,
> since I'm not a kernel developer and can't vouch for the code; please
> take over whatever is useful. An AI assistant wrote the code and the
> logs (Assisted-by in each patch). I'm happy to test.
>
> Tested on glymur (Zenbook A16, laptops tree 65f4ae73 with these four
> and the iris patches listed in [2]): v4l2-compliance passes, and
> GStreamer and a spec-following client decode bit-exact across
> resolution changes. ffmpeg's h264_v4l2m2m still stops at the first
> source change when it sets up CAPTURE early (problem 1 in [2]).
> Build-tested on media-committers next with W=1, sparse and smatch.
>
> Changes in v2:
> - 1/4: shorter log, with the traced firmware flags (Bryan)
> - 2/4: shorter log (Bryan)
> - 3/4: one helper for the EOS check (Bryan)
> - 4/4: comment states the 500 ms limit, no domain check, warn on
> timeout (Bryan)
> - v1 5/5 dropped: too much for stable, and broken (Bryan)
>
> [1] https://lore.kernel.org/linux-media/20261027021934.22113-1-ccortner@gmail.com/
> [2] https://lore.kernel.org/linux-media/20261026160952.22082-1-ccortner@gmail.com/
>
> Christian Cortner (4):
> media: iris: Don't flag an empty source change LAST buffer as an error
> media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT)
> media: iris: Signal V4L2_EVENT_EOS only at the end of a drain
> media: iris: Let a resolution change drain before stopping CAPTURE
>
> .../media/platform/qcom/iris/iris_buffer.c | 26 +++++---
> .../media/platform/qcom/iris/iris_buffer.h | 1 +
> .../qcom/iris/iris_hfi_gen2_response.c | 7 ++-
> .../media/platform/qcom/iris/iris_instance.h | 3 +
> drivers/media/platform/qcom/iris/iris_state.c | 8 ++-
> drivers/media/platform/qcom/iris/iris_vb2.c | 26 ++++++--
> drivers/media/platform/qcom/iris/iris_vdec.c | 61 ++++++++++---------
> drivers/media/platform/qcom/iris/iris_vidc.c | 1 +
> 8 files changed, 91 insertions(+), 42 deletions(-)
>
>
> base-commit: d7e7bca7169873b46e857c025c10f3336c1258d8
> --
> 2.56.0
Thank you for your bug report and suggested fixes.
I will mark is as under-review and ensure we do Closes: and
Suggested-by: with whatever lads upstream.
---
bod
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-28 10:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <-D3aZIsoO4_H5CdnB-7Co7GWmm5F9FuU6aFuhXWogBXhfqNOaqC2Y8tkBxT9ljDcy84UAX1jmUWGl7NtGUG6Mg==@protonmail.internalid>
2026-10-28 3:43 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 1/4] media: iris: Don't flag an empty source change LAST buffer as an error Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 2/4] media: iris: Update the CAPTURE stride and size on S_FMT(OUTPUT) Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 3/4] media: iris: Signal V4L2_EVENT_EOS only at the end of a drain Christian Cortner
2026-10-28 3:43 ` [RFC PATCH v2 4/4] media: iris: Let a resolution change drain before stopping CAPTURE Christian Cortner
2026-10-28 10:00 ` [RFC PATCH v2 0/4] media: iris: decoder fixes for resolution changes Bryan O'Donoghue
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox