aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch
diff options
context:
space:
mode:
authorÁlvaro Fernández Rojas <noltari@gmail.com>2022-05-16 23:40:32 +0200
committerÁlvaro Fernández Rojas <noltari@gmail.com>2022-05-17 15:11:22 +0200
commit20ea6adbf199097c4f5f591ffee088340630dae4 (patch)
treed6719d95e136611a1c25bbf7789652d6d402779d /target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch
parentbca05bd072180dc38ef740b37ded9572a6db1981 (diff)
downloadupstream-20ea6adbf199097c4f5f591ffee088340630dae4.tar.gz
upstream-20ea6adbf199097c4f5f591ffee088340630dae4.tar.bz2
upstream-20ea6adbf199097c4f5f591ffee088340630dae4.zip
bcm27xx: add support for linux v5.15
Build system: x86_64 Build-tested: bcm2708, bcm2709, bcm2710, bcm2711 Run-tested: bcm2708/RPiB+, bcm2709/RPi3B, bcm2710/RPi3B, bcm2711/RPi4B Signed-off-by: Marty Jones <mj8263788@gmail.com> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch b/target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch
new file mode 100644
index 0000000000..064ebaf2e4
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.15/950-0397-media-rpivid-Add-a-Pass0-to-accumulate-slices-and-re.patch
@@ -0,0 +1,1049 @@
+From 006d6d95a003be26df5b34be959f29725ded0bb6 Mon Sep 17 00:00:00 2001
+From: John Cox <jc@kynesim.co.uk>
+Date: Thu, 11 Mar 2021 19:08:00 +0000
+Subject: [PATCH] media: rpivid: Add a Pass0 to accumulate slices and
+ rework job finish
+
+Due to overheads in assembling controls and requests it is worth having
+the slice assembly phase separate from the h/w pass1 processing. Create
+a queue to service pass1 rather than have the pass1 finished callback
+trigger the next slice job.
+
+This requires a rework of the logic that splits up the buffer and
+request done events. This code contains two ways of doing that, we use
+Ezequiel Garcias <ezequiel@collabora.com> solution, but expect that
+in the future this will be handled by the framework in a cleaner manner.
+
+Fix up the handling of some of the memory exhaustion crashes uncovered
+in the process of writing this code.
+
+Signed-off-by: John Cox <jc@kynesim.co.uk>
+---
+ drivers/media/v4l2-core/v4l2-mem2mem.c | 2 -
+ drivers/staging/media/rpivid/rpivid.c | 11 +-
+ drivers/staging/media/rpivid/rpivid.h | 20 +-
+ drivers/staging/media/rpivid/rpivid_dec.c | 32 +-
+ drivers/staging/media/rpivid/rpivid_h265.c | 432 ++++++++++++++++-----
+ drivers/staging/media/rpivid/rpivid_hw.c | 8 +-
+ 6 files changed, 374 insertions(+), 131 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
++++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
+@@ -492,8 +492,6 @@ void v4l2_m2m_job_finish(struct v4l2_m2m
+ * holding capture buffers. Those should use
+ * v4l2_m2m_buf_done_and_job_finish() instead.
+ */
+- WARN_ON(m2m_ctx->out_q_ctx.q.subsystem_flags &
+- VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF);
+ spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+ schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx);
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+--- a/drivers/staging/media/rpivid/rpivid.c
++++ b/drivers/staging/media/rpivid/rpivid.c
+@@ -79,17 +79,24 @@ static const struct rpivid_control rpivi
+
+ #define rpivid_ctrls_COUNT ARRAY_SIZE(rpivid_ctrls)
+
+-void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id)
++struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id)
+ {
+ unsigned int i;
+
+ for (i = 0; ctx->ctrls[i]; i++)
+ if (ctx->ctrls[i]->id == id)
+- return ctx->ctrls[i]->p_cur.p;
++ return ctx->ctrls[i];
+
+ return NULL;
+ }
+
++void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id)
++{
++ struct v4l2_ctrl *const ctrl = rpivid_find_ctrl(ctx, id);
++
++ return !ctrl ? NULL : ctrl->p_cur.p;
++}
++
+ static int rpivid_init_ctrls(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
+ {
+ struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+--- a/drivers/staging/media/rpivid/rpivid.h
++++ b/drivers/staging/media/rpivid/rpivid.h
+@@ -24,6 +24,10 @@
+
+ #define OPT_DEBUG_POLL_IRQ 0
+
++#define RPIVID_DEC_ENV_COUNT 6
++#define RPIVID_P1BUF_COUNT 3
++#define RPIVID_P2BUF_COUNT 3
++
+ #define RPIVID_NAME "rpivid"
+
+ #define RPIVID_CAPABILITY_UNTILED BIT(0)
+@@ -45,6 +49,7 @@ struct rpivid_control {
+ };
+
+ struct rpivid_h265_run {
++ u32 slice_ents;
+ const struct v4l2_ctrl_hevc_sps *sps;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ const struct v4l2_ctrl_hevc_slice_params *slice_params;
+@@ -64,7 +69,6 @@ struct rpivid_buffer {
+
+ struct rpivid_dec_state;
+ struct rpivid_dec_env;
+-#define RPIVID_DEC_ENV_COUNT 3
+
+ struct rpivid_gptr {
+ size_t size;
+@@ -79,7 +83,6 @@ typedef void (*rpivid_irq_callback)(stru
+ struct rpivid_q_aux;
+ #define RPIVID_AUX_ENT_COUNT VB2_MAX_FRAME
+
+-#define RPIVID_P2BUF_COUNT 2
+
+ struct rpivid_ctx {
+ struct v4l2_fh fh;
+@@ -108,11 +111,13 @@ struct rpivid_ctx {
+
+ struct rpivid_dec_env *dec_pool;
+
+- /* Some of these should be in dev */
+- struct rpivid_gptr bitbufs[1]; /* Will be 2 */
+- struct rpivid_gptr cmdbufs[1]; /* Will be 2 */
++ unsigned int p1idx;
++ atomic_t p1out;
++ struct rpivid_gptr bitbufs[RPIVID_P1BUF_COUNT];
++ struct rpivid_gptr cmdbufs[RPIVID_P1BUF_COUNT];
++
++ /* *** Should be in dev *** */
+ unsigned int p2idx;
+- atomic_t p2out;
+ struct rpivid_gptr pu_bufs[RPIVID_P2BUF_COUNT];
+ struct rpivid_gptr coeff_bufs[RPIVID_P2BUF_COUNT];
+
+@@ -141,6 +146,8 @@ struct rpivid_variant {
+
+ struct rpivid_hw_irq_ent;
+
++#define RPIVID_ICTL_ENABLE_UNLIMITED (-1)
++
+ struct rpivid_hw_irq_ctrl {
+ /* Spinlock protecting claim and tail */
+ spinlock_t lock;
+@@ -182,6 +189,7 @@ struct rpivid_dev {
+
+ extern struct rpivid_dec_ops rpivid_dec_ops_h265;
+
++struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id);
+ void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id);
+
+ #endif
+--- a/drivers/staging/media/rpivid/rpivid_dec.c
++++ b/drivers/staging/media/rpivid/rpivid_dec.c
+@@ -21,8 +21,8 @@
+
+ void rpivid_device_run(void *priv)
+ {
+- struct rpivid_ctx *ctx = priv;
+- struct rpivid_dev *dev = ctx->dev;
++ struct rpivid_ctx *const ctx = priv;
++ struct rpivid_dev *const dev = ctx->dev;
+ struct rpivid_run run = {};
+ struct media_request *src_req;
+
+@@ -32,19 +32,17 @@ void rpivid_device_run(void *priv)
+ if (!run.src || !run.dst) {
+ v4l2_err(&dev->v4l2_dev, "%s: Missing buffer: src=%p, dst=%p\n",
+ __func__, run.src, run.dst);
+- /* We are stuffed - this probably won't dig us out of our
+- * current situation but it is better than nothing
+- */
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_ERROR);
+- return;
++ goto fail;
+ }
+
+- /* Apply request(s) controls if needed. */
++ /* Apply request(s) controls */
+ src_req = run.src->vb2_buf.req_obj.req;
++ if (!src_req) {
++ v4l2_err(&dev->v4l2_dev, "%s: Missing request\n", __func__);
++ goto fail;
++ }
+
+- if (src_req)
+- v4l2_ctrl_request_setup(src_req, &ctx->hdl);
++ v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_HEVC_SLICE:
+@@ -70,10 +68,14 @@ void rpivid_device_run(void *priv)
+
+ dev->dec_ops->setup(ctx, &run);
+
+- /* Complete request(s) controls if needed. */
+-
+- if (src_req)
+- v4l2_ctrl_request_complete(src_req, &ctx->hdl);
++ /* Complete request(s) controls */
++ v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
+ dev->dec_ops->trigger(ctx);
++ return;
++
++fail:
++ /* We really shouldn't get here but tidy up what we can */
++ v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
++ VB2_BUF_STATE_ERROR);
+ }
+--- a/drivers/staging/media/rpivid/rpivid_h265.c
++++ b/drivers/staging/media/rpivid/rpivid_h265.c
+@@ -22,6 +22,8 @@
+ #define DEBUG_TRACE_P1_CMD 0
+ #define DEBUG_TRACE_EXECUTION 0
+
++#define USE_REQUEST_PIN 1
++
+ #if DEBUG_TRACE_EXECUTION
+ #define xtrace_in(dev_, de_)\
+ v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: in\n", __func__,\
+@@ -192,8 +194,6 @@ struct rpivid_dec_env {
+ unsigned int decode_order;
+ int p1_status; /* P1 status - what to realloc */
+
+- struct rpivid_dec_env *phase_wait_q_next;
+-
+ struct rpi_cmd *cmd_fifo;
+ unsigned int cmd_len, cmd_max;
+ unsigned int num_slice_msgs;
+@@ -219,6 +219,7 @@ struct rpivid_dec_env {
+ u32 rpi_currpoc;
+
+ struct vb2_v4l2_buffer *frame_buf; // Detached dest buffer
++ struct vb2_v4l2_buffer *src_buf; // Detached src buffer
+ unsigned int frame_c_offset;
+ unsigned int frame_stride;
+ dma_addr_t frame_addr;
+@@ -235,9 +236,15 @@ struct rpivid_dec_env {
+ size_t bit_copy_len;
+ struct rpivid_gptr *cmd_copy_gptr;
+
+- u16 slice_msgs[2 * HEVC_MAX_REFS * 8 + 3];
++#define SLICE_MSGS_MAX (2 * HEVC_MAX_REFS * 8 + 3)
++ u16 slice_msgs[SLICE_MSGS_MAX];
+ u8 scaling_factors[NUM_SCALING_FACTORS];
+
++#if USE_REQUEST_PIN
++ struct media_request *req_pin;
++#else
++ struct media_request_object *req_obj;
++#endif
+ struct rpivid_hw_irq_ent irq_ent;
+ };
+
+@@ -286,6 +293,17 @@ struct rpivid_dec_state {
+ unsigned int prev_ctb_y;
+ };
+
++#if !USE_REQUEST_PIN
++static void dst_req_obj_release(struct media_request_object *object)
++{
++ kfree(object);
++}
++
++static const struct media_request_object_ops dst_req_obj_ops = {
++ .release = dst_req_obj_release,
++};
++#endif
++
+ static inline int clip_int(const int x, const int lo, const int hi)
+ {
+ return x < lo ? lo : x > hi ? hi : x;
+@@ -298,15 +316,48 @@ static inline int clip_int(const int x,
+ static int p1_z;
+ #endif
+
++static int cmds_check_space(struct rpivid_dec_env *const de, unsigned int n)
++{
++ struct rpi_cmd *a;
++ unsigned int newmax;
++
++ if (n > 0x100000) {
++ v4l2_err(&de->ctx->dev->v4l2_dev,
++ "%s: n %u implausible\n", __func__, n);
++ return -ENOMEM;
++ }
++
++ if (de->cmd_len + n <= de->cmd_max)
++ return 0;
++
++ newmax = 2 << log2_size(de->cmd_len + n);
++
++ a = krealloc(de->cmd_fifo, newmax * sizeof(struct rpi_cmd),
++ GFP_KERNEL);
++ if (!a) {
++ v4l2_err(&de->ctx->dev->v4l2_dev,
++ "Failed cmd buffer realloc from %u to %u\n",
++ de->cmd_max, newmax);
++ return -ENOMEM;
++ }
++ v4l2_info(&de->ctx->dev->v4l2_dev,
++ "cmd buffer realloc from %u to %u\n", de->cmd_max, newmax);
++
++ de->cmd_fifo = a;
++ de->cmd_max = newmax;
++ return 0;
++}
++
+ // ???? u16 addr - put in u32
+-static int p1_apb_write(struct rpivid_dec_env *const de, const u16 addr,
+- const u32 data)
++static void p1_apb_write(struct rpivid_dec_env *const de, const u16 addr,
++ const u32 data)
+ {
+- if (de->cmd_len == de->cmd_max)
+- de->cmd_fifo =
+- krealloc(de->cmd_fifo,
+- (de->cmd_max *= 2) * sizeof(struct rpi_cmd),
+- GFP_KERNEL);
++ if (de->cmd_len >= de->cmd_max) {
++ v4l2_err(&de->ctx->dev->v4l2_dev,
++ "%s: Overflow @ %d\n", __func__, de->cmd_len);
++ return;
++ }
++
+ de->cmd_fifo[de->cmd_len].addr = addr;
+ de->cmd_fifo[de->cmd_len].data = data;
+
+@@ -316,8 +367,7 @@ static int p1_apb_write(struct rpivid_de
+ de->cmd_len, addr, data);
+ }
+ #endif
+-
+- return de->cmd_len++;
++ de->cmd_len++;
+ }
+
+ static int ctb_to_tile(unsigned int ctb, unsigned int *bd, int num)
+@@ -511,6 +561,7 @@ static const u8 prob_init[3][156] = {
+ },
+ };
+
++#define CMDS_WRITE_PROB ((RPI_PROB_ARRAY_SIZE / 4) + 1)
+ static void write_prob(struct rpivid_dec_env *const de,
+ const struct rpivid_dec_state *const s)
+ {
+@@ -554,6 +605,7 @@ static void write_prob(struct rpivid_dec
+ p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
+ }
+
++#define CMDS_WRITE_SCALING_FACTORS NUM_SCALING_FACTORS
+ static void write_scaling_factors(struct rpivid_dec_env *const de)
+ {
+ int i;
+@@ -569,8 +621,9 @@ static inline __u32 dma_to_axi_addr(dma_
+ return (__u32)(a >> 6);
+ }
+
+-static void write_bitstream(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s)
++#define CMDS_WRITE_BITSTREAM 4
++static int write_bitstream(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s)
+ {
+ // Note that FFmpeg V4L2 does not remove emulation prevention bytes,
+ // so this is matched in the configuration here.
+@@ -584,6 +637,13 @@ static void write_bitstream(struct rpivi
+ if (s->src_addr != 0) {
+ addr = s->src_addr + offset;
+ } else {
++ if (len + de->bit_copy_len > de->bit_copy_gptr->size) {
++ v4l2_warn(&de->ctx->dev->v4l2_dev,
++ "Bit copy buffer overflow: size=%zu, offset=%zu, len=%u\n",
++ de->bit_copy_gptr->size,
++ de->bit_copy_len, len);
++ return -ENOMEM;
++ }
+ memcpy(de->bit_copy_gptr->ptr + de->bit_copy_len,
+ s->src_buf + offset, len);
+ addr = de->bit_copy_gptr->addr + de->bit_copy_len;
+@@ -595,6 +655,7 @@ static void write_bitstream(struct rpivi
+ p1_apb_write(de, RPI_BFNUM, len);
+ p1_apb_write(de, RPI_BFCONTROL, offset + (1 << 7)); // Stop
+ p1_apb_write(de, RPI_BFCONTROL, offset + (rpi_use_emu << 6));
++ return 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+@@ -623,6 +684,7 @@ static u32 slice_reg_const(const struct
+
+ //////////////////////////////////////////////////////////////////////////////
+
++#define CMDS_NEW_SLICE_SEGMENT (4 + CMDS_WRITE_SCALING_FACTORS)
+ static void new_slice_segment(struct rpivid_dec_env *const de,
+ const struct rpivid_dec_state *const s)
+ {
+@@ -706,6 +768,7 @@ static void msg_slice(struct rpivid_dec_
+ de->slice_msgs[de->num_slice_msgs++] = msg;
+ }
+
++#define CMDS_PROGRAM_SLICECMDS (1 + SLICE_MSGS_MAX)
+ static void program_slicecmds(struct rpivid_dec_env *const de,
+ const int sliceid)
+ {
+@@ -902,6 +965,7 @@ static void pre_slice_decode(struct rpiv
+ (sh->slice_cb_qp_offset & 31)); // CMD_QPOFF
+ }
+
++#define CMDS_WRITE_SLICE 1
+ static void write_slice(struct rpivid_dec_env *const de,
+ const struct rpivid_dec_state *const s,
+ const u32 slice_const,
+@@ -927,6 +991,7 @@ static void write_slice(struct rpivid_de
+ * N.B. This can be called to fill in data from the previous slice so must not
+ * use any state data that may change from slice to slice (e.g. qp)
+ */
++#define CMDS_NEW_ENTRY_POINT (6 + CMDS_WRITE_SLICE)
+ static void new_entry_point(struct rpivid_dec_env *const de,
+ const struct rpivid_dec_state *const s,
+ const bool do_bte,
+@@ -977,6 +1042,7 @@ static void new_entry_point(struct rpivi
+ //////////////////////////////////////////////////////////////////////////////
+ // Wavefront mode
+
++#define CMDS_WPP_PAUSE 4
+ static void wpp_pause(struct rpivid_dec_env *const de, int ctb_row)
+ {
+ p1_apb_write(de, RPI_STATUS, (ctb_row << 18) | 0x25);
+@@ -987,12 +1053,19 @@ static void wpp_pause(struct rpivid_dec_
+ p1_apb_write(de, RPI_CONTROL, (ctb_row << 16) + 2);
+ }
+
+-static void wpp_entry_fill(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s,
+- const unsigned int last_y)
++#define CMDS_WPP_ENTRY_FILL_1 (CMDS_WPP_PAUSE + 2 + CMDS_NEW_ENTRY_POINT)
++static int wpp_entry_fill(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s,
++ const unsigned int last_y)
+ {
++ int rv;
+ const unsigned int last_x = s->ctb_width - 1;
+
++ rv = cmds_check_space(de, CMDS_WPP_ENTRY_FILL_1 *
++ (last_y - de->entry_ctb_y));
++ if (rv)
++ return rv;
++
+ while (de->entry_ctb_y < last_y) {
+ /* wpp_entry_x/y set by wpp_entry_point */
+ if (s->ctb_width > 2)
+@@ -1010,12 +1083,21 @@ static void wpp_entry_fill(struct rpivid
+ 0, 0, 0, de->entry_ctb_y + 1,
+ de->entry_qp, de->entry_slice);
+ }
++ return 0;
+ }
+
+-static void wpp_end_previous_slice(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s)
++static int wpp_end_previous_slice(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s)
+ {
+- wpp_entry_fill(de, s, s->prev_ctb_y);
++ int rv;
++
++ rv = wpp_entry_fill(de, s, s->prev_ctb_y);
++ if (rv)
++ return rv;
++
++ rv = cmds_check_space(de, CMDS_WPP_PAUSE + 2);
++ if (rv)
++ return rv;
+
+ if (de->entry_ctb_x < 2 &&
+ (de->entry_ctb_y < s->start_ctb_y || s->start_ctb_x > 2) &&
+@@ -1026,21 +1108,38 @@ static void wpp_end_previous_slice(struc
+ if (s->start_ctb_x == 2 ||
+ (s->ctb_width == 2 && de->entry_ctb_y < s->start_ctb_y))
+ p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP);
++ return 0;
+ }
+
+ /* Only main profile supported so WPP => !Tiles which makes some of the
+ * next chunk code simpler
+ */
+-static void wpp_decode_slice(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s)
++static int wpp_decode_slice(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s)
+ {
+ bool reset_qp_y = true;
+ const bool indep = !s->dependent_slice_segment_flag;
++ int rv;
+
+- if (s->start_ts)
+- wpp_end_previous_slice(de, s);
++ if (s->start_ts) {
++ rv = wpp_end_previous_slice(de, s);
++ if (rv)
++ return rv;
++ }
+ pre_slice_decode(de, s);
+- write_bitstream(de, s);
++
++ rv = cmds_check_space(de,
++ CMDS_WRITE_BITSTREAM +
++ CMDS_WRITE_PROB +
++ CMDS_PROGRAM_SLICECMDS +
++ CMDS_NEW_SLICE_SEGMENT +
++ CMDS_NEW_ENTRY_POINT);
++ if (rv)
++ return rv;
++
++ rv = write_bitstream(de, s);
++ if (rv)
++ return rv;
+
+ if (!s->start_ts || indep || s->ctb_width == 1)
+ write_prob(de, s);
+@@ -1056,7 +1155,13 @@ static void wpp_decode_slice(struct rpiv
+ s->slice_qp, slice_reg_const(s));
+
+ if (s->frame_end) {
+- wpp_entry_fill(de, s, s->ctb_height - 1);
++ rv = wpp_entry_fill(de, s, s->ctb_height - 1);
++ if (rv)
++ return rv;
++
++ rv = cmds_check_space(de, CMDS_WPP_PAUSE + 1);
++ if (rv)
++ return rv;
+
+ if (de->entry_ctb_x < 2 && s->ctb_width > 2)
+ wpp_pause(de, s->ctb_height - 1);
+@@ -1065,25 +1170,32 @@ static void wpp_decode_slice(struct rpiv
+ 1 | ((s->ctb_width - 1) << 5) |
+ ((s->ctb_height - 1) << 18));
+ }
+-
++ return 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Tiles mode
+
+-static void tile_entry_fill(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s,
+- const unsigned int last_tile_x,
+- const unsigned int last_tile_y)
++// Guarantees 1 cmd entry free on exit
++static int tile_entry_fill(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s,
++ const unsigned int last_tile_x,
++ const unsigned int last_tile_y)
+ {
+ while (de->entry_tile_y < last_tile_y ||
+ (de->entry_tile_y == last_tile_y &&
+ de->entry_tile_x < last_tile_x)) {
++ int rv;
+ unsigned int t_x = de->entry_tile_x;
+ unsigned int t_y = de->entry_tile_y;
+ const unsigned int last_x = s->col_bd[t_x + 1] - 1;
+ const unsigned int last_y = s->row_bd[t_y + 1] - 1;
+
++ // One more than needed here
++ rv = cmds_check_space(de, CMDS_NEW_ENTRY_POINT + 3);
++ if (rv)
++ return rv;
++
+ p1_apb_write(de, RPI_STATUS,
+ 2 | (last_x << 5) | (last_y << 18));
+ p1_apb_write(de, RPI_TRANSFER, PROB_RELOAD);
+@@ -1098,33 +1210,55 @@ static void tile_entry_fill(struct rpivi
+ t_x, t_y, s->col_bd[t_x], s->row_bd[t_y],
+ de->entry_qp, de->entry_slice);
+ }
++ return 0;
+ }
+
+ /*
+ * Write STATUS register with expected end CTU address of previous slice
+ */
+-static void end_previous_slice(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s)
++static int end_previous_slice(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s)
+ {
+- tile_entry_fill(de, s,
+- ctb_to_tile_x(s, s->prev_ctb_x),
+- ctb_to_tile_y(s, s->prev_ctb_y));
++ int rv;
++
++ rv = tile_entry_fill(de, s,
++ ctb_to_tile_x(s, s->prev_ctb_x),
++ ctb_to_tile_y(s, s->prev_ctb_y));
++ if (rv)
++ return rv;
++
+ p1_apb_write(de, RPI_STATUS,
+ 1 | (s->prev_ctb_x << 5) | (s->prev_ctb_y << 18));
++ return 0;
+ }
+
+-static void decode_slice(struct rpivid_dec_env *const de,
+- const struct rpivid_dec_state *const s)
++static int decode_slice(struct rpivid_dec_env *const de,
++ const struct rpivid_dec_state *const s)
+ {
+ bool reset_qp_y;
+ unsigned int tile_x = ctb_to_tile_x(s, s->start_ctb_x);
+ unsigned int tile_y = ctb_to_tile_y(s, s->start_ctb_y);
++ int rv;
+
+- if (s->start_ts)
+- end_previous_slice(de, s);
++ if (s->start_ts) {
++ rv = end_previous_slice(de, s);
++ if (rv)
++ return rv;
++ }
++
++ rv = cmds_check_space(de,
++ CMDS_WRITE_BITSTREAM +
++ CMDS_WRITE_PROB +
++ CMDS_PROGRAM_SLICECMDS +
++ CMDS_NEW_SLICE_SEGMENT +
++ CMDS_NEW_ENTRY_POINT);
++ if (rv)
++ return rv;
+
+ pre_slice_decode(de, s);
+- write_bitstream(de, s);
++ rv = write_bitstream(de, s);
++ if (rv)
++ return rv;
+
+ reset_qp_y = !s->start_ts ||
+ !s->dependent_slice_segment_flag ||
+@@ -1146,13 +1280,16 @@ static void decode_slice(struct rpivid_d
+ * when it will be known where this slice finishes
+ */
+ if (s->frame_end) {
+- tile_entry_fill(de, s,
+- s->tile_width - 1,
+- s->tile_height - 1);
++ rv = tile_entry_fill(de, s,
++ s->tile_width - 1,
++ s->tile_height - 1);
++ if (rv)
++ return rv;
+ p1_apb_write(de, RPI_STATUS,
+ 1 | ((s->ctb_width - 1) << 5) |
+ ((s->ctb_height - 1) << 18));
+ }
++ return 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+@@ -1524,7 +1661,7 @@ static void rpivid_h265_setup(struct rpi
+ struct rpivid_dev *const dev = ctx->dev;
+ const struct v4l2_ctrl_hevc_slice_params *const sh =
+ run->h265.slice_params;
+- const struct v4l2_hevc_pred_weight_table *pred_weight_table;
++// const struct v4l2_hevc_pred_weight_table *pred_weight_table;
+ struct rpivid_q_aux *dpb_q_aux[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+ struct rpivid_dec_state *const s = ctx->state;
+ struct vb2_queue *vq;
+@@ -1532,11 +1669,12 @@ static void rpivid_h265_setup(struct rpi
+ unsigned int prev_rs;
+ unsigned int i;
+ int use_aux;
++ int rv;
+ bool slice_temporal_mvp;
+
+ xtrace_in(dev, de);
+
+- pred_weight_table = &sh->pred_weight_table;
++// pred_weight_table = &sh->pred_weight_table;
+
+ s->frame_end =
+ ((run->src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) == 0);
+@@ -1608,9 +1746,9 @@ static void rpivid_h265_setup(struct rpi
+ de->cmd_len = 0;
+ de->dpbno_col = ~0U;
+
+- de->bit_copy_gptr = ctx->bitbufs + 0;
++ de->bit_copy_gptr = ctx->bitbufs + ctx->p1idx;
+ de->bit_copy_len = 0;
+- de->cmd_copy_gptr = ctx->cmdbufs + 0;
++ de->cmd_copy_gptr = ctx->cmdbufs + ctx->p1idx;
+
+ de->frame_c_offset = ctx->dst_fmt.height * 128;
+ de->frame_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128;
+@@ -1727,6 +1865,9 @@ static void rpivid_h265_setup(struct rpi
+ bits_alloc = wxh < 983040 ? wxh * 3 / 4 :
+ wxh < 983040 * 2 ? 983040 * 3 / 4 :
+ wxh * 3 / 8;
++ /* Allow for bit depth */
++ bits_alloc += (bits_alloc *
++ s->sps.bit_depth_luma_minus8) / 8;
+ bits_alloc = round_up_size(bits_alloc);
+
+ if (gptr_alloc(dev, de->bit_copy_gptr,
+@@ -1743,18 +1884,35 @@ static void rpivid_h265_setup(struct rpi
+ }
+ }
+
+- // Pre calc a few things
+- s->src_addr =
+- !s->frame_end ?
+- 0 :
+- vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
+- s->src_buf = s->src_addr != 0 ? NULL :
+- vb2_plane_vaddr(&run->src->vb2_buf, 0);
++ // Either map src buffer or use directly
++ s->src_addr = 0;
++ s->src_buf = NULL;
++
++ if (run->src->planes[0].bytesused < (sh->bit_size + 7) / 8) {
++ v4l2_warn(&dev->v4l2_dev,
++ "Bit size %d > bytesused %d\n",
++ sh->bit_size, run->src->planes[0].bytesused);
++ goto fail;
++ }
++ if (sh->data_bit_offset >= sh->bit_size ||
++ sh->bit_size - sh->data_bit_offset < 8) {
++ v4l2_warn(&dev->v4l2_dev,
++ "Bit size %d < Bit offset %d + 8\n",
++ sh->bit_size, sh->data_bit_offset);
++ goto fail;
++ }
++
++ if (s->frame_end)
++ s->src_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf,
++ 0);
++ if (!s->src_addr)
++ s->src_buf = vb2_plane_vaddr(&run->src->vb2_buf, 0);
+ if (!s->src_addr && !s->src_buf) {
+ v4l2_err(&dev->v4l2_dev, "Failed to map src buffer\n");
+ goto fail;
+ }
+
++ // Pre calc a few things
+ s->sh = sh;
+ s->slice_qp = 26 + s->pps.init_qp_minus26 + s->sh->slice_qp_delta;
+ s->max_num_merge_cand = sh->slice_type == HEVC_SLICE_I ?
+@@ -1785,9 +1943,11 @@ static void rpivid_h265_setup(struct rpi
+ s->prev_ctb_y = prev_rs / de->pic_width_in_ctbs_y;
+
+ if ((s->pps.flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED))
+- wpp_decode_slice(de, s);
++ rv = wpp_decode_slice(de, s);
+ else
+- decode_slice(de, s);
++ rv = decode_slice(de, s);
++ if (rv)
++ goto fail;
+
+ if (!s->frame_end) {
+ xtrace_ok(dev, de);
+@@ -1945,29 +2105,28 @@ static int check_status(const struct rpi
+ return -1;
+ }
+
+-static void cb_phase2(struct rpivid_dev *const dev, void *v)
++static void phase2_cb(struct rpivid_dev *const dev, void *v)
+ {
+ struct rpivid_dec_env *const de = v;
+- struct rpivid_ctx *const ctx = de->ctx;
+
+ xtrace_in(dev, de);
+
+- v4l2_m2m_cap_buf_return(dev->m2m_dev, ctx->fh.m2m_ctx, de->frame_buf,
+- VB2_BUF_STATE_DONE);
+- de->frame_buf = NULL;
++ /* Done with buffers - allow new P1 */
++ rpivid_hw_irq_active1_enable_claim(dev, 1);
+
+- /* Delete de before finish as finish might immediately trigger a reuse
+- * of de
+- */
+- dec_env_delete(de);
++ v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_DONE);
++ de->frame_buf = NULL;
+
+- if (atomic_add_return(-1, &ctx->p2out) >= RPIVID_P2BUF_COUNT - 1) {
+- xtrace_fin(dev, de);
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_DONE);
+- }
++#if USE_REQUEST_PIN
++ media_request_unpin(de->req_pin);
++ de->req_pin = NULL;
++#else
++ media_request_object_complete(de->req_obj);
++ de->req_obj = NULL;
++#endif
+
+ xtrace_ok(dev, de);
++ dec_env_delete(de);
+ }
+
+ static void phase2_claimed(struct rpivid_dev *const dev, void *v)
+@@ -2023,7 +2182,7 @@ static void phase2_claimed(struct rpivid
+ // de->ctx->colmvbuf.addr, de->ctx->colmvbuf.addr +
+ // de->ctx->colmvbuf.size);
+
+- rpivid_hw_irq_active2_irq(dev, &de->irq_ent, cb_phase2, de);
++ rpivid_hw_irq_active2_irq(dev, &de->irq_ent, phase2_cb, de);
+
+ apb_write_final(dev, RPI_NUMROWS, de->pic_height_in_ctbs_y);
+
+@@ -2032,6 +2191,39 @@ static void phase2_claimed(struct rpivid
+
+ static void phase1_claimed(struct rpivid_dev *const dev, void *v);
+
++// release any and all objects associated with de
++// and reenable phase 1 if required
++static void phase1_err_fin(struct rpivid_dev *const dev,
++ struct rpivid_ctx *const ctx,
++ struct rpivid_dec_env *const de)
++{
++ /* Return all detached buffers */
++ if (de->src_buf)
++ v4l2_m2m_buf_done(de->src_buf, VB2_BUF_STATE_ERROR);
++ de->src_buf = NULL;
++ if (de->frame_buf)
++ v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_ERROR);
++ de->frame_buf = NULL;
++#if USE_REQUEST_PIN
++ if (de->req_pin)
++ media_request_unpin(de->req_pin);
++ de->req_pin = NULL;
++#else
++ if (de->req_obj)
++ media_request_object_complete(de->req_obj);
++ de->req_obj = NULL;
++#endif
++
++ dec_env_delete(de);
++
++ /* Reenable phase 0 if we were blocking */
++ if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1)
++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
++
++ /* Done with P1-P2 buffers - allow new P1 */
++ rpivid_hw_irq_active1_enable_claim(dev, 1);
++}
++
+ static void phase1_thread(struct rpivid_dev *const dev, void *v)
+ {
+ struct rpivid_dec_env *const de = v;
+@@ -2076,15 +2268,12 @@ fail:
+ __func__);
+ ctx->fatal_err = 1;
+ }
+- dec_env_delete(de);
+- xtrace_fin(dev, de);
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_ERROR);
+ xtrace_fail(dev, de);
++ phase1_err_fin(dev, ctx, de);
+ }
+
+ /* Always called in irq context (this is good) */
+-static void cb_phase1(struct rpivid_dev *const dev, void *v)
++static void phase1_cb(struct rpivid_dev *const dev, void *v)
+ {
+ struct rpivid_dec_env *const de = v;
+ struct rpivid_ctx *const ctx = de->ctx;
+@@ -2092,6 +2281,7 @@ static void cb_phase1(struct rpivid_dev
+ xtrace_in(dev, de);
+
+ de->p1_status = check_status(dev);
++
+ if (de->p1_status != 0) {
+ v4l2_info(&dev->v4l2_dev, "%s: Post wait: %#x\n",
+ __func__, de->p1_status);
+@@ -2105,24 +2295,17 @@ static void cb_phase1(struct rpivid_dev
+ return;
+ }
+
+- /* After the frame-buf is detached it must be returned but from
+- * this point onward (phase2_claimed, cb_phase2) there are no error
+- * paths so the return at the end of cb_phase2 is all that is needed
+- */
+- de->frame_buf = v4l2_m2m_cap_buf_detach(dev->m2m_dev, ctx->fh.m2m_ctx);
+- if (!de->frame_buf) {
+- v4l2_err(&dev->v4l2_dev, "%s: No detached buffer\n", __func__);
+- goto fail;
+- }
++ v4l2_m2m_buf_done(de->src_buf, VB2_BUF_STATE_DONE);
++ de->src_buf = NULL;
+
++ /* All phase1 error paths done - it is safe to inc p2idx */
+ ctx->p2idx =
+ (ctx->p2idx + 1 >= RPIVID_P2BUF_COUNT) ? 0 : ctx->p2idx + 1;
+
+- // Enable the next setup if our Q isn't too big
+- if (atomic_add_return(1, &ctx->p2out) < RPIVID_P2BUF_COUNT) {
++ /* Renable the next setup if we were blocking */
++ if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1) {
+ xtrace_fin(dev, de);
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_DONE);
++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
+ }
+
+ rpivid_hw_irq_active2_claim(dev, &de->irq_ent, phase2_claimed, de);
+@@ -2131,11 +2314,8 @@ static void cb_phase1(struct rpivid_dev
+ return;
+
+ fail:
+- dec_env_delete(de);
+- xtrace_fin(dev, de);
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_ERROR);
+ xtrace_fail(dev, de);
++ phase1_err_fin(dev, ctx, de);
+ }
+
+ static void phase1_claimed(struct rpivid_dev *const dev, void *v)
+@@ -2160,6 +2340,10 @@ static void phase1_claimed(struct rpivid
+ de->coeff_stride =
+ ALIGN_DOWN(coeff_gptr->size / de->pic_height_in_ctbs_y, 64);
+
++ /* phase1_claimed blocked until cb_phase1 completed so p2idx inc
++ * in cb_phase1 after error detection
++ */
++
+ apb_write_vc_addr(dev, RPI_PUWBASE, de->pu_base_vc);
+ apb_write_vc_len(dev, RPI_PUWSTRIDE, de->pu_stride);
+ apb_write_vc_addr(dev, RPI_COEFFWBASE, de->coeff_base_vc);
+@@ -2169,7 +2353,7 @@ static void phase1_claimed(struct rpivid
+ apb_write(dev, RPI_CFNUM, de->cmd_len);
+
+ // Claim irq
+- rpivid_hw_irq_active1_irq(dev, &de->irq_ent, cb_phase1, de);
++ rpivid_hw_irq_active1_irq(dev, &de->irq_ent, phase1_cb, de);
+
+ // And start the h/w
+ apb_write_vc_addr_final(dev, RPI_CFBASE, de->cmd_copy_gptr->addr);
+@@ -2178,11 +2362,8 @@ static void phase1_claimed(struct rpivid
+ return;
+
+ fail:
+- dec_env_delete(de);
+- xtrace_fin(dev, de);
+- v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+- VB2_BUF_STATE_ERROR);
+ xtrace_fail(dev, de);
++ phase1_err_fin(dev, ctx, de);
+ }
+
+ static void dec_state_delete(struct rpivid_ctx *const ctx)
+@@ -2315,7 +2496,9 @@ static void rpivid_h265_trigger(struct r
+ case RPIVID_DECODE_SLICE_CONTINUE:
+ v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+ VB2_BUF_STATE_DONE);
++ xtrace_ok(dev, de);
+ break;
++
+ default:
+ v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", __func__,
+ de->state);
+@@ -2329,14 +2512,59 @@ static void rpivid_h265_trigger(struct r
+ v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx,
+ VB2_BUF_STATE_ERROR);
+ break;
++
+ case RPIVID_DECODE_PHASE1:
+ ctx->dec0 = NULL;
++
++#if !USE_REQUEST_PIN
++ /* Alloc a new request object - needs to be alloced dynamically
++ * as the media request will release it some random time after
++ * it is completed
++ */
++ de->req_obj = kmalloc(sizeof(*de->req_obj), GFP_KERNEL);
++ if (!de->req_obj) {
++ xtrace_fail(dev, de);
++ dec_env_delete(de);
++ v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev,
++ ctx->fh.m2m_ctx,
++ VB2_BUF_STATE_ERROR);
++ break;
++ }
++ media_request_object_init(de->req_obj);
++#warning probably needs to _get the req obj too
++#endif
++ ctx->p1idx = (ctx->p1idx + 1 >= RPIVID_P1BUF_COUNT) ?
++ 0 : ctx->p1idx + 1;
++
++ /* We know we have src & dst so no need to test */
++ de->src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
++ de->frame_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
++
++#if USE_REQUEST_PIN
++ de->req_pin = de->src_buf->vb2_buf.req_obj.req;
++ media_request_pin(de->req_pin);
++#else
++ media_request_object_bind(de->src_buf->vb2_buf.req_obj.req,
++ &dst_req_obj_ops, de, false,
++ de->req_obj);
++#endif
++
++ /* We could get rid of the src buffer here if we've already
++ * copied it, but we don't copy the last buffer unless it
++ * didn't return a contig dma addr and that shouldn't happen
++ */
++
++ /* Enable the next setup if our Q isn't too big */
++ if (atomic_add_return(1, &ctx->p1out) < RPIVID_P1BUF_COUNT) {
++ xtrace_fin(dev, de);
++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
++ }
++
+ rpivid_hw_irq_active1_claim(dev, &de->irq_ent, phase1_claimed,
+ de);
++ xtrace_ok(dev, de);
+ break;
+ }
+-
+- xtrace_ok(dev, de);
+ }
+
+ struct rpivid_dec_ops rpivid_dec_ops_h265 = {
+--- a/drivers/staging/media/rpivid/rpivid_hw.c
++++ b/drivers/staging/media/rpivid/rpivid_hw.c
+@@ -185,14 +185,14 @@ static void do_enable_claim(struct rpivi
+ sched_cb(dev, ictl, ient);
+ }
+
+-static void ictl_init(struct rpivid_hw_irq_ctrl * const ictl)
++static void ictl_init(struct rpivid_hw_irq_ctrl * const ictl, int enables)
+ {
+ spin_lock_init(&ictl->lock);
+ ictl->claim = NULL;
+ ictl->tail = NULL;
+ ictl->irq = NULL;
+ ictl->no_sched = 0;
+- ictl->enable = -1;
++ ictl->enable = enables;
+ ictl->thread_reqed = false;
+ }
+
+@@ -308,8 +308,8 @@ int rpivid_hw_probe(struct rpivid_dev *d
+ int irq_dec;
+ int ret = 0;
+
+- ictl_init(&dev->ic_active1);
+- ictl_init(&dev->ic_active2);
++ ictl_init(&dev->ic_active1, RPIVID_P2BUF_COUNT);
++ ictl_init(&dev->ic_active2, RPIVID_ICTL_ENABLE_UNLIMITED);
+
+ res = platform_get_resource_byname(dev->pdev, IORESOURCE_MEM, "intc");
+ if (!res)