aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-02-08 15:59:02 -0500
committerEric Anholt <eric@anholt.net>2016-02-16 15:21:01 -0500
commit36cb6253f9383fd9a59ee7b8458c6232ef48577c (patch)
treee2e1d30ebfd5125f31bbeefd813bce744b692a15
parent001bdb55d9eb72a9e2d5b623bacfc52da74ae03e (diff)
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: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h6
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c26
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c12
3 files changed, 26 insertions, 18 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 8ac3788846ce..51a63330d4f8 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -91,6 +91,11 @@ struct vc4_dev {
91 struct vc4_bo *overflow_mem; 91 struct vc4_bo *overflow_mem;
92 struct work_struct overflow_mem_work; 92 struct work_struct overflow_mem_work;
93 93
94 int power_refcount;
95
96 /* Mutex controlling the power refcount. */
97 struct mutex power_lock;
98
94 struct { 99 struct {
95 struct timer_list timer; 100 struct timer_list timer;
96 struct work_struct reset_work; 101 struct work_struct reset_work;
@@ -439,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
439extern struct platform_driver vc4_v3d_driver; 444extern struct platform_driver vc4_v3d_driver;
440int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); 445int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
441int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); 446int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
442int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
443 447
444/* vc4_validate.c */ 448/* vc4_validate.c */
445int 449int
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 4e0391cbf9d0..202aa1544acc 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -229,8 +229,16 @@ vc4_reset(struct drm_device *dev)
229 struct vc4_dev *vc4 = to_vc4_dev(dev); 229 struct vc4_dev *vc4 = to_vc4_dev(dev);
230 230
231 DRM_INFO("Resetting GPU.\n"); 231 DRM_INFO("Resetting GPU.\n");
232 vc4_v3d_set_power(vc4, false); 232
233 vc4_v3d_set_power(vc4, true); 233 mutex_lock(&vc4->power_lock);
234 if (vc4->power_refcount) {
235 /* Power the device off and back on the by dropping the
236 * reference on runtime PM.
237 */
238 pm_runtime_put_sync_suspend(&vc4->v3d->pdev->dev);
239 pm_runtime_get_sync(&vc4->v3d->pdev->dev);
240 }
241 mutex_unlock(&vc4->power_lock);
234 242
235 vc4_irq_reset(dev); 243 vc4_irq_reset(dev);
236 244
@@ -641,7 +649,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
641 } 649 }
642 mutex_unlock(&dev->struct_mutex); 650 mutex_unlock(&dev->struct_mutex);
643 651
644 pm_runtime_put(&vc4->v3d->pdev->dev); 652 mutex_lock(&vc4->power_lock);
653 if (--vc4->power_refcount == 0)
654 pm_runtime_put(&vc4->v3d->pdev->dev);
655 mutex_unlock(&vc4->power_lock);
645 656
646 kfree(exec); 657 kfree(exec);
647} 658}
@@ -783,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
783 struct vc4_dev *vc4 = to_vc4_dev(dev); 794 struct vc4_dev *vc4 = to_vc4_dev(dev);
784 struct drm_vc4_submit_cl *args = data; 795 struct drm_vc4_submit_cl *args = data;
785 struct vc4_exec_info *exec; 796 struct vc4_exec_info *exec;
786 int ret; 797 int ret = 0;
787 798
788 if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { 799 if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
789 DRM_ERROR("Unknown flags: 0x%02x\n", args->flags); 800 DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
@@ -796,7 +807,10 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
796 return -ENOMEM; 807 return -ENOMEM;
797 } 808 }
798 809
799 ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); 810 mutex_lock(&vc4->power_lock);
811 if (vc4->power_refcount++ == 0)
812 ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
813 mutex_unlock(&vc4->power_lock);
800 if (ret < 0) { 814 if (ret < 0) {
801 kfree(exec); 815 kfree(exec);
802 return ret; 816 return ret;
@@ -856,6 +870,8 @@ vc4_gem_init(struct drm_device *dev)
856 (unsigned long)dev); 870 (unsigned long)dev);
857 871
858 INIT_WORK(&vc4->job_done_work, vc4_job_done_work); 872 INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
873
874 mutex_init(&vc4->power_lock);
859} 875}
860 876
861void 877void
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index cb38b6bf4119..31de5d17bc85 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -145,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
145} 145}
146#endif /* CONFIG_DEBUG_FS */ 146#endif /* CONFIG_DEBUG_FS */
147 147
148int
149vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
150{
151 /* XXX: This interface is needed for GPU reset, and the way to
152 * do it is to turn our power domain off and back on. We
153 * can't just reset from within the driver, because the reset
154 * bits are in the power domain's register area, and get set
155 * during the poweron process.
156 */
157 return 0;
158}
159
160static void vc4_v3d_init_hw(struct drm_device *dev) 148static void vc4_v3d_init_hw(struct drm_device *dev)
161{ 149{
162 struct vc4_dev *vc4 = to_vc4_dev(dev); 150 struct vc4_dev *vc4 = to_vc4_dev(dev);