From: "Jackson.lee" <jackson.lee@chipsnmedia.com>
To: mchehab@kernel.org, hverkuil-cisco@xs4all.nl,
nicolas.dufresne@collabora.com, bob.beckett@collabora.com
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com,
b-brnich@ti.com, hverkuil@xs4all.nl, nas.chung@chipsnmedia.com,
stable@vger.kernel.org
Subject: [PATCH v1 6/9] media: chips-media: wave5: decode only when the ring holds unclaimed bitstream
Date: Wed, 7 Oct 2026 10:59:43 +0900 [thread overview]
Message-ID: <20261007015946.53-7-jackson.lee@chipsnmedia.com> (raw)
In-Reply-To: <20261007015946.53-1-jackson.lee@chipsnmedia.com>
From: Jackson Lee <jackson.lee@chipsnmedia.com>
device_run() decides whether to issue a DEC_PIC by comparing the instance
queue count against the number of OUTPUT buffers held. Those two count
unrelated things and diverge routinely with interrupt timing, so commands
go out against an empty ring buffer, or duplicate one already in flight,
corrupting the decoded output and producing display results the driver is
not expecting.
Decide on the real state instead: decode only when the ring still holds
bitstream and no queued command will consume it.
That can leave an instance idle with data still buffered. If the in-flight
command completes without freeing an OUTPUT buffer, nothing re-runs
device_run() and a client that has queued every buffer it owns cannot
restart it. Re-check on a 100 ms timer, which a normal wait outruns.
Fixes: 8c5a74a24cbb ("media: chips-media: wave5: avoid skipping device_run while VPU has work")
Cc: stable@vger.kernel.org
Signed-off-by: Jackson Lee <jackson.lee@chipsnmedia.com>
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../chips-media/wave5/wave5-vpu-dec.c | 62 +++++++++++++++++--
.../platform/chips-media/wave5/wave5-vpuapi.h | 1 +
2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
index 18400af036dc..0c92b6c9a913 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -1619,6 +1619,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
else
streamoff_capture(q);
+ cancel_delayed_work_sync(&inst->unstall_work);
inst->empty_queue = false;
inst->sent_eos = false;
pm_runtime_put_autosuspend(inst->dev->dev);
@@ -1699,6 +1700,31 @@ static bool wave5_is_draining_or_eos(struct vpu_instance *inst)
return m2m_ctx->is_draining || inst->eos;
}
+/*
+ * How long an instance may sit idle with bitstream still buffered before it is
+ * assumed stuck. A normal wait -- including one instance queued behind others on
+ * a shared VPU -- clears in a few milliseconds, so this never fires for it.
+ */
+#define WAVE5_UNSTALL_DELAY_MS 100
+
+static void wave5_vpu_dec_unstall_work(struct work_struct *work)
+{
+ struct vpu_instance *inst = container_of(to_delayed_work(work),
+ struct vpu_instance, unstall_work);
+
+ /*
+ * Someone already made progress, or the instance is no longer running a
+ * picture. Poking the scheduler for an instance that is tearing down
+ * would queue a job against a context that is about to be freed.
+ */
+ if (!inst->empty_queue || inst->state != VPU_INST_STATE_PIC_RUN)
+ return;
+
+ dev_dbg(inst->dev->dev, "%s: restarting a stalled instance\n", __func__);
+ inst->empty_queue = false;
+ v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
+}
+
static void wave5_vpu_dec_device_run(void *priv)
{
struct vpu_instance *inst = priv;
@@ -1717,14 +1743,32 @@ static void wave5_vpu_dec_device_run(void *priv)
if (ret < 0) {
dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
goto finish_job_and_return;
- } else if (!inst->eos &&
- inst->queuing_num == 0 &&
- inst->state == VPU_INST_STATE_PIC_RUN) {
+ } else if (!inst->eos && inst->state == VPU_INST_STATE_PIC_RUN) {
+ struct dec_info *dec_info = &inst->codec_info->dec_info;
+ bool ring_has_data;
+
wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
- if (q_status.instance_queue_count == v4l2_m2m_num_src_bufs_ready(m2m_ctx)) {
+ ring_has_data = dec_info->stream_rd_ptr != dec_info->stream_wr_ptr;
+
+ /*
+ * Nothing new to feed, so stop here and wait -- unless the
+ * ring still holds bitstream that no queued command will
+ * consume. Decoding an empty ring, or redoing what an
+ * in-flight command will take, corrupts the output.
+ */
+ if (q_status.instance_queue_count || !ring_has_data) {
dev_dbg(inst->dev->dev, "%s: no bitstream, skip\n",
__func__);
inst->empty_queue = true;
+ /*
+ * Stopping with data left over relies on the
+ * in-flight command to bring us back. If it ends
+ * without freeing an OUTPUT buffer, a client that
+ * holds them all cannot queue one to restart us.
+ */
+ if (ring_has_data)
+ mod_delayed_work(system_percpu_wq, &inst->unstall_work,
+ msecs_to_jiffies(WAVE5_UNSTALL_DELAY_MS));
goto finish_job_and_return;
}
}
@@ -1954,6 +1998,7 @@ static int wave5_vpu_open_dec(struct file *filp)
spin_lock_init(&inst->state_spinlock);
mutex_init(&inst->feed_lock);
INIT_LIST_HEAD(&inst->avail_src_bufs);
+ INIT_DELAYED_WORK(&inst->unstall_work, wave5_vpu_dec_unstall_work);
inst->codec_info = kzalloc_obj(*inst->codec_info);
if (!inst->codec_info) {
@@ -2048,6 +2093,15 @@ static int wave5_vpu_open_dec(struct file *filp)
static int wave5_vpu_dec_release(struct file *filp)
{
+ struct vpu_instance *inst = file_to_vpu_inst(filp);
+
+ /*
+ * The unstall timer dereferences both m2m_ctx and inst, which
+ * wave5_vpu_release_device() frees. stop_streaming() disarms it for a
+ * streaming instance; make sure nothing is left pending on any other path.
+ */
+ cancel_delayed_work_sync(&inst->unstall_work);
+
return wave5_vpu_release_device(filp, wave5_vpu_dec_close, "decoder");
}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index a338e39be1c9..abfe94fa18e7 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -9,6 +9,7 @@
#define VPUAPI_H_INCLUDED
#include <linux/kfifo.h>
+#include <linux/workqueue.h>
#include <linux/idr.h>
#include <linux/genalloc.h>
#include <media/v4l2-device.h>
--
2.43.0
next prev parent reply other threads:[~2026-10-07 2:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 1:59 [PATCH v1 0/9] fix decoder corruption, stalls and seek issues Jackson.lee
2026-10-07 1:59 ` [PATCH v1 1/9] media: chips-media: wave5: Ensure Atomic Access to src_buf list Jackson.lee
2026-10-07 1:59 ` [PATCH v1 2/9] media: chips-media: wave5: drop the consumed-byte tally on OUTPUT streamoff Jackson.lee
2026-10-07 1:59 ` [PATCH v1 3/9] media: chips-media: wave5: wait before retrying a refused flush Jackson.lee
2026-10-07 1:59 ` [PATCH v1 4/9] media: chips-media: wave5: ack the interrupt after dispatching it Jackson.lee
2026-10-07 1:59 ` [PATCH v1 5/9] media: chips-media: wave5: finish a job only once Jackson.lee
2026-10-07 1:59 ` Jackson.lee [this message]
2026-10-07 1:59 ` [PATCH v1 7/9] media: chips-media: wave5: stamp decoded pictures from a decode-order queue Jackson.lee
2026-10-07 1:59 ` [PATCH v1 8/9] media: chips-media: wave5: restore the display flags after a flush Jackson.lee
2026-10-07 1:59 ` [PATCH v1 9/9] media: chips-media: wave5: Stop FrameBuf Reset During Seek Jackson.lee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261007015946.53-7-jackson.lee@chipsnmedia.com \
--to=jackson.lee@chipsnmedia.com \
--cc=b-brnich@ti.com \
--cc=bob.beckett@collabora.com \
--cc=hverkuil-cisco@xs4all.nl \
--cc=hverkuil@xs4all.nl \
--cc=lafley.kim@chipsnmedia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=nas.chung@chipsnmedia.com \
--cc=nicolas.dufresne@collabora.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®