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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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");
+3 −0
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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));
}
+25 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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