* [PATCH V6 00/31] Reset improvements for GC10+
@ 2025-06-05 1:45 Alex Deucher
2025-06-05 1:45 ` [PATCH 01/31] drm/amdgpu: enable legacy enforce isolation by default Alex Deucher
` (30 more replies)
0 siblings, 31 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
This set improves per queue reset support for GC10+.
When we reset the queue, the queue is lost so we need
to re-emit the unprocessed state from subsequent submissions.
To that end, in order to make sure we actually restore
unprocessed state, we need to enable legacy enforce isolation
so that we can safely re-emit the unprocessed state. If
we don't multiple jobs can run in parallel and we may not
end up resetting the correct one. This is similar to how
windows handles queues. This also gives us correct guilty
tracking for GC.
Tested on GC 10 and 11 chips with a game running and
then running hang tests. The game pauses when the
hang happens, then continues after the queue reset.
I tried this same approach and GC8 and 9, but it
was not as reliable as soft recovery. As such, I've dropped
the KGQ reset code for pre-GC10.
The same approach is extended to SDMA and VCN.
They don't need enforce isolation because those engines
are single threaded so they always operate serially.
Rework re-emit to signal the seq number of the bad job and
verify that to verify that the reset worked, then re-emit the
rest of the non-guilty state. This way we are not waiting on
the rest of the state to complete, and if the subsequent state
also contains a bad job, we'll end up in queue reset again rather
than adapter reset.
v4: Drop explicit padding patches
Drop new timeout macro
Rework re-emit sequence
v5: Add a helper for reemit
Convert VCN, JPEG, SDMA to use new helpers
v6: Update SDMA 4.4.2 to use new helpers
Move ptr tracking to amdgpu_fence
Skip all jobs from the bad context on the ring
Alex Deucher (30):
drm/amdgpu: enable legacy enforce isolation by default
drm/amdgpu/gfx7: drop reset_kgq
drm/amdgpu/gfx8: drop reset_kgq
drm/amdgpu/gfx9: drop reset_kgq
drm/amdgpu: switch job hw_fence to amdgpu_fence
drm/amdgpu: move force completion into ring resets
drm/amdgpu: track ring state associated with a job
drm/amdgpu: optimize amdgpu_ring_reemit_unprocessed_jobs()
drm/amdgpu/gfx10: re-emit unprocessed state on ring reset
drm/amdgpu/gfx11: re-emit unprocessed state on ring reset
drm/amdgpu/gfx12: re-emit unprocessed state on ring reset
drm/amdgpu/gfx9: re-emit unprocessed state on kcq reset
drm/amdgpu/gfx9.4.3: re-emit unprocessed state on kcq reset
drm/amdgpu/sdma4.4.2: re-emit unprocessed state on ring reset
drm/amdgpu/sdma5: re-emit unprocessed state on ring reset
drm/amdgpu/sdma5.2: re-emit unprocessed state on ring reset
drm/amdgpu/sdma6: re-emit unprocessed state on ring reset
drm/amdgpu/sdma7: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg2: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg2.5: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg3: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg4: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg4.0.3: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg5.0.0: add queue reset
drm/amdgpu/jpeg5: re-emit unprocessed state on ring reset
drm/amdgpu/jpeg5.0.1: re-emit unprocessed state on ring reset
drm/amdgpu/vcn4: re-emit unprocessed state on ring reset
drm/amdgpu/vcn4.0.3: re-emit unprocessed state on ring reset
drm/amdgpu/vcn4.0.5: re-emit unprocessed state on ring reset
drm/amdgpu/vcn5: re-emit unprocessed state on ring reset
Christian König (1):
drm/amdgpu: rework queue reset scheduler interaction
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 45 +++++-----
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 13 ++-
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 60 +++++++------
drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 97 +++++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 31 +++++++
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 31 ++-----
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 21 +----
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 21 +----
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 71 ---------------
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 71 ---------------
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 51 +----------
drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 6 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 3 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 3 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 3 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 3 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 3 +-
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 12 +++
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 3 +-
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 28 +++++-
drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 4 +-
drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 6 +-
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 6 +-
drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 6 +-
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 2 +-
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 3 +-
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 2 +-
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 2 +-
31 files changed, 286 insertions(+), 331 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 01/31] drm/amdgpu: enable legacy enforce isolation by default
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 02/31] drm/amdgpu/gfx7: drop reset_kgq Alex Deucher
` (29 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Enable legacy enforce isolation (just serialize kernel
GC submissions). This way we can reset a ring and
only affect the the process currently using that ring.
This mirrors what windows does.
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 72e41781afb06..ca882e3d95bb7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2148,9 +2148,7 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
for (i = 0; i < MAX_XCP; i++) {
switch (amdgpu_enforce_isolation) {
- case -1:
case 0:
- default:
/* disable */
adev->enforce_isolation[i] = AMDGPU_ENFORCE_ISOLATION_DISABLE;
break;
@@ -2159,7 +2157,9 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
adev->enforce_isolation[i] =
AMDGPU_ENFORCE_ISOLATION_ENABLE;
break;
+ case -1:
case 2:
+ default:
/* enable legacy mode */
adev->enforce_isolation[i] =
AMDGPU_ENFORCE_ISOLATION_ENABLE_LEGACY;
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 02/31] drm/amdgpu/gfx7: drop reset_kgq
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
2025-06-05 1:45 ` [PATCH 01/31] drm/amdgpu: enable legacy enforce isolation by default Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 03/31] drm/amdgpu/gfx8: " Alex Deucher
` (28 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
It doesn't work reliably and we have soft recover and
full adapter reset so drop this.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 71 ---------------------------
1 file changed, 71 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index da0534ff1271a..2aa323dab34e3 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -4884,76 +4884,6 @@ static void gfx_v7_0_emit_mem_sync_compute(struct amdgpu_ring *ring)
amdgpu_ring_write(ring, 0x0000000A); /* poll interval */
}
-static void gfx_v7_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
- int mem_space, int opt, uint32_t addr0,
- uint32_t addr1, uint32_t ref, uint32_t mask,
- uint32_t inv)
-{
- amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
- amdgpu_ring_write(ring,
- /* memory (1) or register (0) */
- (WAIT_REG_MEM_MEM_SPACE(mem_space) |
- WAIT_REG_MEM_OPERATION(opt) | /* wait */
- WAIT_REG_MEM_FUNCTION(3) | /* equal */
- WAIT_REG_MEM_ENGINE(eng_sel)));
-
- if (mem_space)
- BUG_ON(addr0 & 0x3); /* Dword align */
- amdgpu_ring_write(ring, addr0);
- amdgpu_ring_write(ring, addr1);
- amdgpu_ring_write(ring, ref);
- amdgpu_ring_write(ring, mask);
- amdgpu_ring_write(ring, inv); /* poll interval */
-}
-
-static void gfx_v7_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
- uint32_t val, uint32_t mask)
-{
- gfx_v7_0_wait_reg_mem(ring, 0, 0, 0, reg, 0, val, mask, 0x20);
-}
-
-static int gfx_v7_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- struct amdgpu_kiq *kiq = &adev->gfx.kiq[0];
- struct amdgpu_ring *kiq_ring = &kiq->ring;
- unsigned long flags;
- u32 tmp;
- int r;
-
- if (amdgpu_sriov_vf(adev))
- return -EINVAL;
-
- if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
- return -EINVAL;
-
- spin_lock_irqsave(&kiq->ring_lock, flags);
-
- if (amdgpu_ring_alloc(kiq_ring, 5)) {
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
- return -ENOMEM;
- }
-
- tmp = REG_SET_FIELD(0, CP_VMID_RESET, RESET_REQUEST, 1 << vmid);
- gfx_v7_0_ring_emit_wreg(kiq_ring, mmCP_VMID_RESET, tmp);
- amdgpu_ring_commit(kiq_ring);
-
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r)
- return r;
-
- if (amdgpu_ring_alloc(ring, 7 + 12 + 5))
- return -ENOMEM;
- gfx_v7_0_ring_emit_fence_gfx(ring, ring->fence_drv.gpu_addr,
- ring->fence_drv.sync_seq, AMDGPU_FENCE_FLAG_EXEC);
- gfx_v7_0_ring_emit_reg_wait(ring, mmCP_VMID_RESET, 0, 0xffff);
- gfx_v7_0_ring_emit_wreg(ring, mmCP_VMID_RESET, 0);
-
- return amdgpu_ring_test_ring(ring);
-}
-
static const struct amd_ip_funcs gfx_v7_0_ip_funcs = {
.name = "gfx_v7_0",
.early_init = gfx_v7_0_early_init,
@@ -5003,7 +4933,6 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
.emit_wreg = gfx_v7_0_ring_emit_wreg,
.soft_recovery = gfx_v7_0_ring_soft_recovery,
.emit_mem_sync = gfx_v7_0_emit_mem_sync,
- .reset = gfx_v7_0_reset_kgq,
};
static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 03/31] drm/amdgpu/gfx8: drop reset_kgq
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
2025-06-05 1:45 ` [PATCH 01/31] drm/amdgpu: enable legacy enforce isolation by default Alex Deucher
2025-06-05 1:45 ` [PATCH 02/31] drm/amdgpu/gfx7: drop reset_kgq Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 04/31] drm/amdgpu/gfx9: " Alex Deucher
` (27 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
It doesn't work reliably and we have soft recover and
full adapter reset so drop this.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 71 ---------------------------
1 file changed, 71 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 5ee2237d8ee8f..68c401ecb3eca 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -6339,34 +6339,6 @@ static void gfx_v8_0_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg,
amdgpu_ring_write(ring, val);
}
-static void gfx_v8_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
- int mem_space, int opt, uint32_t addr0,
- uint32_t addr1, uint32_t ref, uint32_t mask,
- uint32_t inv)
-{
- amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
- amdgpu_ring_write(ring,
- /* memory (1) or register (0) */
- (WAIT_REG_MEM_MEM_SPACE(mem_space) |
- WAIT_REG_MEM_OPERATION(opt) | /* wait */
- WAIT_REG_MEM_FUNCTION(3) | /* equal */
- WAIT_REG_MEM_ENGINE(eng_sel)));
-
- if (mem_space)
- BUG_ON(addr0 & 0x3); /* Dword align */
- amdgpu_ring_write(ring, addr0);
- amdgpu_ring_write(ring, addr1);
- amdgpu_ring_write(ring, ref);
- amdgpu_ring_write(ring, mask);
- amdgpu_ring_write(ring, inv); /* poll interval */
-}
-
-static void gfx_v8_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
- uint32_t val, uint32_t mask)
-{
- gfx_v8_0_wait_reg_mem(ring, 0, 0, 0, reg, 0, val, mask, 0x20);
-}
-
static void gfx_v8_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid)
{
struct amdgpu_device *adev = ring->adev;
@@ -6843,48 +6815,6 @@ static void gfx_v8_0_emit_wave_limit(struct amdgpu_ring *ring, bool enable)
}
-static int gfx_v8_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- struct amdgpu_kiq *kiq = &adev->gfx.kiq[0];
- struct amdgpu_ring *kiq_ring = &kiq->ring;
- unsigned long flags;
- u32 tmp;
- int r;
-
- if (amdgpu_sriov_vf(adev))
- return -EINVAL;
-
- if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
- return -EINVAL;
-
- spin_lock_irqsave(&kiq->ring_lock, flags);
-
- if (amdgpu_ring_alloc(kiq_ring, 5)) {
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
- return -ENOMEM;
- }
-
- tmp = REG_SET_FIELD(0, CP_VMID_RESET, RESET_REQUEST, 1 << vmid);
- gfx_v8_0_ring_emit_wreg(kiq_ring, mmCP_VMID_RESET, tmp);
- amdgpu_ring_commit(kiq_ring);
-
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r)
- return r;
-
- if (amdgpu_ring_alloc(ring, 7 + 12 + 5))
- return -ENOMEM;
- gfx_v8_0_ring_emit_fence_gfx(ring, ring->fence_drv.gpu_addr,
- ring->fence_drv.sync_seq, AMDGPU_FENCE_FLAG_EXEC);
- gfx_v8_0_ring_emit_reg_wait(ring, mmCP_VMID_RESET, 0, 0xffff);
- gfx_v8_0_ring_emit_wreg(ring, mmCP_VMID_RESET, 0);
-
- return amdgpu_ring_test_ring(ring);
-}
-
static const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
.name = "gfx_v8_0",
.early_init = gfx_v8_0_early_init,
@@ -6950,7 +6880,6 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
.emit_wreg = gfx_v8_0_ring_emit_wreg,
.soft_recovery = gfx_v8_0_ring_soft_recovery,
.emit_mem_sync = gfx_v8_0_emit_mem_sync,
- .reset = gfx_v8_0_reset_kgq,
};
static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 04/31] drm/amdgpu/gfx9: drop reset_kgq
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (2 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 03/31] drm/amdgpu/gfx8: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 05/31] drm/amdgpu: switch job hw_fence to amdgpu_fence Alex Deucher
` (26 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
It doesn't work reliably and we have soft recover and
full adapter reset so drop this.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 46 ---------------------------
1 file changed, 46 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index d377a7c57d5e1..d50e125fd3e0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -7152,51 +7152,6 @@ static void gfx_v9_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop)
amdgpu_ring_insert_nop(ring, num_nop - 1);
}
-static int gfx_v9_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- struct amdgpu_kiq *kiq = &adev->gfx.kiq[0];
- struct amdgpu_ring *kiq_ring = &kiq->ring;
- unsigned long flags;
- u32 tmp;
- int r;
-
- if (amdgpu_sriov_vf(adev))
- return -EINVAL;
-
- if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
- return -EINVAL;
-
- spin_lock_irqsave(&kiq->ring_lock, flags);
-
- if (amdgpu_ring_alloc(kiq_ring, 5)) {
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
- return -ENOMEM;
- }
-
- tmp = REG_SET_FIELD(0, CP_VMID_RESET, RESET_REQUEST, 1 << vmid);
- gfx_v9_0_ring_emit_wreg(kiq_ring,
- SOC15_REG_OFFSET(GC, 0, mmCP_VMID_RESET), tmp);
- amdgpu_ring_commit(kiq_ring);
-
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r)
- return r;
-
- if (amdgpu_ring_alloc(ring, 7 + 7 + 5))
- return -ENOMEM;
- gfx_v9_0_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
- ring->fence_drv.sync_seq, AMDGPU_FENCE_FLAG_EXEC);
- gfx_v9_0_ring_emit_reg_wait(ring,
- SOC15_REG_OFFSET(GC, 0, mmCP_VMID_RESET), 0, 0xffff);
- gfx_v9_0_ring_emit_wreg(ring,
- SOC15_REG_OFFSET(GC, 0, mmCP_VMID_RESET), 0);
-
- return amdgpu_ring_test_ring(ring);
-}
-
static int gfx_v9_0_reset_kcq(struct amdgpu_ring *ring,
unsigned int vmid)
{
@@ -7477,7 +7432,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = {
.emit_reg_write_reg_wait = gfx_v9_0_ring_emit_reg_write_reg_wait,
.soft_recovery = gfx_v9_0_ring_soft_recovery,
.emit_mem_sync = gfx_v9_0_emit_mem_sync,
- .reset = gfx_v9_0_reset_kgq,
.emit_cleaner_shader = gfx_v9_0_ring_emit_cleaner_shader,
.begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use,
.end_use = amdgpu_gfx_enforce_isolation_ring_end_use,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 05/31] drm/amdgpu: switch job hw_fence to amdgpu_fence
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (3 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 04/31] drm/amdgpu/gfx9: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 06/31] drm/amdgpu: rework queue reset scheduler interaction Alex Deucher
` (25 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Use the amdgpu fence container so we can store additional
data in the fence.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 30 +++++----------------
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 12 ++++-----
drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 16 +++++++++++
6 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index 8e626f50b362e..f81608330a3d0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -1902,7 +1902,7 @@ static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring)
continue;
}
job = to_amdgpu_job(s_job);
- if (preempted && (&job->hw_fence) == fence)
+ if (preempted && (&job->hw_fence.base) == fence)
/* mark the job as preempted */
job->preemption_status |= AMDGPU_IB_PREEMPTED;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index ca882e3d95bb7..b30cec1b6a9a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -6337,7 +6337,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
*
* job->base holds a reference to parent fence
*/
- if (job && dma_fence_is_signaled(&job->hw_fence)) {
+ if (job && dma_fence_is_signaled(&job->hw_fence.base)) {
job_signaled = true;
dev_info(adev->dev, "Guilty job already signaled, skipping HW reset");
goto skip_hw_reset;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index 2f24a6aa13bf6..569e0e5373927 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -41,22 +41,6 @@
#include "amdgpu_trace.h"
#include "amdgpu_reset.h"
-/*
- * Fences mark an event in the GPUs pipeline and are used
- * for GPU/CPU synchronization. When the fence is written,
- * it is expected that all buffers associated with that fence
- * are no longer in use by the associated ring on the GPU and
- * that the relevant GPU caches have been flushed.
- */
-
-struct amdgpu_fence {
- struct dma_fence base;
-
- /* RB, DMA, etc. */
- struct amdgpu_ring *ring;
- ktime_t start_timestamp;
-};
-
static struct kmem_cache *amdgpu_fence_slab;
int amdgpu_fence_slab_init(void)
@@ -151,12 +135,12 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
am_fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC);
if (am_fence == NULL)
return -ENOMEM;
- fence = &am_fence->base;
- am_fence->ring = ring;
} else {
/* take use of job-embedded fence */
- fence = &job->hw_fence;
+ am_fence = &job->hw_fence;
}
+ fence = &am_fence->base;
+ am_fence->ring = ring;
seq = ++ring->fence_drv.sync_seq;
if (job && job->job_run_counter) {
@@ -718,7 +702,7 @@ void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
* it right here or we won't be able to track them in fence_drv
* and they will remain unsignaled during sa_bo free.
*/
- job = container_of(old, struct amdgpu_job, hw_fence);
+ job = container_of(old, struct amdgpu_job, hw_fence.base);
if (!job->base.s_fence && !dma_fence_is_signaled(old))
dma_fence_signal(old);
RCU_INIT_POINTER(*ptr, NULL);
@@ -780,7 +764,7 @@ static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
static const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f)
{
- struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
+ struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence.base);
return (const char *)to_amdgpu_ring(job->base.sched)->name;
}
@@ -810,7 +794,7 @@ static bool amdgpu_fence_enable_signaling(struct dma_fence *f)
*/
static bool amdgpu_job_fence_enable_signaling(struct dma_fence *f)
{
- struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
+ struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence.base);
if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer))
amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched));
@@ -845,7 +829,7 @@ static void amdgpu_job_fence_free(struct rcu_head *rcu)
struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
/* free job if fence has a parent job */
- kfree(container_of(f, struct amdgpu_job, hw_fence));
+ kfree(container_of(f, struct amdgpu_job, hw_fence.base));
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index acb21fc8b3ce5..ddb9d3269357c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -272,8 +272,8 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
/* Check if any fences where initialized */
if (job->base.s_fence && job->base.s_fence->finished.ops)
f = &job->base.s_fence->finished;
- else if (job->hw_fence.ops)
- f = &job->hw_fence;
+ else if (job->hw_fence.base.ops)
+ f = &job->hw_fence.base;
else
f = NULL;
@@ -290,10 +290,10 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
amdgpu_sync_free(&job->explicit_sync);
/* only put the hw fence if has embedded fence */
- if (!job->hw_fence.ops)
+ if (!job->hw_fence.base.ops)
kfree(job);
else
- dma_fence_put(&job->hw_fence);
+ dma_fence_put(&job->hw_fence.base);
}
void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
@@ -322,10 +322,10 @@ void amdgpu_job_free(struct amdgpu_job *job)
if (job->gang_submit != &job->base.s_fence->scheduled)
dma_fence_put(job->gang_submit);
- if (!job->hw_fence.ops)
+ if (!job->hw_fence.base.ops)
kfree(job);
else
- dma_fence_put(&job->hw_fence);
+ dma_fence_put(&job->hw_fence.base);
}
struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
index f2c049129661f..931fed8892cc1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
@@ -48,7 +48,7 @@ struct amdgpu_job {
struct drm_sched_job base;
struct amdgpu_vm *vm;
struct amdgpu_sync explicit_sync;
- struct dma_fence hw_fence;
+ struct amdgpu_fence hw_fence;
struct dma_fence *gang_submit;
uint32_t preamble_status;
uint32_t preemption_status;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index b95b471107692..e1f25218943a4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -127,6 +127,22 @@ struct amdgpu_fence_driver {
struct dma_fence **fences;
};
+/*
+ * Fences mark an event in the GPUs pipeline and are used
+ * for GPU/CPU synchronization. When the fence is written,
+ * it is expected that all buffers associated with that fence
+ * are no longer in use by the associated ring on the GPU and
+ * that the relevant GPU caches have been flushed.
+ */
+
+struct amdgpu_fence {
+ struct dma_fence base;
+
+ /* RB, DMA, etc. */
+ struct amdgpu_ring *ring;
+ ktime_t start_timestamp;
+};
+
extern const struct drm_sched_backend_ops amdgpu_sched_ops;
void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 06/31] drm/amdgpu: rework queue reset scheduler interaction
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (4 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 05/31] drm/amdgpu: switch job hw_fence to amdgpu_fence Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 07/31] drm/amdgpu: move force completion into ring resets Alex Deucher
` (24 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Christian König, Alex Deucher
From: Christian König <ckoenig.leichtzumerken@gmail.com>
Stopping the scheduler for queue reset is generally a good idea because
it prevents any worker from touching the ring buffer.
But using amdgpu_fence_driver_force_completion() before restarting it was
a really bad idea because it marked fences as failed while the work was
potentially still running.
Stop doing that and cleanup the comment a bit.
v2: keep amdgpu_fence_driver_force_completion() for non-gfx rings
v3: drop amdgpu_fence_driver_force_completion() for compute ring
v4: avoid a warning when setting an error on the fence
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 37 +++++++++++++++----------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index ddb9d3269357c..821f88b64f3f6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -91,8 +91,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
struct amdgpu_job *job = to_amdgpu_job(s_job);
struct amdgpu_task_info *ti;
struct amdgpu_device *adev = ring->adev;
- int idx;
- int r;
+ bool set_error = false;
+ int idx, r;
if (!drm_dev_enter(adev_to_drm(adev), &idx)) {
dev_info(adev->dev, "%s - device unplugged skipping recovery on scheduler:%s",
@@ -136,10 +136,12 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
} else if (amdgpu_gpu_recovery && ring->funcs->reset) {
bool is_guilty;
- dev_err(adev->dev, "Starting %s ring reset\n", s_job->sched->name);
- /* stop the scheduler, but don't mess with the
- * bad job yet because if ring reset fails
- * we'll fall back to full GPU reset.
+ dev_err(adev->dev, "Starting %s ring reset\n",
+ s_job->sched->name);
+
+ /*
+ * Stop the scheduler to prevent anybody else from touching the
+ * ring buffer.
*/
drm_sched_wqueue_stop(&ring->sched);
@@ -154,24 +156,29 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
if (is_guilty)
dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
+ set_error = true;
+ }
r = amdgpu_ring_reset(ring, job->vmid);
if (!r) {
- if (amdgpu_ring_sched_ready(ring))
- drm_sched_stop(&ring->sched, s_job);
if (is_guilty) {
atomic_inc(&ring->adev->gpu_reset_counter);
- amdgpu_fence_driver_force_completion(ring);
+ if ((ring->funcs->type != AMDGPU_RING_TYPE_GFX) &&
+ (ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE))
+ amdgpu_fence_driver_force_completion(ring);
}
- if (amdgpu_ring_sched_ready(ring))
- drm_sched_start(&ring->sched, 0);
- dev_err(adev->dev, "Ring %s reset succeeded\n", ring->sched.name);
- drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE);
+ drm_sched_wqueue_start(&ring->sched);
+ dev_err(adev->dev, "Ring %s reset succeeded\n",
+ ring->sched.name);
+ drm_dev_wedged_event(adev_to_drm(adev),
+ DRM_WEDGE_RECOVERY_NONE);
goto exit;
}
- dev_err(adev->dev, "Ring %s reset failure\n", ring->sched.name);
+ dev_err(adev->dev, "Ring %s reset failed\n", ring->sched.name);
}
- dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
+
+ if (!set_error)
+ dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
if (amdgpu_device_should_recover_gpu(ring->adev)) {
struct amdgpu_reset_context reset_context;
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 07/31] drm/amdgpu: move force completion into ring resets
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (5 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 06/31] drm/amdgpu: rework queue reset scheduler interaction Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 08/31] drm/amdgpu: track ring state associated with a job Alex Deucher
` (23 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Move the force completion handling into each ring
reset function so that each engine can determine
whether or not it needs to force completion on the
jobs in the ring.
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 6 +-----
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 1 +
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 +
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 +
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 4 ++++
drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 5 ++++-
drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 5 ++++-
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 +
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 5 ++---
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 +
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 +
16 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index 821f88b64f3f6..23b6a0fc0c691 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -161,12 +161,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
r = amdgpu_ring_reset(ring, job->vmid);
if (!r) {
- if (is_guilty) {
+ if (is_guilty)
atomic_inc(&ring->adev->gpu_reset_counter);
- if ((ring->funcs->type != AMDGPU_RING_TYPE_GFX) &&
- (ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE))
- amdgpu_fence_driver_force_completion(ring);
- }
drm_sched_wqueue_start(&ring->sched);
dev_err(adev->dev, "Ring %s reset succeeded\n",
ring->sched.name);
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
index 4cde8a8bcc837..336ca44950dfa 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
@@ -768,6 +768,7 @@ static int jpeg_v2_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v2_0_stop(ring->adev);
jpeg_v2_0_start(ring->adev);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index 8b39e114f3be1..72d739e38a8ae 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -647,6 +647,7 @@ static int jpeg_v2_5_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v2_5_stop_inst(ring->adev, ring->me);
jpeg_v2_5_start_inst(ring->adev, ring->me);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
index 2f8510c2986b9..7974d04c15e92 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
@@ -559,6 +559,7 @@ static int jpeg_v3_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v3_0_stop(ring->adev);
jpeg_v3_0_start(ring->adev);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index f17ec5414fd69..9301d0ff2593b 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -727,6 +727,7 @@ static int jpeg_v4_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v4_0_stop(ring->adev);
jpeg_v4_0_start(ring->adev);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index 79e342d5ab28d..ef5075e111300 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -1150,6 +1150,7 @@ static int jpeg_v4_0_3_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v4_0_3_core_stall_reset(ring);
jpeg_v4_0_3_start_jrbc(ring);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
index 3b6f65a256464..858b930d1dd54 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
@@ -841,6 +841,7 @@ static int jpeg_v5_0_1_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v5_0_1_core_stall_reset(ring);
jpeg_v5_0_1_init_jrbc(ring);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
index 9c169112a5e7b..eb78bf04a490b 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
@@ -1670,6 +1670,7 @@ static bool sdma_v4_4_2_page_ring_is_guilty(struct amdgpu_ring *ring)
static int sdma_v4_4_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
+ bool is_guilty = ring->funcs->is_guilty(ring);
u32 id = GET_INST(SDMA0, ring->me);
int r;
@@ -1680,6 +1681,9 @@ static int sdma_v4_4_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
r = amdgpu_sdma_reset_engine(adev, id);
amdgpu_amdkfd_resume(adev, false);
+ if (is_guilty)
+ amdgpu_fence_driver_force_completion(ring);
+
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index 9505ae96fbecc..43885dc04b632 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -1542,8 +1542,11 @@ static int sdma_v5_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
+ int r;
- return amdgpu_sdma_reset_engine(adev, inst_id);
+ r = amdgpu_sdma_reset_engine(adev, inst_id);
+ amdgpu_fence_driver_force_completion(ring);
+ return r;
}
static int sdma_v5_0_stop_queue(struct amdgpu_ring *ring)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
index a6e612b4a8928..ee94e457ee25d 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
@@ -1455,8 +1455,11 @@ static int sdma_v5_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
+ int r;
- return amdgpu_sdma_reset_engine(adev, inst_id);
+ r = amdgpu_sdma_reset_engine(adev, inst_id);
+ amdgpu_fence_driver_force_completion(ring);
+ return r;
}
static int sdma_v5_2_stop_queue(struct amdgpu_ring *ring)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index 5a70ae17be04e..86ef0e30a89e8 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -1559,6 +1559,7 @@ static int sdma_v6_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
if (r)
return r;
+ amdgpu_fence_driver_force_completion(ring);
return sdma_v6_0_gfx_resume_instance(adev, i, true);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index ad47d0bdf7775..25cec4de13131 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -824,6 +824,7 @@ static int sdma_v7_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
if (r)
return r;
+ amdgpu_fence_driver_force_completion(ring);
return sdma_v7_0_gfx_resume_instance(adev, i, true);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index b5071f77f78d2..f1ccc6c7be390 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1977,6 +1977,7 @@ static int vcn_v4_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v4_0_stop(vinst);
vcn_v4_0_start(vinst);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 5a33140f57235..6ef5944584e56 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -1620,9 +1620,8 @@ static int vcn_v4_0_3_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
adev->vcn.caps |= AMDGPU_VCN_CAPS(RRMT_ENABLED);
vcn_v4_0_3_hw_init_inst(vinst);
vcn_v4_0_3_start_dpg_mode(vinst, adev->vcn.inst[ring->me].indirect_sram);
- r = amdgpu_ring_test_helper(ring);
-
- return r;
+ amdgpu_fence_driver_force_completion(ring);
+ return amdgpu_ring_test_helper(ring);
}
static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 16ade84facc78..1c13ceb3bed8b 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1475,6 +1475,7 @@ static int vcn_v4_0_5_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v4_0_5_stop(vinst);
vcn_v4_0_5_start(vinst);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index f8e3f0b882da5..a998708bc0745 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -1202,6 +1202,7 @@ static int vcn_v5_0_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v5_0_0_stop(vinst);
vcn_v5_0_0_start(vinst);
+ amdgpu_fence_driver_force_completion(ring);
return amdgpu_ring_test_helper(ring);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 08/31] drm/amdgpu: track ring state associated with a job
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (6 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 07/31] drm/amdgpu: move force completion into ring resets Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 12:11 ` Christian König
2025-06-05 1:45 ` [PATCH 09/31] drm/amdgpu: optimize amdgpu_ring_reemit_unprocessed_jobs() Alex Deucher
` (22 subsequent siblings)
30 siblings, 1 reply; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
We need to know the wptr and sequence number associated
with a job so that we can re-emit the unprocessed state
after a ring reset. Pre-allocate storage space for
the ring buffer contents and add a helper to save off
the unprocessed state so that it can be re-emitted
after the queue is reset.
Add a helper that ring reset callbacks can use to verify
that the ring has reset successfully and to reemit any
unprocessed ring contents from subsequent jobs.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 15 ++++
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 13 +++-
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 11 ++-
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 92 +++++++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 15 ++++
5 files changed, 143 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index 569e0e5373927..25a664273bf0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -141,6 +141,9 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
}
fence = &am_fence->base;
am_fence->ring = ring;
+ am_fence->start_ring_wptr = 0;
+ am_fence->end_ring_wptr = 0;
+ am_fence->context = 0;
seq = ++ring->fence_drv.sync_seq;
if (job && job->job_run_counter) {
@@ -748,6 +751,18 @@ void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
amdgpu_fence_process(ring);
}
+/**
+ * amdgpu_fence_driver_seq_force_completion - force signal of specified sequence
+ *
+ * @ring: fence of the ring to signal
+ *
+ */
+void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring, u32 seq)
+{
+ amdgpu_fence_write(ring, seq);
+ amdgpu_fence_process(ring);
+}
+
/*
* Common fence implementation
*/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index 802743efa3b39..636941697a740 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -126,7 +126,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
struct dma_fence **f)
{
struct amdgpu_device *adev = ring->adev;
+ u64 start_ring_wptr, end_ring_wptr;
struct amdgpu_ib *ib = &ibs[0];
+ struct amdgpu_fence *am_fence;
struct dma_fence *tmp = NULL;
bool need_ctx_switch;
struct amdgpu_vm *vm;
@@ -138,7 +140,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
int vmid = AMDGPU_JOB_GET_VMID(job);
bool need_pipe_sync = false;
unsigned int cond_exec;
-
unsigned int i;
int r = 0;
@@ -187,6 +188,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
return r;
}
+ start_ring_wptr = ring->wptr;
need_ctx_switch = ring->current_ctx != fence_ctx;
if (ring->funcs->emit_pipeline_sync && job &&
@@ -306,6 +308,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
amdgpu_ring_ib_end(ring);
amdgpu_ring_commit(ring);
+ /* This must be last for resets to work properly
+ * as we need to save the wptr associated with this
+ * fence.
+ */
+ end_ring_wptr = ring->wptr;
+ am_fence = container_of(*f, struct amdgpu_fence, base);
+ am_fence->start_ring_wptr = start_ring_wptr;
+ am_fence->end_ring_wptr = end_ring_wptr;
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index 23b6a0fc0c691..73c26e2e01647 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -89,8 +89,9 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
{
struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
struct amdgpu_job *job = to_amdgpu_job(s_job);
- struct amdgpu_task_info *ti;
+ struct amdgpu_fence *am_fence = &job->hw_fence;
struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_task_info *ti;
bool set_error = false;
int idx, r;
@@ -154,7 +155,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
else
is_guilty = true;
- if (is_guilty)
+ amdgpu_ring_backup_unprocessed_jobs(ring, is_guilty, am_fence);
+ if (is_guilty) {
dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
set_error = true;
}
@@ -409,6 +411,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched);
struct amdgpu_device *adev = ring->adev;
struct dma_fence *fence = NULL, *finished;
+ struct amdgpu_fence *am_fence;
struct amdgpu_job *job;
int r = 0;
@@ -433,6 +436,10 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
"Error scheduling IBs (%d) in ring(%s)", r,
ring->name);
}
+ if (fence && finished) {
+ am_fence = container_of(fence, struct amdgpu_fence, base);
+ am_fence->context = finished->context;
+ }
job->job_run_counter++;
amdgpu_job_free_resources(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 426834806fbf2..3a0e0883bd8e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -333,6 +333,12 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
/* Initialize cached_rptr to 0 */
ring->cached_rptr = 0;
+ if (!ring->ring_backup) {
+ ring->ring_backup = kvzalloc(ring->ring_size, GFP_KERNEL);
+ if (!ring->ring_backup)
+ return -ENOMEM;
+ }
+
/* Allocate ring buffer */
if (ring->ring_obj == NULL) {
r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
@@ -342,6 +348,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
(void **)&ring->ring);
if (r) {
dev_err(adev->dev, "(%d) ring create failed\n", r);
+ kvfree(ring->ring_backup);
return r;
}
amdgpu_ring_clear_ring(ring);
@@ -385,6 +392,8 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
amdgpu_bo_free_kernel(&ring->ring_obj,
&ring->gpu_addr,
(void **)&ring->ring);
+ kvfree(ring->ring_backup);
+ ring->ring_backup = NULL;
dma_fence_put(ring->vmid_wait);
ring->vmid_wait = NULL;
@@ -753,3 +762,86 @@ bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring)
return true;
}
+
+static void amdgpu_ring_backup_unprocessed_job(struct amdgpu_ring *ring,
+ unsigned int idx,
+ u64 start_wptr, u32 end_wptr)
+{
+ unsigned int first_idx = start_wptr & ring->buf_mask;
+ unsigned int last_idx = end_wptr & ring->buf_mask;
+ unsigned int i, j, entries_to_copy;
+
+ if (last_idx < first_idx) {
+ entries_to_copy = ring->buf_mask + 1 - first_idx;
+ for (i = 0; i < entries_to_copy; i++)
+ ring->ring_backup[idx + i] = ring->ring[first_idx + i];
+ ring->ring_backup_entries_to_copy += entries_to_copy;
+ entries_to_copy = last_idx;
+ for (j = 0; j < entries_to_copy; j++)
+ ring->ring_backup[idx + i + j] = ring->ring[j];
+ ring->ring_backup_entries_to_copy += entries_to_copy;
+ } else {
+ entries_to_copy = last_idx - first_idx;
+ for (i = 0; i < entries_to_copy; i++)
+ ring->ring_backup[idx + i] = ring->ring[first_idx + i];
+ ring->ring_backup_entries_to_copy += entries_to_copy;
+ }
+}
+
+void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
+ bool is_guilty,
+ struct amdgpu_fence *bad_fence)
+{
+ struct amdgpu_fence *fence;
+ struct dma_fence *old, **ptr;
+ int i;
+
+ ring->ring_backup_entries_to_copy = 0;
+ for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
+ ptr = &ring->fence_drv.fences[i];
+ rcu_read_lock();
+ old = rcu_dereference(*ptr);
+
+ if (old && !dma_fence_is_signaled(old)) {
+ fence = container_of(old, struct amdgpu_fence, base);
+ /* save everything if the ring is not guilty, otherwise
+ * just save the content from other contexts.
+ */
+ if (!is_guilty || (fence->context != bad_fence->context))
+ amdgpu_ring_backup_unprocessed_job(ring,
+ ring->ring_backup_entries_to_copy,
+ fence->start_ring_wptr,
+ fence->end_ring_wptr);
+ }
+ rcu_read_unlock();
+ }
+
+ ring->ring_bad_seq = bad_fence->base.seqno;
+}
+
+int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring)
+{
+ unsigned int i;
+ int r;
+
+ /* verify that the ring is functional */
+ r = amdgpu_ring_test_ring(ring);
+ if (r)
+ return r;
+ /* re-emit the unprocessed ring contents */
+ if (ring->ring_backup_entries_to_copy) {
+ r = amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
+ if (r)
+ return r;
+ /* signal the fence of the bad job */
+ amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
+ for (i = 0; i < ring->ring_backup_entries_to_copy; i++)
+ amdgpu_ring_write(ring, ring->ring_backup[i]);
+ amdgpu_ring_commit(ring);
+ } else {
+ /* signal the fence of the bad job */
+ amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index e1f25218943a4..69b71401adb7a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -141,6 +141,12 @@ struct amdgpu_fence {
/* RB, DMA, etc. */
struct amdgpu_ring *ring;
ktime_t start_timestamp;
+
+ /* wptrs for the fence for resets */
+ u64 start_ring_wptr;
+ u64 end_ring_wptr;
+ /* fence context for resets */
+ u64 context;
};
extern const struct drm_sched_backend_ops amdgpu_sched_ops;
@@ -148,6 +154,8 @@ extern const struct drm_sched_backend_ops amdgpu_sched_ops;
void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error);
void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
+void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring,
+ u32 seq);
int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
@@ -284,6 +292,9 @@ struct amdgpu_ring {
struct amdgpu_bo *ring_obj;
uint32_t *ring;
+ uint32_t *ring_backup;
+ unsigned int ring_backup_entries_to_copy;
+ uint64_t ring_bad_seq;
unsigned rptr_offs;
u64 rptr_gpu_addr;
volatile u32 *rptr_cpu_addr;
@@ -550,4 +561,8 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev);
void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring);
+void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
+ bool is_guilty,
+ struct amdgpu_fence *bad_fence);
+int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring);
#endif
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 09/31] drm/amdgpu: optimize amdgpu_ring_reemit_unprocessed_jobs()
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (7 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 08/31] drm/amdgpu: track ring state associated with a job Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 10/31] drm/amdgpu/gfx10: re-emit unprocessed state on ring reset Alex Deucher
` (21 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
If we fail to allocate enough ring space to reemit the
previous contents, process all fences, but return
success to avoid an adapter reset.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index 3a0e0883bd8e7..717c128b2d6fc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -831,8 +831,13 @@ int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring)
/* re-emit the unprocessed ring contents */
if (ring->ring_backup_entries_to_copy) {
r = amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
- if (r)
- return r;
+ if (r) {
+ /* if we can't re-emit the rest of the ring contents, force completion
+ * for all jobs, but return success to avoid an adapter reset.
+ */
+ amdgpu_fence_driver_force_completion(ring);
+ return 0;
+ }
/* signal the fence of the bad job */
amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
for (i = 0; i < ring->ring_backup_entries_to_copy; i++)
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 10/31] drm/amdgpu/gfx10: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (8 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 09/31] drm/amdgpu: optimize amdgpu_ring_reemit_unprocessed_jobs() Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 11/31] drm/amdgpu/gfx11: " Alex Deucher
` (20 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 31 +++++---------------------
1 file changed, 5 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 75ea071744eb5..18ca21d719d2a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -9046,21 +9046,6 @@ static void gfx_v10_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring,
ref, mask);
}
-static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring,
- unsigned int vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- uint32_t value = 0;
-
- value = REG_SET_FIELD(value, SQ_CMD, CMD, 0x03);
- value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
- value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
- value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
- amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
- WREG32_SOC15(GC, 0, mmSQ_CMD, value);
- amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
-}
-
static void
gfx_v10_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
uint32_t me, uint32_t pipe,
@@ -9562,10 +9547,8 @@ static int gfx_v10_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
SOC15_REG_OFFSET(GC, 0, mmCP_VMID_RESET), 0, 0xffffffff);
kiq->pmf->kiq_map_queues(kiq_ring, ring);
amdgpu_ring_commit(kiq_ring);
-
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
r = amdgpu_ring_test_ring(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
if (r)
return r;
@@ -9575,7 +9558,7 @@ static int gfx_v10_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
return r;
}
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int gfx_v10_0_reset_kcq(struct amdgpu_ring *ring,
@@ -9603,9 +9586,8 @@ static int gfx_v10_0_reset_kcq(struct amdgpu_ring *ring,
kiq->pmf->kiq_unmap_queues(kiq_ring, ring, RESET_QUEUES,
0, 0);
amdgpu_ring_commit(kiq_ring);
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
r = amdgpu_ring_test_ring(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
if (r)
return r;
@@ -9641,13 +9623,12 @@ static int gfx_v10_0_reset_kcq(struct amdgpu_ring *ring,
}
kiq->pmf->kiq_map_queues(kiq_ring, ring);
amdgpu_ring_commit(kiq_ring);
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
r = amdgpu_ring_test_ring(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
if (r)
return r;
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static void gfx_v10_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p)
@@ -9882,7 +9863,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = {
.emit_wreg = gfx_v10_0_ring_emit_wreg,
.emit_reg_wait = gfx_v10_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v10_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v10_0_ring_soft_recovery,
.emit_mem_sync = gfx_v10_0_emit_mem_sync,
.reset = gfx_v10_0_reset_kgq,
.emit_cleaner_shader = gfx_v10_0_ring_emit_cleaner_shader,
@@ -9923,7 +9903,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = {
.emit_wreg = gfx_v10_0_ring_emit_wreg,
.emit_reg_wait = gfx_v10_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v10_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v10_0_ring_soft_recovery,
.emit_mem_sync = gfx_v10_0_emit_mem_sync,
.reset = gfx_v10_0_reset_kcq,
.emit_cleaner_shader = gfx_v10_0_ring_emit_cleaner_shader,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 11/31] drm/amdgpu/gfx11: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (9 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 10/31] drm/amdgpu/gfx10: re-emit unprocessed state on ring reset Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 12/31] drm/amdgpu/gfx12: " Alex Deucher
` (19 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 21 ++-------------------
1 file changed, 2 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index afd6d59164bfa..4e0a6dcce91fa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -6278,21 +6278,6 @@ static void gfx_v11_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring,
ref, mask, 0x20);
}
-static void gfx_v11_0_ring_soft_recovery(struct amdgpu_ring *ring,
- unsigned vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- uint32_t value = 0;
-
- value = REG_SET_FIELD(value, SQ_CMD, CMD, 0x03);
- value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
- value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
- value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
- amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
- WREG32_SOC15(GC, 0, regSQ_CMD, value);
- amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
-}
-
static void
gfx_v11_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
uint32_t me, uint32_t pipe,
@@ -6835,7 +6820,7 @@ static int gfx_v11_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
return r;
}
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int gfx_v11_0_reset_compute_pipe(struct amdgpu_ring *ring)
@@ -6995,7 +6980,7 @@ static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring, unsigned int vmid)
return r;
}
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static void gfx_v11_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p)
@@ -7231,7 +7216,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = {
.emit_wreg = gfx_v11_0_ring_emit_wreg,
.emit_reg_wait = gfx_v11_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v11_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v11_0_ring_soft_recovery,
.emit_mem_sync = gfx_v11_0_emit_mem_sync,
.reset = gfx_v11_0_reset_kgq,
.emit_cleaner_shader = gfx_v11_0_ring_emit_cleaner_shader,
@@ -7273,7 +7257,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = {
.emit_wreg = gfx_v11_0_ring_emit_wreg,
.emit_reg_wait = gfx_v11_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v11_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v11_0_ring_soft_recovery,
.emit_mem_sync = gfx_v11_0_emit_mem_sync,
.reset = gfx_v11_0_reset_kcq,
.emit_cleaner_shader = gfx_v11_0_ring_emit_cleaner_shader,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 12/31] drm/amdgpu/gfx12: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (10 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 11/31] drm/amdgpu/gfx11: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 13/31] drm/amdgpu/gfx9: re-emit unprocessed state on kcq reset Alex Deucher
` (18 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 21 ++-------------------
1 file changed, 2 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index 1234c8d64e20d..70abe13c774ac 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -4690,21 +4690,6 @@ static void gfx_v12_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring,
ref, mask, 0x20);
}
-static void gfx_v12_0_ring_soft_recovery(struct amdgpu_ring *ring,
- unsigned vmid)
-{
- struct amdgpu_device *adev = ring->adev;
- uint32_t value = 0;
-
- value = REG_SET_FIELD(value, SQ_CMD, CMD, 0x03);
- value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
- value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
- value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
- amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
- WREG32_SOC15(GC, 0, regSQ_CMD, value);
- amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
-}
-
static void
gfx_v12_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
uint32_t me, uint32_t pipe,
@@ -5335,7 +5320,7 @@ static int gfx_v12_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
return r;
}
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int gfx_v12_0_reset_compute_pipe(struct amdgpu_ring *ring)
@@ -5448,7 +5433,7 @@ static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring, unsigned int vmid)
return r;
}
- return amdgpu_ring_test_ring(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static void gfx_v12_0_ring_begin_use(struct amdgpu_ring *ring)
@@ -5526,7 +5511,6 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_gfx = {
.emit_wreg = gfx_v12_0_ring_emit_wreg,
.emit_reg_wait = gfx_v12_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v12_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v12_0_ring_soft_recovery,
.emit_mem_sync = gfx_v12_0_emit_mem_sync,
.reset = gfx_v12_0_reset_kgq,
.emit_cleaner_shader = gfx_v12_0_ring_emit_cleaner_shader,
@@ -5565,7 +5549,6 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_compute = {
.emit_wreg = gfx_v12_0_ring_emit_wreg,
.emit_reg_wait = gfx_v12_0_ring_emit_reg_wait,
.emit_reg_write_reg_wait = gfx_v12_0_ring_emit_reg_write_reg_wait,
- .soft_recovery = gfx_v12_0_ring_soft_recovery,
.emit_mem_sync = gfx_v12_0_emit_mem_sync,
.reset = gfx_v12_0_reset_kcq,
.emit_cleaner_shader = gfx_v12_0_ring_emit_cleaner_shader,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 13/31] drm/amdgpu/gfx9: re-emit unprocessed state on kcq reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (11 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 12/31] drm/amdgpu/gfx12: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 14/31] drm/amdgpu/gfx9.4.3: " Alex Deucher
` (17 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index d50e125fd3e0d..0bf8613b937f1 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -7216,13 +7216,14 @@ static int gfx_v9_0_reset_kcq(struct amdgpu_ring *ring,
}
kiq->pmf->kiq_map_queues(kiq_ring, ring);
amdgpu_ring_commit(kiq_ring);
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
r = amdgpu_ring_test_ring(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
if (r) {
DRM_ERROR("fail to remap queue\n");
return r;
}
- return amdgpu_ring_test_ring(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static void gfx_v9_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p)
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 14/31] drm/amdgpu/gfx9.4.3: re-emit unprocessed state on kcq reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (12 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 13/31] drm/amdgpu/gfx9: re-emit unprocessed state on kcq reset Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 15/31] drm/amdgpu/sdma4.4.2: re-emit unprocessed state on ring reset Alex Deucher
` (16 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
index c233edf605694..409cfdfe54ac3 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
@@ -3612,14 +3612,14 @@ static int gfx_v9_4_3_reset_kcq(struct amdgpu_ring *ring,
}
kiq->pmf->kiq_map_queues(kiq_ring, ring);
amdgpu_ring_commit(kiq_ring);
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
r = amdgpu_ring_test_ring(kiq_ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
if (r) {
dev_err(adev->dev, "fail to remap queue\n");
return r;
}
- return amdgpu_ring_test_ring(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
enum amdgpu_gfx_cp_ras_mem_id {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 15/31] drm/amdgpu/sdma4.4.2: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (13 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 14/31] drm/amdgpu/gfx9.4.3: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 16/31] drm/amdgpu/sdma5: " Alex Deucher
` (15 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 32 ++++++++++++++++++------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
index eb78bf04a490b..a744efd5c0354 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
@@ -1670,7 +1670,6 @@ static bool sdma_v4_4_2_page_ring_is_guilty(struct amdgpu_ring *ring)
static int sdma_v4_4_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
- bool is_guilty = ring->funcs->is_guilty(ring);
u32 id = GET_INST(SDMA0, ring->me);
int r;
@@ -1681,9 +1680,6 @@ static int sdma_v4_4_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
r = amdgpu_sdma_reset_engine(adev, id);
amdgpu_amdkfd_resume(adev, false);
- if (is_guilty)
- amdgpu_fence_driver_force_completion(ring);
-
return r;
}
@@ -1728,8 +1724,8 @@ static int sdma_v4_4_2_stop_queue(struct amdgpu_ring *ring)
static int sdma_v4_4_2_restore_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
- u32 inst_mask;
- int i;
+ u32 inst_mask, tmp_mask;
+ int i, r;
inst_mask = 1 << ring->me;
udelay(50);
@@ -1746,7 +1742,29 @@ static int sdma_v4_4_2_restore_queue(struct amdgpu_ring *ring)
return -ETIMEDOUT;
}
- return sdma_v4_4_2_inst_start(adev, inst_mask, true);
+ r = sdma_v4_4_2_inst_start(adev, inst_mask, true);
+ if (r) {
+ return r;
+ }
+
+ tmp_mask = inst_mask;
+ for_each_inst(i, tmp_mask) {
+ ring = &adev->sdma.instance[i].ring;
+
+ r = amdgpu_ring_reemit_unprocessed_jobs(ring);
+ if (r)
+ return r;
+
+ if (adev->sdma.has_page_queue) {
+ struct amdgpu_ring *page = &adev->sdma.instance[i].page;
+
+ r = amdgpu_ring_reemit_unprocessed_jobs(page);
+ if (r)
+ return r;
+ }
+ }
+
+ return r;
}
static int sdma_v4_4_2_set_trap_irq_state(struct amdgpu_device *adev,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 16/31] drm/amdgpu/sdma5: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (14 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 15/31] drm/amdgpu/sdma4.4.2: re-emit unprocessed state on ring reset Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 17/31] drm/amdgpu/sdma5.2: " Alex Deucher
` (14 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index 43885dc04b632..39352605e3fe6 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -1542,11 +1542,8 @@ static int sdma_v5_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
- int r;
- r = amdgpu_sdma_reset_engine(adev, inst_id);
- amdgpu_fence_driver_force_completion(ring);
- return r;
+ return amdgpu_sdma_reset_engine(adev, inst_id);
}
static int sdma_v5_0_stop_queue(struct amdgpu_ring *ring)
@@ -1613,7 +1610,9 @@ static int sdma_v5_0_restore_queue(struct amdgpu_ring *ring)
r = sdma_v5_0_gfx_resume_instance(adev, inst_id, true);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
- return r;
+ if (r)
+ return r;
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int sdma_v5_0_ring_preempt_ib(struct amdgpu_ring *ring)
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 17/31] drm/amdgpu/sdma5.2: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (15 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 16/31] drm/amdgpu/sdma5: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 18/31] drm/amdgpu/sdma6: " Alex Deucher
` (13 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
index ee94e457ee25d..7bdfdaefbf49b 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
@@ -1455,11 +1455,8 @@ static int sdma_v5_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
- int r;
- r = amdgpu_sdma_reset_engine(adev, inst_id);
- amdgpu_fence_driver_force_completion(ring);
- return r;
+ return amdgpu_sdma_reset_engine(adev, inst_id);
}
static int sdma_v5_2_stop_queue(struct amdgpu_ring *ring)
@@ -1525,11 +1522,11 @@ static int sdma_v5_2_restore_queue(struct amdgpu_ring *ring)
freeze = RREG32(sdma_v5_2_get_reg_offset(adev, inst_id, mmSDMA0_FREEZE));
freeze = REG_SET_FIELD(freeze, SDMA0_FREEZE, FREEZE, 0);
WREG32(sdma_v5_2_get_reg_offset(adev, inst_id, mmSDMA0_FREEZE), freeze);
-
r = sdma_v5_2_gfx_resume_instance(adev, inst_id, true);
-
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
- return r;
+ if (r)
+ return r;
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int sdma_v5_2_ring_preempt_ib(struct amdgpu_ring *ring)
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 18/31] drm/amdgpu/sdma6: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (16 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 17/31] drm/amdgpu/sdma5.2: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 19/31] drm/amdgpu/sdma7: " Alex Deucher
` (12 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index 86ef0e30a89e8..09c4e3b228632 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -1559,8 +1559,11 @@ static int sdma_v6_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
if (r)
return r;
- amdgpu_fence_driver_force_completion(ring);
- return sdma_v6_0_gfx_resume_instance(adev, i, true);
+ r = sdma_v6_0_gfx_resume_instance(adev, i, true);
+ if (r)
+ return r;
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static int sdma_v6_0_set_trap_irq_state(struct amdgpu_device *adev,
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 19/31] drm/amdgpu/sdma7: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (17 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 18/31] drm/amdgpu/sdma6: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 20/31] drm/amdgpu/jpeg2: " Alex Deucher
` (11 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index 25cec4de13131..3af2dbd96a2e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -824,8 +824,11 @@ static int sdma_v7_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
if (r)
return r;
- amdgpu_fence_driver_force_completion(ring);
- return sdma_v7_0_gfx_resume_instance(adev, i, true);
+ r = sdma_v7_0_gfx_resume_instance(adev, i, true);
+ if (r)
+ return r;
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 20/31] drm/amdgpu/jpeg2: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (18 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 19/31] drm/amdgpu/sdma7: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 21/31] drm/amdgpu/jpeg2.5: " Alex Deucher
` (10 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
index 336ca44950dfa..aa3f587e2004d 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
@@ -768,8 +768,8 @@ static int jpeg_v2_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v2_0_stop(ring->adev);
jpeg_v2_0_start(ring->adev);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 21/31] drm/amdgpu/jpeg2.5: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (19 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 20/31] drm/amdgpu/jpeg2: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 22/31] drm/amdgpu/jpeg3: " Alex Deucher
` (9 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index 72d739e38a8ae..7105c5b995275 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -647,8 +647,8 @@ static int jpeg_v2_5_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v2_5_stop_inst(ring->adev, ring->me);
jpeg_v2_5_start_inst(ring->adev, ring->me);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v2_5_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 22/31] drm/amdgpu/jpeg3: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (20 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 21/31] drm/amdgpu/jpeg2.5: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 23/31] drm/amdgpu/jpeg4: " Alex Deucher
` (8 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
index 7974d04c15e92..382126f3caae9 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
@@ -559,8 +559,8 @@ static int jpeg_v3_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
{
jpeg_v3_0_stop(ring->adev);
jpeg_v3_0_start(ring->adev);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 23/31] drm/amdgpu/jpeg4: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (21 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 22/31] drm/amdgpu/jpeg3: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 24/31] drm/amdgpu/jpeg4.0.3: " Alex Deucher
` (7 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index 9301d0ff2593b..4e644b645bd25 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -727,8 +727,8 @@ static int jpeg_v4_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v4_0_stop(ring->adev);
jpeg_v4_0_start(ring->adev);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 24/31] drm/amdgpu/jpeg4.0.3: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (22 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 23/31] drm/amdgpu/jpeg4: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 25/31] drm/amdgpu/jpeg5.0.0: add queue reset Alex Deucher
` (6 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index ef5075e111300..986fcfb2ca726 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -1150,8 +1150,8 @@ static int jpeg_v4_0_3_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v4_0_3_core_stall_reset(ring);
jpeg_v4_0_3_start_jrbc(ring);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 25/31] drm/amdgpu/jpeg5.0.0: add queue reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (23 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 24/31] drm/amdgpu/jpeg4.0.3: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 26/31] drm/amdgpu/jpeg5: re-emit unprocessed state on ring reset Alex Deucher
` (5 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Add queue reset support for jpeg 5.0.0.
Untested.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 31d213ccbe0a8..231639f2ef0d1 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -644,6 +644,17 @@ static int jpeg_v5_0_0_process_interrupt(struct amdgpu_device *adev,
return 0;
}
+static int jpeg_v5_0_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
+{
+ if (amdgpu_sriov_vf(ring->adev))
+ return -EINVAL;
+
+ jpeg_v5_0_0_stop(ring->adev);
+ jpeg_v5_0_0_start(ring->adev);
+ amdgpu_fence_driver_force_completion(ring);
+ return amdgpu_ring_test_helper(ring);
+}
+
static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {
.name = "jpeg_v5_0_0",
.early_init = jpeg_v5_0_0_early_init,
@@ -689,6 +700,7 @@ static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = {
.emit_wreg = jpeg_v4_0_3_dec_ring_emit_wreg,
.emit_reg_wait = jpeg_v4_0_3_dec_ring_emit_reg_wait,
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
+ .reset = jpeg_v5_0_0_ring_reset,
};
static void jpeg_v5_0_0_set_dec_ring_funcs(struct amdgpu_device *adev)
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 26/31] drm/amdgpu/jpeg5: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (24 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 25/31] drm/amdgpu/jpeg5.0.0: add queue reset Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 27/31] drm/amdgpu/jpeg5.0.1: " Alex Deucher
` (4 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 231639f2ef0d1..89f3cdb8616f5 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -651,8 +651,8 @@ static int jpeg_v5_0_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v5_0_0_stop(ring->adev);
jpeg_v5_0_0_start(ring->adev);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 27/31] drm/amdgpu/jpeg5.0.1: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (25 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 26/31] drm/amdgpu/jpeg5: re-emit unprocessed state on ring reset Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 28/31] drm/amdgpu/vcn4: " Alex Deucher
` (3 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
index 858b930d1dd54..56112a319c375 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
@@ -841,8 +841,8 @@ static int jpeg_v5_0_1_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
jpeg_v5_0_1_core_stall_reset(ring);
jpeg_v5_0_1_init_jrbc(ring);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 28/31] drm/amdgpu/vcn4: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (26 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 27/31] drm/amdgpu/jpeg5.0.1: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:45 ` [PATCH 29/31] drm/amdgpu/vcn4.0.3: " Alex Deucher
` (2 subsequent siblings)
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index f1ccc6c7be390..04b4712a8f2e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1977,9 +1977,8 @@ static int vcn_v4_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v4_0_stop(vinst);
vcn_v4_0_start(vinst);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 29/31] drm/amdgpu/vcn4.0.3: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (27 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 28/31] drm/amdgpu/vcn4: " Alex Deucher
@ 2025-06-05 1:45 ` Alex Deucher
2025-06-05 1:46 ` [PATCH 30/31] drm/amdgpu/vcn4.0.5: " Alex Deucher
2025-06-05 1:46 ` [PATCH 31/31] drm/amdgpu/vcn5: " Alex Deucher
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:45 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 6ef5944584e56..aa0ae2cd65da4 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -1620,8 +1620,8 @@ static int vcn_v4_0_3_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
adev->vcn.caps |= AMDGPU_VCN_CAPS(RRMT_ENABLED);
vcn_v4_0_3_hw_init_inst(vinst);
vcn_v4_0_3_start_dpg_mode(vinst, adev->vcn.inst[ring->me].indirect_sram);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 30/31] drm/amdgpu/vcn4.0.5: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (28 preceding siblings ...)
2025-06-05 1:45 ` [PATCH 29/31] drm/amdgpu/vcn4.0.3: " Alex Deucher
@ 2025-06-05 1:46 ` Alex Deucher
2025-06-05 1:46 ` [PATCH 31/31] drm/amdgpu/vcn5: " Alex Deucher
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:46 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 1c13ceb3bed8b..311d44edff224 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1475,9 +1475,8 @@ static int vcn_v4_0_5_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v4_0_5_stop(vinst);
vcn_v4_0_5_start(vinst);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 31/31] drm/amdgpu/vcn5: re-emit unprocessed state on ring reset
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
` (29 preceding siblings ...)
2025-06-05 1:46 ` [PATCH 30/31] drm/amdgpu/vcn4.0.5: " Alex Deucher
@ 2025-06-05 1:46 ` Alex Deucher
30 siblings, 0 replies; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 1:46 UTC (permalink / raw)
To: amd-gfx, christian.koenig; +Cc: Alex Deucher
Re-emit the unprocessed state after resetting the queue.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index a998708bc0745..3cc49c82e324a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -1202,9 +1202,8 @@ static int vcn_v5_0_0_ring_reset(struct amdgpu_ring *ring, unsigned int vmid)
vcn_v5_0_0_stop(vinst);
vcn_v5_0_0_start(vinst);
- amdgpu_fence_driver_force_completion(ring);
- return amdgpu_ring_test_helper(ring);
+ return amdgpu_ring_reemit_unprocessed_jobs(ring);
}
static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = {
--
2.49.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH 08/31] drm/amdgpu: track ring state associated with a job
2025-06-05 1:45 ` [PATCH 08/31] drm/amdgpu: track ring state associated with a job Alex Deucher
@ 2025-06-05 12:11 ` Christian König
2025-06-05 13:21 ` Alex Deucher
0 siblings, 1 reply; 35+ messages in thread
From: Christian König @ 2025-06-05 12:11 UTC (permalink / raw)
To: Alex Deucher, amd-gfx
On 6/5/25 03:45, Alex Deucher wrote:
> We need to know the wptr and sequence number associated
> with a job so that we can re-emit the unprocessed state
> after a ring reset. Pre-allocate storage space for
> the ring buffer contents and add a helper to save off
> the unprocessed state so that it can be re-emitted
> after the queue is reset.
>
> Add a helper that ring reset callbacks can use to verify
> that the ring has reset successfully and to reemit any
> unprocessed ring contents from subsequent jobs.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 15 ++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 13 +++-
> drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 11 ++-
> drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 92 +++++++++++++++++++++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 15 ++++
> 5 files changed, 143 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> index 569e0e5373927..25a664273bf0d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> @@ -141,6 +141,9 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
> }
> fence = &am_fence->base;
> am_fence->ring = ring;
> + am_fence->start_ring_wptr = 0;
> + am_fence->end_ring_wptr = 0;
Why do we need the start here? I would just keep the end around and then jump from fence to fence while re-submitting them.
> + am_fence->context = 0;
>
> seq = ++ring->fence_drv.sync_seq;
> if (job && job->job_run_counter) {
> @@ -748,6 +751,18 @@ void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
> amdgpu_fence_process(ring);
> }
>
> +/**
> + * amdgpu_fence_driver_seq_force_completion - force signal of specified sequence
> + *
> + * @ring: fence of the ring to signal
> + *
> + */
> +void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring, u32 seq)
Better give the full fence structure here.
> +{
> + amdgpu_fence_write(ring, seq);
> + amdgpu_fence_process(ring);
> +}
> +
> /*
> * Common fence implementation
> */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> index 802743efa3b39..636941697a740 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> @@ -126,7 +126,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> struct dma_fence **f)
> {
> struct amdgpu_device *adev = ring->adev;
> + u64 start_ring_wptr, end_ring_wptr;
> struct amdgpu_ib *ib = &ibs[0];
> + struct amdgpu_fence *am_fence;
> struct dma_fence *tmp = NULL;
> bool need_ctx_switch;
> struct amdgpu_vm *vm;
> @@ -138,7 +140,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> int vmid = AMDGPU_JOB_GET_VMID(job);
> bool need_pipe_sync = false;
> unsigned int cond_exec;
> -
> unsigned int i;
> int r = 0;
>
> @@ -187,6 +188,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
> return r;
> }
> + start_ring_wptr = ring->wptr;
>
> need_ctx_switch = ring->current_ctx != fence_ctx;
> if (ring->funcs->emit_pipeline_sync && job &&
> @@ -306,6 +308,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
>
> amdgpu_ring_ib_end(ring);
> amdgpu_ring_commit(ring);
> + /* This must be last for resets to work properly
> + * as we need to save the wptr associated with this
> + * fence.
> + */
> + end_ring_wptr = ring->wptr;
> + am_fence = container_of(*f, struct amdgpu_fence, base);
> + am_fence->start_ring_wptr = start_ring_wptr;
> + am_fence->end_ring_wptr = end_ring_wptr;
The end_ring_wptr variable is superflous and I would put assigning that into a helper in amdgpu_fence.c
> +
> return 0;
> }
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> index 23b6a0fc0c691..73c26e2e01647 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> @@ -89,8 +89,9 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
> {
> struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
> struct amdgpu_job *job = to_amdgpu_job(s_job);
> - struct amdgpu_task_info *ti;
> + struct amdgpu_fence *am_fence = &job->hw_fence;
> struct amdgpu_device *adev = ring->adev;
> + struct amdgpu_task_info *ti;
> bool set_error = false;
> int idx, r;
>
> @@ -154,7 +155,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
> else
> is_guilty = true;
>
> - if (is_guilty)
> + amdgpu_ring_backup_unprocessed_jobs(ring, is_guilty, am_fence);
> + if (is_guilty) {
> dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
> set_error = true;
> }
> @@ -409,6 +411,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
> struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched);
> struct amdgpu_device *adev = ring->adev;
> struct dma_fence *fence = NULL, *finished;
> + struct amdgpu_fence *am_fence;
> struct amdgpu_job *job;
> int r = 0;
>
> @@ -433,6 +436,10 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
> "Error scheduling IBs (%d) in ring(%s)", r,
> ring->name);
> }
> + if (fence && finished) {
> + am_fence = container_of(fence, struct amdgpu_fence, base);
> + am_fence->context = finished->context;
> + }
Better put that into amdgpu_fence_emit().
>
> job->job_run_counter++;
> amdgpu_job_free_resources(job);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> index 426834806fbf2..3a0e0883bd8e7 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> @@ -333,6 +333,12 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
> /* Initialize cached_rptr to 0 */
> ring->cached_rptr = 0;
>
> + if (!ring->ring_backup) {
> + ring->ring_backup = kvzalloc(ring->ring_size, GFP_KERNEL);
> + if (!ring->ring_backup)
> + return -ENOMEM;
> + }
> +
> /* Allocate ring buffer */
> if (ring->ring_obj == NULL) {
> r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
> @@ -342,6 +348,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
> (void **)&ring->ring);
> if (r) {
> dev_err(adev->dev, "(%d) ring create failed\n", r);
> + kvfree(ring->ring_backup);
> return r;
> }
> amdgpu_ring_clear_ring(ring);
> @@ -385,6 +392,8 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
> amdgpu_bo_free_kernel(&ring->ring_obj,
> &ring->gpu_addr,
> (void **)&ring->ring);
> + kvfree(ring->ring_backup);
> + ring->ring_backup = NULL;
>
> dma_fence_put(ring->vmid_wait);
> ring->vmid_wait = NULL;
> @@ -753,3 +762,86 @@ bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring)
>
> return true;
> }
> +
> +static void amdgpu_ring_backup_unprocessed_job(struct amdgpu_ring *ring,
> + unsigned int idx,
> + u64 start_wptr, u32 end_wptr)
Drop the job from all function names.
We are really re-emitting unprocessed commands.
> +{
> + unsigned int first_idx = start_wptr & ring->buf_mask;
> + unsigned int last_idx = end_wptr & ring->buf_mask;
> + unsigned int i, j, entries_to_copy;
> +
> + if (last_idx < first_idx) {
> + entries_to_copy = ring->buf_mask + 1 - first_idx;
> + for (i = 0; i < entries_to_copy; i++)
> + ring->ring_backup[idx + i] = ring->ring[first_idx + i];
> + ring->ring_backup_entries_to_copy += entries_to_copy;
> + entries_to_copy = last_idx;
> + for (j = 0; j < entries_to_copy; j++)
> + ring->ring_backup[idx + i + j] = ring->ring[j];
> + ring->ring_backup_entries_to_copy += entries_to_copy;
> + } else {
> + entries_to_copy = last_idx - first_idx;
> + for (i = 0; i < entries_to_copy; i++)
> + ring->ring_backup[idx + i] = ring->ring[first_idx + i];
> + ring->ring_backup_entries_to_copy += entries_to_copy;
> + }
> +}
> +
> +void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
> + bool is_guilty,
> + struct amdgpu_fence *bad_fence)
> +{
> + struct amdgpu_fence *fence;
> + struct dma_fence *old, **ptr;
> + int i;
> +
> + ring->ring_backup_entries_to_copy = 0;
> + for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
That is the wrong order for the fences, you need to start/end at the last submitted one.
I strongly suggest to implement that in amdgpu_fence.c
Regards,
Christian.
> + ptr = &ring->fence_drv.fences[i];
> + rcu_read_lock();
> + old = rcu_dereference(*ptr);
> +
> + if (old && !dma_fence_is_signaled(old)) {
> + fence = container_of(old, struct amdgpu_fence, base);
> + /* save everything if the ring is not guilty, otherwise
> + * just save the content from other contexts.
> + */
> + if (!is_guilty || (fence->context != bad_fence->context))
> + amdgpu_ring_backup_unprocessed_job(ring,
> + ring->ring_backup_entries_to_copy,
> + fence->start_ring_wptr,
> + fence->end_ring_wptr);
> + }
> + rcu_read_unlock();
> + }
> +
> + ring->ring_bad_seq = bad_fence->base.seqno;
> +}
> +
> +int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring)
> +{
> + unsigned int i;
> + int r;
> +
> + /* verify that the ring is functional */
> + r = amdgpu_ring_test_ring(ring);
> + if (r)
> + return r;
> + /* re-emit the unprocessed ring contents */
> + if (ring->ring_backup_entries_to_copy) {
> + r = amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
> + if (r)
> + return r;
> + /* signal the fence of the bad job */
> + amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
> + for (i = 0; i < ring->ring_backup_entries_to_copy; i++)
> + amdgpu_ring_write(ring, ring->ring_backup[i]);
> + amdgpu_ring_commit(ring);
> + } else {
> + /* signal the fence of the bad job */
> + amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> index e1f25218943a4..69b71401adb7a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> @@ -141,6 +141,12 @@ struct amdgpu_fence {
> /* RB, DMA, etc. */
> struct amdgpu_ring *ring;
> ktime_t start_timestamp;
> +
> + /* wptrs for the fence for resets */
> + u64 start_ring_wptr;
> + u64 end_ring_wptr;
> + /* fence context for resets */
> + u64 context;
> };
>
> extern const struct drm_sched_backend_ops amdgpu_sched_ops;
> @@ -148,6 +154,8 @@ extern const struct drm_sched_backend_ops amdgpu_sched_ops;
> void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
> void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error);
> void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
> +void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring,
> + u32 seq);
>
> int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
> int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
> @@ -284,6 +292,9 @@ struct amdgpu_ring {
>
> struct amdgpu_bo *ring_obj;
> uint32_t *ring;
> + uint32_t *ring_backup;
> + unsigned int ring_backup_entries_to_copy;
> + uint64_t ring_bad_seq;
> unsigned rptr_offs;
> u64 rptr_gpu_addr;
> volatile u32 *rptr_cpu_addr;
> @@ -550,4 +561,8 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev);
> void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
> int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
> bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring);
> +void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
> + bool is_guilty,
> + struct amdgpu_fence *bad_fence);
> +int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring);
> #endif
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/31] drm/amdgpu: track ring state associated with a job
2025-06-05 12:11 ` Christian König
@ 2025-06-05 13:21 ` Alex Deucher
2025-06-05 13:50 ` Christian König
0 siblings, 1 reply; 35+ messages in thread
From: Alex Deucher @ 2025-06-05 13:21 UTC (permalink / raw)
To: Christian König; +Cc: Alex Deucher, amd-gfx
On Thu, Jun 5, 2025 at 8:22 AM Christian König <christian.koenig@amd.com> wrote:
>
> On 6/5/25 03:45, Alex Deucher wrote:
> > We need to know the wptr and sequence number associated
> > with a job so that we can re-emit the unprocessed state
> > after a ring reset. Pre-allocate storage space for
> > the ring buffer contents and add a helper to save off
> > the unprocessed state so that it can be re-emitted
> > after the queue is reset.
> >
> > Add a helper that ring reset callbacks can use to verify
> > that the ring has reset successfully and to reemit any
> > unprocessed ring contents from subsequent jobs.
> >
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > ---
> > drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 15 ++++
> > drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 13 +++-
> > drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 11 ++-
> > drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 92 +++++++++++++++++++++++
> > drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 15 ++++
> > 5 files changed, 143 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> > index 569e0e5373927..25a664273bf0d 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
> > @@ -141,6 +141,9 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
> > }
> > fence = &am_fence->base;
> > am_fence->ring = ring;
> > + am_fence->start_ring_wptr = 0;
> > + am_fence->end_ring_wptr = 0;
>
> Why do we need the start here? I would just keep the end around and then jump from fence to fence while re-submitting them.
I need to know the start and end of the ring contents associated with
each fence. When I re-emit, I just copy over the ring contents for
all fences that don't match the bad one. Also we submit multiple
fences per IB depending on whether we do a vm flush. Those fences are
internal to the IB frame so they don't really need a start and end,
hence 0.
>
> > + am_fence->context = 0;
> >
> > seq = ++ring->fence_drv.sync_seq;
> > if (job && job->job_run_counter) {
> > @@ -748,6 +751,18 @@ void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
> > amdgpu_fence_process(ring);
> > }
> >
> > +/**
> > + * amdgpu_fence_driver_seq_force_completion - force signal of specified sequence
> > + *
> > + * @ring: fence of the ring to signal
> > + *
> > + */
> > +void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring, u32 seq)
>
> Better give the full fence structure here.
You mean pass the fence directly?
>
> > +{
> > + amdgpu_fence_write(ring, seq);
> > + amdgpu_fence_process(ring);
> > +}
> > +
> > /*
> > * Common fence implementation
> > */
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> > index 802743efa3b39..636941697a740 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
> > @@ -126,7 +126,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> > struct dma_fence **f)
> > {
> > struct amdgpu_device *adev = ring->adev;
> > + u64 start_ring_wptr, end_ring_wptr;
> > struct amdgpu_ib *ib = &ibs[0];
> > + struct amdgpu_fence *am_fence;
> > struct dma_fence *tmp = NULL;
> > bool need_ctx_switch;
> > struct amdgpu_vm *vm;
> > @@ -138,7 +140,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> > int vmid = AMDGPU_JOB_GET_VMID(job);
> > bool need_pipe_sync = false;
> > unsigned int cond_exec;
> > -
> > unsigned int i;
> > int r = 0;
> >
> > @@ -187,6 +188,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> > dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
> > return r;
> > }
> > + start_ring_wptr = ring->wptr;
> >
> > need_ctx_switch = ring->current_ctx != fence_ctx;
> > if (ring->funcs->emit_pipeline_sync && job &&
> > @@ -306,6 +308,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
> >
> > amdgpu_ring_ib_end(ring);
> > amdgpu_ring_commit(ring);
> > + /* This must be last for resets to work properly
> > + * as we need to save the wptr associated with this
> > + * fence.
> > + */
> > + end_ring_wptr = ring->wptr;
> > + am_fence = container_of(*f, struct amdgpu_fence, base);
> > + am_fence->start_ring_wptr = start_ring_wptr;
> > + am_fence->end_ring_wptr = end_ring_wptr;
>
> The end_ring_wptr variable is superflous and I would put assigning that into a helper in amdgpu_fence.c
I'm not following. I need the start and end wptrs in order to know
what ranges of the ring I need to save.
>
> > +
> > return 0;
> > }
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> > index 23b6a0fc0c691..73c26e2e01647 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> > @@ -89,8 +89,9 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
> > {
> > struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
> > struct amdgpu_job *job = to_amdgpu_job(s_job);
> > - struct amdgpu_task_info *ti;
> > + struct amdgpu_fence *am_fence = &job->hw_fence;
> > struct amdgpu_device *adev = ring->adev;
> > + struct amdgpu_task_info *ti;
> > bool set_error = false;
> > int idx, r;
> >
> > @@ -154,7 +155,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
> > else
> > is_guilty = true;
> >
> > - if (is_guilty)
> > + amdgpu_ring_backup_unprocessed_jobs(ring, is_guilty, am_fence);
> > + if (is_guilty) {
> > dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
> > set_error = true;
> > }
> > @@ -409,6 +411,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
> > struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched);
> > struct amdgpu_device *adev = ring->adev;
> > struct dma_fence *fence = NULL, *finished;
> > + struct amdgpu_fence *am_fence;
> > struct amdgpu_job *job;
> > int r = 0;
> >
> > @@ -433,6 +436,10 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
> > "Error scheduling IBs (%d) in ring(%s)", r,
> > ring->name);
> > }
> > + if (fence && finished) {
> > + am_fence = container_of(fence, struct amdgpu_fence, base);
> > + am_fence->context = finished->context;
> > + }
>
> Better put that into amdgpu_fence_emit().
Makes sense.
>
> >
> > job->job_run_counter++;
> > amdgpu_job_free_resources(job);
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> > index 426834806fbf2..3a0e0883bd8e7 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
> > @@ -333,6 +333,12 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
> > /* Initialize cached_rptr to 0 */
> > ring->cached_rptr = 0;
> >
> > + if (!ring->ring_backup) {
> > + ring->ring_backup = kvzalloc(ring->ring_size, GFP_KERNEL);
> > + if (!ring->ring_backup)
> > + return -ENOMEM;
> > + }
> > +
> > /* Allocate ring buffer */
> > if (ring->ring_obj == NULL) {
> > r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE,
> > @@ -342,6 +348,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
> > (void **)&ring->ring);
> > if (r) {
> > dev_err(adev->dev, "(%d) ring create failed\n", r);
> > + kvfree(ring->ring_backup);
> > return r;
> > }
> > amdgpu_ring_clear_ring(ring);
> > @@ -385,6 +392,8 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
> > amdgpu_bo_free_kernel(&ring->ring_obj,
> > &ring->gpu_addr,
> > (void **)&ring->ring);
> > + kvfree(ring->ring_backup);
> > + ring->ring_backup = NULL;
> >
> > dma_fence_put(ring->vmid_wait);
> > ring->vmid_wait = NULL;
> > @@ -753,3 +762,86 @@ bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring)
> >
> > return true;
> > }
> > +
> > +static void amdgpu_ring_backup_unprocessed_job(struct amdgpu_ring *ring,
> > + unsigned int idx,
> > + u64 start_wptr, u32 end_wptr)
>
> Drop the job from all function names.
>
> We are really re-emitting unprocessed commands.
Will do.
>
> > +{
> > + unsigned int first_idx = start_wptr & ring->buf_mask;
> > + unsigned int last_idx = end_wptr & ring->buf_mask;
> > + unsigned int i, j, entries_to_copy;
> > +
> > + if (last_idx < first_idx) {
> > + entries_to_copy = ring->buf_mask + 1 - first_idx;
> > + for (i = 0; i < entries_to_copy; i++)
> > + ring->ring_backup[idx + i] = ring->ring[first_idx + i];
> > + ring->ring_backup_entries_to_copy += entries_to_copy;
> > + entries_to_copy = last_idx;
> > + for (j = 0; j < entries_to_copy; j++)
> > + ring->ring_backup[idx + i + j] = ring->ring[j];
> > + ring->ring_backup_entries_to_copy += entries_to_copy;
> > + } else {
> > + entries_to_copy = last_idx - first_idx;
> > + for (i = 0; i < entries_to_copy; i++)
> > + ring->ring_backup[idx + i] = ring->ring[first_idx + i];
> > + ring->ring_backup_entries_to_copy += entries_to_copy;
> > + }
> > +}
> > +
> > +void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
> > + bool is_guilty,
> > + struct amdgpu_fence *bad_fence)
> > +{
> > + struct amdgpu_fence *fence;
> > + struct dma_fence *old, **ptr;
> > + int i;
> > +
> > + ring->ring_backup_entries_to_copy = 0;
> > + for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
>
> That is the wrong order for the fences, you need to start/end at the last submitted one.
I'm not sure I follow. When I backup the ring contents, I need to go
from oldest to newest so the order is correct when I re-emit.
Alex
>
> I strongly suggest to implement that in amdgpu_fence.c
>
> Regards,
> Christian.
>
> > + ptr = &ring->fence_drv.fences[i];
> > + rcu_read_lock();
> > + old = rcu_dereference(*ptr);
> > +
> > + if (old && !dma_fence_is_signaled(old)) {
> > + fence = container_of(old, struct amdgpu_fence, base);
> > + /* save everything if the ring is not guilty, otherwise
> > + * just save the content from other contexts.
> > + */
> > + if (!is_guilty || (fence->context != bad_fence->context))
> > + amdgpu_ring_backup_unprocessed_job(ring,
> > + ring->ring_backup_entries_to_copy,
> > + fence->start_ring_wptr,
> > + fence->end_ring_wptr);
> > + }
> > + rcu_read_unlock();
> > + }
> > +
> > + ring->ring_bad_seq = bad_fence->base.seqno;
> > +}
> > +
> > +int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring)
> > +{
> > + unsigned int i;
> > + int r;
> > +
> > + /* verify that the ring is functional */
> > + r = amdgpu_ring_test_ring(ring);
> > + if (r)
> > + return r;
> > + /* re-emit the unprocessed ring contents */
> > + if (ring->ring_backup_entries_to_copy) {
> > + r = amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
> > + if (r)
> > + return r;
> > + /* signal the fence of the bad job */
> > + amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
> > + for (i = 0; i < ring->ring_backup_entries_to_copy; i++)
> > + amdgpu_ring_write(ring, ring->ring_backup[i]);
> > + amdgpu_ring_commit(ring);
> > + } else {
> > + /* signal the fence of the bad job */
> > + amdgpu_fence_driver_seq_force_completion(ring, ring->ring_bad_seq);
> > + }
> > +
> > + return 0;
> > +}
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> > index e1f25218943a4..69b71401adb7a 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
> > @@ -141,6 +141,12 @@ struct amdgpu_fence {
> > /* RB, DMA, etc. */
> > struct amdgpu_ring *ring;
> > ktime_t start_timestamp;
> > +
> > + /* wptrs for the fence for resets */
> > + u64 start_ring_wptr;
> > + u64 end_ring_wptr;
> > + /* fence context for resets */
> > + u64 context;
> > };
> >
> > extern const struct drm_sched_backend_ops amdgpu_sched_ops;
> > @@ -148,6 +154,8 @@ extern const struct drm_sched_backend_ops amdgpu_sched_ops;
> > void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
> > void amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error);
> > void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
> > +void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring,
> > + u32 seq);
> >
> > int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
> > int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
> > @@ -284,6 +292,9 @@ struct amdgpu_ring {
> >
> > struct amdgpu_bo *ring_obj;
> > uint32_t *ring;
> > + uint32_t *ring_backup;
> > + unsigned int ring_backup_entries_to_copy;
> > + uint64_t ring_bad_seq;
> > unsigned rptr_offs;
> > u64 rptr_gpu_addr;
> > volatile u32 *rptr_cpu_addr;
> > @@ -550,4 +561,8 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev);
> > void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
> > int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
> > bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring);
> > +void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
> > + bool is_guilty,
> > + struct amdgpu_fence *bad_fence);
> > +int amdgpu_ring_reemit_unprocessed_jobs(struct amdgpu_ring *ring);
> > #endif
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/31] drm/amdgpu: track ring state associated with a job
2025-06-05 13:21 ` Alex Deucher
@ 2025-06-05 13:50 ` Christian König
0 siblings, 0 replies; 35+ messages in thread
From: Christian König @ 2025-06-05 13:50 UTC (permalink / raw)
To: Alex Deucher; +Cc: Alex Deucher, amd-gfx
On 6/5/25 15:21, Alex Deucher wrote:
>>> + am_fence->start_ring_wptr = 0;
>>> + am_fence->end_ring_wptr = 0;
>>
>> Why do we need the start here? I would just keep the end around and then jump from fence to fence while re-submitting them.
>
> I need to know the start and end of the ring contents associated with
> each fence. When I re-emit, I just copy over the ring contents for
> all fences that don't match the bad one. Also we submit multiple
> fences per IB depending on whether we do a vm flush. Those fences are
> internal to the IB frame so they don't really need a start and end,
> hence 0.
What I wanted to do is the following:
ptr = bad_fence->wend_ring_wptr;
for (i = (bad_fence->seq + 1) & fence_drv->mask; i != bad_fence_seq; ++i &= fence_drv->mask)
fence = fence_drv->fences[i]
if (dma_fence_is_signaled(fence))
break;
if (!fence->end_ring_wptr)
continue;
if (fence->context != bad_fence->context)
backup(ptr, fence->end_ring_wptr);
ptr = fence->end_ring_wptr;
}
But could be that it is better to backup start/end explicitly.
>>> +void amdgpu_fence_driver_seq_force_completion(struct amdgpu_ring *ring, u32 seq)
>>
>> Better give the full fence structure here.
>
> You mean pass the fence directly?
Yes.
>
>>
>>> +{
>>> + amdgpu_fence_write(ring, seq);
>>> + amdgpu_fence_process(ring);
>>> +}
>>> +
>>> /*
>>> * Common fence implementation
>>> */
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
>>> index 802743efa3b39..636941697a740 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
>>> @@ -126,7 +126,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
>>> struct dma_fence **f)
>>> {
>>> struct amdgpu_device *adev = ring->adev;
>>> + u64 start_ring_wptr, end_ring_wptr;
>>> struct amdgpu_ib *ib = &ibs[0];
>>> + struct amdgpu_fence *am_fence;
>>> struct dma_fence *tmp = NULL;
>>> bool need_ctx_switch;
>>> struct amdgpu_vm *vm;
>>> @@ -138,7 +140,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
>>> int vmid = AMDGPU_JOB_GET_VMID(job);
>>> bool need_pipe_sync = false;
>>> unsigned int cond_exec;
>>> -
>>> unsigned int i;
>>> int r = 0;
>>>
>>> @@ -187,6 +188,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
>>> dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
>>> return r;
>>> }
>>> + start_ring_wptr = ring->wptr;
>>>
>>> need_ctx_switch = ring->current_ctx != fence_ctx;
>>> if (ring->funcs->emit_pipeline_sync && job &&
>>> @@ -306,6 +308,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
>>>
>>> amdgpu_ring_ib_end(ring);
>>> amdgpu_ring_commit(ring);
>>> + /* This must be last for resets to work properly
>>> + * as we need to save the wptr associated with this
>>> + * fence.
>>> + */
>>> + end_ring_wptr = ring->wptr;
>>> + am_fence = container_of(*f, struct amdgpu_fence, base);
>>> + am_fence->start_ring_wptr = start_ring_wptr;
>>> + am_fence->end_ring_wptr = end_ring_wptr;
>>
>> The end_ring_wptr variable is superflous and I would put assigning that into a helper in amdgpu_fence.c
>
> I'm not following. I need the start and end wptrs in order to know
> what ranges of the ring I need to save.
But you have
end_ring_wptr = ring->wptr;
...
am_fence->end_ring_wptr = end_ring_wptr;
start_ring_wptr is available as ring->wptr_old btw.
>>> +void amdgpu_ring_backup_unprocessed_jobs(struct amdgpu_ring *ring,
>>> + bool is_guilty,
>>> + struct amdgpu_fence *bad_fence)
>>> +{
>>> + struct amdgpu_fence *fence;
>>> + struct dma_fence *old, **ptr;
>>> + int i;
>>> +
>>> + ring->ring_backup_entries_to_copy = 0;
>>> + for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) {
>>
>> That is the wrong order for the fences, you need to start/end at the last submitted one.
>
> I'm not sure I follow. When I backup the ring contents, I need to go
> from oldest to newest so the order is correct when I re-emit.
Yeah, but 0 is not the oldest. fence_drv->fences is a ring buffer!
You need to start with something like fence_drv->fences[bad_fence->seq & mask].
Christian.
>
> Alex
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2025-06-05 13:50 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-05 1:45 [PATCH V6 00/31] Reset improvements for GC10+ Alex Deucher
2025-06-05 1:45 ` [PATCH 01/31] drm/amdgpu: enable legacy enforce isolation by default Alex Deucher
2025-06-05 1:45 ` [PATCH 02/31] drm/amdgpu/gfx7: drop reset_kgq Alex Deucher
2025-06-05 1:45 ` [PATCH 03/31] drm/amdgpu/gfx8: " Alex Deucher
2025-06-05 1:45 ` [PATCH 04/31] drm/amdgpu/gfx9: " Alex Deucher
2025-06-05 1:45 ` [PATCH 05/31] drm/amdgpu: switch job hw_fence to amdgpu_fence Alex Deucher
2025-06-05 1:45 ` [PATCH 06/31] drm/amdgpu: rework queue reset scheduler interaction Alex Deucher
2025-06-05 1:45 ` [PATCH 07/31] drm/amdgpu: move force completion into ring resets Alex Deucher
2025-06-05 1:45 ` [PATCH 08/31] drm/amdgpu: track ring state associated with a job Alex Deucher
2025-06-05 12:11 ` Christian König
2025-06-05 13:21 ` Alex Deucher
2025-06-05 13:50 ` Christian König
2025-06-05 1:45 ` [PATCH 09/31] drm/amdgpu: optimize amdgpu_ring_reemit_unprocessed_jobs() Alex Deucher
2025-06-05 1:45 ` [PATCH 10/31] drm/amdgpu/gfx10: re-emit unprocessed state on ring reset Alex Deucher
2025-06-05 1:45 ` [PATCH 11/31] drm/amdgpu/gfx11: " Alex Deucher
2025-06-05 1:45 ` [PATCH 12/31] drm/amdgpu/gfx12: " Alex Deucher
2025-06-05 1:45 ` [PATCH 13/31] drm/amdgpu/gfx9: re-emit unprocessed state on kcq reset Alex Deucher
2025-06-05 1:45 ` [PATCH 14/31] drm/amdgpu/gfx9.4.3: " Alex Deucher
2025-06-05 1:45 ` [PATCH 15/31] drm/amdgpu/sdma4.4.2: re-emit unprocessed state on ring reset Alex Deucher
2025-06-05 1:45 ` [PATCH 16/31] drm/amdgpu/sdma5: " Alex Deucher
2025-06-05 1:45 ` [PATCH 17/31] drm/amdgpu/sdma5.2: " Alex Deucher
2025-06-05 1:45 ` [PATCH 18/31] drm/amdgpu/sdma6: " Alex Deucher
2025-06-05 1:45 ` [PATCH 19/31] drm/amdgpu/sdma7: " Alex Deucher
2025-06-05 1:45 ` [PATCH 20/31] drm/amdgpu/jpeg2: " Alex Deucher
2025-06-05 1:45 ` [PATCH 21/31] drm/amdgpu/jpeg2.5: " Alex Deucher
2025-06-05 1:45 ` [PATCH 22/31] drm/amdgpu/jpeg3: " Alex Deucher
2025-06-05 1:45 ` [PATCH 23/31] drm/amdgpu/jpeg4: " Alex Deucher
2025-06-05 1:45 ` [PATCH 24/31] drm/amdgpu/jpeg4.0.3: " Alex Deucher
2025-06-05 1:45 ` [PATCH 25/31] drm/amdgpu/jpeg5.0.0: add queue reset Alex Deucher
2025-06-05 1:45 ` [PATCH 26/31] drm/amdgpu/jpeg5: re-emit unprocessed state on ring reset Alex Deucher
2025-06-05 1:45 ` [PATCH 27/31] drm/amdgpu/jpeg5.0.1: " Alex Deucher
2025-06-05 1:45 ` [PATCH 28/31] drm/amdgpu/vcn4: " Alex Deucher
2025-06-05 1:45 ` [PATCH 29/31] drm/amdgpu/vcn4.0.3: " Alex Deucher
2025-06-05 1:46 ` [PATCH 30/31] drm/amdgpu/vcn4.0.5: " Alex Deucher
2025-06-05 1:46 ` [PATCH 31/31] drm/amdgpu/vcn5: " Alex Deucher
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.