On 02-Sep-26 8:36 PM, Srinivasan Shanmugam wrote:
MES owns kernel queue VMIDs (1..first_kfd_vmid-1) but does not program
SQ_SHADER_TBA/TMA registers for them. Add infrastructure to let the
driver program the first-level CWSR trap handler for these VMIDs directly
via SRBM select.
Add kq_tma_bo — a pinned GTT BO used as device-level TMA scratch for
kernel queue VMIDs. Unlike per-process TMA (created in amdgpu_trap_alloc),
this is device-level and lives for the lifetime of the device. It is
zero-initialized by the OS: the second-level handler address is 0 until
userspace calls SET_L2_TRAP.
Add amdgpu_trap_program_kernel_vmids() which dispatches to a per-HW
vmhub callback, and a new program_kernel_trap_vmids hook in
amdgpu_vmhub_funcs for per-GFX-generation register writes.
Required for:
- RADV graphics debugging on Vega/Navi/Steam Deck (Valve request)
- Consistent trap handler behavior when switching between kernel
queues and user queues
Suggested-by: Christian König <[email protected]>
Cc: Alexander Deucher <[email protected]>
Signed-off-by: Srinivasan Shanmugam <[email protected]>
Change-Id: I0709e788835b69d3d492864de8d5c2d36d0f08c8
---
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c | 37 ++++++++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h | 2 ++
3 files changed, 40 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
index 3ca187f5ade8..5624a5ab5c62 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
@@ -115,6 +115,7 @@ struct amdgpu_vmhub_funcs {
void (*print_l2_protection_fault_status)(struct amdgpu_device *adev,
uint32_t status);
uint32_t (*get_invalidate_req)(unsigned int vmid, uint32_t flush_type);
+ void (*program_kernel_trap_vmids)(struct amdgpu_device *adev);
};
struct amdgpu_vmhub {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
index 31f653ec3fb1..0e0aeea0aa2d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
@@ -256,8 +256,23 @@ int amdgpu_trap_init(struct amdgpu_device *adev)
memcpy(ptr, trap_info->isa_buf, trap_info->isa_sz);
+ /*
+ * Device-level TMA for kernel queue VMIDs. Pinned GTT — not subject
+ * to eviction. Zero-initialized by OS: second-level handler address
+ * is 0 until userspace calls SET_L2_TRAP.
How is the exclusivity maintained as a user app doesn't 'own' kernel
queue? How is the conflict of different user apps trying to install
their own second level handler on a kernel queue handled?
Thanks,
Lijo
+ */
+ r = amdgpu_bo_create_kernel(adev, AMDGPU_TRAP_TMA_MAX_SIZE, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_GTT,
+ &trap_info->kq_tma_bo, NULL, NULL);
+ if (r) {
+ /* isa_bo freed explicitly; trap_info struct freed by __free */
+ amdgpu_bo_free_kernel(&trap_info->isa_bo, NULL, NULL);
+ return r;
+ }
+
amdgpu_trap_cwsr_init_save_area_info(adev, trap_info);
adev->trap_info = no_free_ptr(trap_info);
+ amdgpu_trap_program_kernel_vmids(adev);
return 0;
}
@@ -267,11 +282,33 @@ void amdgpu_trap_fini(struct amdgpu_device *adev)
if (!amdgpu_trap_is_enabled(adev))
return;
+ amdgpu_bo_free_kernel(&adev->trap_info->kq_tma_bo, NULL, NULL);
amdgpu_bo_free_kernel(&adev->trap_info->isa_bo, NULL, NULL);
kfree(adev->trap_info);
adev->trap_info = NULL;
}
+/**
+ * amdgpu_trap_program_kernel_vmids - program first-level trap handler for
+ * kernel queue VMIDs
+ * @adev: amdgpu device pointer
+ *
+ * Programs SQ_SHADER_TBA/TMA for kernel queue VMIDs (1..first_kfd_vmid-1)
+ * via SRBM select. MES owns these VMIDs but does not program trap handler
+ * state. Called after trap init and on GPU resume via setup_vmid_config.
+ */
+void amdgpu_trap_program_kernel_vmids(struct amdgpu_device *adev)
+{
+ struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_GFXHUB(0)];
+
+ if (!amdgpu_trap_is_enabled(adev))
+ return;
+ if (!hub->vmhub_funcs || !hub->vmhub_funcs->program_kernel_trap_vmids)
+ return;
+
+ hub->vmhub_funcs->program_kernel_trap_vmids(adev);
+}
+
/*
* amdgpu_map_cwsr_trap_handler should be called during amdgpu_vm_init
* it maps virtual address amdgpu_trap_tba_vaddr() to this VM, and each
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
index 6d4664469bad..326910f1d94d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.h
@@ -48,6 +48,7 @@ struct amdgpu_trap_obj {
struct amdgpu_trap_info {
/* cwsr isa */
struct amdgpu_bo *isa_bo;
+ struct amdgpu_bo *kq_tma_bo; /* pinned GTT, device-level TMA for
kernel queue VMIDs */
const void *isa_buf;
uint32_t isa_sz;
/* cwsr size info per XCC*/
@@ -70,6 +71,7 @@ struct amdgpu_trap_usr_addr {
};
int amdgpu_trap_init(struct amdgpu_device *adev);
+void amdgpu_trap_program_kernel_vmids(struct amdgpu_device *adev);
void amdgpu_trap_fini(struct amdgpu_device *adev);
int amdgpu_trap_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,