Merge pull request #6214 from jernejsk/hevc-fixes

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

View File

@ -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 <jernej.skrabec@siol.net>
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 <jernej.skrabec@siol.net>
---
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 <jernej.skrabec@siol.net>
} 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 <jernej.skrabec@siol.net>
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 <jernej.skrabec@siol.net>
+ 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 <jernej.skrabec@siol.net>
};
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 <jernej.skrabec@siol.net>
{
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 <jernej.skrabec@siol.net>
}
}
@@ -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 <jernej.skrabec@siol.net>
/* 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 <jernej.skrabec@siol.net>
/* 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 <jernej.skrabec@siol.net>
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 <jernej.skrabec@siol.net>
/* 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 <jernej.skrabec@siol.net>
- }
-
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 <jernej.skrabec@siol.net>
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,

View File

@ -0,0 +1,34 @@
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(-)
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

View File

@ -0,0 +1,123 @@
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(+)
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 <linux/iopoll.h>
#include <linux/platform_device.h>
+#include <linux/workqueue.h>
#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