* [PATCH v1 2/6] drm/amdgpu: move devcoredump generation to a worker
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-02-11 10:26 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:02 ` Alex Deucher
2026-02-11 10:26 ` [PATCH v1 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
` (4 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-11 10:26 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.
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 ++
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 66 +++++++++++++++++--
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++
3 files changed, 74 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 057c8bd2ad89..ae81a428cfb5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1200,6 +1200,11 @@ struct amdgpu_device {
struct amdgpu_reset_domain *reset_domain;
+#ifdef CONFIG_DEV_COREDUMP
+ /* If a coredump state capture is in progress don't start a new one. */
+ bool coredump_in_progress;
+#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..0808ca98ccd9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -34,6 +34,8 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
}
#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 +198,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 +208,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,11 +322,60 @@ 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;
+
+ flush_work(&coredump->work);
+
+ 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)
{
+ struct amdgpu_coredump_info *coredump = data;
+
+ cancel_work_sync(&coredump->work);
+ coredump->adev->coredump_in_progress = false;
+ kfree(coredump->formatted);
kfree(data);
}
+static void amdgpu_devcoredump_deferred_work(struct work_struct *work)
+{
+ struct amdgpu_coredump_info *coredump = container_of(work, typeof(*coredump), work);
+
+ dev_coredumpm(coredump->adev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
+ amdgpu_devcoredump_read, amdgpu_devcoredump_free);
+
+ /* 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)
+ return;
+ amdgpu_devcoredump_format(coredump->formatted, coredump->formatted_size, coredump);
+ coredump->adev->coredump_in_progress = false;
+}
+
void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
bool vram_lost, struct amdgpu_job *job)
{
@@ -335,10 +383,15 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
struct amdgpu_coredump_info *coredump;
struct drm_sched_job *s_job;
+ if (adev->coredump_in_progress)
+ return;
+
coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
if (!coredump)
return;
+ adev->coredump_in_progress = true;
+
coredump->skip_vram_check = skip_vram_check;
coredump->reset_vram_lost = vram_lost;
@@ -361,8 +414,9 @@ 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);
+ /* Kick off coredump formatting to a worker thread. */
+ INIT_WORK(&coredump->work, amdgpu_devcoredump_deferred_work);
+ queue_work(system_unbound_wq, &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",
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
index ef9772c6bcc9..4c37a852b74a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
@@ -35,9 +35,18 @@ struct amdgpu_coredump_info {
struct amdgpu_device *adev;
struct amdgpu_task_info reset_task_info;
struct timespec64 reset_time;
+
+ struct work_struct work;
+
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
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 2/6] drm/amdgpu: move devcoredump generation to a worker
2026-02-11 10:26 ` [PATCH v1 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:02 ` Alex Deucher
0 siblings, 0 replies; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:02 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
On Wed, Feb 11, 2026 at 5:28 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> 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.
>
> 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 | 5 ++
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 66 +++++++++++++++++--
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++
> 3 files changed, 74 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 057c8bd2ad89..ae81a428cfb5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -1200,6 +1200,11 @@ struct amdgpu_device {
>
> struct amdgpu_reset_domain *reset_domain;
>
> +#ifdef CONFIG_DEV_COREDUMP
> + /* If a coredump state capture is in progress don't start a new one. */
> + bool coredump_in_progress;
> +#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..0808ca98ccd9 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> @@ -34,6 +34,8 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> }
> #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 +198,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 +208,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,11 +322,60 @@ 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;
> +
> + flush_work(&coredump->work);
> +
> + 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)
> {
> + struct amdgpu_coredump_info *coredump = data;
> +
> + cancel_work_sync(&coredump->work);
> + coredump->adev->coredump_in_progress = false;
> + kfree(coredump->formatted);
> kfree(data);
> }
>
> +static void amdgpu_devcoredump_deferred_work(struct work_struct *work)
> +{
> + struct amdgpu_coredump_info *coredump = container_of(work, typeof(*coredump), work);
> +
> + dev_coredumpm(coredump->adev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT,
> + amdgpu_devcoredump_read, amdgpu_devcoredump_free);
> +
> + /* 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)
> + return;
> + amdgpu_devcoredump_format(coredump->formatted, coredump->formatted_size, coredump);
> + coredump->adev->coredump_in_progress = false;
> +}
> +
> void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> bool vram_lost, struct amdgpu_job *job)
> {
> @@ -335,10 +383,15 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> struct amdgpu_coredump_info *coredump;
> struct drm_sched_job *s_job;
>
> + if (adev->coredump_in_progress)
> + return;
> +
> coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
> if (!coredump)
> return;
>
> + adev->coredump_in_progress = true;
> +
> coredump->skip_vram_check = skip_vram_check;
> coredump->reset_vram_lost = vram_lost;
>
> @@ -361,8 +414,9 @@ 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);
> + /* Kick off coredump formatting to a worker thread. */
> + INIT_WORK(&coredump->work, amdgpu_devcoredump_deferred_work);
> + queue_work(system_unbound_wq, &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",
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> index ef9772c6bcc9..4c37a852b74a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h
> @@ -35,9 +35,18 @@ struct amdgpu_coredump_info {
> struct amdgpu_device *adev;
> struct amdgpu_task_info reset_task_info;
> struct timespec64 reset_time;
> +
> + struct work_struct work;
> +
> 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
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v1 3/6] drm/amdgpu: save ring content before resetting the device
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
2026-02-11 10:26 ` [PATCH v1 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
@ 2026-02-11 10:26 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:11 ` Alex Deucher
2026-02-11 10:26 ` [PATCH v1 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
` (3 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-11 10:26 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>
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 85 +++++++++++++++----
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 13 ++-
2 files changed, 81 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 0808ca98ccd9..0bf85ab43204 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -204,7 +204,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;
@@ -294,23 +296,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]);
}
}
@@ -354,6 +358,8 @@ static void amdgpu_devcoredump_free(void *data)
cancel_work_sync(&coredump->work);
coredump->adev->coredump_in_progress = false;
kfree(coredump->formatted);
+ kfree(coredump->rings);
+ kfree(coredump->rings_dw);
kfree(data);
}
@@ -382,6 +388,12 @@ 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;
+
+ if (adev->coredump_in_progress)
+ return;
if (adev->coredump_in_progress)
return;
@@ -410,6 +422,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 {
+ kfree(coredump->rings_dw);
+ kfree(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 4c37a852b74a..1c3d22356cc7 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;
@@ -41,12 +48,16 @@ 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).
*/
ssize_t formatted_size;
char *formatted;
-
};
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 3/6] drm/amdgpu: save ring content before resetting the device
2026-02-11 10:26 ` [PATCH v1 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:11 ` Alex Deucher
0 siblings, 0 replies; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:11 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
On Wed, Feb 11, 2026 at 5:29 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> wrote:
>
> 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 | 85 +++++++++++++++----
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 13 ++-
> 2 files changed, 81 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> index 0808ca98ccd9..0bf85ab43204 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> @@ -204,7 +204,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;
> @@ -294,23 +296,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]);
> }
> }
>
> @@ -354,6 +358,8 @@ static void amdgpu_devcoredump_free(void *data)
> cancel_work_sync(&coredump->work);
> coredump->adev->coredump_in_progress = false;
> kfree(coredump->formatted);
> + kfree(coredump->rings);
> + kfree(coredump->rings_dw);
> kfree(data);
> }
>
> @@ -382,6 +388,12 @@ 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;
> +
> + if (adev->coredump_in_progress)
> + return;
>
> if (adev->coredump_in_progress)
> return;
> @@ -410,6 +422,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 {
> + kfree(coredump->rings_dw);
> + kfree(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 4c37a852b74a..1c3d22356cc7 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;
> @@ -41,12 +48,16 @@ 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).
> */
> ssize_t formatted_size;
> char *formatted;
> -
> };
> #endif
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v1 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
2026-02-11 10:26 ` [PATCH v1 2/6] drm/amdgpu: move devcoredump generation to a worker Pierre-Eric Pelloux-Prayer
2026-02-11 10:26 ` [PATCH v1 3/6] drm/amdgpu: save ring content before resetting the device Pierre-Eric Pelloux-Prayer
@ 2026-02-11 10:26 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:21 ` Alex Deucher
2026-02-11 10:26 ` [PATCH v1 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
` (2 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-11 10:26 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>
---
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] 15+ messages in thread* Re: [PATCH v1 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault
2026-02-11 10:26 ` [PATCH v1 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:21 ` Alex Deucher
0 siblings, 0 replies; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:21 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
On Wed, Feb 11, 2026 at 5:37 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> wrote:
>
> 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] 15+ messages in thread
* [PATCH v1 5/6] drm/amdgpu: store ib info for devcoredump
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
` (2 preceding siblings ...)
2026-02-11 10:26 ` [PATCH v1 4/6] drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault Pierre-Eric Pelloux-Prayer
@ 2026-02-11 10:26 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:21 ` Alex Deucher
2026-02-11 10:26 ` [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
2026-02-17 16:02 ` [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Alex Deucher
5 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-11 10:26 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>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 13 ++++++++++---
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++++++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 0bf85ab43204..d0af8a294abf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -387,6 +387,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;
@@ -395,10 +396,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
if (adev->coredump_in_progress)
return;
- if (adev->coredump_in_progress)
- return;
+ if (job && job->pasid)
+ size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
- coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
+ coredump = kzalloc(size, GFP_NOWAIT);
if (!coredump)
return;
@@ -406,6 +407,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
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;
@@ -415,6 +417,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 1c3d22356cc7..49486d1f6a5d 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;
@@ -58,6 +63,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] 15+ messages in thread* Re: [PATCH v1 5/6] drm/amdgpu: store ib info for devcoredump
2026-02-11 10:26 ` [PATCH v1 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:21 ` Alex Deucher
0 siblings, 0 replies; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:21 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
Kees Cook, Gustavo A. R. Silva, amd-gfx, dri-devel, linux-kernel,
linux-hardening
On Wed, Feb 11, 2026 at 5:29 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> wrote:
>
> 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 | 13 ++++++++++---
> drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++++++++
> 2 files changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> index 0bf85ab43204..d0af8a294abf 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> @@ -387,6 +387,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;
> @@ -395,10 +396,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
> if (adev->coredump_in_progress)
> return;
>
> - if (adev->coredump_in_progress)
> - return;
> + if (job && job->pasid)
> + size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
>
> - coredump = kzalloc(sizeof(*coredump), GFP_NOWAIT);
> + coredump = kzalloc(size, GFP_NOWAIT);
> if (!coredump)
> return;
>
> @@ -406,6 +407,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
>
> 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;
> @@ -415,6 +417,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 1c3d22356cc7..49486d1f6a5d 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;
> @@ -58,6 +63,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] 15+ messages in thread
* [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
` (3 preceding siblings ...)
2026-02-11 10:26 ` [PATCH v1 5/6] drm/amdgpu: store ib info for devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-02-11 10:26 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:20 ` Alex Deucher
2026-02-17 16:02 ` [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Alex Deucher
5 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-11 10:26 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.
Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
---
.../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 84 ++++++++++++++++++-
1 file changed, 83 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 d0af8a294abf..d576518c212d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -200,12 +200,20 @@ 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;
iter.data = buffer;
@@ -323,6 +331,80 @@ 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) {
+ if (buffer)
+ vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
+ else
+ vm = NULL;
+
+ for (int i = 0; i < coredump->num_ibs && (!buffer || vm); i++) {
+ ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
+ GFP_KERNEL);
+ if (!ib_content)
+ continue;
+
+ 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:
+ kfree(ib_content);
+ }
+ if (vm) {
+ amdgpu_bo_unreserve(root);
+ amdgpu_bo_unref(&root);
+ }
+ }
+
return count - iter.remain;
}
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-02-11 10:26 ` [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:20 ` Alex Deucher
2026-02-17 16:38 ` Pierre-Eric Pelloux-Prayer
0 siblings, 1 reply; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:20 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
On Wed, Feb 11, 2026 at 6:07 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> wrote:
>
> 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.
>
> Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
> ---
> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 84 ++++++++++++++++++-
> 1 file changed, 83 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 d0af8a294abf..d576518c212d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> @@ -200,12 +200,20 @@ 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;
>
> iter.data = buffer;
> @@ -323,6 +331,80 @@ 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) {
> + if (buffer)
> + vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
> + else
> + vm = NULL;
Is there any point in doing the loop if the vm is NULL?
> +
> + for (int i = 0; i < coredump->num_ibs && (!buffer || vm); i++) {
> + ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
> + GFP_KERNEL);
Shouldn't this be GFP_NOWAIT?
Alex
> + if (!ib_content)
> + continue;
> +
> + 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:
> + kfree(ib_content);
> + }
> + if (vm) {
> + amdgpu_bo_unreserve(root);
> + amdgpu_bo_unref(&root);
> + }
> + }
> +
> return count - iter.remain;
> }
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-02-17 16:20 ` Alex Deucher
@ 2026-02-17 16:38 ` Pierre-Eric Pelloux-Prayer
2026-02-17 16:47 ` Alex Deucher
0 siblings, 1 reply; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-17 16:38 UTC (permalink / raw)
To: Alex Deucher, Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
Le 17/02/2026 à 17:20, Alex Deucher a écrit :
> On Wed, Feb 11, 2026 at 6:07 AM Pierre-Eric Pelloux-Prayer
> <pierre-eric.pelloux-prayer@amd.com> wrote:
>>
>> 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.
>>
>> Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
>> ---
>> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 84 ++++++++++++++++++-
>> 1 file changed, 83 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 d0af8a294abf..d576518c212d 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
>> @@ -200,12 +200,20 @@ 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;
>>
>> iter.data = buffer;
>> @@ -323,6 +331,80 @@ 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) {
>> + if (buffer)
>> + vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
>> + else
>> + vm = NULL;
>
> Is there any point in doing the loop if the vm is NULL?
Yes : when doing the first pass to size the final buffer I skip the
buffers mapping + read operations that might be slow and instead just
account for the outputting of ib_size_dw dwords.
>
>> +
>> + for (int i = 0; i < coredump->num_ibs && (!buffer || vm); i++) {
>> + ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
>> + GFP_KERNEL);
>
> Shouldn't this be GFP_NOWAIT?
This is executed by a worker so GFP_KERNEL should be ok?
Pierre-Eric
>
> Alex
>
>> + if (!ib_content)
>> + continue;
>> +
>> + 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:
>> + kfree(ib_content);
>> + }
>> + if (vm) {
>> + amdgpu_bo_unreserve(root);
>> + amdgpu_bo_unref(&root);
>> + }
>> + }
>> +
>> return count - iter.remain;
>> }
>>
>> --
>> 2.43.0
>>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-02-17 16:38 ` Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:47 ` Alex Deucher
2026-02-23 15:03 ` Pierre-Eric Pelloux-Prayer
0 siblings, 1 reply; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:47 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Pierre-Eric Pelloux-Prayer, Alex Deucher, Christian König,
David Airlie, Simona Vetter, amd-gfx, dri-devel, linux-kernel
On Tue, Feb 17, 2026 at 11:38 AM Pierre-Eric Pelloux-Prayer
<pierre-eric@damsy.net> wrote:
>
>
>
> Le 17/02/2026 à 17:20, Alex Deucher a écrit :
> > On Wed, Feb 11, 2026 at 6:07 AM Pierre-Eric Pelloux-Prayer
> > <pierre-eric.pelloux-prayer@amd.com> wrote:
> >>
> >> 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.
> >>
> >> Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
> >> ---
> >> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 84 ++++++++++++++++++-
> >> 1 file changed, 83 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 d0af8a294abf..d576518c212d 100644
> >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
> >> @@ -200,12 +200,20 @@ 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;
> >>
> >> iter.data = buffer;
> >> @@ -323,6 +331,80 @@ 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) {
> >> + if (buffer)
> >> + vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
> >> + else
> >> + vm = NULL;
> >
> > Is there any point in doing the loop if the vm is NULL?
>
> Yes : when doing the first pass to size the final buffer I skip the
> buffers mapping + read operations that might be slow and instead just
> account for the outputting of ib_size_dw dwords.
But if you don't map the buffer, you'll just be dumping the random
content from ib_content[].
>
> >
> >> +
> >> + for (int i = 0; i < coredump->num_ibs && (!buffer || vm); i++) {
> >> + ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
> >> + GFP_KERNEL);
> >
> > Shouldn't this be GFP_NOWAIT?
>
> This is executed by a worker so GFP_KERNEL should be ok?
Oh, right. Yeah, should be ok.
Alex
>
> Pierre-Eric
>
> >
> > Alex
> >
> >> + if (!ib_content)
> >> + continue;
> >> +
> >> + 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:
> >> + kfree(ib_content);
> >> + }
> >> + if (vm) {
> >> + amdgpu_bo_unreserve(root);
> >> + amdgpu_bo_unref(&root);
> >> + }
> >> + }
> >> +
> >> return count - iter.remain;
> >> }
> >>
> >> --
> >> 2.43.0
> >>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump
2026-02-17 16:47 ` Alex Deucher
@ 2026-02-23 15:03 ` Pierre-Eric Pelloux-Prayer
0 siblings, 0 replies; 15+ messages in thread
From: Pierre-Eric Pelloux-Prayer @ 2026-02-23 15:03 UTC (permalink / raw)
To: Alex Deucher
Cc: Pierre-Eric Pelloux-Prayer, Alex Deucher, Christian König,
David Airlie, Simona Vetter, amd-gfx, dri-devel, linux-kernel
Le 17/02/2026 à 17:47, Alex Deucher a écrit :
> On Tue, Feb 17, 2026 at 11:38 AM Pierre-Eric Pelloux-Prayer
> <pierre-eric@damsy.net> wrote:
>>
>>
>>
>> Le 17/02/2026 à 17:20, Alex Deucher a écrit :
>>> On Wed, Feb 11, 2026 at 6:07 AM Pierre-Eric Pelloux-Prayer
>>> <pierre-eric.pelloux-prayer@amd.com> wrote:
>>>>
>>>> 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.
>>>>
>>>> Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
>>>> ---
>>>> .../gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 84 ++++++++++++++++++-
>>>> 1 file changed, 83 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 d0af8a294abf..d576518c212d 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
>>>> @@ -200,12 +200,20 @@ 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;
>>>>
>>>> iter.data = buffer;
>>>> @@ -323,6 +331,80 @@ 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) {
>>>> + if (buffer)
>>>> + vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
>>>> + else
>>>> + vm = NULL;
>>>
>>> Is there any point in doing the loop if the vm is NULL?
>>
>> Yes : when doing the first pass to size the final buffer I skip the
>> buffers mapping + read operations that might be slow and instead just
>> account for the outputting of ib_size_dw dwords.
>
> But if you don't map the buffer, you'll just be dumping the random
> content from ib_content[].
No. I'll send a v2 with more comments, but what's happening is that this
function is called twice:
* the first time with buffer=NULL. In this case we just need the
drm_printf calls to happen. Because the output' size isn't dependent on
the values read from ib_content it's fine to jump to the
output_ib_content label as early as possible.
* the second time buffer is not NULL. If the vm is now NULL, we won't
enter the loop at all.
The other advantage of skipping the vm lookup and bo mapping when sizing
the buffer is that we size the buffer as if all future lookups/mapping
are successful.
Pierre-Eric
>
>>
>>>
>>>> +
>>>> + for (int i = 0; i < coredump->num_ibs && (!buffer || vm); i++) {
>>>> + ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
>>>> + GFP_KERNEL);
>>>
>>> Shouldn't this be GFP_NOWAIT?
>>
>> This is executed by a worker so GFP_KERNEL should be ok?
>
> Oh, right. Yeah, should be ok.
>
> Alex
>
>>
>> Pierre-Eric
>>
>>>
>>> Alex
>>>
>>>> + if (!ib_content)
>>>> + continue;
>>>> +
>>>> + 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:
>>>> + kfree(ib_content);
>>>> + }
>>>> + if (vm) {
>>>> + amdgpu_bo_unreserve(root);
>>>> + amdgpu_bo_unref(&root);
>>>> + }
>>>> + }
>>>> +
>>>> return count - iter.remain;
>>>> }
>>>>
>>>> --
>>>> 2.43.0
>>>>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump
2026-02-11 10:26 [PATCH v1 1/6] drm/amdgpu: include ip discovery data in devcoredump Pierre-Eric Pelloux-Prayer
` (4 preceding siblings ...)
2026-02-11 10:26 ` [PATCH v1 6/6] drm/amdgpu: dump job ibs in the devcoredump Pierre-Eric Pelloux-Prayer
@ 2026-02-17 16:02 ` Alex Deucher
5 siblings, 0 replies; 15+ messages in thread
From: Alex Deucher @ 2026-02-17 16:02 UTC (permalink / raw)
To: Pierre-Eric Pelloux-Prayer
Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
amd-gfx, dri-devel, linux-kernel
On Wed, Feb 11, 2026 at 5:28 AM Pierre-Eric Pelloux-Prayer
<pierre-eric.pelloux-prayer@amd.com> wrote:
>
> 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] 15+ messages in thread