diff options
author | Eric Anholt <eric@anholt.net> | 2016-02-08 15:59:02 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2016-02-16 15:21:01 -0500 |
commit | 36cb6253f9383fd9a59ee7b8458c6232ef48577c (patch) | |
tree | e2e1d30ebfd5125f31bbeefd813bce744b692a15 | |
parent | 001bdb55d9eb72a9e2d5b623bacfc52da74ae03e (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.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_gem.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_v3d.c | 12 |
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, | |||
439 | extern struct platform_driver vc4_v3d_driver; | 444 | extern struct platform_driver vc4_v3d_driver; |
440 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); | 445 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); |
441 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); | 446 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); |
442 | int vc4_v3d_set_power(struct vc4_dev *vc4, bool on); | ||
443 | 447 | ||
444 | /* vc4_validate.c */ | 448 | /* vc4_validate.c */ |
445 | int | 449 | int |
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 | ||
861 | void | 877 | void |
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 | ||
148 | int | ||
149 | vc4_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 | |||
160 | static void vc4_v3d_init_hw(struct drm_device *dev) | 148 | static 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); |