* [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6
@ 2026-07-13 13:06 Timur Kristóf
2026-07-13 13:06 ` [PATCH 01/11] drm/amdgpu/gfx6: Improve emit_cntxcntl() Timur Kristóf
` (10 more replies)
0 siblings, 11 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:06 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Fix up various things in the GFX6 code to prepare it
to work with IP block soft reset. The main challenge
was figuring out how to properly initialize the
compute queues so that they work well after a reset,
as well as realizing that on GFX6 the compute queues
also have a PFP (as opposed to GFX7+ where PFP is
a graphics only thing). There are also other minor
fixes.
Implement GFX6 IP block soft reset: just reset everything
in the GFX IP block (instead of taking a guess at which
parts need to be reset) to make it consistent, and
also handle clock and power gating to make sure not to
degrade GPU functionality after a GFX IP block soft reset.
This improves current user experience on all GFX6 chips:
On GFX6 dGPUs, the current GPU recovery method
always clears the contents of VRAM, which means that
a buggy (hanging) app can crash the whole graphical
session, which is less than ideal.
Using GFX IP block soft reset means that we can now
move on from GFX hangs on dGPUs without crashing the
whole system.
Tested on the following chips:
Tahiti (FirePro W9000, Radeon HD 7870 XT)
Cape Verde (Radeon R7 450)
Pitcairn (Radeon R9 270X)
Oland (Radeon 430)
Timur Kristóf (11):
drm/amdgpu/gfx6: Improve emit_cntxcntl()
drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets
drm/amdgpu/gfx6: Use PFP on the compute queues too
drm/amdgpu/gfx6: Initialize compute rings before CP start
drm/amdgpu/gfx6: Clean up rings during reset
drm/amdgpu/gfx6: Execute CLEAR_STATE when initializing compute rings
drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst
interrupts
drm/amdgpu/gfx6: Adjust how harvested TCCs are set up
drm/amdgpu/gfx6: Use COND_EXEC
drm/amdgpu/gfx6: Add IP block soft reset implementation
drm/amdgpu/gfx6: Enable IP block soft reset as a GPU recovery method
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 403 +++++++++++++-----
.../include/asic_reg/gca/gfx_6_0_sh_mask.h | 32 +-
2 files changed, 316 insertions(+), 119 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/11] drm/amdgpu/gfx6: Improve emit_cntxcntl()
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
@ 2026-07-13 13:06 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 02/11] drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets Timur Kristóf
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:06 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Set bits on dword 2 like GFX7-8 except load_global_uconfig
which doesn't exist on GFX6.
Emit VS_PARTIAL_FLUSH before VGT_FLUSH like GFX7-8.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 28 ++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index ac90d8e9d86a..6d7baee04372 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1881,11 +1881,13 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
return r;
}
-static void gfx_v6_0_ring_emit_vgt_flush(struct amdgpu_ring *ring)
+static void gfx_v6_0_ring_emit_event_write(struct amdgpu_ring *ring,
+ uint32_t event_type,
+ uint32_t event_index)
{
amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE, 0));
- amdgpu_ring_write(ring, EVENT_TYPE(VGT_FLUSH) |
- EVENT_INDEX(0));
+ amdgpu_ring_write(ring, EVENT_TYPE(event_type) |
+ EVENT_INDEX(event_index));
}
static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
@@ -2998,10 +3000,22 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)
static void gfx_v6_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
{
- if (flags & AMDGPU_HAVE_CTX_SWITCH)
- gfx_v6_0_ring_emit_vgt_flush(ring);
+ u32 dw2 = 0x80000000; /* set load_enable otherwise this package is just NOPs */
+
+ if (flags & AMDGPU_HAVE_CTX_SWITCH) {
+ gfx_v6_0_ring_emit_event_write(ring, VS_PARTIAL_FLUSH, 4);
+ gfx_v6_0_ring_emit_event_write(ring, VGT_FLUSH, 0);
+
+ /* set load_global_config (load_global_uconfig doesn't exist on GFX6) */
+ dw2 |= 0x1;
+ /* set load_cs_sh_regs */
+ dw2 |= 0x01000000;
+ /* set load_per_context_state & load_gfx_sh_regs */
+ dw2 |= 0x10002;
+ }
+
amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
- amdgpu_ring_write(ring, 0x80000000);
+ amdgpu_ring_write(ring, dw2);
amdgpu_ring_write(ring, 0);
}
@@ -3529,7 +3543,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
7 + 4 + /* gfx_v6_0_ring_emit_pipeline_sync */
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v6_0_ring_emit_vm_flush */
- 3 + 2 + /* gfx_v6_ring_emit_cntxcntl including vgt flush */
+ 3 + 2 + 2 + /* gfx_v6_ring_emit_cntxcntl including VGT flush */
5, /* SURFACE_SYNC */
.emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */
.emit_ib = gfx_v6_0_ring_emit_ib,
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/11] drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
2026-07-13 13:06 ` [PATCH 01/11] drm/amdgpu/gfx6: Improve emit_cntxcntl() Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 03/11] drm/amdgpu/gfx6: Use PFP on the compute queues too Timur Kristóf
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Implement the emit_switch_buffer() function instead of emitting
them duing emit_ib, emit_pipeline_sync and emit_vm_flush.
Note that it isn't necessary to emit these in both
emit_pipeline_sync() and emit_vm_flush() because
amdgpu_vm_flush() already calls these when calling
either of those functions.
Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8")
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 38 ++++++++++-----------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 6d7baee04372..1a9866e40912 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1926,12 +1926,6 @@ static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
- /* insert SWITCH_BUFFER packet before first IB in the ring frame */
- if (flags & AMDGPU_HAVE_CTX_SWITCH) {
- amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
- amdgpu_ring_write(ring, 0);
- }
-
if (ib->flags & AMDGPU_IB_FLAG_CE)
header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
else
@@ -2366,14 +2360,6 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring, 0xffffffff);
amdgpu_ring_write(ring, 4); /* poll interval */
-
- if (usepfp) {
- /* synce CE with ME to prevent CE fetch CEIB before context switch done */
- amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
- amdgpu_ring_write(ring, 0);
- amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
- amdgpu_ring_write(ring, 0);
- }
}
static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
@@ -2397,12 +2383,6 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
/* sync PFP to ME, otherwise we might get invalid PFP reads */
amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
amdgpu_ring_write(ring, 0x0);
-
- /* synce CE with ME to prevent CE fetch CEIB before context switch done */
- amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
- amdgpu_ring_write(ring, 0);
- amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
- amdgpu_ring_write(ring, 0);
}
}
@@ -2998,6 +2978,12 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)
return clock;
}
+static void gfx_v6_0_ring_emit_sb(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+ amdgpu_ring_write(ring, 0);
+}
+
static void gfx_v6_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
{
u32 dw2 = 0x80000000; /* set load_enable otherwise this package is just NOPs */
@@ -3541,11 +3527,12 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
.emit_frame_size =
5 + 5 + /* hdp flush / invalidate */
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
- 7 + 4 + /* gfx_v6_0_ring_emit_pipeline_sync */
- SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v6_0_ring_emit_vm_flush */
+ 7 + /* gfx_v6_0_ring_emit_pipeline_sync */
+ SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v6_0_ring_emit_vm_flush */
+ 3 * 2 + /* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
3 + 2 + 2 + /* gfx_v6_ring_emit_cntxcntl including VGT flush */
5, /* SURFACE_SYNC */
- .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */
+ .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */
.emit_ib = gfx_v6_0_ring_emit_ib,
.emit_fence = gfx_v6_0_ring_emit_fence,
.emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3553,6 +3540,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
.test_ring = gfx_v6_0_ring_test_ring,
.test_ib = gfx_v6_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
+ .emit_switch_buffer = gfx_v6_0_ring_emit_sb,
.emit_cntxcntl = gfx_v6_ring_emit_cntxcntl,
.emit_wreg = gfx_v6_0_ring_emit_wreg,
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
@@ -3570,8 +3558,9 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v6_0_ring_emit_vm_flush */
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
+ 3 * 2 + /* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
5, /* SURFACE_SYNC */
- .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */
+ .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */
.emit_ib = gfx_v6_0_ring_emit_ib,
.emit_fence = gfx_v6_0_ring_emit_fence,
.emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3579,6 +3568,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
.test_ring = gfx_v6_0_ring_test_ring,
.test_ib = gfx_v6_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
+ .emit_switch_buffer = gfx_v6_0_ring_emit_sb,
.emit_wreg = gfx_v6_0_ring_emit_wreg,
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
};
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/11] drm/amdgpu/gfx6: Use PFP on the compute queues too
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
2026-07-13 13:06 ` [PATCH 01/11] drm/amdgpu/gfx6: Improve emit_cntxcntl() Timur Kristóf
2026-07-13 13:07 ` [PATCH 02/11] drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 04/11] drm/amdgpu/gfx6: Initialize compute rings before CP start Timur Kristóf
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
On GFX6, the compute rings use the same CP path as
the graphics ring. The only difference is that they
don't support draw commands. (As opposed to GFX7 and
newer which have a separate command parser that is
called MEC for compute queues.)
This means that we have to take into consideration
that the PFP also exists on compute queues on GFX6:
Use PFP for register writes on both graphics and
compute queues.
In the pipeline sync, use the PFP to wait for the
previous fence (and not the ME) to prevent the PFP
from starting to execute the next submission while
the ME is still in the previous submission.
In the VM flush, writing the TLB flush registers
is now done by the PFP. Synchronize PFP to ME before
doing the TLB flush to make sure the ME isn't using the
VMID being flushed. Then the register is read by the
PFP now so there is no need to sync with ME afterwards.
Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8")
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 1a9866e40912..8e8e5fe487f5 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -2347,14 +2347,13 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)
static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
{
- int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
uint32_t seq = ring->fence_drv.sync_seq;
uint64_t addr = ring->fence_drv.gpu_addr;
amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
WAIT_REG_MEM_FUNCTION(3) | /* equal */
- WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */
+ WAIT_REG_MEM_ENGINE(1))); /* pfp */
amdgpu_ring_write(ring, addr & 0xfffffffc);
amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
amdgpu_ring_write(ring, seq);
@@ -2365,34 +2364,29 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
unsigned vmid, uint64_t pd_addr)
{
- int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
+ /* sync PFP to ME, otherwise ME might still use the VMID when we flush it */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+ amdgpu_ring_write(ring, 0x0);
+ /* Write VM_CONTEXT0_PAGE_TABLE_BASE_ADDR and VM_INVALIDATE_REQUEST using PFP */
amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr);
/* wait for the invalidate to complete */
amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
amdgpu_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */
- WAIT_REG_MEM_ENGINE(0))); /* me */
+ WAIT_REG_MEM_ENGINE(1))); /* pfp */
amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST);
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring, 0); /* ref */
amdgpu_ring_write(ring, 0); /* mask */
amdgpu_ring_write(ring, 0x20); /* poll interval */
-
- if (usepfp) {
- /* sync PFP to ME, otherwise we might get invalid PFP reads */
- amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
- amdgpu_ring_write(ring, 0x0);
- }
}
static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val)
{
- int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
-
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
- amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
+ amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | /* pfp */
WRITE_DATA_DST_SEL(0)));
amdgpu_ring_write(ring, reg);
amdgpu_ring_write(ring, 0);
@@ -3556,7 +3550,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
.emit_frame_size =
5 + 5 + /* hdp flush / invalidate */
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
- SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v6_0_ring_emit_vm_flush */
+ SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v6_0_ring_emit_vm_flush */
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
3 * 2 + /* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
5, /* SURFACE_SYNC */
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/11] drm/amdgpu/gfx6: Initialize compute rings before CP start
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (2 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 03/11] drm/amdgpu/gfx6: Use PFP on the compute queues too Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 05/11] drm/amdgpu/gfx6: Clean up rings during reset Timur Kristóf
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
In GFX6 GPUs, compute takes the same CP path as graphics.
CP ME command parser executes packets for each ring buffer:
RB0 supports graphics, RB1 and RB2 are compute only.
Initialize all three rings before calling gfx_v6_0_cp_gfx_start()
to make sure they are all in a sane state before execution starts.
Previously, the two compute-only rings were initialized after
the ME had been already started, which could cause the ME to
start executing the ring contents before the rings could be
properly initialized. This happens to work when the HW is first
initialized, but not during an IP block reset where we want
to reinitialize the compute rings before starting the ME
to prevent it from executing garbage from these rings.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 134 ++++++++++++++------------
1 file changed, 70 insertions(+), 64 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 8e8e5fe487f5..ca6a62e822b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -2128,12 +2128,24 @@ static int gfx_v6_0_cp_gfx_start(struct amdgpu_device *adev)
return 0;
}
+/**
+ * gfx_v6_0_cp_gfx_resume() - Initialize CP rings
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * In GFX6 GPUs, compute takes the same CP path as graphics.
+ * CP ME command parser executes packets for each ring buffer:
+ * RB0 supports graphics, RB1 and RB2 are compute only.
+ * Initialize all three rings before calling gfx_v6_0_cp_gfx_start()
+ * to make sure they are all in a sane state before execution starts.
+ */
static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
{
struct amdgpu_ring *ring;
u32 tmp;
u32 rb_bufsz;
int r;
+ int i;
u64 rptr_addr;
WREG32(mmCP_SEM_WAIT_TIMER, 0x0);
@@ -2173,12 +2185,69 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB0_BASE, ring->gpu_addr >> 8);
+ /* ring 1 - compute only */
+ if (adev->gfx.num_compute_rings >= 1) {
+ ring = &adev->gfx.compute_ring[0];
+
+ rb_bufsz = order_base_2(ring->ring_size / 8);
+ tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+ tmp |= BUF_SWAP_32BIT;
+#endif
+ WREG32(mmCP_RB1_CNTL, tmp);
+
+ WREG32(mmCP_RB1_CNTL, tmp | CP_RB1_CNTL__RB_RPTR_WR_ENA_MASK);
+ ring->wptr = 0;
+ WREG32(mmCP_RB1_WPTR, ring->wptr);
+
+ rptr_addr = ring->rptr_gpu_addr;
+ WREG32(mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
+ WREG32(mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
+
+ mdelay(1);
+ WREG32(mmCP_RB1_CNTL, tmp);
+ WREG32(mmCP_RB1_BASE, ring->gpu_addr >> 8);
+ }
+
+ /* ring 2 - compute only */
+ if (adev->gfx.num_compute_rings >= 2) {
+ ring = &adev->gfx.compute_ring[1];
+
+ rb_bufsz = order_base_2(ring->ring_size / 8);
+ tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+ tmp |= BUF_SWAP_32BIT;
+#endif
+ WREG32(mmCP_RB2_CNTL, tmp);
+
+ WREG32(mmCP_RB2_CNTL, tmp | CP_RB2_CNTL__RB_RPTR_WR_ENA_MASK);
+ ring->wptr = 0;
+ WREG32(mmCP_RB2_WPTR, ring->wptr);
+ rptr_addr = ring->rptr_gpu_addr;
+ WREG32(mmCP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
+ WREG32(mmCP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
+
+ mdelay(1);
+ WREG32(mmCP_RB2_CNTL, tmp);
+ WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
+ }
+
/* start the rings */
gfx_v6_0_cp_gfx_start(adev);
- r = amdgpu_ring_test_helper(ring);
+
+ /* Wait for the initial packets to finish, run gfx ring test */
+ r = amdgpu_ring_test_helper(&adev->gfx.gfx_ring[0]);
if (r)
return r;
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
+ return r;
+ }
+
return 0;
}
@@ -2225,66 +2294,6 @@ static void gfx_v6_0_ring_set_wptr_compute(struct amdgpu_ring *ring)
}
-static int gfx_v6_0_cp_compute_resume(struct amdgpu_device *adev)
-{
- struct amdgpu_ring *ring;
- u32 tmp;
- u32 rb_bufsz;
- int i, r;
- u64 rptr_addr;
-
- /* ring1 - compute only */
- /* Set ring buffer size */
-
- ring = &adev->gfx.compute_ring[0];
- rb_bufsz = order_base_2(ring->ring_size / 8);
- tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
-#ifdef __BIG_ENDIAN
- tmp |= BUF_SWAP_32BIT;
-#endif
- WREG32(mmCP_RB1_CNTL, tmp);
-
- WREG32(mmCP_RB1_CNTL, tmp | CP_RB1_CNTL__RB_RPTR_WR_ENA_MASK);
- ring->wptr = 0;
- WREG32(mmCP_RB1_WPTR, ring->wptr);
-
- rptr_addr = ring->rptr_gpu_addr;
- WREG32(mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
- WREG32(mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
-
- mdelay(1);
- WREG32(mmCP_RB1_CNTL, tmp);
- WREG32(mmCP_RB1_BASE, ring->gpu_addr >> 8);
-
- ring = &adev->gfx.compute_ring[1];
- rb_bufsz = order_base_2(ring->ring_size / 8);
- tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
-#ifdef __BIG_ENDIAN
- tmp |= BUF_SWAP_32BIT;
-#endif
- WREG32(mmCP_RB2_CNTL, tmp);
-
- WREG32(mmCP_RB2_CNTL, tmp | CP_RB2_CNTL__RB_RPTR_WR_ENA_MASK);
- ring->wptr = 0;
- WREG32(mmCP_RB2_WPTR, ring->wptr);
- rptr_addr = ring->rptr_gpu_addr;
- WREG32(mmCP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
- WREG32(mmCP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
-
- mdelay(1);
- WREG32(mmCP_RB2_CNTL, tmp);
- WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
-
-
- for (i = 0; i < 2; i++) {
- r = amdgpu_ring_test_helper(&adev->gfx.compute_ring[i]);
- if (r)
- return r;
- }
-
- return 0;
-}
-
static void gfx_v6_0_cp_enable(struct amdgpu_device *adev, bool enable)
{
gfx_v6_0_cp_gfx_enable(adev, enable);
@@ -2334,9 +2343,6 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)
return r;
r = gfx_v6_0_cp_gfx_resume(adev);
- if (r)
- return r;
- r = gfx_v6_0_cp_compute_resume(adev);
if (r)
return r;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/11] drm/amdgpu/gfx6: Clean up rings during reset
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (3 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 04/11] drm/amdgpu/gfx6: Initialize compute rings before CP start Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 06/11] drm/amdgpu/gfx6: Execute CLEAR_STATE when initializing compute rings Timur Kristóf
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Clear the WPTR and RPTR at ring initialization.
Additionally clear the ring contents during reset.
This is necessary so that the IP block soft reset can
bring the rings back to a clean state.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 28 +++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index ca6a62e822b1..eeada89bb31a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -2158,8 +2158,14 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmSCRATCH_ADDR, 0);
/* ring 0 - compute and gfx */
- /* Set ring buffer size */
ring = &adev->gfx.gfx_ring[0];
+ atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
+ atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0);
+
+ if (amdgpu_in_reset(adev))
+ amdgpu_ring_clear_ring(ring);
+
+ /* Set ring buffer size */
rb_bufsz = order_base_2(ring->ring_size / 8);
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
@@ -2171,7 +2177,8 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
/* Initialize the ring buffer's read and write pointers */
WREG32(mmCP_RB0_CNTL, tmp | CP_RB0_CNTL__RB_RPTR_WR_ENA_MASK);
ring->wptr = 0;
- WREG32(mmCP_RB0_WPTR, ring->wptr);
+ WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr));
+ WREG32(mmCP_RB0_RPTR, lower_32_bits(ring->wptr));
/* set the wb address whether it's enabled or not */
rptr_addr = ring->rptr_gpu_addr;
@@ -2188,6 +2195,11 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
/* ring 1 - compute only */
if (adev->gfx.num_compute_rings >= 1) {
ring = &adev->gfx.compute_ring[0];
+ atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
+ atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0);
+
+ if (amdgpu_in_reset(adev))
+ amdgpu_ring_clear_ring(ring);
rb_bufsz = order_base_2(ring->ring_size / 8);
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
@@ -2198,7 +2210,8 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB1_CNTL, tmp | CP_RB1_CNTL__RB_RPTR_WR_ENA_MASK);
ring->wptr = 0;
- WREG32(mmCP_RB1_WPTR, ring->wptr);
+ WREG32(mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
+ WREG32(mmCP_RB1_RPTR, lower_32_bits(ring->wptr));
rptr_addr = ring->rptr_gpu_addr;
WREG32(mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
@@ -2212,6 +2225,11 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
/* ring 2 - compute only */
if (adev->gfx.num_compute_rings >= 2) {
ring = &adev->gfx.compute_ring[1];
+ atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
+ atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0);
+
+ if (amdgpu_in_reset(adev))
+ amdgpu_ring_clear_ring(ring);
rb_bufsz = order_base_2(ring->ring_size / 8);
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
@@ -2222,7 +2240,9 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB2_CNTL, tmp | CP_RB2_CNTL__RB_RPTR_WR_ENA_MASK);
ring->wptr = 0;
- WREG32(mmCP_RB2_WPTR, ring->wptr);
+ WREG32(mmCP_RB2_WPTR, lower_32_bits(ring->wptr));
+ WREG32(mmCP_RB2_RPTR, lower_32_bits(ring->wptr));
+
rptr_addr = ring->rptr_gpu_addr;
WREG32(mmCP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
WREG32(mmCP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/11] drm/amdgpu/gfx6: Execute CLEAR_STATE when initializing compute rings
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (4 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 05/11] drm/amdgpu/gfx6: Clean up rings during reset Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts Timur Kristóf
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Emit a compute CLEAR_STATE packet on the compute rings after
the GFX ring already finished executing ME_INITIALIZE and
before the ring test, so that gfx_v6_0_cp_gfx_resume() can
wait until the CLEAR_STATE is complete.
For reference, see si_cp_start() in the old radeon driver.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index eeada89bb31a..5b570a4b5c01 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -2263,6 +2263,14 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
+ r = amdgpu_ring_alloc(ring, 2);
+ if (r)
+ return r;
+
+ amdgpu_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0));
+ amdgpu_ring_write(ring, 0);
+ amdgpu_ring_commit(ring);
+
r = amdgpu_ring_test_helper(ring);
if (r)
return r;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (5 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 06/11] drm/amdgpu/gfx6: Execute CLEAR_STATE when initializing compute rings Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-15 10:19 ` Tvrtko Ursulin
2026-07-13 13:07 ` [PATCH 08/11] drm/amdgpu/gfx6: Adjust how harvested TCCs are set up Timur Kristóf
` (3 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
These were used without ever calling get()/put() on them.
Implement it like on GFX7-8:
* Call amdgpu_irq_get() from gfx_v6_0_late_init()
* Call amdgpu_irq_put() from gfx_v6_0_hw_fini()
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 5b570a4b5c01..1c7cd265fbca 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -3131,6 +3131,22 @@ static int gfx_v6_0_early_init(struct amdgpu_ip_block *ip_block)
return 0;
}
+static int gfx_v6_0_late_init(struct amdgpu_ip_block *ip_block)
+{
+ struct amdgpu_device *adev = ip_block->adev;
+ int r;
+
+ r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
+ if (r)
+ return r;
+
+ r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
+ if (r)
+ return r;
+
+ return 0;
+}
+
static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_ring *ring;
@@ -3243,6 +3259,8 @@ static int gfx_v6_0_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
+ amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
+ amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
gfx_v6_0_cp_enable(adev, false);
adev->gfx.rlc.funcs->stop(adev);
gfx_v6_0_fini_pg(adev);
@@ -3532,6 +3550,7 @@ static void gfx_v6_0_emit_mem_sync(struct amdgpu_ring *ring)
static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
.name = "gfx_v6_0",
.early_init = gfx_v6_0_early_init,
+ .late_init = gfx_v6_0_late_init,
.sw_init = gfx_v6_0_sw_init,
.sw_fini = gfx_v6_0_sw_fini,
.hw_init = gfx_v6_0_hw_init,
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/11] drm/amdgpu/gfx6: Adjust how harvested TCCs are set up
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (6 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 09/11] drm/amdgpu/gfx6: Use COND_EXEC Timur Kristóf
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Adjust gfx_v6_0_setup_tcc() to keep it working after
a GFX IP block soft reset. On a soft reset, the
TCP_CHAN_STEER_LO/HI registers are not cleared so
the function needs a slight adjustment to how the
number of active TCCs are calculated.
Additionally, let's expose the disabled TCC mask
in the tcc_disabled_mask field, like on other GPUs.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 1c7cd265fbca..3e0cd46cd091 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1596,7 +1596,7 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)
*/
static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
{
- u32 i, tcc, tcp_addr_config, num_active_tcc = 0;
+ u32 i, tcc, tcp_addr_config, num_active_tcc = 0, num_max_active_tcc;
u64 chan_steer, patched_chan_steer = 0;
const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches;
const u32 dis_tcc_mask =
@@ -1610,6 +1610,8 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
if (!dis_tcc_mask)
return;
+ num_max_active_tcc = num_max_tcc - hweight32(dis_tcc_mask);
+
/* Each 4-bit nibble contains the index of a TCC used by all TCPs */
chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull);
@@ -1622,9 +1624,12 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc);
++num_active_tcc;
}
+
+ if (num_active_tcc == num_max_active_tcc)
+ break;
}
- WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask));
+ WARN_ON(num_active_tcc != num_max_active_tcc);
/* Patch number of TCCs used by TCPs */
tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG),
@@ -1634,6 +1639,8 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config);
WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer));
WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer));
+
+ adev->gfx.config.tcc_disabled_mask = dis_tcc_mask;
}
static void gfx_v6_0_config_init(struct amdgpu_device *adev)
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/11] drm/amdgpu/gfx6: Use COND_EXEC
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (7 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 08/11] drm/amdgpu/gfx6: Adjust how harvested TCCs are set up Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 10/11] drm/amdgpu/gfx6: Add IP block soft reset implementation Timur Kristóf
2026-07-13 13:07 ` [PATCH 11/11] drm/amdgpu/gfx6: Enable IP block soft reset as a GPU recovery method Timur Kristóf
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
COND_EXEC tells the CP to discard the dwords following it
when its condition is zero (false).
This is useful for GPU recovery because it can help reduce
collateral damage during GFX IP block soft reset, meaning
that it reduces the likelyhood that we fail some jobs which
are not guilty of the hang as the IP block soft reset
mechanism clears the condition before doing the reset.
Note that this packet is only 4 DW on GFX6 (as opposed
to GFX7 and newer where it's 5 DW).
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 3e0cd46cd091..7f7b81c3919a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -2423,6 +2423,24 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, 0x20); /* poll interval */
}
+static unsigned int gfx_v6_0_ring_emit_init_cond_exec(struct amdgpu_ring *ring,
+ uint64_t gpu_addr)
+{
+ unsigned int ret;
+
+ /*
+ * Discard following DWs after this packet when gpu_addr==0
+ * The packet is only 4 DW on GFX6 (as opposed to GFX7+).
+ */
+ amdgpu_ring_write(ring, PACKET3(PACKET3_COND_EXEC, 2));
+ amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
+ ret = ring->wptr & ring->buf_mask;
+ /* patch dummy value later */
+ amdgpu_ring_write(ring, 0);
+ return ret;
+}
+
static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val)
{
@@ -3579,6 +3597,8 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
.get_wptr = gfx_v6_0_ring_get_wptr,
.set_wptr = gfx_v6_0_ring_set_wptr_gfx,
.emit_frame_size =
+ 4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
+ 4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
5 + 5 + /* hdp flush / invalidate */
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
@@ -3596,6 +3616,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
.insert_nop = amdgpu_ring_insert_nop,
.emit_switch_buffer = gfx_v6_0_ring_emit_sb,
.emit_cntxcntl = gfx_v6_ring_emit_cntxcntl,
+ .init_cond_exec = gfx_v6_0_ring_emit_init_cond_exec,
.emit_wreg = gfx_v6_0_ring_emit_wreg,
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
};
@@ -3608,6 +3629,8 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
.get_wptr = gfx_v6_0_ring_get_wptr,
.set_wptr = gfx_v6_0_ring_set_wptr_compute,
.emit_frame_size =
+ 4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
+ 4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
5 + 5 + /* hdp flush / invalidate */
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v6_0_ring_emit_vm_flush */
@@ -3623,6 +3646,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
.test_ib = gfx_v6_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
.emit_switch_buffer = gfx_v6_0_ring_emit_sb,
+ .init_cond_exec = gfx_v6_0_ring_emit_init_cond_exec,
.emit_wreg = gfx_v6_0_ring_emit_wreg,
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
};
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/11] drm/amdgpu/gfx6: Add IP block soft reset implementation
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (8 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 09/11] drm/amdgpu/gfx6: Use COND_EXEC Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
2026-07-13 13:07 ` [PATCH 11/11] drm/amdgpu/gfx6: Enable IP block soft reset as a GPU recovery method Timur Kristóf
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Update the register definition for GRBM_SOFT_RESET
to match what was in the old radeon driver and use
these bits in the soft reset implementation.
Use basically the same implementation as GFX8,
except GFX6 doesn't have MQD/HQD.
Reset every block using the GRBM, then proceed
to reset the GRBM and SEM blocks using the SRBM.
The soft reset also calls the clock and powergating
functions of the IP block. This is necessary for
correct operation, otherwise the GPU might fall
off the PCIe bus.
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 94 +++++++++++++++++++
.../include/asic_reg/gca/gfx_6_0_sh_mask.h | 32 +++++--
2 files changed, 118 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 7f7b81c3919a..a033da5fc307 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -3326,6 +3326,99 @@ static int gfx_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
+static int gfx_v6_0_soft_reset(struct amdgpu_ip_block *ip_block)
+{
+ struct amdgpu_device *adev = ip_block->adev;
+ u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+ u32 tmp;
+ int r;
+
+ grbm_soft_reset =
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CB, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_DB, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GDS, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_PA, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SC, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_BCI, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SPI, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SX, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_TC, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_TA, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_VGT, 1) |
+ REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_IA, 1);
+
+ srbm_soft_reset =
+ REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) |
+ REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
+
+ ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE);
+ ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE);
+ ip_block->version->funcs->suspend(ip_block);
+
+ if (grbm_soft_reset || srbm_soft_reset) {
+ tmp = RREG32(mmGMCON_DEBUG);
+ tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1);
+ tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1);
+ WREG32(mmGMCON_DEBUG, tmp);
+
+ udelay(100);
+ }
+
+ if (grbm_soft_reset) {
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+ tmp |= grbm_soft_reset;
+ dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmGRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+
+ udelay(100);
+
+ tmp &= ~grbm_soft_reset;
+ WREG32(mmGRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+
+ udelay(100);
+ }
+
+ if (srbm_soft_reset) {
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(100);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(100);
+ }
+
+ if (grbm_soft_reset || srbm_soft_reset) {
+ tmp = RREG32(mmGMCON_DEBUG);
+ tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0);
+ tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0);
+ WREG32(mmGMCON_DEBUG, tmp);
+ }
+
+ /* Wait a little for things to settle down */
+ udelay(100);
+
+ r = ip_block->version->funcs->resume(ip_block);
+ r |= ip_block->version->funcs->late_init(ip_block);
+ if (r)
+ return r;
+
+ ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE);
+ ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE);
+
+ return 0;
+}
+
static void gfx_v6_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
enum amdgpu_interrupt_state state)
{
@@ -3584,6 +3677,7 @@ static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
.resume = gfx_v6_0_resume,
.is_idle = gfx_v6_0_is_idle,
.wait_for_idle = gfx_v6_0_wait_for_idle,
+ .soft_reset = gfx_v6_0_soft_reset,
.set_clockgating_state = gfx_v6_0_set_clockgating_state,
.set_powergating_state = gfx_v6_0_set_powergating_state,
};
diff --git a/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_6_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_6_0_sh_mask.h
index b5e634749665..0434fc2ba710 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_6_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/gca/gfx_6_0_sh_mask.h
@@ -4877,18 +4877,34 @@
#define GRBM_SKEW_CNTL__SKEW_COUNT__SHIFT 0x00000006
#define GRBM_SKEW_CNTL__SKEW_TOP_THRESHOLD_MASK 0x0000003fL
#define GRBM_SKEW_CNTL__SKEW_TOP_THRESHOLD__SHIFT 0x00000000
-#define GRBM_SOFT_RESET__SOFT_RESET_CPC_MASK 0x00040000L
-#define GRBM_SOFT_RESET__SOFT_RESET_CPC__SHIFT 0x00000012
-#define GRBM_SOFT_RESET__SOFT_RESET_CPF_MASK 0x00020000L
-#define GRBM_SOFT_RESET__SOFT_RESET_CPF__SHIFT 0x00000011
-#define GRBM_SOFT_RESET__SOFT_RESET_CPG_MASK 0x00080000L
-#define GRBM_SOFT_RESET__SOFT_RESET_CPG__SHIFT 0x00000013
#define GRBM_SOFT_RESET__SOFT_RESET_CP_MASK 0x00000001L
#define GRBM_SOFT_RESET__SOFT_RESET_CP__SHIFT 0x00000000
-#define GRBM_SOFT_RESET__SOFT_RESET_GFX_MASK 0x00010000L
-#define GRBM_SOFT_RESET__SOFT_RESET_GFX__SHIFT 0x00000010
+#define GRBM_SOFT_RESET__SOFT_RESET_CB_MASK 0x00000002L
+#define GRBM_SOFT_RESET__SOFT_RESET_CB__SHIFT 0x00000001
#define GRBM_SOFT_RESET__SOFT_RESET_RLC_MASK 0x00000004L
#define GRBM_SOFT_RESET__SOFT_RESET_RLC__SHIFT 0x00000002
+#define GRBM_SOFT_RESET__SOFT_RESET_DB_MASK 0x00000008L
+#define GRBM_SOFT_RESET__SOFT_RESET_DB__SHIFT 0x00000003
+#define GRBM_SOFT_RESET__SOFT_RESET_GDS_MASK 0x00000010L
+#define GRBM_SOFT_RESET__SOFT_RESET_GDS__SHIFT 0x00000004
+#define GRBM_SOFT_RESET__SOFT_RESET_PA_MASK 0x00000020L
+#define GRBM_SOFT_RESET__SOFT_RESET_PA__SHIFT 0x00000005
+#define GRBM_SOFT_RESET__SOFT_RESET_SC_MASK 0x00000040L
+#define GRBM_SOFT_RESET__SOFT_RESET_SC__SHIFT 0x00000006
+#define GRBM_SOFT_RESET__SOFT_RESET_BCI_MASK 0x00000080L
+#define GRBM_SOFT_RESET__SOFT_RESET_BCI__SHIFT 0x00000007
+#define GRBM_SOFT_RESET__SOFT_RESET_SPI_MASK 0x00000100L
+#define GRBM_SOFT_RESET__SOFT_RESET_SPI__SHIFT 0x00000008
+#define GRBM_SOFT_RESET__SOFT_RESET_SX_MASK 0x00000400L
+#define GRBM_SOFT_RESET__SOFT_RESET_SX__SHIFT 0x0000000a
+#define GRBM_SOFT_RESET__SOFT_RESET_TC_MASK 0x00000800L
+#define GRBM_SOFT_RESET__SOFT_RESET_TC__SHIFT 0x0000000b
+#define GRBM_SOFT_RESET__SOFT_RESET_TA_MASK 0x00001000L
+#define GRBM_SOFT_RESET__SOFT_RESET_TA__SHIFT 0x0000000c
+#define GRBM_SOFT_RESET__SOFT_RESET_VGT_MASK 0x00004000L
+#define GRBM_SOFT_RESET__SOFT_RESET_VGT__SHIFT 0x0000000e
+#define GRBM_SOFT_RESET__SOFT_RESET_IA_MASK 0x00008000L
+#define GRBM_SOFT_RESET__SOFT_RESET_IA__SHIFT 0x0000000f
#define GRBM_STATUS2__CPC_BUSY_MASK 0x20000000L
#define GRBM_STATUS2__CPC_BUSY__SHIFT 0x0000001d
#define GRBM_STATUS2__CPF_BUSY_MASK 0x10000000L
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 11/11] drm/amdgpu/gfx6: Enable IP block soft reset as a GPU recovery method
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
` (9 preceding siblings ...)
2026-07-13 13:07 ` [PATCH 10/11] drm/amdgpu/gfx6: Add IP block soft reset implementation Timur Kristóf
@ 2026-07-13 13:07 ` Timur Kristóf
10 siblings, 0 replies; 15+ messages in thread
From: Timur Kristóf @ 2026-07-13 13:07 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig, Tvrtko Ursulin,
pierre-eric.pelloux-prayer, Natalie Vock
Cc: Timur Kristóf
Enable IP block soft reset as a GPU recovery method for GFX6
graphics and compute rings.
This improves current user experience on all GFX6 chips.
The current GPU recovery method is a legacy ASIC reset which
always clears the contents of VRAM, which means that a buggy
(hanging) app can crash the whole graphical session, which
is less than ideal. Also on some GPUs the ASIC reset causes
the GPU to fall off the PCIe bus so it's not desireable.
Using GFX IP block soft reset means that we can now
move on from GFX hangs on GFX6 dGPUs without crashing the
whole system.
Tested with the "hard_reset_cp_wait" test case from the
Hang Test Suite created by Natalie Vock and Konstantin Seurer.
This Vulkan testcase waits for an event that never occurs,
effectively a WAIT_REG_MEM packet that intentionally hangs.
IP block soft reset can resolve that hang and allow
the rest of the system to move on and keep functioning
without needing a full ASIC reset.
Tested on the following chips:
Tahiti (FirePro W9000, Radeon HD 7870 XT)
Cape Verde (Radeon R7 450)
Pitcairn (Radeon R9 270X)
Oland (Radeon 430)
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
---
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index a033da5fc307..f24129b54408 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -3242,6 +3242,11 @@ static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
adev->gfx.compute_supported_reset =
amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]);
+ if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) {
+ adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
+ adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
+ }
+
return r;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts
2026-07-13 13:07 ` [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts Timur Kristóf
@ 2026-07-15 10:19 ` Tvrtko Ursulin
2026-07-15 10:53 ` Timur Kristóf
0 siblings, 1 reply; 15+ messages in thread
From: Tvrtko Ursulin @ 2026-07-15 10:19 UTC (permalink / raw)
To: Timur Kristóf, amd-gfx, Alex Deucher, christian.koenig,
pierre-eric.pelloux-prayer, Natalie Vock
On 13/07/2026 14:07, Timur Kristóf wrote:
> These were used without ever calling get()/put() on them.
> Implement it like on GFX7-8:
Used as in how? Are they even enabled without this change and if not
then does this patch fixes something other than being prep work for soft
reset?
Regards,
Tvrtko
> * Call amdgpu_irq_get() from gfx_v6_0_late_init()
> * Call amdgpu_irq_put() from gfx_v6_0_hw_fini()
>
> Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
> ---
> drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> index 5b570a4b5c01..1c7cd265fbca 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> @@ -3131,6 +3131,22 @@ static int gfx_v6_0_early_init(struct amdgpu_ip_block *ip_block)
> return 0;
> }
>
> +static int gfx_v6_0_late_init(struct amdgpu_ip_block *ip_block)
> +{
> + struct amdgpu_device *adev = ip_block->adev;
> + int r;
> +
> + r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
> + if (r)
> + return r;
> +
> + r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
> + if (r)
> + return r;
> +
> + return 0;
> +}
> +
> static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
> {
> struct amdgpu_ring *ring;
> @@ -3243,6 +3259,8 @@ static int gfx_v6_0_hw_fini(struct amdgpu_ip_block *ip_block)
> {
> struct amdgpu_device *adev = ip_block->adev;
>
> + amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
> + amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
> gfx_v6_0_cp_enable(adev, false);
> adev->gfx.rlc.funcs->stop(adev);
> gfx_v6_0_fini_pg(adev);
> @@ -3532,6 +3550,7 @@ static void gfx_v6_0_emit_mem_sync(struct amdgpu_ring *ring)
> static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
> .name = "gfx_v6_0",
> .early_init = gfx_v6_0_early_init,
> + .late_init = gfx_v6_0_late_init,
> .sw_init = gfx_v6_0_sw_init,
> .sw_fini = gfx_v6_0_sw_fini,
> .hw_init = gfx_v6_0_hw_init,
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts
2026-07-15 10:19 ` Tvrtko Ursulin
@ 2026-07-15 10:53 ` Timur Kristóf
2026-07-15 11:22 ` Tvrtko Ursulin
0 siblings, 1 reply; 15+ messages in thread
From: Timur Kristóf @ 2026-07-15 10:53 UTC (permalink / raw)
To: amd-gfx, Alex Deucher, christian.koenig,
pierre-eric.pelloux-prayer, Natalie Vock, Tvrtko Ursulin
On 2026. július 15., szerda 12:19:40 közép-európai nyári idő Tvrtko Ursulin
wrote:
> On 13/07/2026 14:07, Timur Kristóf wrote:
> > These were used without ever calling get()/put() on them.
>
> > Implement it like on GFX7-8:
> Used as in how? Are they even enabled without this change and if not
> then does this patch fixes something other than being prep work for soft
> reset?
If you open gfx_v6_0.c and search for priv_reg or priv_inst, you can see that
the interrupts are used in the same manner as gfx7 and newer, but without
get() and put().
>
> > * Call amdgpu_irq_get() from gfx_v6_0_late_init()
> > * Call amdgpu_irq_put() from gfx_v6_0_hw_fini()
> >
> > Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
> > ---
> >
> > drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 19 +++++++++++++++++++
> > 1 file changed, 19 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> > b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 5b570a4b5c01..1c7cd265fbca
> > 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
> > @@ -3131,6 +3131,22 @@ static int gfx_v6_0_early_init(struct
> > amdgpu_ip_block *ip_block)>
> > return 0;
> >
> > }
> >
> > +static int gfx_v6_0_late_init(struct amdgpu_ip_block *ip_block)
> > +{
> > + struct amdgpu_device *adev = ip_block->adev;
> > + int r;
> > +
> > + r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
> > + if (r)
> > + return r;
> > +
> > + r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
> > + if (r)
> > + return r;
> > +
> > + return 0;
> > +}
> > +
> >
> > static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
> > {
> >
> > struct amdgpu_ring *ring;
> >
> > @@ -3243,6 +3259,8 @@ static int gfx_v6_0_hw_fini(struct amdgpu_ip_block
> > *ip_block)>
> > {
> >
> > struct amdgpu_device *adev = ip_block->adev;
> >
> > + amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
> > + amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
> >
> > gfx_v6_0_cp_enable(adev, false);
> > adev->gfx.rlc.funcs->stop(adev);
> > gfx_v6_0_fini_pg(adev);
> >
> > @@ -3532,6 +3550,7 @@ static void gfx_v6_0_emit_mem_sync(struct
> > amdgpu_ring *ring)>
> > static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
> >
> > .name = "gfx_v6_0",
> > .early_init = gfx_v6_0_early_init,
> >
> > + .late_init = gfx_v6_0_late_init,
> >
> > .sw_init = gfx_v6_0_sw_init,
> > .sw_fini = gfx_v6_0_sw_fini,
> > .hw_init = gfx_v6_0_hw_init,
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts
2026-07-15 10:53 ` Timur Kristóf
@ 2026-07-15 11:22 ` Tvrtko Ursulin
0 siblings, 0 replies; 15+ messages in thread
From: Tvrtko Ursulin @ 2026-07-15 11:22 UTC (permalink / raw)
To: Timur Kristóf, amd-gfx, Alex Deucher, christian.koenig,
pierre-eric.pelloux-prayer, Natalie Vock
On 15/07/2026 11:53, Timur Kristóf wrote:
> On 2026. július 15., szerda 12:19:40 közép-európai nyári idő Tvrtko Ursulin
> wrote:
>> On 13/07/2026 14:07, Timur Kristóf wrote:
>>> These were used without ever calling get()/put() on them.
>>
>>> Implement it like on GFX7-8:
>> Used as in how? Are they even enabled without this change and if not
>> then does this patch fixes something other than being prep work for soft
>> reset?
>
> If you open gfx_v6_0.c and search for priv_reg or priv_inst, you can see that
> the interrupts are used in the same manner as gfx7 and newer, but without
> get() and put().
Yes, they are used in code. Are they used in reality was my question. :)
I ask because it appears that without amdgpu_irq_get() they may not even
get enabled so never received. Yes or no? Consequences if yes?
Regards,
Tvrtko
>>
>>> * Call amdgpu_irq_get() from gfx_v6_0_late_init()
>>> * Call amdgpu_irq_put() from gfx_v6_0_hw_fini()
>>>
>>> Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
>>> ---
>>>
>>> drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 19 +++++++++++++++++++
>>> 1 file changed, 19 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
>>> b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 5b570a4b5c01..1c7cd265fbca
>>> 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
>>> @@ -3131,6 +3131,22 @@ static int gfx_v6_0_early_init(struct
>>> amdgpu_ip_block *ip_block)>
>>> return 0;
>>>
>>> }
>>>
>>> +static int gfx_v6_0_late_init(struct amdgpu_ip_block *ip_block)
>>> +{
>>> + struct amdgpu_device *adev = ip_block->adev;
>>> + int r;
>>> +
>>> + r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
>>> + if (r)
>>> + return r;
>>> +
>>> + r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
>>> + if (r)
>>> + return r;
>>> +
>>> + return 0;
>>> +}
>>> +
>>>
>>> static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
>>> {
>>>
>>> struct amdgpu_ring *ring;
>>>
>>> @@ -3243,6 +3259,8 @@ static int gfx_v6_0_hw_fini(struct amdgpu_ip_block
>>> *ip_block)>
>>> {
>>>
>>> struct amdgpu_device *adev = ip_block->adev;
>>>
>>> + amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
>>> + amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
>>>
>>> gfx_v6_0_cp_enable(adev, false);
>>> adev->gfx.rlc.funcs->stop(adev);
>>> gfx_v6_0_fini_pg(adev);
>>>
>>> @@ -3532,6 +3550,7 @@ static void gfx_v6_0_emit_mem_sync(struct
>>> amdgpu_ring *ring)>
>>> static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
>>>
>>> .name = "gfx_v6_0",
>>> .early_init = gfx_v6_0_early_init,
>>>
>>> + .late_init = gfx_v6_0_late_init,
>>>
>>> .sw_init = gfx_v6_0_sw_init,
>>> .sw_fini = gfx_v6_0_sw_fini,
>>> .hw_init = gfx_v6_0_hw_init,
>
>
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-07-15 11:22 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 13:06 [PATCH 00/11] drm/amdgpu/gfx6: Use GFX IP block soft reset on GFX6 Timur Kristóf
2026-07-13 13:06 ` [PATCH 01/11] drm/amdgpu/gfx6: Improve emit_cntxcntl() Timur Kristóf
2026-07-13 13:07 ` [PATCH 02/11] drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets Timur Kristóf
2026-07-13 13:07 ` [PATCH 03/11] drm/amdgpu/gfx6: Use PFP on the compute queues too Timur Kristóf
2026-07-13 13:07 ` [PATCH 04/11] drm/amdgpu/gfx6: Initialize compute rings before CP start Timur Kristóf
2026-07-13 13:07 ` [PATCH 05/11] drm/amdgpu/gfx6: Clean up rings during reset Timur Kristóf
2026-07-13 13:07 ` [PATCH 06/11] drm/amdgpu/gfx6: Execute CLEAR_STATE when initializing compute rings Timur Kristóf
2026-07-13 13:07 ` [PATCH 07/11] drm/amdgpu/gfx6: Properly enable/disable priv_req and priv_inst interrupts Timur Kristóf
2026-07-15 10:19 ` Tvrtko Ursulin
2026-07-15 10:53 ` Timur Kristóf
2026-07-15 11:22 ` Tvrtko Ursulin
2026-07-13 13:07 ` [PATCH 08/11] drm/amdgpu/gfx6: Adjust how harvested TCCs are set up Timur Kristóf
2026-07-13 13:07 ` [PATCH 09/11] drm/amdgpu/gfx6: Use COND_EXEC Timur Kristóf
2026-07-13 13:07 ` [PATCH 10/11] drm/amdgpu/gfx6: Add IP block soft reset implementation Timur Kristóf
2026-07-13 13:07 ` [PATCH 11/11] drm/amdgpu/gfx6: Enable IP block soft reset as a GPU recovery method Timur Kristóf
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.