Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/gpu: Add the buffer objects from the submit to the crash dump

For hangs, dump copy out the contents of the buffer objects attached to the
guilty submission and print them in the crash dump report.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Jordan Crouse and committed by
Rob Clark
cdb95931 50f8d218

+116 -13
+14
Documentation/gpu/msm-crash-dump.rst
··· 66 66 The contents of the ring encoded as ascii85. Only the used 67 67 portions of the ring will be printed. 68 68 69 + bo 70 + List of buffers from the hanging submission if available. 71 + Each buffer object will have a uinque iova. 72 + 73 + iova 74 + GPU address of the buffer object. 75 + 76 + size 77 + Allocated size of the buffer object. 78 + 79 + data 80 + The contents of the buffer object encoded with ascii85. Only 81 + Trailing zeros at the end of the buffer will be skipped. 82 + 69 83 registers 70 84 Set of registers values. Each entry is on its own line enclosed 71 85 by brackets { }.
+48 -10
drivers/gpu/drm/msm/adreno/adreno_gpu.c
··· 437 437 for (i = 0; i < ARRAY_SIZE(state->ring); i++) 438 438 kfree(state->ring[i].data); 439 439 440 + for (i = 0; state->bos && i < state->nr_bos; i++) 441 + kvfree(state->bos[i].data); 442 + 443 + kfree(state->bos); 440 444 kfree(state->comm); 441 445 kfree(state->cmd); 442 446 kfree(state->registers); ··· 464 460 } 465 461 466 462 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 463 + 464 + static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) 465 + { 466 + char out[ASCII85_BUFSZ]; 467 + long l, datalen, i; 468 + 469 + if (!ptr || !len) 470 + return; 471 + 472 + /* 473 + * Only dump the non-zero part of the buffer - rarely will any data 474 + * completely fill the entire allocated size of the buffer 475 + */ 476 + for (datalen = 0, i = 0; i < len >> 2; i++) { 477 + if (ptr[i]) 478 + datalen = (i << 2) + 1; 479 + } 480 + 481 + /* Skip printing the object if it is empty */ 482 + if (datalen == 0) 483 + return; 484 + 485 + l = ascii85_encode_len(datalen); 486 + 487 + drm_puts(p, " data: !!ascii85 |\n"); 488 + drm_puts(p, " "); 489 + 490 + for (i = 0; i < l; i++) 491 + drm_puts(p, ascii85_encode(ptr[i], out)); 492 + 493 + drm_puts(p, "\n"); 494 + } 495 + 467 496 void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, 468 497 struct drm_printer *p) 469 498 { ··· 524 487 drm_printf(p, " wptr: %d\n", state->ring[i].wptr); 525 488 drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); 526 489 527 - if (state->ring[i].data && state->ring[i].data_size) { 528 - u32 *ptr = (u32 *) state->ring[i].data; 529 - char out[ASCII85_BUFSZ]; 530 - long len = ascii85_encode_len(state->ring[i].data_size); 531 - int j; 490 + adreno_show_object(p, state->ring[i].data, 491 + state->ring[i].data_size); 492 + } 532 493 533 - drm_printf(p, " data: !!ascii85 |\n"); 534 - drm_printf(p, " "); 494 + if (state->bos) { 495 + drm_puts(p, "bos:\n"); 535 496 536 - for (j = 0; j < len; j++) 537 - drm_printf(p, ascii85_encode(ptr[j], out)); 497 + for (i = 0; i < state->nr_bos; i++) { 498 + drm_printf(p, " - iova: 0x%016llx\n", 499 + state->bos[i].iova); 500 + drm_printf(p, " size: %zd\n", state->bos[i].size); 538 501 539 - drm_printf(p, "\n"); 502 + adreno_show_object(p, state->bos[i].data, 503 + state->bos[i].size); 540 504 } 541 505 } 542 506
+45 -3
drivers/gpu/drm/msm/msm_gpu.c
··· 318 318 msm_gpu_crashstate_put(gpu); 319 319 } 320 320 321 - static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, char *comm, 322 - char *cmd) 321 + static void msm_gpu_crashstate_get_bo(struct msm_gpu_state *state, 322 + struct msm_gem_object *obj, u64 iova, u32 flags) 323 + { 324 + struct msm_gpu_state_bo *state_bo = &state->bos[state->nr_bos]; 325 + 326 + /* Don't record write only objects */ 327 + 328 + state_bo->size = obj->base.size; 329 + state_bo->iova = iova; 330 + 331 + /* Only store the data for buffer objects marked for read */ 332 + if ((flags & MSM_SUBMIT_BO_READ)) { 333 + void *ptr; 334 + 335 + state_bo->data = kvmalloc(obj->base.size, GFP_KERNEL); 336 + if (!state_bo->data) 337 + return; 338 + 339 + ptr = msm_gem_get_vaddr_active(&obj->base); 340 + if (IS_ERR(ptr)) { 341 + kvfree(state_bo->data); 342 + return; 343 + } 344 + 345 + memcpy(state_bo->data, ptr, obj->base.size); 346 + msm_gem_put_vaddr(&obj->base); 347 + } 348 + 349 + state->nr_bos++; 350 + } 351 + 352 + static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, 353 + struct msm_gem_submit *submit, char *comm, char *cmd) 323 354 { 324 355 struct msm_gpu_state *state; 325 356 ··· 365 334 /* Fill in the additional crash state information */ 366 335 state->comm = kstrdup(comm, GFP_KERNEL); 367 336 state->cmd = kstrdup(cmd, GFP_KERNEL); 337 + 338 + if (submit) { 339 + int i; 340 + 341 + state->bos = kcalloc(submit->nr_bos, 342 + sizeof(struct msm_gpu_state_bo), GFP_KERNEL); 343 + 344 + for (i = 0; state->bos && i < submit->nr_bos; i++) 345 + msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, 346 + submit->bos[i].iova, submit->bos[i].flags); 347 + } 368 348 369 349 /* Set the active crash state to be dumped on failure */ 370 350 gpu->crashstate = state; ··· 476 434 477 435 /* Record the crash state */ 478 436 pm_runtime_get_sync(&gpu->pdev->dev); 479 - msm_gpu_crashstate_capture(gpu, comm, cmd); 437 + msm_gpu_crashstate_capture(gpu, submit, comm, cmd); 480 438 pm_runtime_put_sync(&gpu->pdev->dev); 481 439 482 440 kfree(cmd);
+9
drivers/gpu/drm/msm/msm_gpu.h
··· 181 181 struct kref ref; 182 182 }; 183 183 184 + struct msm_gpu_state_bo { 185 + u64 iova; 186 + size_t size; 187 + void *data; 188 + }; 189 + 184 190 struct msm_gpu_state { 185 191 struct kref ref; 186 192 struct timeval time; ··· 208 202 209 203 char *comm; 210 204 char *cmd; 205 + 206 + int nr_bos; 207 + struct msm_gpu_state_bo *bos; 211 208 }; 212 209 213 210 static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)