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

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
...@@ -91,6 +91,11 @@ struct vc4_dev { ...@@ -91,6 +91,11 @@ struct vc4_dev {
struct vc4_bo *overflow_mem; struct vc4_bo *overflow_mem;
struct work_struct overflow_mem_work; struct work_struct overflow_mem_work;
int power_refcount;
/* Mutex controlling the power refcount. */
struct mutex power_lock;
struct { struct {
struct timer_list timer; struct timer_list timer;
struct work_struct reset_work; struct work_struct reset_work;
...@@ -439,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, ...@@ -439,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
extern struct platform_driver vc4_v3d_driver; extern struct platform_driver vc4_v3d_driver;
int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); 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_debugfs_regs(struct seq_file *m, void *unused);
int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
/* vc4_validate.c */ /* vc4_validate.c */
int int
......
...@@ -229,8 +229,16 @@ vc4_reset(struct drm_device *dev) ...@@ -229,8 +229,16 @@ vc4_reset(struct drm_device *dev)
struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_dev *vc4 = to_vc4_dev(dev);
DRM_INFO("Resetting GPU.\n"); 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); vc4_irq_reset(dev);
...@@ -641,7 +649,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) ...@@ -641,7 +649,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
pm_runtime_put(&vc4->v3d->pdev->dev); mutex_lock(&vc4->power_lock);
if (--vc4->power_refcount == 0)
pm_runtime_put(&vc4->v3d->pdev->dev);
mutex_unlock(&vc4->power_lock);
kfree(exec); kfree(exec);
} }
...@@ -783,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ...@@ -783,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_vc4_submit_cl *args = data; struct drm_vc4_submit_cl *args = data;
struct vc4_exec_info *exec; struct vc4_exec_info *exec;
int ret; int ret = 0;
if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
DRM_ERROR("Unknown flags: 0x%02x\n", args->flags); DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
...@@ -796,7 +807,10 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, ...@@ -796,7 +807,10 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
return -ENOMEM; return -ENOMEM;
} }
ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); 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) { if (ret < 0) {
kfree(exec); kfree(exec);
return ret; return ret;
...@@ -856,6 +870,8 @@ vc4_gem_init(struct drm_device *dev) ...@@ -856,6 +870,8 @@ vc4_gem_init(struct drm_device *dev)
(unsigned long)dev); (unsigned long)dev);
INIT_WORK(&vc4->job_done_work, vc4_job_done_work); INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
mutex_init(&vc4->power_lock);
} }
void void
......
...@@ -145,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused) ...@@ -145,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
} }
#endif /* CONFIG_DEBUG_FS */ #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) static void vc4_v3d_init_hw(struct drm_device *dev)
{ {
struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_dev *vc4 = to_vc4_dev(dev);
......
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