aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-02-08 14:19:14 -0500
committerEric Anholt <eric@anholt.net>2016-02-16 15:21:00 -0500
commitc4ce60dc30912df09b2438f1e5594eae1ef64d1e (patch)
tree6d248da2d9bd32a4d8f5cc9e0405a512e863932e
parent2ee94657e2bbd13b358060edc91b2b2fdef9038f (diff)
drm/vc4: Fix spurious GPU resets due to BO reuse.
We were tracking the "where are the head pointers pointing" globally, so if another job reused the same BOs and execution was at the same point as last time we checked, we'd stop and trigger a reset even though the GPU had made progress. 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.c19
2 files changed, 19 insertions, 6 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 080865ec2bae..b6ccf8181643 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -92,7 +92,6 @@ struct vc4_dev {
92 struct work_struct overflow_mem_work; 92 struct work_struct overflow_mem_work;
93 93
94 struct { 94 struct {
95 uint32_t last_ct0ca, last_ct1ca;
96 struct timer_list timer; 95 struct timer_list timer;
97 struct work_struct reset_work; 96 struct work_struct reset_work;
98 } hangcheck; 97 } hangcheck;
@@ -192,6 +191,11 @@ struct vc4_exec_info {
192 /* Sequence number for this bin/render job. */ 191 /* Sequence number for this bin/render job. */
193 uint64_t seqno; 192 uint64_t seqno;
194 193
194 /* Last current addresses the hardware was processing when the
195 * hangcheck timer checked on us.
196 */
197 uint32_t last_ct0ca, last_ct1ca;
198
195 /* Kernel-space copy of the ioctl arguments */ 199 /* Kernel-space copy of the ioctl arguments */
196 struct drm_vc4_submit_cl *args; 200 struct drm_vc4_submit_cl *args;
197 201
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index a9d020e7e891..1a819dd826f8 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -257,10 +257,17 @@ vc4_hangcheck_elapsed(unsigned long data)
257 struct drm_device *dev = (struct drm_device *)data; 257 struct drm_device *dev = (struct drm_device *)data;
258 struct vc4_dev *vc4 = to_vc4_dev(dev); 258 struct vc4_dev *vc4 = to_vc4_dev(dev);
259 uint32_t ct0ca, ct1ca; 259 uint32_t ct0ca, ct1ca;
260 unsigned long irqflags;
261 struct vc4_exec_info *exec;
262
263 spin_lock_irqsave(&vc4->job_lock, irqflags);
264 exec = vc4_first_job(vc4);
260 265
261 /* If idle, we can stop watching for hangs. */ 266 /* If idle, we can stop watching for hangs. */
262 if (list_empty(&vc4->job_list)) 267 if (!exec) {
268 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
263 return; 269 return;
270 }
264 271
265 ct0ca = V3D_READ(V3D_CTNCA(0)); 272 ct0ca = V3D_READ(V3D_CTNCA(0));
266 ct1ca = V3D_READ(V3D_CTNCA(1)); 273 ct1ca = V3D_READ(V3D_CTNCA(1));
@@ -268,14 +275,16 @@ vc4_hangcheck_elapsed(unsigned long data)
268 /* If we've made any progress in execution, rearm the timer 275 /* If we've made any progress in execution, rearm the timer
269 * and wait. 276 * and wait.
270 */ 277 */
271 if (ct0ca != vc4->hangcheck.last_ct0ca || 278 if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
272 ct1ca != vc4->hangcheck.last_ct1ca) { 279 exec->last_ct0ca = ct0ca;
273 vc4->hangcheck.last_ct0ca = ct0ca; 280 exec->last_ct1ca = ct1ca;
274 vc4->hangcheck.last_ct1ca = ct1ca; 281 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
275 vc4_queue_hangcheck(dev); 282 vc4_queue_hangcheck(dev);
276 return; 283 return;
277 } 284 }
278 285
286 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
287
279 /* We've gone too long with no progress, reset. This has to 288 /* We've gone too long with no progress, reset. This has to
280 * be done from a work struct, since resetting can sleep and 289 * be done from a work struct, since resetting can sleep and
281 * this timer hook isn't allowed to. 290 * this timer hook isn't allowed to.