media: platform: Add mechanism to handle jpeg hardware's locking up

There is a delayed work scheduled before starting the hardware and
canceled in the interrupt handler. If the delayed work is executed, it
resets the hardware and reports the failure to V4L2, so that the
execution can continue from next frames.

Reviewed-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Xia Jiang <xia.jiang@mediatek.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Xia Jiang 2020-08-14 09:11:42 +02:00 committed by Mauro Carvalho Chehab
parent f9f964519c
commit 0058ff2bef
2 changed files with 29 additions and 0 deletions

View File

@ -816,6 +816,9 @@ static void mtk_jpeg_device_run(void *priv)
if (ret < 0) if (ret < 0)
goto dec_end; goto dec_end;
schedule_delayed_work(&jpeg->job_timeout_work,
msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb)) if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb))
goto dec_end; goto dec_end;
@ -911,6 +914,8 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
u32 dec_ret; u32 dec_ret;
int i; int i;
cancel_delayed_work(&jpeg->job_timeout_work);
dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base); dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base);
dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret); dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret);
ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
@ -1066,6 +1071,25 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
return PTR_ERR_OR_ZERO(jpeg->clk_jdec_smi); return PTR_ERR_OR_ZERO(jpeg->clk_jdec_smi);
} }
static void mtk_jpeg_job_timeout_work(struct work_struct *work)
{
struct mtk_jpeg_dev *jpeg = container_of(work, struct mtk_jpeg_dev,
job_timeout_work.work);
struct mtk_jpeg_ctx *ctx;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
mtk_jpeg_dec_reset(jpeg->dec_reg_base);
pm_runtime_put(jpeg->dev);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
static int mtk_jpeg_probe(struct platform_device *pdev) static int mtk_jpeg_probe(struct platform_device *pdev)
{ {
struct mtk_jpeg_dev *jpeg; struct mtk_jpeg_dev *jpeg;
@ -1080,6 +1104,7 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
mutex_init(&jpeg->lock); mutex_init(&jpeg->lock);
spin_lock_init(&jpeg->hw_lock); spin_lock_init(&jpeg->hw_lock);
jpeg->dev = &pdev->dev; jpeg->dev = &pdev->dev;
INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res); jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res);

View File

@ -28,6 +28,8 @@
#define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024) #define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024)
#define MTK_JPEG_HW_TIMEOUT_MSEC 1000
enum mtk_jpeg_ctx_state { enum mtk_jpeg_ctx_state {
MTK_JPEG_INIT = 0, MTK_JPEG_INIT = 0,
MTK_JPEG_RUNNING, MTK_JPEG_RUNNING,
@ -48,6 +50,7 @@ enum mtk_jpeg_ctx_state {
* @clk_jdec: JPEG hw working clock * @clk_jdec: JPEG hw working clock
* @clk_jdec_smi: JPEG SMI bus clock * @clk_jdec_smi: JPEG SMI bus clock
* @larb: SMI device * @larb: SMI device
* @job_timeout_work: IRQ timeout structure
*/ */
struct mtk_jpeg_dev { struct mtk_jpeg_dev {
struct mutex lock; struct mutex lock;
@ -62,6 +65,7 @@ struct mtk_jpeg_dev {
struct clk *clk_jdec; struct clk *clk_jdec;
struct clk *clk_jdec_smi; struct clk *clk_jdec_smi;
struct device *larb; struct device *larb;
struct delayed_work job_timeout_work;
}; };
/** /**