mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 11:03:07 -04:00
drm/amdgpu: Allocate coredump ring buffers per ring
Allocate each ring buffer separately. A single allocation summing all ring sizes can exceed the page allocator's MAX_ORDER limit and fail; per-ring buffers stay small enough to satisfy. The existing allocation style doesn't capture any ring data if the huge allocation fails. Splitting into multiple allocations helps to capture as much data as possible for the core dump. A failed ring is left with a NULL buffer and skipped when formatting. Fixes:eea85914d1("drm/amdgpu: save ring content before resetting the device") Signed-off-by: Lijo Lazar <lijo.lazar@amd.com> Assisted-by: Claude Code Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit3e8e92b789) Cc: stable@vger.kernel.org
This commit is contained in:
@@ -342,7 +342,7 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
struct amdgpu_ring *ring;
|
||||
int ver, i, j;
|
||||
u32 ring_idx, off;
|
||||
u32 ring_idx;
|
||||
bool sizing_pass;
|
||||
|
||||
sizing_pass = buffer == NULL;
|
||||
@@ -442,7 +442,6 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
for (i = 0; i < coredump->num_rings; i++) {
|
||||
ring_idx = coredump->rings[i].ring_index;
|
||||
ring = coredump->adev->rings[ring_idx];
|
||||
off = coredump->rings[i].offset;
|
||||
|
||||
drm_printf(&p, "ring name: %s\n", ring->name);
|
||||
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
|
||||
@@ -451,12 +450,18 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
ring->buf_mask);
|
||||
drm_printf(&p, "Ring size in dwords: %d\n",
|
||||
ring->ring_size / 4);
|
||||
|
||||
if (!coredump->rings[i].ring_dw) {
|
||||
drm_printf(&p, "Ring contents unavailable\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_printf(&p, "Ring contents\n");
|
||||
drm_printf(&p, "Offset \t Value\n");
|
||||
|
||||
for (j = 0; j < ring->ring_size; j += 4)
|
||||
drm_printf(&p, "0x%x \t 0x%x\n", j,
|
||||
coredump->rings_dw[off + j / 4]);
|
||||
coredump->rings[i].ring_dw[j / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,10 +502,12 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
|
||||
static void amdgpu_devcoredump_free(void *data)
|
||||
{
|
||||
struct amdgpu_coredump_info *coredump = data;
|
||||
u32 i;
|
||||
|
||||
kvfree(coredump->formatted);
|
||||
for (i = 0; i < coredump->num_rings; i++)
|
||||
kvfree(coredump->rings[i].ring_dw);
|
||||
kvfree(coredump->rings);
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(data);
|
||||
}
|
||||
|
||||
@@ -542,9 +549,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
struct amdgpu_coredump_info *coredump;
|
||||
size_t size = sizeof(*coredump);
|
||||
struct drm_sched_job *s_job;
|
||||
u64 total_ring_size, ring_count;
|
||||
u64 ring_count;
|
||||
struct amdgpu_ring *ring;
|
||||
int i, off, idx;
|
||||
int i, idx;
|
||||
|
||||
/* No need to generate a new coredump if there's one in progress already. */
|
||||
if (work_busy(&adev->coredump_work))
|
||||
@@ -584,7 +591,6 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
|
||||
/* Dump ring content if memory allocation succeeds. */
|
||||
ring_count = 0;
|
||||
total_ring_size = 0;
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
@@ -593,38 +599,34 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
total_ring_size += ring->ring_size;
|
||||
ring_count++;
|
||||
}
|
||||
if (ring_count) {
|
||||
coredump->rings_dw = kvzalloc(total_ring_size, GFP_NOWAIT);
|
||||
if (ring_count)
|
||||
coredump->rings = kvcalloc(ring_count,
|
||||
sizeof(struct amdgpu_coredump_ring),
|
||||
GFP_NOWAIT);
|
||||
}
|
||||
if (coredump->rings && coredump->rings_dw) {
|
||||
for (i = 0, off = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
if (coredump->rings) {
|
||||
for (i = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
struct amdgpu_coredump_ring *cdump_ring;
|
||||
|
||||
ring = adev->rings[i];
|
||||
|
||||
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
coredump->rings[idx].ring_index = ring->idx;
|
||||
coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring);
|
||||
coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring);
|
||||
coredump->rings[idx].offset = off;
|
||||
cdump_ring = &coredump->rings[idx];
|
||||
|
||||
memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
|
||||
off += ring->ring_size / 4;
|
||||
cdump_ring->ring_dw = kvzalloc(ring->ring_size, GFP_NOWAIT);
|
||||
if (cdump_ring->ring_dw)
|
||||
memcpy(cdump_ring->ring_dw, ring->ring, ring->ring_size);
|
||||
|
||||
cdump_ring->ring_index = ring->idx;
|
||||
cdump_ring->rptr = amdgpu_ring_get_rptr(ring);
|
||||
cdump_ring->wptr = amdgpu_ring_get_wptr(ring);
|
||||
idx++;
|
||||
}
|
||||
coredump->num_rings = idx;
|
||||
} else {
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(coredump->rings);
|
||||
coredump->rings_dw = NULL;
|
||||
coredump->rings = NULL;
|
||||
}
|
||||
|
||||
coredump->adev = adev;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
struct amdgpu_coredump_ring {
|
||||
u64 rptr;
|
||||
u64 wptr;
|
||||
u32 *ring_dw;
|
||||
u32 ring_index;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct amdgpu_coredump_ib_info {
|
||||
@@ -53,7 +53,6 @@ struct amdgpu_coredump_info {
|
||||
struct amdgpu_ring *ring;
|
||||
|
||||
struct amdgpu_coredump_ring *rings;
|
||||
u32 *rings_dw;
|
||||
u32 num_rings;
|
||||
|
||||
/* Readable form of coredevdump, generate once to speed up
|
||||
|
||||
Reference in New Issue
Block a user