User queues already support a second-level trap handler registered via
AMDGPU_VM_OP_SET_L2_TRAP. Kernel queues had no equivalent because the
first-level TMA for kernel VMIDs was not writable by the driver.

Now that each VM has a per-VM kq_tma_bo mapped read-only at
AMDGPU_VA_RESERVED_TRAP_START (added in patch 1/3), the driver has a
CPU mapping (kq_tma_map) to write the second-level handler address into
it. The TMA layout mirrors the existing user queue TMA ABI:

  offset 0  (u64): second-level TBA virtual address
  offset 8  (u64): second-level TMA virtual address
  offset 16 (u64): debug flag

When userspace calls SET_L2_TRAP the driver writes both the per-process
user queue TMA (trap_obj->tma_map) and the per-VM kernel queue TMA
(vm->kq_tma_map). When CLEAR_L2_TRAP is called both are zeroed.

The evict -> TLB flush -> write -> restore sequence already used for
user queues covers kernel queues as well since both share the same VMID.
No additional synchronization is required.

After this patch RADV on GFX9/GFX10 hardware (which uses kernel queues
because user queues are not supported there) can install a second-level
trap handler for shader debugging via the same SET_L2_TRAP ioctl.

Suggested-by: Christian König <[email protected]>
Suggested-by: Alexander Deucher <[email protected]>
Cc: Lijo Lazar <[email protected]>
Cc: Timur Kristóf <[email protected]>
Cc: Samuel Pitoiset <[email protected]>
Cc: Natalie Vock <[email protected]>
Signed-off-by: Srinivasan Shanmugam <[email protected]>
Change-Id: Ie692cc9e6d8334f4124e3297f0520629140737ff
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c | 27 ++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
index e913488ca3fa..cf6dcbb903d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trap.c
@@ -717,6 +717,23 @@ int amdgpu_trap_vm_set_l2_trap(struct amdgpu_device *adev,
        iosys_map_wr(&trap_obj->tma_map,
                     AMDGPU_TRAP_L2_TBA_INDEX * sizeof(u64), u64, tba_va);
 
+       /*
+        * Mirror to the per-VM kernel queue TMA so that kernel queues
+        * get the same second-level handler. The kq_tma_map CPU mapping
+        * is valid for the lifetime of the VM; iosys_map_is_null guards
+        * against VMs where trap is disabled or kq_tma_alloc failed.
+        */
+       if (!iosys_map_is_null(&vm->kq_tma_map)) {
+               iosys_map_wr(&vm->kq_tma_map,
+                            AMDGPU_TRAP_L2_TBA_INDEX * sizeof(u64), u64, 0);
+               dma_wmb();
+               iosys_map_wr(&vm->kq_tma_map,
+                            AMDGPU_TRAP_L2_TMA_INDEX * sizeof(u64), u64, 
tma_va);
+               dma_wmb();
+               iosys_map_wr(&vm->kq_tma_map,
+                            AMDGPU_TRAP_L2_TBA_INDEX * sizeof(u64), u64, 
tba_va);
+       }
+
        trap_obj->l2_tba_addr = tba_va;
        trap_obj->l2_tba_size = tba_sz;
        trap_obj->l2_tma_addr = tma_va;
@@ -749,8 +766,18 @@ int amdgpu_trap_vm_clear_l2_trap(struct amdgpu_device 
*adev,
        amdgpu_trap_clear_l2_handler(vm, trap_obj);
        trap_obj->l2_trap_removed = false;
 
+       /* Clear kernel queue TMA as well */
+       if (!iosys_map_is_null(&vm->kq_tma_map)) {
+               iosys_map_wr(&vm->kq_tma_map,
+                            AMDGPU_TRAP_L2_TBA_INDEX * sizeof(u64), u64, 0);
+               dma_wmb();
+               iosys_map_wr(&vm->kq_tma_map,
+                            AMDGPU_TRAP_L2_TMA_INDEX * sizeof(u64), u64, 0);
+       }
+
        amdgpu_bo_unreserve(vm->root.bo);
        amdgpu_userq_restore_all(uq_mgr);
+
        return 0;
 }
 
-- 
2.34.1

Reply via email to