diff --git a/projects/Allwinner/patches/linux/0021-media-cedrus-hevc-Improve-buffer-management.patch b/projects/Allwinner/patches/linux/0021-media-cedrus-hevc-Improve-buffer-management.patch index bf630474b7..3d13ce4333 100644 --- a/projects/Allwinner/patches/linux/0021-media-cedrus-hevc-Improve-buffer-management.patch +++ b/projects/Allwinner/patches/linux/0021-media-cedrus-hevc-Improve-buffer-management.patch @@ -1,17 +1,19 @@ -From d4ffac11f0d8b3a844f528e963b953a6bfe540af Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 9 Nov 2019 13:22:05 +0100 -Subject: [PATCH 29/44] media: cedrus: hevc: Improve buffer management +Subject: [PATCH] media: cedrus: hevc: Improve buffer management Signed-off-by: Jernej Skrabec --- drivers/staging/media/sunxi/cedrus/cedrus.h | 9 +- - .../staging/media/sunxi/cedrus/cedrus_h265.c | 117 ++++++++++-------- - 2 files changed, 69 insertions(+), 57 deletions(-) + .../staging/media/sunxi/cedrus/cedrus_h265.c | 119 ++++++++++-------- + 2 files changed, 69 insertions(+), 59 deletions(-) +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h +index ab7653c8915e..54a860ec738d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h -@@ -105,6 +105,11 @@ struct cedrus_buffer { +@@ -106,6 +106,11 @@ struct cedrus_buffer { unsigned int position; enum cedrus_h264_pic_type pic_type; } h264; @@ -23,7 +25,7 @@ Signed-off-by: Jernej Skrabec } codec; }; -@@ -138,10 +143,6 @@ struct cedrus_ctx { +@@ -139,10 +144,6 @@ struct cedrus_ctx { ssize_t intra_pred_buf_size; } h264; struct { @@ -34,9 +36,11 @@ Signed-off-by: Jernej Skrabec void *neighbor_info_buf; dma_addr_t neighbor_info_buf_addr; void *entry_points_buf; +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +index 4b01d3881214..4d425196d415 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -@@ -91,26 +91,66 @@ static void cedrus_h265_sram_write_data( +@@ -91,26 +91,65 @@ static void cedrus_h265_sram_write_data(struct cedrus_dev *dev, void *data, static inline dma_addr_t cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx, @@ -62,19 +66,18 @@ Signed-off-by: Jernej Skrabec + return 0; + + if (!cedrus_buf->codec.h265.mv_col_buf_size) { -+ unsigned int ctb_size_luma, width_in_ctb_luma; + unsigned int log2_max_luma_coding_block_size; ++ unsigned int ctb_size_luma; + + log2_max_luma_coding_block_size = + sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_luma = 1 << log2_max_luma_coding_block_size; -+ width_in_ctb_luma = DIV_ROUND_UP(sps->pic_width_in_luma_samples, -+ ctb_size_luma); + -+ cedrus_buf->codec.h265.mv_col_buf_size = ALIGN(width_in_ctb_luma * ++ cedrus_buf->codec.h265.mv_col_buf_size = ++ DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma) * + DIV_ROUND_UP(sps->pic_height_in_luma_samples, ctb_size_luma) * -+ CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE, 1024); ++ CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE + SZ_1K; + + cedrus_buf->codec.h265.mv_col_buf = + dma_alloc_attrs(ctx->dev->dev, @@ -111,7 +114,7 @@ Signed-off-by: Jernej Skrabec }; u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO + VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index; -@@ -134,7 +174,8 @@ static void cedrus_h265_frame_info_write +@@ -134,7 +173,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx, static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, const struct v4l2_hevc_dpb_entry *dpb, @@ -121,7 +124,7 @@ Signed-off-by: Jernej Skrabec { struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); -@@ -149,7 +190,7 @@ static void cedrus_h265_frame_info_write +@@ -149,7 +189,7 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic, pic_order_cnt, @@ -130,7 +133,7 @@ Signed-off-by: Jernej Skrabec } } -@@ -388,37 +429,6 @@ static void cedrus_h265_setup(struct ced +@@ -388,37 +428,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, width_in_ctb_luma = DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma); @@ -168,7 +171,7 @@ Signed-off-by: Jernej Skrabec /* Activate H265 engine. */ cedrus_engine_enable(ctx, CEDRUS_CODEC_H265); -@@ -671,7 +682,7 @@ static void cedrus_h265_setup(struct ced +@@ -672,7 +681,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Write decoded picture buffer in pic list. */ cedrus_h265_frame_info_write_dpb(ctx, decode_params->dpb, @@ -177,7 +180,7 @@ Signed-off-by: Jernej Skrabec /* Output frame. */ -@@ -682,7 +693,7 @@ static void cedrus_h265_setup(struct ced +@@ -683,7 +692,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, cedrus_h265_frame_info_write_single(ctx, output_pic_list_index, slice_params->pic_struct != 0, pic_order_cnt, @@ -186,7 +189,7 @@ Signed-off-by: Jernej Skrabec cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index); -@@ -731,9 +742,6 @@ static int cedrus_h265_start(struct cedr +@@ -732,9 +741,6 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; @@ -196,7 +199,7 @@ Signed-off-by: Jernej Skrabec /* Buffer is never accessed by CPU, so we can skip kernel mapping. */ ctx->codec.h265.neighbor_info_buf = dma_alloc_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, -@@ -759,15 +767,6 @@ static void cedrus_h265_stop(struct cedr +@@ -761,15 +767,6 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; @@ -210,9 +213,9 @@ Signed-off-by: Jernej Skrabec - } - dma_free_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, - ctx->codec.h265.neighbor_info_buf, - ctx->codec.h265.neighbor_info_buf_addr); -@@ -782,6 +782,17 @@ static void cedrus_h265_trigger(struct c + ctx->codec.h265.neighbor_info_buf, + ctx->codec.h265.neighbor_info_buf_addr, +@@ -786,6 +783,17 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx) cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE); } @@ -230,7 +233,7 @@ Signed-off-by: Jernej Skrabec struct cedrus_dec_ops cedrus_dec_ops_h265 = { .irq_clear = cedrus_h265_irq_clear, .irq_disable = cedrus_h265_irq_disable, -@@ -790,4 +800,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h26 +@@ -794,4 +802,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = { .start = cedrus_h265_start, .stop = cedrus_h265_stop, .trigger = cedrus_h265_trigger, diff --git a/projects/Allwinner/patches/linux/0088-media-cedrus-Fix-H265-aux-buffer-size.patch b/projects/Allwinner/patches/linux/0088-media-cedrus-Fix-H265-aux-buffer-size.patch new file mode 100644 index 0000000000..415c6062e2 --- /dev/null +++ b/projects/Allwinner/patches/linux/0088-media-cedrus-Fix-H265-aux-buffer-size.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Wed, 9 Feb 2022 19:03:06 +0100 +Subject: [PATCH] media: cedrus: Fix H265 aux buffer size + +Neighbour info buffer size needs to be 794 kiB in size on H6. This is +actually mentioned in comment, but smaller size is used nevertheless. + +Increase buffer size to conform H6 needs. Since increase is not that big +in absolute numbers, it doesn't make sense to complicate logic for older +generations. + +Bug was discovered using iommu, which reported access error when trying +to play H265 video. + +Fixes: 86caab29da78 ("media: cedrus: Add HEVC/H.265 decoding support") +Signed-off-by: Jernej Skrabec +--- + drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +index dec519bc55d4..ef51ddf9d0d7 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +@@ -23,7 +23,7 @@ + * Subsequent BSP implementations seem to double the neighbor info buffer size + * for the H6 SoC, which may be related to 10 bit H265 support. + */ +-#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) ++#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (794 * SZ_1K) + #define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) + #define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 + diff --git a/projects/Allwinner/patches/linux/0089-media-cedrus-Add-watchdog-for-job-completion.patch b/projects/Allwinner/patches/linux/0089-media-cedrus-Add-watchdog-for-job-completion.patch new file mode 100644 index 0000000000..7dcb3025c5 --- /dev/null +++ b/projects/Allwinner/patches/linux/0089-media-cedrus-Add-watchdog-for-job-completion.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Tue, 1 Feb 2022 19:14:18 +0100 +Subject: [PATCH] media: cedrus: Add watchdog for job completion + +Currently, if job is not completed for whatever reason, userspace +application can hang on ioctl and thus become unkillable. + +In order to prevent that, implement watchdog, which will complete job +after 2 seconds with error state. + +Concept is borrowed from hantro driver. + +Signed-off-by: Jernej Skrabec +--- + drivers/staging/media/sunxi/cedrus/cedrus.c | 2 ++ + drivers/staging/media/sunxi/cedrus/cedrus.h | 3 +++ + .../staging/media/sunxi/cedrus/cedrus_dec.c | 4 +++ + .../staging/media/sunxi/cedrus/cedrus_hw.c | 25 +++++++++++++++++++ + .../staging/media/sunxi/cedrus/cedrus_hw.h | 2 ++ + 5 files changed, 36 insertions(+) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index 4a4b714b0f26..68b3dcdb5df3 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -439,6 +439,8 @@ static int cedrus_probe(struct platform_device *pdev) + + mutex_init(&dev->dev_mutex); + ++ INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog); ++ + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register V4L2 device\n"); +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h +index c345f2984041..3bc094eb497f 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.h ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.h +@@ -24,6 +24,7 @@ + + #include + #include ++#include + + #define CEDRUS_NAME "cedrus" + +@@ -194,6 +195,8 @@ struct cedrus_dev { + struct reset_control *rstc; + + unsigned int capabilities; ++ ++ struct delayed_work watchdog_work; + }; + + extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +index a16c1422558f..9c7200299465 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +@@ -97,4 +97,8 @@ void cedrus_device_run(void *priv) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + + dev->dec_ops[ctx->current_codec]->trigger(ctx); ++ ++ /* Start the watchdog timer. */ ++ schedule_delayed_work(&dev->watchdog_work, ++ msecs_to_jiffies(2000)); + } +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +index 2d7663726467..a6470a89851e 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +@@ -118,6 +118,13 @@ static irqreturn_t cedrus_irq(int irq, void *data) + enum vb2_buffer_state state; + enum cedrus_irq_status status; + ++ /* ++ * If cancel_delayed_work returns false it means watchdog already ++ * executed and finished the job. ++ */ ++ if (!cancel_delayed_work(&dev->watchdog_work)) ++ return IRQ_HANDLED; ++ + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (!ctx) { + v4l2_err(&dev->v4l2_dev, +@@ -143,6 +150,24 @@ static irqreturn_t cedrus_irq(int irq, void *data) + return IRQ_HANDLED; + } + ++void cedrus_watchdog(struct work_struct *work) ++{ ++ struct cedrus_dev *dev; ++ struct cedrus_ctx *ctx; ++ ++ dev = container_of(to_delayed_work(work), ++ struct cedrus_dev, watchdog_work); ++ ++ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); ++ if (!ctx) ++ return; ++ ++ v4l2_err(&dev->v4l2_dev, "frame processing timed out!\n"); ++ reset_control_reset(dev->rstc); ++ v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, ++ VB2_BUF_STATE_ERROR); ++} ++ + int cedrus_hw_suspend(struct device *device) + { + struct cedrus_dev *dev = dev_get_drvdata(device); +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h +index 45f641f0bfa2..7c92f00e36da 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h +@@ -28,4 +28,6 @@ int cedrus_hw_resume(struct device *device); + int cedrus_hw_probe(struct cedrus_dev *dev); + void cedrus_hw_remove(struct cedrus_dev *dev); + ++void cedrus_watchdog(struct work_struct *work); ++ + #endif