[PATCH 2/2] drm/amdgpu: Allocate coredump ring buffers per ring
Lijo Lazar <[email protected]> Wed, 29 Jul 2026 17:31:18 +0530
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
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: eea85914d15b ("drm/amdgpu: save ring content before resetting the device")
Signed-off-by: Lijo Lazar <[email protected]>
Assisted-by: Claude Code
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 50 ++++++++++---------
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 3 +-
2 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 4dfea36997d4..87e15e39eb30 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -343,7 +343,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;
@@ -443,7 +443,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",
@@ -452,12 +451,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]);
}
}
@@ -498,10 +503,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);
}
@@ -543,9 +550,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))
@@ -585,7 +592,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];
@@ -594,38 +600,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];
+
+ 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);
- memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
- off += ring->ring_size / 4;
+ 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;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
index 63f27337c09a..cb874d8c3394 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
@@ -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
--
2.49.0