* [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump
@ 2026-03-03 16:18 Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel
This is the best way to describe the GPU to a tool loading
the devcoredump.
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 2 +
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 42 +++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h | 3 ++
3 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 0bb430853a9f..42a969512dcc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -262,6 +262,8 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
}
}
+ amdgpu_discovery_dump(coredump->adev, &p);
+
/* IP firmware information */
drm_printf(&p, "\nIP Firmwares\n");
amdgpu_devcoredump_fw_info(coredump->adev, &p);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 41e63c286912..d7325c23fa53 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -1380,6 +1380,48 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
kobject_put(&ip_top->kobj);
}
+/* devcoredump support */
+void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p)
+{
+ struct ip_discovery_top *ip_top = adev->discovery.ip_top;
+ struct ip_die_entry *ip_die_entry;
+ struct list_head *el_die, *el_hw_id, *el_hw_inst;
+ struct ip_hw_id *hw_id;
+ struct kset *die_kset;
+ struct ip_hw_instance *ip_inst;
+ int i = 0, j;
+
+ die_kset = &ip_top->die_kset;
+
+ drm_printf(p, "\nHW IP Discovery\n");
+ spin_lock(&die_kset->list_lock);
+ list_for_each(el_die, &die_kset->list) {
+ drm_printf(p, "die %d\n", i++);
+ ip_die_entry = to_ip_die_entry(list_to_kobj(el_die));
+
+ list_for_each(el_hw_id, &ip_die_entry->ip_kset.list) {
+ hw_id = to_ip_hw_id(list_to_kobj(el_hw_id));
+ drm_printf(p, "hw_id %d %s\n", hw_id->hw_id, hw_id_names[hw_id->hw_id]);
+
+ list_for_each(el_hw_inst, &hw_id->hw_id_kset.list) {
+ ip_inst = to_ip_hw_instance(list_to_kobj(el_hw_inst));
+ drm_printf(p, "\tinstance %d\n", ip_inst->num_instance);
+ drm_printf(p, "\tmajor %d\n", ip_inst->major);
+ drm_printf(p, "\tminor %d\n", ip_inst->minor);
+ drm_printf(p, "\trevision %d\n", ip_inst->revision);
+ drm_printf(p, "\tharvest 0x%01X\n", ip_inst->harvest);
+ drm_printf(p, "\tnum_base_addresses %d\n",
+ ip_inst->num_base_addresses);
+ for (j = 0; j < ip_inst->num_base_addresses; j++)
+ drm_printf(p, "\tbase_addr[%d] 0x%08X\n",
+ j, ip_inst->base_addr[j]);
+ }
+ }
+ }
+ spin_unlock(&die_kset->list_lock);
+}
+
+
/* ================================================== */
static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
index 4ce04486cc31..c8242992c912 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
@@ -30,6 +30,7 @@
#define DISCOVERY_TMR_OFFSET (64 << 10)
struct ip_discovery_top;
+struct drm_printer;
struct amdgpu_discovery_info {
struct debugfs_blob_wrapper debugfs_blob;
@@ -47,4 +48,6 @@ int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev,
struct amdgpu_gmc_memrange **ranges,
int *range_cnt, bool refresh);
+void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p);
+
#endif /* __AMDGPU_DISCOVERY__ */
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-03-03 16:18 ` Pierre-Eric Pelloux-Prayer
2026-03-04 7:51 ` Christian König
2026-03-03 16:18 ` [PATCH v3 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel
Update the way drm_coredump_printer is used based on its documentation
and Xe's code: the main idea is to generate the final version in one go
and then use memcpy to return the chunks requested by the caller of
amdgpu_devcoredump_read.
The generation is moved to a separate worker thread.
This cuts the time to copy the dump from 40s to ~0s on my machine.
---
v3:
- removed adev->coredump_in_progress and instead use work as
the synchronisation mechanism
- use kvfree instead of kfree
---
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 6 ++
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 83 +++++++++++++++++--
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 7 ++
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +
4 files changed, 91 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 057c8bd2ad89..e31dac2421b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -328,6 +328,7 @@ struct kfd_vm_fault_info;
struct amdgpu_hive_info;
struct amdgpu_reset_context;
struct amdgpu_reset_control;
+struct amdgpu_coredump_info;
enum amdgpu_cp_irq {
AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0,
@@ -1200,6 +1201,11 @@ struct amdgpu_device {
struct amdgpu_reset_domain *reset_domain;
+#ifdef CONFIG_DEV_COREDUMP
+ struct amdgpu_coredump_info *coredump;
+ struct work_struct coredump_work;
+#endif
+
struct mutex benchmark_mutex;
bool scpm_enabled;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 42a969512dcc..0c7fc3800f17 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -32,8 +32,13 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
bool vram_lost, struct amdgpu_job *job)
{
}
+void amdgpu_coredump_init(struct amdgpu_device *adev)
+{
+}
#else
+#define AMDGPU_CORE_DUMP_SIZE_MAX (256 * 1024 * 1024)
+
const char *hw_ip_names[MAX_HWIP] = {
[GC_HWIP] = "GC",
[HDP_HWIP] = "HDP",
@@ -196,11 +201,9 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
}
static ssize_t
-amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
- void *data, size_t datalen)
+amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
{
struct drm_printer p;
- struct amdgpu_coredump_info *coredump = data;
struct drm_print_iterator iter;
struct amdgpu_vm_fault_info *fault_info;
struct amdgpu_ip_block *ip_block;
@@ -208,7 +211,6 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
iter.data = buffer;
iter.offset = 0;
- iter.start = offset;
iter.remain = count;
p = drm_coredump_printer(&iter);
@@ -323,9 +325,63 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
return count - iter.remain;
}
+static ssize_t
+amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
+ void *data, size_t datalen)
+{
+ struct amdgpu_coredump_info *coredump = data;
+ ssize_t byte_copied;
+
+ if (!coredump)
+ return -ENODEV;
+
+ if (!coredump->formatted)
+ return -ENODEV;
+
+ if (offset >= coredump->formatted_size)
+ return 0;
+
+ byte_copied = count < coredump->formatted_size - offset ? count :
+ coredump->formatted_size - offset;
+ memcpy(buffer, coredump->formatted + offset, byte_copied);
+
+ return byte_copied;
+}
+
static void amdgpu_devcoredump_free(void *data)
{
- kfree(data);
+ struct amdgpu_coredump_info *coredump = data;
+
+ kvfree(coredump->formatted);
+ kvfree(data);
+}
+
+static void amdgpu_devcoredump_deferred_work(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, typeof(*adev), coredump_work);
+ struct amdgpu_coredump_info *coredump = adev->coredump;
+
+ /* Do a one-time preparation of the coredump output because
+ * repeatingly calling drm_coredump_printer is very slow.
+ */
+ coredump->formatted_size = amdgpu_devcoredump_format(
+ NULL, AMDGPU_CORE_DUMP_SIZE_MAX, coredump);
+ coredump->formatted = kvzalloc(coredump->formatted_size, GFP_KERNEL);
+ if (!coredump->formatted) {
+ amdgpu_devcoredump_free(coredump);
+ goto end;
+ }
+
+ amdgpu_devcoredump_format(coredump->formatted, coredump->formatted_size, coredump);
+
+ /* If there's an existing coredump for this device, the free function will be
+ * called immediately so coredump might be invalid after the call to dev_coredumpm.
+ */
+ dev_coredumpm(coredump->adev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
+ amdgpu_devcoredump_read, amdgpu_devcoredump_free);
+
+end:
+ adev->coredump = NULL;
}
void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
@@ -335,6 +391,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
struct amdgpu_coredump_info *coredump;
struct drm_sched_job *s_job;
+ /* No need to generate a new coredump if there's one in progress already. */
+ if (work_pending(&adev->coredump_work))
+ return;
+
coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
if (!coredump)
return;
@@ -361,11 +421,20 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
ktime_get_ts64(&coredump->reset_time);
- dev_coredumpm(dev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
- amdgpu_devcoredump_read, amdgpu_devcoredump_free);
+ /* Update the current coredump pointer (no lock needed, this function can only be called
+ * from a single thread)
+ */
+ adev->coredump = coredump;
+ /* Kick off coredump formatting to a worker thread. */
+ queue_work(system_unbound_wq, &adev->coredump_work);
drm_info(dev, "AMDGPU device coredump file has been created\n");
drm_info(dev, "Check your /sys/class/drm/card%d/device/devcoredump/data\n",
dev->primary->index);
}
+
+void amdgpu_coredump_init(struct amdgpu_device *adev)
+{
+ INIT_WORK(&adev->coredump_work, amdgpu_devcoredump_deferred_work);
+}
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
index ef9772c6bcc9..b3582d0b4ca4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
@@ -35,12 +35,19 @@ struct amdgpu_coredump_info {
struct amdgpu_device *adev;
struct amdgpu_task_info reset_task_info;
struct timespec64 reset_time;
+
bool skip_vram_check;
bool reset_vram_lost;
struct amdgpu_ring *ring;
+ /* Readable form of coredevdump, generate once to speed up
+ * reading it (see drm_coredump_printer's documentation).
+ */
+ ssize_t formatted_size;
+ char *formatted;
};
#endif
void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
bool vram_lost, struct amdgpu_job *job);
+void amdgpu_coredump_init(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 48540300b10a..1cb88955f651 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4503,6 +4503,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
INIT_WORK(&adev->userq_reset_work, amdgpu_userq_reset_work);
+ amdgpu_coredump_init(adev);
+
adev->gfx.gfx_off_req_count = 1;
adev->gfx.gfx_off_residency = 0;
adev->gfx.gfx_off_entrycount = 0;
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 3/6] drm/amdgpu: save ring content before resetting the device
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
@ 2026-03-03 16:18 ` Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel
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>
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 82 +++++++++++++++----
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 12 +++
2 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 0c7fc3800f17..58b2e764dd7c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -207,7 +207,9 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
struct drm_print_iterator iter;
struct amdgpu_vm_fault_info *fault_info;
struct amdgpu_ip_block *ip_block;
- int ver;
+ struct amdgpu_ring *ring;
+ int ver, i, j;
+ u32 ring_idx, off;
iter.data = buffer;
iter.offset = 0;
@@ -297,23 +299,25 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
/* Add ring buffer information */
drm_printf(&p, "Ring buffer information\n");
- for (int i = 0; i < coredump->adev->num_rings; i++) {
- int j = 0;
- struct amdgpu_ring *ring = coredump->adev->rings[i];
+ if (coredump->num_rings) {
+ 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",
- amdgpu_ring_get_rptr(ring),
- amdgpu_ring_get_wptr(ring),
- ring->buf_mask);
- drm_printf(&p, "Ring size in dwords: %d\n",
- ring->ring_size / 4);
- drm_printf(&p, "Ring contents\n");
- drm_printf(&p, "Offset \t Value\n");
+ drm_printf(&p, "ring name: %s\n", ring->name);
+ drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
+ coredump->rings[i].rptr,
+ coredump->rings[i].wptr,
+ ring->buf_mask);
+ drm_printf(&p, "Ring size in dwords: %d\n",
+ ring->ring_size / 4);
+ drm_printf(&p, "Ring contents\n");
+ drm_printf(&p, "Offset \t Value\n");
- while (j < ring->ring_size) {
- drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]);
- j += 4;
+ 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]);
}
}
@@ -353,6 +357,8 @@ static void amdgpu_devcoredump_free(void *data)
struct amdgpu_coredump_info *coredump = data;
kvfree(coredump->formatted);
+ kvfree(coredump->rings);
+ kvfree(coredump->rings_dw);
kvfree(data);
}
@@ -390,6 +396,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_coredump_info *coredump;
struct drm_sched_job *s_job;
+ u64 total_ring_size, ring_count;
+ struct amdgpu_ring *ring;
+ int i, off, idx;
/* No need to generate a new coredump if there's one in progress already. */
if (work_pending(&adev->coredump_work))
@@ -417,6 +426,47 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
coredump->ring = to_amdgpu_ring(s_job->sched);
}
+ /* 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];
+
+ /* Only dump rings with unsignalled fences. */
+ if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
+ coredump->ring != ring)
+ continue;
+
+ total_ring_size += ring->ring_size;
+ ring_count++;
+ }
+ coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
+ coredump->rings = kcalloc(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; i++) {
+ 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;
+
+ memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
+ off += ring->ring_size;
+ idx++;
+ }
+ coredump->num_rings = idx;
+ } else {
+ kvfree(coredump->rings_dw);
+ kvfree(coredump->rings);
+ coredump->rings_dw = NULL;
+ coredump->rings = NULL;
+ }
+
coredump->adev = adev;
ktime_get_ts64(&coredump->reset_time);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
index b3582d0b4ca4..5d6c58abf589 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
@@ -31,6 +31,13 @@
#define AMDGPU_COREDUMP_VERSION "1"
+struct amdgpu_coredump_ring {
+ u64 rptr;
+ u64 wptr;
+ u32 ring_index;
+ u32 offset;
+};
+
struct amdgpu_coredump_info {
struct amdgpu_device *adev;
struct amdgpu_task_info reset_task_info;
@@ -39,6 +46,11 @@ struct amdgpu_coredump_info {
bool skip_vram_check;
bool reset_vram_lost;
struct amdgpu_ring *ring;
+
+ struct amdgpu_coredump_ring *rings;
+ u32 *rings_dw;
+ u32 num_rings;
+
/* Readable form of coredevdump, generate once to speed up
* reading it (see drm_coredump_printer's documentation).
*/
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
@ 2026-03-03 16:18 ` Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
4 siblings, 0 replies; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel
This is tricky to implement right and we're going to need
it from the devcoredump.
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 84 +++++++++++++++++---------
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 3 +
2 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 807f8bcc7de5..6a5b3e148554 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -2930,6 +2930,50 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return 0;
}
+/**
+ * amdgpu_vm_lock_by_pasid - return an amdgpu_vm and its root bo from a pasid, if possible.
+ * @adev: amdgpu device pointer
+ * @root: root BO of the VM
+ * @pasid: PASID of the VM
+ * The caller needs to unreserve and unref the root bo on success.
+ */
+struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
+ struct amdgpu_bo **root, u32 pasid)
+{
+ unsigned long irqflags;
+ struct amdgpu_vm *vm;
+ int r;
+
+ xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
+ vm = xa_load(&adev->vm_manager.pasids, pasid);
+ *root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
+ xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
+
+ if (!*root)
+ return NULL;
+
+ r = amdgpu_bo_reserve(*root, true);
+ if (r)
+ goto error_unref;
+
+ /* Double check that the VM still exists */
+ xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
+ vm = xa_load(&adev->vm_manager.pasids, pasid);
+ if (vm && vm->root.bo != *root)
+ vm = NULL;
+ xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
+ if (!vm)
+ goto error_unlock;
+
+ return vm;
+error_unlock:
+ amdgpu_bo_unreserve(*root);
+
+error_unref:
+ amdgpu_bo_unref(root);
+ return NULL;
+}
+
/**
* amdgpu_vm_handle_fault - graceful handling of VM faults.
* @adev: amdgpu device pointer
@@ -2945,50 +2989,31 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
* shouldn't be reported any more.
*/
bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
- u32 vmid, u32 node_id, uint64_t addr, uint64_t ts,
- bool write_fault)
+ u32 vmid, u32 node_id, uint64_t addr,
+ uint64_t ts, bool write_fault)
{
bool is_compute_context = false;
struct amdgpu_bo *root;
- unsigned long irqflags;
uint64_t value, flags;
struct amdgpu_vm *vm;
int r;
- xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
- vm = xa_load(&adev->vm_manager.pasids, pasid);
- if (vm) {
- root = amdgpu_bo_ref(vm->root.bo);
- is_compute_context = vm->is_compute_context;
- } else {
- root = NULL;
- }
- xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
-
- if (!root)
+ vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
+ if (!vm)
return false;
+ is_compute_context = vm->is_compute_context;
+
addr /= AMDGPU_GPU_PAGE_SIZE;
- if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
- node_id, addr, ts, write_fault)) {
+ if (is_compute_context &&
+ !svm_range_restore_pages(adev, pasid, vmid, node_id, addr,
+ ts, write_fault)) {
+ amdgpu_bo_unreserve(root);
amdgpu_bo_unref(&root);
return true;
}
- r = amdgpu_bo_reserve(root, true);
- if (r)
- goto error_unref;
-
- /* Double check that the VM still exists */
- xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
- vm = xa_load(&adev->vm_manager.pasids, pasid);
- if (vm && vm->root.bo != root)
- vm = NULL;
- xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
- if (!vm)
- goto error_unlock;
-
flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED |
AMDGPU_PTE_SYSTEM;
@@ -3027,7 +3052,6 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
if (r < 0)
dev_err(adev->dev, "Can't handle page fault (%d)\n", r);
-error_unref:
amdgpu_bo_unref(&root);
return false;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 139642eacdd0..2051eda55c99 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -589,6 +589,9 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
u32 vmid, u32 node_id, uint64_t addr, uint64_t ts,
bool write_fault);
+struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
+ struct amdgpu_bo **root, u32 pasid);
+
void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 5/6] drm/amdgpu: store ib info for devcoredump
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
` (2 preceding siblings ...)
2026-03-03 16:18 ` [PATCH v3 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
@ 2026-03-03 16:18 ` Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
4 siblings, 0 replies; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter,
Kees Cook, Gustavo A. R. Silva
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel,
linux-hardening
Store the basic state of IBs so we can read it back in the
amdgpu_devcoredump_format function.
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 12 +++++++++++-
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 58b2e764dd7c..82814646695d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -395,6 +395,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
{
struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_coredump_info *coredump;
+ size_t size = sizeof(*coredump);
struct drm_sched_job *s_job;
u64 total_ring_size, ring_count;
struct amdgpu_ring *ring;
@@ -404,12 +405,16 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
if (work_pending(&adev->coredump_work))
return;
- coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
+ if (job && job->pasid)
+ size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
+
+ coredump = kzalloc(size, GFP_NOWAIT);
if (!coredump)
return;
coredump->skip_vram_check = skip_vram_check;
coredump->reset_vram_lost = vram_lost;
+ coredump->pasid = job->pasid;
if (job && job->pasid) {
struct amdgpu_task_info *ti;
@@ -419,6 +424,11 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
coredump->reset_task_info = *ti;
amdgpu_vm_put_task_info(ti);
}
+ coredump->num_ibs = job->num_ibs;
+ for (i = 0; i < job->num_ibs; ++i) {
+ coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr;
+ coredump->ibs[i].ib_size_dw = job->ibs[i].length_dw;
+ }
}
if (job) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
index 5d6c58abf589..cdcdde39f88a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
@@ -38,6 +38,11 @@ struct amdgpu_coredump_ring {
u32 offset;
};
+struct amdgpu_coredump_ib_info {
+ uint64_t gpu_addr;
+ u32 ib_size_dw;
+};
+
struct amdgpu_coredump_info {
struct amdgpu_device *adev;
struct amdgpu_task_info reset_task_info;
@@ -56,6 +61,10 @@ struct amdgpu_coredump_info {
*/
ssize_t formatted_size;
char *formatted;
+
+ unsigned int pasid;
+ int num_ibs;
+ struct amdgpu_coredump_ib_info ibs[] __counted_by(num_ibs);
};
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
` (3 preceding siblings ...)
2026-03-03 16:18 ` [PATCH v3 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-03-03 16:18 ` Pierre-Eric Pelloux-Prayer
4 siblings, 0 replies; 7+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher, Christian König, David Airlie, Simona Vetter
Cc: Pierre-Eric Pelloux-Prayer, amd-gfx, dri-devel, linux-kernel
Now that we have a worker thread, we can try to access the
IBs of the job. The process is:
* get the VM from the PASID
* get the BO from its VA and the VM
* map the BO for CPU access
* copy everything, then add it to the dump
Each step can fail so we have to be cautious.
These operations can be slow so when amdgpu_devcoredump_format
is called only to determine the size of the buffer we skip all
of them and assume they will succeed.
---
v3: use kvfree
---
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 93 ++++++++++++++++++-
1 file changed, 92 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 82814646695d..3115835617cc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -203,14 +203,24 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
static ssize_t
amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
{
+ struct amdgpu_device *adev = coredump->adev;
struct drm_printer p;
struct drm_print_iterator iter;
struct amdgpu_vm_fault_info *fault_info;
+ struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_ip_block *ip_block;
+ struct amdgpu_res_cursor cursor;
+ struct amdgpu_bo *abo, *root;
+ uint64_t va_start, offset;
struct amdgpu_ring *ring;
- int ver, i, j;
+ struct amdgpu_vm *vm;
+ u32 *ib_content;
+ uint8_t *kptr;
+ int ver, i, j, r;
u32 ring_idx, off;
+ bool sizing_pass;
+ sizing_pass = buffer == NULL;
iter.data = buffer;
iter.offset = 0;
iter.remain = count;
@@ -326,6 +336,87 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
else if (coredump->reset_vram_lost)
drm_printf(&p, "VRAM is lost due to GPU reset!\n");
+ if (coredump->num_ibs) {
+ /* Don't try to lookup the VM or map the BOs when calculating the
+ * size required to store the devcoredump.
+ */
+ if (sizing_pass)
+ vm = NULL;
+ else
+ vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
+
+ for (int i = 0; i < coredump->num_ibs && (sizing_pass || vm); i++) {
+ ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
+ GFP_KERNEL);
+ if (!ib_content)
+ continue;
+
+ /* vm=NULL can only happen when 'sizing_pass' is true. Skip to the
+ * drm_printf() calls (ib_content doesn't need to be initialized
+ * as its content won't be written anywhere).
+ */
+ if (!vm)
+ goto output_ib_content;
+
+ va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK;
+ mapping = amdgpu_vm_bo_lookup_mapping(vm, va_start / AMDGPU_GPU_PAGE_SIZE);
+ if (!mapping)
+ goto free_ib_content;
+
+ offset = va_start - (mapping->start * AMDGPU_GPU_PAGE_SIZE);
+ abo = amdgpu_bo_ref(mapping->bo_va->base.bo);
+ r = amdgpu_bo_reserve(abo, false);
+ if (r)
+ goto free_ib_content;
+
+ if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
+ off = 0;
+
+ if (abo->tbo.resource->mem_type != TTM_PL_VRAM)
+ goto unreserve_abo;
+
+ amdgpu_res_first(abo->tbo.resource, offset,
+ coredump->ibs[i].ib_size_dw * 4,
+ &cursor);
+ while (cursor.remaining) {
+ amdgpu_device_mm_access(adev, cursor.start / 4,
+ &ib_content[off], cursor.size / 4,
+ false);
+ off += cursor.size;
+ amdgpu_res_next(&cursor, cursor.size);
+ }
+ } else {
+ r = ttm_bo_kmap(&abo->tbo, 0,
+ PFN_UP(abo->tbo.base.size),
+ &abo->kmap);
+ if (r)
+ goto unreserve_abo;
+
+ kptr = amdgpu_bo_kptr(abo);
+ kptr += offset;
+ memcpy(ib_content, kptr,
+ coredump->ibs[i].ib_size_dw * 4);
+
+ amdgpu_bo_kunmap(abo);
+ }
+
+output_ib_content:
+ drm_printf(&p, "\nIB #%d 0x%llx %d dw\n",
+ i, coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw);
+ for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
+ drm_printf(&p, "0x%08x\n", ib_content[j]);
+unreserve_abo:
+ if (vm)
+ amdgpu_bo_unreserve(abo);
+free_ib_content:
+ kvfree(ib_content);
+ }
+ if (vm) {
+ amdgpu_bo_unreserve(root);
+ amdgpu_bo_unref(&root);
+ }
+ }
+
return count - iter.remain;
}
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker
2026-03-03 16:18 ` [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
@ 2026-03-04 7:51 ` Christian König
0 siblings, 0 replies; 7+ messages in thread
From: Christian König @ 2026-03-04 7:51 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer, Alex Deucher, David Airlie, Simona Vetter
Cc: amd-gfx, dri-devel, linux-kernel
On 3/3/26 17:18, Pierre-Eric Pelloux-Prayer wrote:
> Update the way drm_coredump_printer is used based on its documentation
> and Xe's code: the main idea is to generate the final version in one go
> and then use memcpy to return the chunks requested by the caller of
> amdgpu_devcoredump_read.
>
> The generation is moved to a separate worker thread.
>
> This cuts the time to copy the dump from 40s to ~0s on my machine.
>
> ---
> v3:
> - removed adev->coredump_in_progress and instead use work as
> the synchronisation mechanism
> - use kvfree instead of kfree
> ---
>
> Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
> Acked-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 6 ++
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 83 +++++++++++++++++--
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 7 ++
> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +
> 4 files changed, 91 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 057c8bd2ad89..e31dac2421b4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -328,6 +328,7 @@ struct kfd_vm_fault_info;
> struct amdgpu_hive_info;
> struct amdgpu_reset_context;
> struct amdgpu_reset_control;
> +struct amdgpu_coredump_info;
>
> enum amdgpu_cp_irq {
> AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0,
> @@ -1200,6 +1201,11 @@ struct amdgpu_device {
>
> struct amdgpu_reset_domain *reset_domain;
>
> +#ifdef CONFIG_DEV_COREDUMP
> + struct amdgpu_coredump_info *coredump;
> + struct work_struct coredump_work;
> +#endif
> +
> struct mutex benchmark_mutex;
>
> bool scpm_enabled;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> index 42a969512dcc..0c7fc3800f17 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> @@ -32,8 +32,13 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> bool vram_lost, struct amdgpu_job *job)
> {
> }
> +void amdgpu_coredump_init(struct amdgpu_device *adev)
> +{
> +}
> #else
>
> +#define AMDGPU_CORE_DUMP_SIZE_MAX (256 * 1024 * 1024)
> +
> const char *hw_ip_names[MAX_HWIP] = {
> [GC_HWIP] = "GC",
> [HDP_HWIP] = "HDP",
> @@ -196,11 +201,9 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
> }
>
> static ssize_t
> -amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
> - void *data, size_t datalen)
> +amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
> {
> struct drm_printer p;
> - struct amdgpu_coredump_info *coredump = data;
> struct drm_print_iterator iter;
> struct amdgpu_vm_fault_info *fault_info;
> struct amdgpu_ip_block *ip_block;
> @@ -208,7 +211,6 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
>
> iter.data = buffer;
> iter.offset = 0;
> - iter.start = offset;
> iter.remain = count;
>
> p = drm_coredump_printer(&iter);
> @@ -323,9 +325,63 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
> return count - iter.remain;
> }
>
> +static ssize_t
> +amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
> + void *data, size_t datalen)
> +{
> + struct amdgpu_coredump_info *coredump = data;
> + ssize_t byte_copied;
> +
> + if (!coredump)
> + return -ENODEV;
> +
> + if (!coredump->formatted)
> + return -ENODEV;
> +
> + if (offset >= coredump->formatted_size)
> + return 0;
> +
> + byte_copied = count < coredump->formatted_size - offset ? count :
> + coredump->formatted_size - offset;
> + memcpy(buffer, coredump->formatted + offset, byte_copied);
> +
> + return byte_copied;
> +}
> +
> static void amdgpu_devcoredump_free(void *data)
> {
> - kfree(data);
> + struct amdgpu_coredump_info *coredump = data;
> +
> + kvfree(coredump->formatted);
> + kvfree(data);
> +}
> +
> +static void amdgpu_devcoredump_deferred_work(struct work_struct *work)
> +{
> + struct amdgpu_device *adev = container_of(work, typeof(*adev), coredump_work);
> + struct amdgpu_coredump_info *coredump = adev->coredump;
> +
> + /* Do a one-time preparation of the coredump output because
> + * repeatingly calling drm_coredump_printer is very slow.
> + */
> + coredump->formatted_size = amdgpu_devcoredump_format(
> + NULL, AMDGPU_CORE_DUMP_SIZE_MAX, coredump);
> + coredump->formatted = kvzalloc(coredump->formatted_size, GFP_KERNEL);
> + if (!coredump->formatted) {
> + amdgpu_devcoredump_free(coredump);
> + goto end;
> + }
> +
> + amdgpu_devcoredump_format(coredump->formatted, coredump->formatted_size, coredump);
> +
> + /* If there's an existing coredump for this device, the free function will be
> + * called immediately so coredump might be invalid after the call to dev_coredumpm.
> + */
> + dev_coredumpm(coredump->adev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
> + amdgpu_devcoredump_read, amdgpu_devcoredump_free);
> +
> +end:
> + adev->coredump = NULL;
> }
>
> void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> @@ -335,6 +391,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> struct amdgpu_coredump_info *coredump;
> struct drm_sched_job *s_job;
>
> + /* No need to generate a new coredump if there's one in progress already. */
> + if (work_pending(&adev->coredump_work))
> + return;
> +
> coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
> if (!coredump)
> return;
> @@ -361,11 +421,20 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
>
> ktime_get_ts64(&coredump->reset_time);
>
> - dev_coredumpm(dev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
> - amdgpu_devcoredump_read, amdgpu_devcoredump_free);
> + /* Update the current coredump pointer (no lock needed, this function can only be called
> + * from a single thread)
> + */
> + adev->coredump = coredump;
> + /* Kick off coredump formatting to a worker thread. */
> + queue_work(system_unbound_wq, &adev->coredump_work);
>
> drm_info(dev, "AMDGPU device coredump file has been created\n");
> drm_info(dev, "Check your /sys/class/drm/card%d/device/devcoredump/data\n",
> dev->primary->index);
> }
> +
> +void amdgpu_coredump_init(struct amdgpu_device *adev)
> +{
> + INIT_WORK(&adev->coredump_work, amdgpu_devcoredump_deferred_work);
> +}
> #endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> index ef9772c6bcc9..b3582d0b4ca4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> @@ -35,12 +35,19 @@ struct amdgpu_coredump_info {
> struct amdgpu_device *adev;
> struct amdgpu_task_info reset_task_info;
> struct timespec64 reset_time;
> +
> bool skip_vram_check;
> bool reset_vram_lost;
> struct amdgpu_ring *ring;
> + /* Readable form of coredevdump, generate once to speed up
> + * reading it (see drm_coredump_printer's documentation).
> + */
> + ssize_t formatted_size;
> + char *formatted;
> };
> #endif
>
> void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> bool vram_lost, struct amdgpu_job *job);
> +void amdgpu_coredump_init(struct amdgpu_device *adev);
> #endif
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 48540300b10a..1cb88955f651 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -4503,6 +4503,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
> INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
> INIT_WORK(&adev->userq_reset_work, amdgpu_userq_reset_work);
>
> + amdgpu_coredump_init(adev);
> +
> adev->gfx.gfx_off_req_count = 1;
> adev->gfx.gfx_off_residency = 0;
> adev->gfx.gfx_off_entrycount = 0;
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-03-04 7:51 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-03 16:18 [PATCH v3 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
2026-03-04 7:51 ` Christian König
2026-03-03 16:18 ` [PATCH v3 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
2026-03-03 16:18 ` [PATCH v3 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®