Linux-Amlogic Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] staging: media: meson: vdec: fix advanced concurrency and UAF bugs
@ 2026-07-13 18:16 Alfie Varghese
  2026-07-13 18:33 ` sashiko-bot
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Alfie Varghese @ 2026-07-13 18:16 UTC (permalink / raw)
  To: neil.armstrong, gregkh, linux-media, linux-amlogic, linux-staging,
	linux-kernel
  Cc: Alfie Varghese

This commit fixes several deep concurrency and race condition issues identified
in the Amlogic video decoder driver:

1. Fix a Use-After-Free window in vdec_close() by moving
   cancel_work_sync(&sess->esparser_queue_work) to execute after the hardware
   is stopped via v4l2_m2m_ctx_release(), preventing interrupts from re-arming it.
2. Fix a Use-After-Free relating to v4l2_m2m_release(). The driver incorrectly
   allocated the m2m_dev per-session rather than per-device. Moved the
   m2m_dev allocation to vdec_probe() and cleanup to vdec_remove() to fix
   the structural UAF when background m2m jobs were pending.
3. Fix a TOCTOU race condition in vdec_isr() by adding synchronize_irq()
   in vdec_stop_streaming() after clearing core->cur_sess, ensuring that
   running interrupt handlers finish before freeing session data.
4. Fix a potential NULL/ERR pointer dereference in vdec_start_streaming()
   by checking the return value of kthread_run() and handling errors gracefully.
5. Fix a memory leak in vdec_close() by freeing the session control
   handler via v4l2_ctrl_handler_free().
6. Prevent a potential NULL pointer dereference in vdec_probe() by adding
   a NULL check for of_match_node().

Signed-off-by: Alfie Varghese <alfievarghese22@gmail.com>
---
 drivers/staging/media/meson/vdec/vdec.c |  52 ++-
 drivers/staging/media/meson/vdec/vdec.h | 586 ++++++++++++------------
 2 files changed, 331 insertions(+), 307 deletions(-)

diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index a039d925c0fe..f57c473da5e1 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -337,9 +337,16 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 
 	sess->sequence_cap = 0;
 	sess->sequence_out = 0;
-	if (vdec_codec_needs_recycle(sess))
+	if (vdec_codec_needs_recycle(sess)) {
 		sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
 						   "vdec_recycle");
+		if (IS_ERR(sess->recycle_thread)) {
+			ret = PTR_ERR(sess->recycle_thread);
+			sess->recycle_thread = NULL;
+			vdec_poweroff(sess);
+			goto vififo_free;
+		}
+	}
 
 	sess->status = STATUS_INIT;
 	core->cur_sess = sess;
@@ -404,7 +411,7 @@ static void vdec_stop_streaming(struct vb2_queue *q)
 	    sess->status == STATUS_INIT ||
 	    (sess->status == STATUS_NEEDS_RESUME &&
 	     (!sess->streamon_out || !sess->streamon_cap))) {
-		if (vdec_codec_needs_recycle(sess))
+		if (vdec_codec_needs_recycle(sess) && sess->recycle_thread)
 			kthread_stop(sess->recycle_thread);
 
 		vdec_poweroff(sess);
@@ -416,6 +423,7 @@ static void vdec_stop_streaming(struct vb2_queue *q)
 		kfree(sess->priv);
 		sess->priv = NULL;
 		core->cur_sess = NULL;
+		synchronize_irq(core->irq);
 		sess->status = STATUS_STOPPED;
 	}
 
@@ -873,18 +881,11 @@ static int vdec_open(struct file *file)
 
 	sess->core = core;
 
-	sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
-	if (IS_ERR(sess->m2m_dev)) {
-		dev_err(dev, "Fail to v4l2_m2m_init\n");
-		ret = PTR_ERR(sess->m2m_dev);
-		goto err_free_sess;
-	}
-
-	sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init);
+	sess->m2m_ctx = v4l2_m2m_ctx_init(core->m2m_dev, sess, m2m_queue_init);
 	if (IS_ERR(sess->m2m_ctx)) {
 		dev_err(dev, "Fail to v4l2_m2m_ctx_init\n");
 		ret = PTR_ERR(sess->m2m_ctx);
-		goto err_m2m_release;
+		goto err_free_sess;
 	}
 
 	ret = vdec_init_ctrls(sess);
@@ -915,8 +916,6 @@ static int vdec_open(struct file *file)
 
 err_m2m_ctx_release:
 	v4l2_m2m_ctx_release(sess->m2m_ctx);
-err_m2m_release:
-	v4l2_m2m_release(sess->m2m_dev);
 err_free_sess:
 	kfree(sess);
 	return ret;
@@ -927,10 +926,12 @@ static int vdec_close(struct file *file)
 	struct amvdec_session *sess = file_to_amvdec_session(file);
 
 	v4l2_m2m_ctx_release(sess->m2m_ctx);
-	v4l2_m2m_release(sess->m2m_dev);
+	cancel_work_sync(&sess->esparser_queue_work);
 	v4l2_fh_del(&sess->fh, file);
 	v4l2_fh_exit(&sess->fh);
 
+	v4l2_ctrl_handler_free(&sess->ctrl_handler);
+
 	mutex_destroy(&sess->lock);
 	mutex_destroy(&sess->bufs_recycle_lock);
 
@@ -953,6 +954,9 @@ static irqreturn_t vdec_isr(int irq, void *data)
 	struct amvdec_core *core = data;
 	struct amvdec_session *sess = core->cur_sess;
 
+	if (!sess)
+		return IRQ_NONE;
+
 	sess->last_irq_jiffies = get_jiffies_64();
 
 	return sess->fmt_out->codec_ops->isr(sess);
@@ -963,6 +967,9 @@ static irqreturn_t vdec_threaded_isr(int irq, void *data)
 	struct amvdec_core *core = data;
 	struct amvdec_session *sess = core->cur_sess;
 
+	if (!sess)
+		return IRQ_NONE;
+
 	return sess->fmt_out->codec_ops->threaded_isr(sess);
 }
 
@@ -1020,6 +1027,8 @@ static int vdec_probe(struct platform_device *pdev)
 		return PTR_ERR(core->canvas);
 
 	of_id = of_match_node(vdec_dt_match, dev->of_node);
+	if (!of_id)
+		return -ENODEV;
 	core->platform = of_id->data;
 
 	if (core->platform->revision == VDEC_REVISION_G12A ||
@@ -1049,6 +1058,8 @@ static int vdec_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
+	core->irq = irq;
+
 	ret = devm_request_threaded_irq(core->dev, irq, vdec_isr,
 					vdec_threaded_isr, IRQF_ONESHOT,
 					"vdec", core);
@@ -1065,10 +1076,17 @@ static int vdec_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	core->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
+	if (IS_ERR(core->m2m_dev)) {
+		dev_err(dev, "Failed to init v4l2 m2m dev\n");
+		ret = PTR_ERR(core->m2m_dev);
+		goto err_v4l2_unreg;
+	}
+
 	vdev = video_device_alloc();
 	if (!vdev) {
 		ret = -ENOMEM;
-		goto err_vdev_release;
+		goto err_m2m_release;
 	}
 
 	core->vdev_dec = vdev;
@@ -1096,6 +1114,9 @@ static int vdec_probe(struct platform_device *pdev)
 
 err_vdev_release:
 	video_device_release(vdev);
+err_m2m_release:
+	v4l2_m2m_release(core->m2m_dev);
+err_v4l2_unreg:
 	v4l2_device_unregister(&core->v4l2_dev);
 	return ret;
 }
@@ -1105,6 +1126,7 @@ static void vdec_remove(struct platform_device *pdev)
 	struct amvdec_core *core = platform_get_drvdata(pdev);
 
 	video_unregister_device(core->vdev_dec);
+	v4l2_m2m_release(core->m2m_dev);
 	v4l2_device_unregister(&core->v4l2_dev);
 }
 
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
index 7a5d8e871d70..b2a606e965b4 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -1,292 +1,294 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2018 BayLibre, SAS
- * Author: Maxime Jourdan <mjourdan@baylibre.com>
- */
-
-#ifndef __MESON_VDEC_CORE_H_
-#define __MESON_VDEC_CORE_H_
-
-#include <linux/irqreturn.h>
-#include <linux/regmap.h>
-#include <linux/list.h>
-#include <media/videobuf2-v4l2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <linux/soc/amlogic/meson-canvas.h>
-
-#include "vdec_platform.h"
-
-/* 32 buffers in 3-plane YUV420 */
-#define MAX_CANVAS (32 * 3)
-
-struct amvdec_buffer {
-	struct list_head list;
-	struct vb2_buffer *vb;
-};
-
-/**
- * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
- *
- * @list: used to make lists out of this struct
- * @tc: timecode from the v4l2 buffer
- * @ts: timestamp from the VB2 buffer
- * @offset: offset in the VIFIFO where the associated packet was written
- * @flags: flags from the v4l2 buffer
- * @used_count: times this timestamp was checked for a match with a dst buffer
- */
-struct amvdec_timestamp {
-	struct list_head list;
-	struct v4l2_timecode tc;
-	u64 ts;
-	u32 offset;
-	u32 flags;
-	u32 used_count;
-};
-
-struct amvdec_session;
-
-/**
- * struct amvdec_core - device parameters, singleton
- *
- * @dos_base: DOS memory base address
- * @esparser_base: PARSER memory base address
- * @regmap_ao: regmap for the AO bus
- * @dev: core device
- * @dev_dec: decoder device
- * @platform: platform-specific data
- * @canvas: canvas provider reference
- * @dos_parser_clk: DOS_PARSER clock
- * @dos_clk: DOS clock
- * @vdec_1_clk: VDEC_1 clock
- * @vdec_hevc_clk: VDEC_HEVC clock
- * @vdec_hevcf_clk: VDEC_HEVCF clock
- * @esparser_reset: RESET for the PARSER
- * @vdev_dec: video device for the decoder
- * @v4l2_dev: v4l2 device
- * @cur_sess: current decoding session
- * @lock: video device lock
- */
-struct amvdec_core {
-	void __iomem *dos_base;
-	void __iomem *esparser_base;
-	struct regmap *regmap_ao;
-
-	struct device *dev;
-	struct device *dev_dec;
-	const struct vdec_platform *platform;
-
-	struct meson_canvas *canvas;
-
-	struct clk *dos_parser_clk;
-	struct clk *dos_clk;
-	struct clk *vdec_1_clk;
-	struct clk *vdec_hevc_clk;
-	struct clk *vdec_hevcf_clk;
-
-	struct reset_control *esparser_reset;
-
-	struct video_device *vdev_dec;
-	struct v4l2_device v4l2_dev;
-
-	struct amvdec_session *cur_sess;
-	struct mutex lock;
-};
-
-/**
- * struct amvdec_ops - vdec operations
- *
- * @start: mandatory call when the vdec needs to initialize
- * @stop: mandatory call when the vdec needs to stop
- * @conf_esparser: mandatory call to let the vdec configure the ESPARSER
- * @vififo_level: mandatory call to get the current amount of data
- *		  in the VIFIFO
- */
-struct amvdec_ops {
-	int (*start)(struct amvdec_session *sess);
-	int (*stop)(struct amvdec_session *sess);
-	void (*conf_esparser)(struct amvdec_session *sess);
-	u32 (*vififo_level)(struct amvdec_session *sess);
-};
-
-/**
- * struct amvdec_codec_ops - codec operations
- *
- * @start: mandatory call when the codec needs to initialize
- * @stop: mandatory call when the codec needs to stop
- * @load_extended_firmware: optional call to load additional firmware bits
- * @num_pending_bufs: optional call to get the number of dst buffers on hold
- * @can_recycle: optional call to know if the codec is ready to recycle
- *		 a dst buffer
- * @recycle: optional call to tell the codec to recycle a dst buffer. Must go
- *	     in pair with @can_recycle
- * @drain: optional call if the codec has a custom way of draining
- * @resume: optional call to resume after a resolution change
- * @eos_sequence: optional call to get an end sequence to send to esparser
- *		  for flush. Mutually exclusive with @drain.
- * @isr: mandatory call when the ISR triggers
- * @threaded_isr: mandatory call for the threaded ISR
- */
-struct amvdec_codec_ops {
-	int (*start)(struct amvdec_session *sess);
-	int (*stop)(struct amvdec_session *sess);
-	int (*load_extended_firmware)(struct amvdec_session *sess,
-				      const u8 *data, u32 len);
-	u32 (*num_pending_bufs)(struct amvdec_session *sess);
-	int (*can_recycle)(struct amvdec_core *core);
-	void (*recycle)(struct amvdec_core *core, u32 buf_idx);
-	void (*drain)(struct amvdec_session *sess);
-	void (*resume)(struct amvdec_session *sess);
-	const u8 * (*eos_sequence)(u32 *len);
-	irqreturn_t (*isr)(struct amvdec_session *sess);
-	irqreturn_t (*threaded_isr)(struct amvdec_session *sess);
-};
-
-/**
- * struct amvdec_format - describes one of the OUTPUT (src) format supported
- *
- * @pixfmt: V4L2 pixel format
- * @min_buffers: minimum amount of CAPTURE (dst) buffers
- * @max_buffers: maximum amount of CAPTURE (dst) buffers
- * @max_width: maximum picture width supported
- * @max_height: maximum picture height supported
- * @flags: enum flags associated with this pixfmt
- * @vdec_ops: the VDEC operations that support this format
- * @codec_ops: the codec operations that support this format
- * @firmware_path: Path to the firmware that supports this format
- * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt
- */
-struct amvdec_format {
-	u32 pixfmt;
-	u32 min_buffers;
-	u32 max_buffers;
-	u32 max_width;
-	u32 max_height;
-	u32 flags;
-
-	struct amvdec_ops *vdec_ops;
-	struct amvdec_codec_ops *codec_ops;
-
-	char *firmware_path;
-	u32 pixfmts_cap[4];
-};
-
-enum amvdec_status {
-	STATUS_STOPPED,
-	STATUS_INIT,
-	STATUS_RUNNING,
-	STATUS_NEEDS_RESUME,
-};
-
-/**
- * struct amvdec_session - decoding session parameters
- *
- * @core: reference to the vdec core struct
- * @fh: v4l2 file handle
- * @m2m_dev: v4l2 m2m device
- * @m2m_ctx: v4l2 m2m context
- * @ctrl_handler: V4L2 control handler
- * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
- * @lock: cap & out queues lock
- * @fmt_out: vdec pixel format for the OUTPUT queue
- * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
- * @src_buffer_size: size in bytes of the OUTPUT buffers' only plane
- * @width: current picture width
- * @height: current picture height
- * @colorspace: current colorspace
- * @ycbcr_enc: current ycbcr_enc
- * @quantization: current quantization
- * @xfer_func: current transfer function
- * @pixelaspect: Pixel Aspect Ratio reported by the decoder
- * @esparser_queued_bufs: number of buffers currently queued into ESPARSER
- * @esparser_queue_work: work struct for the ESPARSER to process src buffers
- * @streamon_cap: stream on flag for capture queue
- * @streamon_out: stream on flag for output queue
- * @sequence_cap: capture sequence counter
- * @sequence_out: output sequence counter
- * @should_stop: flag set if userspace signaled EOS via command
- *		 or empty buffer
- * @keyframe_found: flag set once a keyframe has been parsed
- * @num_dst_bufs: number of destination buffers
- * @changed_format: the format changed
- * @canvas_alloc: array of all the canvas IDs allocated
- * @canvas_num: number of canvas IDs allocated
- * @vififo_vaddr: virtual address for the VIFIFO
- * @vififo_paddr: physical address for the VIFIFO
- * @vififo_size: size of the VIFIFO dma alloc
- * @bufs_recycle: list of buffers that need to be recycled
- * @bufs_recycle_lock: lock for the bufs_recycle list
- * @recycle_thread: task struct for the recycling thread
- * @timestamps: chronological list of src timestamps
- * @ts_spinlock: spinlock for the timestamps list
- * @last_irq_jiffies: tracks last time the vdec triggered an IRQ
- * @last_offset: tracks last offset of vififo
- * @wrap_count: number of times the vififo wrapped around
- * @fw_idx_to_vb2_idx: firmware buffer index to vb2 buffer index
- * @status: current decoding status
- * @priv: codec private data
- */
-struct amvdec_session {
-	struct amvdec_core *core;
-
-	struct v4l2_fh fh;
-	struct v4l2_m2m_dev *m2m_dev;
-	struct v4l2_m2m_ctx *m2m_ctx;
-	struct v4l2_ctrl_handler ctrl_handler;
-	struct v4l2_ctrl *ctrl_min_buf_capture;
-	struct mutex lock;
-
-	const struct amvdec_format *fmt_out;
-	u32 pixfmt_cap;
-	u32 src_buffer_size;
-
-	u32 width;
-	u32 height;
-	u32 colorspace;
-	u8 ycbcr_enc;
-	u8 quantization;
-	u8 xfer_func;
-
-	struct v4l2_fract pixelaspect;
-
-	atomic_t esparser_queued_bufs;
-	struct work_struct esparser_queue_work;
-
-	unsigned int streamon_cap, streamon_out;
-	unsigned int sequence_cap, sequence_out;
-	unsigned int should_stop;
-	unsigned int keyframe_found;
-	unsigned int num_dst_bufs;
-	unsigned int changed_format;
-
-	u8 canvas_alloc[MAX_CANVAS];
-	u32 canvas_num;
-
-	void *vififo_vaddr;
-	dma_addr_t vififo_paddr;
-	u32 vififo_size;
-
-	struct list_head bufs_recycle;
-	struct mutex bufs_recycle_lock; /* bufs_recycle list lock */
-	struct task_struct *recycle_thread;
-
-	struct list_head timestamps;
-	spinlock_t ts_spinlock; /* timestamp list lock */
-
-	u64 last_irq_jiffies;
-	u32 last_offset;
-	u32 wrap_count;
-	u32 fw_idx_to_vb2_idx[32];
-
-	enum amvdec_status status;
-	void *priv;
-};
-
-static inline struct amvdec_session *file_to_amvdec_session(struct file *filp)
-{
-	return container_of(file_to_v4l2_fh(filp), struct amvdec_session, fh);
-}
-
-u32 amvdec_get_output_size(struct amvdec_session *sess);
-
-#endif
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_CORE_H_
+#define __MESON_VDEC_CORE_H_
+
+#include <linux/irqreturn.h>
+#include <linux/regmap.h>
+#include <linux/list.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <linux/soc/amlogic/meson-canvas.h>
+
+#include "vdec_platform.h"
+
+/* 32 buffers in 3-plane YUV420 */
+#define MAX_CANVAS (32 * 3)
+
+struct amvdec_buffer {
+	struct list_head list;
+	struct vb2_buffer *vb;
+};
+
+/**
+ * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
+ *
+ * @list: used to make lists out of this struct
+ * @tc: timecode from the v4l2 buffer
+ * @ts: timestamp from the VB2 buffer
+ * @offset: offset in the VIFIFO where the associated packet was written
+ * @flags: flags from the v4l2 buffer
+ * @used_count: times this timestamp was checked for a match with a dst buffer
+ */
+struct amvdec_timestamp {
+	struct list_head list;
+	struct v4l2_timecode tc;
+	u64 ts;
+	u32 offset;
+	u32 flags;
+	u32 used_count;
+};
+
+struct amvdec_session;
+
+/**
+ * struct amvdec_core - device parameters, singleton
+ *
+ * @dos_base: DOS memory base address
+ * @esparser_base: PARSER memory base address
+ * @regmap_ao: regmap for the AO bus
+ * @dev: core device
+ * @dev_dec: decoder device
+ * @platform: platform-specific data
+ * @canvas: canvas provider reference
+ * @dos_parser_clk: DOS_PARSER clock
+ * @dos_clk: DOS clock
+ * @vdec_1_clk: VDEC_1 clock
+ * @vdec_hevc_clk: VDEC_HEVC clock
+ * @vdec_hevcf_clk: VDEC_HEVCF clock
+ * @esparser_reset: RESET for the PARSER
+ * @vdev_dec: video device for the decoder
+ * @v4l2_dev: v4l2 device
+ * @m2m_dev: v4l2 m2m device
+ * @cur_sess: current decoding session
+ * @lock: video device lock
+ * @irq: decoder irq
+ */
+struct amvdec_core {
+	void __iomem *dos_base;
+	void __iomem *esparser_base;
+	struct regmap *regmap_ao;
+
+	struct device *dev;
+	struct device *dev_dec;
+	const struct vdec_platform *platform;
+
+	struct meson_canvas *canvas;
+
+	struct clk *dos_parser_clk;
+	struct clk *dos_clk;
+	struct clk *vdec_1_clk;
+	struct clk *vdec_hevc_clk;
+	struct clk *vdec_hevcf_clk;
+
+	struct reset_control *esparser_reset;
+
+	struct video_device *vdev_dec;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+
+	struct amvdec_session *cur_sess;
+	struct mutex lock;
+	int irq;
+};
+
+/**
+ * struct amvdec_ops - vdec operations
+ *
+ * @start: mandatory call when the vdec needs to initialize
+ * @stop: mandatory call when the vdec needs to stop
+ * @conf_esparser: mandatory call to let the vdec configure the ESPARSER
+ * @vififo_level: mandatory call to get the current amount of data
+ *		  in the VIFIFO
+ */
+struct amvdec_ops {
+	int (*start)(struct amvdec_session *sess);
+	int (*stop)(struct amvdec_session *sess);
+	void (*conf_esparser)(struct amvdec_session *sess);
+	u32 (*vififo_level)(struct amvdec_session *sess);
+};
+
+/**
+ * struct amvdec_codec_ops - codec operations
+ *
+ * @start: mandatory call when the codec needs to initialize
+ * @stop: mandatory call when the codec needs to stop
+ * @load_extended_firmware: optional call to load additional firmware bits
+ * @num_pending_bufs: optional call to get the number of dst buffers on hold
+ * @can_recycle: optional call to know if the codec is ready to recycle
+ *		 a dst buffer
+ * @recycle: optional call to tell the codec to recycle a dst buffer. Must go
+ *	     in pair with @can_recycle
+ * @drain: optional call if the codec has a custom way of draining
+ * @resume: optional call to resume after a resolution change
+ * @eos_sequence: optional call to get an end sequence to send to esparser
+ *		  for flush. Mutually exclusive with @drain.
+ * @isr: mandatory call when the ISR triggers
+ * @threaded_isr: mandatory call for the threaded ISR
+ */
+struct amvdec_codec_ops {
+	int (*start)(struct amvdec_session *sess);
+	int (*stop)(struct amvdec_session *sess);
+	int (*load_extended_firmware)(struct amvdec_session *sess,
+				      const u8 *data, u32 len);
+	u32 (*num_pending_bufs)(struct amvdec_session *sess);
+	int (*can_recycle)(struct amvdec_core *core);
+	void (*recycle)(struct amvdec_core *core, u32 buf_idx);
+	void (*drain)(struct amvdec_session *sess);
+	void (*resume)(struct amvdec_session *sess);
+	const u8 * (*eos_sequence)(u32 *len);
+	irqreturn_t (*isr)(struct amvdec_session *sess);
+	irqreturn_t (*threaded_isr)(struct amvdec_session *sess);
+};
+
+/**
+ * struct amvdec_format - describes one of the OUTPUT (src) format supported
+ *
+ * @pixfmt: V4L2 pixel format
+ * @min_buffers: minimum amount of CAPTURE (dst) buffers
+ * @max_buffers: maximum amount of CAPTURE (dst) buffers
+ * @max_width: maximum picture width supported
+ * @max_height: maximum picture height supported
+ * @flags: enum flags associated with this pixfmt
+ * @vdec_ops: the VDEC operations that support this format
+ * @codec_ops: the codec operations that support this format
+ * @firmware_path: Path to the firmware that supports this format
+ * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt
+ */
+struct amvdec_format {
+	u32 pixfmt;
+	u32 min_buffers;
+	u32 max_buffers;
+	u32 max_width;
+	u32 max_height;
+	u32 flags;
+
+	struct amvdec_ops *vdec_ops;
+	struct amvdec_codec_ops *codec_ops;
+
+	char *firmware_path;
+	u32 pixfmts_cap[4];
+};
+
+enum amvdec_status {
+	STATUS_STOPPED,
+	STATUS_INIT,
+	STATUS_RUNNING,
+	STATUS_NEEDS_RESUME,
+};
+
+/**
+ * struct amvdec_session - decoding session parameters
+ *
+ * @core: reference to the vdec core struct
+ * @fh: v4l2 file handle
+ * @m2m_ctx: v4l2 m2m context
+ * @ctrl_handler: V4L2 control handler
+ * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+ * @lock: cap & out queues lock
+ * @fmt_out: vdec pixel format for the OUTPUT queue
+ * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
+ * @src_buffer_size: size in bytes of the OUTPUT buffers' only plane
+ * @width: current picture width
+ * @height: current picture height
+ * @colorspace: current colorspace
+ * @ycbcr_enc: current ycbcr_enc
+ * @quantization: current quantization
+ * @xfer_func: current transfer function
+ * @pixelaspect: Pixel Aspect Ratio reported by the decoder
+ * @esparser_queued_bufs: number of buffers currently queued into ESPARSER
+ * @esparser_queue_work: work struct for the ESPARSER to process src buffers
+ * @streamon_cap: stream on flag for capture queue
+ * @streamon_out: stream on flag for output queue
+ * @sequence_cap: capture sequence counter
+ * @sequence_out: output sequence counter
+ * @should_stop: flag set if userspace signaled EOS via command
+ *		 or empty buffer
+ * @keyframe_found: flag set once a keyframe has been parsed
+ * @num_dst_bufs: number of destination buffers
+ * @changed_format: the format changed
+ * @canvas_alloc: array of all the canvas IDs allocated
+ * @canvas_num: number of canvas IDs allocated
+ * @vififo_vaddr: virtual address for the VIFIFO
+ * @vififo_paddr: physical address for the VIFIFO
+ * @vififo_size: size of the VIFIFO dma alloc
+ * @bufs_recycle: list of buffers that need to be recycled
+ * @bufs_recycle_lock: lock for the bufs_recycle list
+ * @recycle_thread: task struct for the recycling thread
+ * @timestamps: chronological list of src timestamps
+ * @ts_spinlock: spinlock for the timestamps list
+ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ
+ * @last_offset: tracks last offset of vififo
+ * @wrap_count: number of times the vififo wrapped around
+ * @fw_idx_to_vb2_idx: firmware buffer index to vb2 buffer index
+ * @status: current decoding status
+ * @priv: codec private data
+ */
+struct amvdec_session {
+	struct amvdec_core *core;
+
+	struct v4l2_fh fh;
+	struct v4l2_m2m_ctx *m2m_ctx;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl *ctrl_min_buf_capture;
+	struct mutex lock;
+
+	const struct amvdec_format *fmt_out;
+	u32 pixfmt_cap;
+	u32 src_buffer_size;
+
+	u32 width;
+	u32 height;
+	u32 colorspace;
+	u8 ycbcr_enc;
+	u8 quantization;
+	u8 xfer_func;
+
+	struct v4l2_fract pixelaspect;
+
+	atomic_t esparser_queued_bufs;
+	struct work_struct esparser_queue_work;
+
+	unsigned int streamon_cap, streamon_out;
+	unsigned int sequence_cap, sequence_out;
+	unsigned int should_stop;
+	unsigned int keyframe_found;
+	unsigned int num_dst_bufs;
+	unsigned int changed_format;
+
+	u8 canvas_alloc[MAX_CANVAS];
+	u32 canvas_num;
+
+	void *vififo_vaddr;
+	dma_addr_t vififo_paddr;
+	u32 vififo_size;
+
+	struct list_head bufs_recycle;
+	struct mutex bufs_recycle_lock; /* bufs_recycle list lock */
+	struct task_struct *recycle_thread;
+
+	struct list_head timestamps;
+	spinlock_t ts_spinlock; /* timestamp list lock */
+
+	u64 last_irq_jiffies;
+	u32 last_offset;
+	u32 wrap_count;
+	u32 fw_idx_to_vb2_idx[32];
+
+	enum amvdec_status status;
+	void *priv;
+};
+
+static inline struct amvdec_session *file_to_amvdec_session(struct file *filp)
+{
+	return container_of(file_to_v4l2_fh(filp), struct amvdec_session, fh);
+}
+
+u32 amvdec_get_output_size(struct amvdec_session *sess);
+
+#endif
-- 
2.54.0.windows.1


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-14 14:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 18:16 [PATCH v2] staging: media: meson: vdec: fix advanced concurrency and UAF bugs Alfie Varghese
2026-07-13 18:33 ` sashiko-bot
2026-07-13 19:37 ` Ferass El Hafidi
2026-07-14  7:15 ` Dan Carpenter
2026-07-14 13:59 ` kernel test robot
2026-07-14 14:23 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox