Merge pull request #6215 from jernejsk/hevc-fixes-10

[LE10] Allwinner: linux: Update cedrus patches
This commit is contained in:
Christian Hewitt 2022-02-10 10:03:46 +04:00 committed by GitHub
commit 8380d94934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 18 deletions

View File

@ -6,8 +6,8 @@ Subject: [PATCH] media: cedrus: hevc: Improve buffer management
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
--- ---
drivers/staging/media/sunxi/cedrus/cedrus.h | 9 +- drivers/staging/media/sunxi/cedrus/cedrus.h | 9 +-
.../staging/media/sunxi/cedrus/cedrus_h265.c | 117 ++++++++++-------- .../staging/media/sunxi/cedrus/cedrus_h265.c | 116 ++++++++++--------
2 files changed, 69 insertions(+), 57 deletions(-) 2 files changed, 68 insertions(+), 57 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index c9ec43be260f..6fa2df354cbf 100644 index c9ec43be260f..6fa2df354cbf 100644
@ -37,10 +37,10 @@ index c9ec43be260f..6fa2df354cbf 100644
dma_addr_t neighbor_info_buf_addr; dma_addr_t neighbor_info_buf_addr;
void *entry_points_buf; void *entry_points_buf;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 3b355de4c097..9e21a40867d7 100644 index 3b355de4c097..802b85434949 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/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(struct cedrus_dev *dev, void *data, @@ -91,26 +91,65 @@ static void cedrus_h265_sram_write_data(struct cedrus_dev *dev, void *data,
static inline dma_addr_t static inline dma_addr_t
cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx, cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx,
@ -66,19 +66,18 @@ index 3b355de4c097..9e21a40867d7 100644
+ return 0; + return 0;
+ +
+ if (!cedrus_buf->codec.h265.mv_col_buf_size) { + 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 log2_max_luma_coding_block_size;
+ unsigned int ctb_size_luma;
+ +
+ log2_max_luma_coding_block_size = + log2_max_luma_coding_block_size =
+ sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size; + sps->log2_diff_max_min_luma_coding_block_size;
+ ctb_size_luma = 1 << log2_max_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) * + 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 = + cedrus_buf->codec.h265.mv_col_buf =
+ dma_alloc_coherent(ctx->dev->dev, + dma_alloc_coherent(ctx->dev->dev,
@ -115,7 +114,7 @@ index 3b355de4c097..9e21a40867d7 100644
}; };
u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO + u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO +
VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index; VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index;
@@ -134,7 +174,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx, @@ -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, static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx,
const struct v4l2_hevc_dpb_entry *dpb, const struct v4l2_hevc_dpb_entry *dpb,
@ -125,7 +124,7 @@ index 3b355de4c097..9e21a40867d7 100644
{ {
struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE); V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -149,7 +190,7 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, @@ -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, cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic,
pic_order_cnt, pic_order_cnt,
@ -134,7 +133,7 @@ index 3b355de4c097..9e21a40867d7 100644
} }
} }
@@ -386,36 +427,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, @@ -386,36 +426,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
width_in_ctb_luma = width_in_ctb_luma =
DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma); DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
@ -171,7 +170,7 @@ index 3b355de4c097..9e21a40867d7 100644
/* Activate H265 engine. */ /* Activate H265 engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_H265); cedrus_engine_enable(ctx, CEDRUS_CODEC_H265);
@@ -669,7 +680,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, @@ -669,7 +679,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Write decoded picture buffer in pic list. */ /* Write decoded picture buffer in pic list. */
cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb, cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb,
@ -180,7 +179,7 @@ index 3b355de4c097..9e21a40867d7 100644
/* Output frame. */ /* Output frame. */
@@ -680,7 +691,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, @@ -680,7 +690,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
cedrus_h265_frame_info_write_single(ctx, output_pic_list_index, cedrus_h265_frame_info_write_single(ctx, output_pic_list_index,
slice_params->pic_struct != 0, slice_params->pic_struct != 0,
pic_order_cnt, pic_order_cnt,
@ -189,7 +188,7 @@ index 3b355de4c097..9e21a40867d7 100644
cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index); cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index);
@@ -729,9 +740,6 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx) @@ -729,9 +739,6 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
{ {
struct cedrus_dev *dev = ctx->dev; struct cedrus_dev *dev = ctx->dev;
@ -199,7 +198,7 @@ index 3b355de4c097..9e21a40867d7 100644
ctx->codec.h265.neighbor_info_buf = ctx->codec.h265.neighbor_info_buf =
dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
&ctx->codec.h265.neighbor_info_buf_addr, &ctx->codec.h265.neighbor_info_buf_addr,
@@ -757,14 +765,6 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx) @@ -757,14 +764,6 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx)
{ {
struct cedrus_dev *dev = ctx->dev; struct cedrus_dev *dev = ctx->dev;
@ -214,7 +213,7 @@ index 3b355de4c097..9e21a40867d7 100644
dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h265.neighbor_info_buf, ctx->codec.h265.neighbor_info_buf,
ctx->codec.h265.neighbor_info_buf_addr); ctx->codec.h265.neighbor_info_buf_addr);
@@ -780,6 +780,16 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx) @@ -780,6 +779,16 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE); cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
} }
@ -231,7 +230,7 @@ index 3b355de4c097..9e21a40867d7 100644
struct cedrus_dec_ops cedrus_dec_ops_h265 = { struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.irq_clear = cedrus_h265_irq_clear, .irq_clear = cedrus_h265_irq_clear,
.irq_disable = cedrus_h265_irq_disable, .irq_disable = cedrus_h265_irq_disable,
@@ -788,4 +798,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = { @@ -788,4 +797,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.start = cedrus_h265_start, .start = cedrus_h265_start,
.stop = cedrus_h265_stop, .stop = cedrus_h265_stop,
.trigger = cedrus_h265_trigger, .trigger = cedrus_h265_trigger,

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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 <jernej.skrabec@gmail.com>
---
drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- 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

View File

@ -0,0 +1,113 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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 <jernej.skrabec@gmail.com>
---
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(+)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -476,6 +476,8 @@ static int cedrus_probe(struct platform_
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");
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -23,6 +23,7 @@
#include <media/videobuf2-dma-contig.h>
#include <linux/platform_device.h>
+#include <linux/workqueue.h>
#define CEDRUS_NAME "cedrus"
@@ -199,6 +200,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;
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -93,4 +93,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));
}
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -117,6 +117,13 @@ static irqreturn_t cedrus_irq(int irq, v
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,
@@ -142,6 +149,24 @@ static irqreturn_t cedrus_irq(int irq, v
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);
--- 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 *devi
int cedrus_hw_probe(struct cedrus_dev *dev);
void cedrus_hw_remove(struct cedrus_dev *dev);
+void cedrus_watchdog(struct work_struct *work);
+
#endif