aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-09-03 07:12:03 -0400
committerRob Clark <robdclark@gmail.com>2013-09-10 13:56:59 -0400
commit26791c48e1dcdc17c6c952585806b0ecc493f939 (patch)
tree357733a7120949bfa636e3830f37a0bc4abfa12c
parentbf6811f304795e7697985449ee870b29a8cbc6c7 (diff)
drm/msm: hangcheck harder
If gpu locks up with the rptr shortly beyond the wrap-around point in the ringbuffer, because the rptr was not reset (but wptr is, by virtue of resetting rb->cur), we could end up in a scenario where we think there is not enough space in the ringbuffer for the next cmds. And since the CP won't reset rptr until after processing an IB, this leaves things in a sort of deadlock. So reset rptr too. And a bit more spiffing up of hangcheck to make things easier to debug. Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c10
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c9
2 files changed, 17 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index a60584763b61..a0b9d8a95b16 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
124 124
125 /* reset completed fence seqno, just discard anything pending: */ 125 /* reset completed fence seqno, just discard anything pending: */
126 adreno_gpu->memptrs->fence = gpu->submitted_fence; 126 adreno_gpu->memptrs->fence = gpu->submitted_fence;
127 adreno_gpu->memptrs->rptr = 0;
128 adreno_gpu->memptrs->wptr = 0;
127 129
128 gpu->funcs->pm_resume(gpu); 130 gpu->funcs->pm_resume(gpu);
129 ret = gpu->funcs->hw_init(gpu); 131 ret = gpu->funcs->hw_init(gpu);
@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
229 return; 231 return;
230 } while(time_before(jiffies, t)); 232 } while(time_before(jiffies, t));
231 233
232 DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name); 234 DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
233 235
234 /* TODO maybe we need to reset GPU here to recover from hang? */ 236 /* TODO maybe we need to reset GPU here to recover from hang? */
235} 237}
@@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
256{ 258{
257 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 259 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
258 uint32_t freedwords; 260 uint32_t freedwords;
261 unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
259 do { 262 do {
260 uint32_t size = gpu->rb->size / 4; 263 uint32_t size = gpu->rb->size / 4;
261 uint32_t wptr = get_wptr(gpu->rb); 264 uint32_t wptr = get_wptr(gpu->rb);
262 uint32_t rptr = adreno_gpu->memptrs->rptr; 265 uint32_t rptr = adreno_gpu->memptrs->rptr;
263 freedwords = (rptr + (size - 1) - wptr) % size; 266 freedwords = (rptr + (size - 1) - wptr) % size;
267
268 if (time_after(jiffies, t)) {
269 DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
270 break;
271 }
264 } while(freedwords < ndwords); 272 } while(freedwords < ndwords);
265} 273}
266 274
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index cb9cdffdc41f..10cc44324166 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -237,8 +237,15 @@ static void hangcheck_handler(unsigned long data)
237 gpu->hangcheck_fence = fence; 237 gpu->hangcheck_fence = fence;
238 } else if (fence < gpu->submitted_fence) { 238 } else if (fence < gpu->submitted_fence) {
239 /* no progress and not done.. hung! */ 239 /* no progress and not done.. hung! */
240 struct msm_drm_private *priv = gpu->dev->dev_private; 240 struct drm_device *dev = gpu->dev;
241 struct msm_drm_private *priv = dev->dev_private;
241 gpu->hangcheck_fence = fence; 242 gpu->hangcheck_fence = fence;
243 dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
244 gpu->name);
245 dev_err(dev->dev, "%s: completed fence: %u\n",
246 gpu->name, fence);
247 dev_err(dev->dev, "%s: submitted fence: %u\n",
248 gpu->name, gpu->submitted_fence);
242 queue_work(priv->wq, &gpu->recover_work); 249 queue_work(priv->wq, &gpu->recover_work);
243 } 250 }
244 251