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:
Родитель
7f9cfb5499
Коммит
7c38a551bd
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче