Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36cb6253 authored by Eric Anholt's avatar Eric Anholt
Browse files

drm/vc4: Use runtime PM to power cycle the device when the GPU hangs.



This gets us functional GPU reset again, like we had until a refactor
at merge time.  Tested with a little patch to stuff in a broken binner
job every 100 frames.

Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 001bdb55
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -91,6 +91,11 @@ struct vc4_dev {
	struct vc4_bo *overflow_mem;
	struct work_struct overflow_mem_work;

	int power_refcount;

	/* Mutex controlling the power refcount. */
	struct mutex power_lock;

	struct {
		struct timer_list timer;
		struct work_struct reset_work;
@@ -439,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
extern struct platform_driver vc4_v3d_driver;
int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);

/* vc4_validate.c */
int
+21 −5
Original line number Diff line number Diff line
@@ -229,8 +229,16 @@ vc4_reset(struct drm_device *dev)
	struct vc4_dev *vc4 = to_vc4_dev(dev);

	DRM_INFO("Resetting GPU.\n");
	vc4_v3d_set_power(vc4, false);
	vc4_v3d_set_power(vc4, true);

	mutex_lock(&vc4->power_lock);
	if (vc4->power_refcount) {
		/* Power the device off and back on the by dropping the
		 * reference on runtime PM.
		 */
		pm_runtime_put_sync_suspend(&vc4->v3d->pdev->dev);
		pm_runtime_get_sync(&vc4->v3d->pdev->dev);
	}
	mutex_unlock(&vc4->power_lock);

	vc4_irq_reset(dev);

@@ -641,7 +649,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
	}
	mutex_unlock(&dev->struct_mutex);

	mutex_lock(&vc4->power_lock);
	if (--vc4->power_refcount == 0)
		pm_runtime_put(&vc4->v3d->pdev->dev);
	mutex_unlock(&vc4->power_lock);

	kfree(exec);
}
@@ -783,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
	struct vc4_dev *vc4 = to_vc4_dev(dev);
	struct drm_vc4_submit_cl *args = data;
	struct vc4_exec_info *exec;
	int ret;
	int ret = 0;

	if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
		DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
@@ -796,7 +807,10 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
		return -ENOMEM;
	}

	mutex_lock(&vc4->power_lock);
	if (vc4->power_refcount++ == 0)
		ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
	mutex_unlock(&vc4->power_lock);
	if (ret < 0) {
		kfree(exec);
		return ret;
@@ -856,6 +870,8 @@ vc4_gem_init(struct drm_device *dev)
		    (unsigned long)dev);

	INIT_WORK(&vc4->job_done_work, vc4_job_done_work);

	mutex_init(&vc4->power_lock);
}

void
+0 −12
Original line number Diff line number Diff line
@@ -145,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
}
#endif /* CONFIG_DEBUG_FS */

int
vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
{
	/* XXX: This interface is needed for GPU reset, and the way to
	 * do it is to turn our power domain off and back on.  We
	 * can't just reset from within the driver, because the reset
	 * bits are in the power domain's register area, and get set
	 * during the poweron process.
	 */
	return 0;
}

static void vc4_v3d_init_hw(struct drm_device *dev)
{
	struct vc4_dev *vc4 = to_vc4_dev(dev);