Commit 7c38a551 authored by Jernej Skrabec's avatar Jernej Skrabec Committed by Hans Verkuil

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: default avatarJernej Skrabec <jernej.skrabec@gmail.com>
Reviewed-by: default avatarEzequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: default avatarPaul Kocialkowski <paul.kocialkowski@bootlin.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent 7f9cfb54
......@@ -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");
......
......@@ -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;
......
......@@ -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));
}
......@@ -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);
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment