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

Configure Feed

Select the types of activity you want to include in your feed.

drm/amdgpu: save ring content before resetting the device

Otherwise the content might not be relevant.

When a coredump is generated the rings with outstanding fences
are saved and then printed to the final devcoredump from the
worker thread.
Since this requires memory allocation, the ring capture might
be missing from the generated devcoredump.

Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Pierre-Eric Pelloux-Prayer and committed by
Alex Deucher
eea85914 48c33af0

+78 -16
+66 -16
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
··· 214 214 struct drm_print_iterator iter; 215 215 struct amdgpu_vm_fault_info *fault_info; 216 216 struct amdgpu_ip_block *ip_block; 217 - int ver; 217 + struct amdgpu_ring *ring; 218 + int ver, i, j; 219 + u32 ring_idx, off; 218 220 219 221 iter.data = buffer; 220 222 iter.offset = 0; ··· 305 303 306 304 /* Add ring buffer information */ 307 305 drm_printf(&p, "Ring buffer information\n"); 308 - for (int i = 0; i < coredump->adev->num_rings; i++) { 309 - int j = 0; 310 - struct amdgpu_ring *ring = coredump->adev->rings[i]; 306 + if (coredump->num_rings) { 307 + for (i = 0; i < coredump->num_rings; i++) { 308 + ring_idx = coredump->rings[i].ring_index; 309 + ring = coredump->adev->rings[ring_idx]; 310 + off = coredump->rings[i].offset; 311 311 312 - drm_printf(&p, "ring name: %s\n", ring->name); 313 - drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n", 314 - amdgpu_ring_get_rptr(ring), 315 - amdgpu_ring_get_wptr(ring), 316 - ring->buf_mask); 317 - drm_printf(&p, "Ring size in dwords: %d\n", 318 - ring->ring_size / 4); 319 - drm_printf(&p, "Ring contents\n"); 320 - drm_printf(&p, "Offset \t Value\n"); 312 + drm_printf(&p, "ring name: %s\n", ring->name); 313 + drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n", 314 + coredump->rings[i].rptr, 315 + coredump->rings[i].wptr, 316 + ring->buf_mask); 317 + drm_printf(&p, "Ring size in dwords: %d\n", 318 + ring->ring_size / 4); 319 + drm_printf(&p, "Ring contents\n"); 320 + drm_printf(&p, "Offset \t Value\n"); 321 321 322 - while (j < ring->ring_size) { 323 - drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]); 324 - j += 4; 322 + for (j = 0; j < ring->ring_size; j += 4) 323 + drm_printf(&p, "0x%x \t 0x%x\n", j, 324 + coredump->rings_dw[off + j / 4]); 325 325 } 326 326 } 327 327 ··· 363 359 struct amdgpu_coredump_info *coredump = data; 364 360 365 361 kvfree(coredump->formatted); 362 + kvfree(coredump->rings); 363 + kvfree(coredump->rings_dw); 366 364 kvfree(data); 367 365 } 368 366 ··· 402 396 struct drm_device *dev = adev_to_drm(adev); 403 397 struct amdgpu_coredump_info *coredump; 404 398 struct drm_sched_job *s_job; 399 + u64 total_ring_size, ring_count; 400 + struct amdgpu_ring *ring; 401 + int i, off, idx; 405 402 406 403 /* No need to generate a new coredump if there's one in progress already. */ 407 404 if (work_pending(&adev->coredump_work)) ··· 430 421 if (job) { 431 422 s_job = &job->base; 432 423 coredump->ring = to_amdgpu_ring(s_job->sched); 424 + } 425 + 426 + /* Dump ring content if memory allocation succeeds. */ 427 + ring_count = 0; 428 + total_ring_size = 0; 429 + for (i = 0; i < adev->num_rings; i++) { 430 + ring = adev->rings[i]; 431 + 432 + /* Only dump rings with unsignalled fences. */ 433 + if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq && 434 + coredump->ring != ring) 435 + continue; 436 + 437 + total_ring_size += ring->ring_size; 438 + ring_count++; 439 + } 440 + coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT); 441 + coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT); 442 + if (coredump->rings && coredump->rings_dw) { 443 + for (i = 0, off = 0, idx = 0; i < adev->num_rings; i++) { 444 + ring = adev->rings[i]; 445 + 446 + if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq && 447 + coredump->ring != ring) 448 + continue; 449 + 450 + coredump->rings[idx].ring_index = ring->idx; 451 + coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring); 452 + coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring); 453 + coredump->rings[idx].offset = off; 454 + 455 + memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size); 456 + off += ring->ring_size; 457 + idx++; 458 + } 459 + coredump->num_rings = idx; 460 + } else { 461 + kvfree(coredump->rings_dw); 462 + kvfree(coredump->rings); 463 + coredump->rings_dw = NULL; 464 + coredump->rings = NULL; 433 465 } 434 466 435 467 coredump->adev = adev;
+12
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
··· 31 31 32 32 #define AMDGPU_COREDUMP_VERSION "1" 33 33 34 + struct amdgpu_coredump_ring { 35 + u64 rptr; 36 + u64 wptr; 37 + u32 ring_index; 38 + u32 offset; 39 + }; 40 + 34 41 struct amdgpu_coredump_info { 35 42 struct amdgpu_device *adev; 36 43 struct amdgpu_task_info reset_task_info; ··· 46 39 bool skip_vram_check; 47 40 bool reset_vram_lost; 48 41 struct amdgpu_ring *ring; 42 + 43 + struct amdgpu_coredump_ring *rings; 44 + u32 *rings_dw; 45 + u32 num_rings; 46 + 49 47 /* Readable form of coredevdump, generate once to speed up 50 48 * reading it (see drm_coredump_printer's documentation). 51 49 */