diff options
| -rw-r--r-- | drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.c | 26 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 52 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.h | 10 |
5 files changed, 87 insertions, 5 deletions
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 13d61bbed302..035bd13dc8bd 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c | |||
| @@ -371,6 +371,7 @@ static const struct adreno_gpu_funcs funcs = { | |||
| 371 | .hw_init = a3xx_hw_init, | 371 | .hw_init = a3xx_hw_init, |
| 372 | .pm_suspend = msm_gpu_pm_suspend, | 372 | .pm_suspend = msm_gpu_pm_suspend, |
| 373 | .pm_resume = msm_gpu_pm_resume, | 373 | .pm_resume = msm_gpu_pm_resume, |
| 374 | .recover = adreno_recover, | ||
| 374 | .last_fence = adreno_last_fence, | 375 | .last_fence = adreno_last_fence, |
| 375 | .submit = adreno_submit, | 376 | .submit = adreno_submit, |
| 376 | .flush = adreno_flush, | 377 | .flush = adreno_flush, |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 282163ee3fa5..a60584763b61 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c | |||
| @@ -111,6 +111,28 @@ uint32_t adreno_last_fence(struct msm_gpu *gpu) | |||
| 111 | return adreno_gpu->memptrs->fence; | 111 | return adreno_gpu->memptrs->fence; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | void adreno_recover(struct msm_gpu *gpu) | ||
| 115 | { | ||
| 116 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||
| 117 | struct drm_device *dev = gpu->dev; | ||
| 118 | int ret; | ||
| 119 | |||
| 120 | gpu->funcs->pm_suspend(gpu); | ||
| 121 | |||
| 122 | /* reset ringbuffer: */ | ||
| 123 | gpu->rb->cur = gpu->rb->start; | ||
| 124 | |||
| 125 | /* reset completed fence seqno, just discard anything pending: */ | ||
| 126 | adreno_gpu->memptrs->fence = gpu->submitted_fence; | ||
| 127 | |||
| 128 | gpu->funcs->pm_resume(gpu); | ||
| 129 | ret = gpu->funcs->hw_init(gpu); | ||
| 130 | if (ret) { | ||
| 131 | dev_err(dev->dev, "gpu hw init failed: %d\n", ret); | ||
| 132 | /* hmm, oh well? */ | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 114 | int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | 136 | int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, |
| 115 | struct msm_file_private *ctx) | 137 | struct msm_file_private *ctx) |
| 116 | { | 138 | { |
| @@ -119,8 +141,6 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | |||
| 119 | struct msm_ringbuffer *ring = gpu->rb; | 141 | struct msm_ringbuffer *ring = gpu->rb; |
| 120 | unsigned i, ibs = 0; | 142 | unsigned i, ibs = 0; |
| 121 | 143 | ||
| 122 | adreno_gpu->last_fence = submit->fence; | ||
| 123 | |||
| 124 | for (i = 0; i < submit->nr_cmds; i++) { | 144 | for (i = 0; i < submit->nr_cmds; i++) { |
| 125 | switch (submit->cmd[i].type) { | 145 | switch (submit->cmd[i].type) { |
| 126 | case MSM_SUBMIT_CMD_IB_TARGET_BUF: | 146 | case MSM_SUBMIT_CMD_IB_TARGET_BUF: |
| @@ -225,7 +245,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) | |||
| 225 | adreno_gpu->rev.patchid); | 245 | adreno_gpu->rev.patchid); |
| 226 | 246 | ||
| 227 | seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, | 247 | seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, |
| 228 | adreno_gpu->last_fence); | 248 | gpu->submitted_fence); |
| 229 | seq_printf(m, "rptr: %d\n", adreno_gpu->memptrs->rptr); | 249 | seq_printf(m, "rptr: %d\n", adreno_gpu->memptrs->rptr); |
| 230 | seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); | 250 | seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); |
| 231 | seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); | 251 | seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 6b49c4f27fec..f73abfba7c22 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h | |||
| @@ -54,8 +54,6 @@ struct adreno_gpu { | |||
| 54 | uint32_t revn; /* numeric revision name */ | 54 | uint32_t revn; /* numeric revision name */ |
| 55 | const struct adreno_gpu_funcs *funcs; | 55 | const struct adreno_gpu_funcs *funcs; |
| 56 | 56 | ||
| 57 | uint32_t last_fence; | ||
| 58 | |||
| 59 | /* firmware: */ | 57 | /* firmware: */ |
| 60 | const struct firmware *pm4, *pfp; | 58 | const struct firmware *pm4, *pfp; |
| 61 | 59 | ||
| @@ -99,6 +97,7 @@ static inline bool adreno_is_a330(struct adreno_gpu *gpu) | |||
| 99 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); | 97 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); |
| 100 | int adreno_hw_init(struct msm_gpu *gpu); | 98 | int adreno_hw_init(struct msm_gpu *gpu); |
| 101 | uint32_t adreno_last_fence(struct msm_gpu *gpu); | 99 | uint32_t adreno_last_fence(struct msm_gpu *gpu); |
| 100 | void adreno_recover(struct msm_gpu *gpu); | ||
| 102 | int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | 101 | int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, |
| 103 | struct msm_file_private *ctx); | 102 | struct msm_file_private *ctx); |
| 104 | void adreno_flush(struct msm_gpu *gpu); | 103 | void adreno_flush(struct msm_gpu *gpu); |
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7c6541e4a7ec..e1e1ec9321ff 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c | |||
| @@ -203,6 +203,51 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) | |||
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /* | 205 | /* |
| 206 | * Hangcheck detection for locked gpu: | ||
| 207 | */ | ||
| 208 | |||
| 209 | static void recover_worker(struct work_struct *work) | ||
| 210 | { | ||
| 211 | struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); | ||
| 212 | struct drm_device *dev = gpu->dev; | ||
| 213 | |||
| 214 | dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); | ||
| 215 | |||
| 216 | mutex_lock(&dev->struct_mutex); | ||
| 217 | gpu->funcs->recover(gpu); | ||
| 218 | mutex_unlock(&dev->struct_mutex); | ||
| 219 | |||
| 220 | msm_gpu_retire(gpu); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void hangcheck_timer_reset(struct msm_gpu *gpu) | ||
| 224 | { | ||
| 225 | DBG("%s", gpu->name); | ||
| 226 | mod_timer(&gpu->hangcheck_timer, | ||
| 227 | round_jiffies_up(jiffies + DRM_MSM_HANGCHECK_JIFFIES)); | ||
| 228 | } | ||
| 229 | |||
| 230 | static void hangcheck_handler(unsigned long data) | ||
| 231 | { | ||
| 232 | struct msm_gpu *gpu = (struct msm_gpu *)data; | ||
| 233 | uint32_t fence = gpu->funcs->last_fence(gpu); | ||
| 234 | |||
| 235 | if (fence != gpu->hangcheck_fence) { | ||
| 236 | /* some progress has been made.. ya! */ | ||
| 237 | gpu->hangcheck_fence = fence; | ||
| 238 | } else if (fence < gpu->submitted_fence) { | ||
| 239 | /* no progress and not done.. hung! */ | ||
| 240 | struct msm_drm_private *priv = gpu->dev->dev_private; | ||
| 241 | gpu->hangcheck_fence = fence; | ||
| 242 | queue_work(priv->wq, &gpu->recover_work); | ||
| 243 | } | ||
| 244 | |||
| 245 | /* if still more pending work, reset the hangcheck timer: */ | ||
| 246 | if (gpu->submitted_fence > gpu->hangcheck_fence) | ||
| 247 | hangcheck_timer_reset(gpu); | ||
| 248 | } | ||
| 249 | |||
| 250 | /* | ||
| 206 | * Cmdstream submission/retirement: | 251 | * Cmdstream submission/retirement: |
| 207 | */ | 252 | */ |
| 208 | 253 | ||
| @@ -254,6 +299,8 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | |||
| 254 | 299 | ||
| 255 | submit->fence = ++priv->next_fence; | 300 | submit->fence = ++priv->next_fence; |
| 256 | 301 | ||
| 302 | gpu->submitted_fence = submit->fence; | ||
| 303 | |||
| 257 | ret = gpu->funcs->submit(gpu, submit, ctx); | 304 | ret = gpu->funcs->submit(gpu, submit, ctx); |
| 258 | priv->lastctx = ctx; | 305 | priv->lastctx = ctx; |
| 259 | 306 | ||
| @@ -276,6 +323,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | |||
| 276 | 323 | ||
| 277 | msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence); | 324 | msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence); |
| 278 | } | 325 | } |
| 326 | hangcheck_timer_reset(gpu); | ||
| 279 | mutex_unlock(&dev->struct_mutex); | 327 | mutex_unlock(&dev->struct_mutex); |
| 280 | 328 | ||
| 281 | return ret; | 329 | return ret; |
| @@ -307,6 +355,10 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, | |||
| 307 | 355 | ||
| 308 | INIT_LIST_HEAD(&gpu->active_list); | 356 | INIT_LIST_HEAD(&gpu->active_list); |
| 309 | INIT_WORK(&gpu->retire_work, retire_worker); | 357 | INIT_WORK(&gpu->retire_work, retire_worker); |
| 358 | INIT_WORK(&gpu->recover_work, recover_worker); | ||
| 359 | |||
| 360 | setup_timer(&gpu->hangcheck_timer, hangcheck_handler, | ||
| 361 | (unsigned long)gpu); | ||
| 310 | 362 | ||
| 311 | BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks)); | 363 | BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks)); |
| 312 | 364 | ||
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 8d2cd6c2226b..8cd829e520bb 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/ | |||
