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>
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
Jernej Skrabec 2022-02-01 19:33:24 +01:00 коммит произвёл Hans Verkuil
Родитель 7f9cfb5499
Коммит 7c38a551bd
5 изменённых файлов: 36 добавлений и 0 удалений

Просмотреть файл

@ -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