[PATCH v2] staging: media: meson: vdec: fix advanced concurrency and UAF bugs
Ferass El Hafidi
funderscore at postmarketos.org
Mon Jul 13 12:37:21 PDT 2026
On Mon, 13 Jul 2026 18:16, Alfie Varghese <alfievarghese22 at gmail.com> wrote:
>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 at 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);
> }
>
It probably would be better to split into multiple commits to make
it easier for maintainers to review your patch.
>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 at 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 at 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
What is this huge diff?
>--
>2.54.0.windows.1
>
>
>_______________________________________________
>linux-amlogic mailing list
>linux-amlogic at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-amlogic
Best regards,
Ferass
More information about the linux-amlogic
mailing list