Add two new VM ioctl operations: AMDGPU_VM_OP_SET_L2_TRAP (op = 3) AMDGPU_VM_OP_CLEAR_L2_TRAP (op = 4)
The second-level trap handler is a per-VM setting. All shader waves executing under this VMID share the same handler regardless of queue type. GFX and compute queues from the same process share the same VMID so one SET_L2_TRAP covers all queue types for this DRM file. The TRAP ioctl and its associated structures are removed entirely; the ioctl number was never part of a released kernel. Both TBA and TMA buffers MUST be allocated with AMDGPU_GEM_CREATE_VM_ALWAYS_VALID. The GPU jumps to TBA automatically on a hardware exception without any software job submission. Signed-off-by: Srinivasan Shanmugam <[email protected]> Cc: Christian König <[email protected]> Cc: Alex Deucher <[email protected]> Cc: Felix Kuehling <[email protected]> Cc: Lijo Lazar <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 26 ++++++ include/uapi/drm/amdgpu_drm.h | 112 ++++++++++++++++++++----- 2 files changed, 118 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d981915ac2f4..562139dc23ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2911,6 +2911,32 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case AMDGPU_VM_OP_UNRESERVE_VMID: amdgpu_vmid_free_reserved(adev, vm, AMDGPU_GFXHUB(0)); break; + case AMDGPU_VM_OP_SET_L2_TRAP: + /* + * Install or replace the per-VM second-level trap handler. + * Applies to all shader waves under this VMID regardless of + * queue type. + */ + if (!vm->trap_obj) + return -EOPNOTSUPP; + return amdgpu_trap_vm_set_l2_trap(adev, vm, + &fpriv->userq_mgr, + vm->trap_obj, + args->in.l2trap.tba_va, + args->in.l2trap.tba_sz, + args->in.l2trap.tma_va, + args->in.l2trap.tma_sz); + case AMDGPU_VM_OP_CLEAR_L2_TRAP: + /* + * Disable the per-VM second-level trap handler. + * Waits for VM idle, evicts queues, flushes TLB, clears + * the handler descriptor. + */ + if (!vm->trap_obj) + return -EOPNOTSUPP; + return amdgpu_trap_vm_clear_l2_trap(adev, vm, + &fpriv->userq_mgr, + vm->trap_obj); default: return -EINVAL; } diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 4785cf48da17..24a08e4f0f36 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -632,10 +632,102 @@ struct drm_amdgpu_userq_wait { #define AMDGPU_VM_OP_RESERVE_VMID 1 #define AMDGPU_VM_OP_UNRESERVE_VMID 2 +/** + * AMDGPU_VM_OP_SET_L2_TRAP - install or replace the second-level trap + * handler for all GFX and compute queues belonging to this VM. + * + * The second-level trap handler is a per-VM setting. All shader waves + * executing under this VMID share the same handler regardless of queue + * type. GFX and compute queues from the same process share the same VMID + * so one SET_L2_TRAP covers all queue types for this DRM file. + * + * IMPORTANT: Both TBA and TMA buffers MUST be allocated with the + * AMDGPU_GEM_CREATE_VM_ALWAYS_VALID flag. The GPU jumps to TBA + * automatically on a hardware exception without any software job + * submission, so the kernel cannot track TBA/TMA in a job's used-buffer + * list. Without VM_ALWAYS_VALID the BO can be evicted and the page + * table entry becomes stale, causing a GPU page fault or memory + * corruption when the next shader exception fires. + * + * The TBA range must contain the handler executable code. + * The TMA range is the handler scratch memory buffer. + * Both ranges must be non-empty and fully mapped in the GPU virtual + * address space of this DRM file descriptor. + * + * For user queues, all active queues are evicted and the GPU TLB is + * flushed before the descriptor is written, then queues are restored. + * This prevents a trapping wave from observing a partially-written + * TBA/TMA pair during the update window. + * + * For kernel queues, the VM is drained via amdgpu_vm_wait_idle() before + * eviction and the descriptor write. This ensures no kernel-queue wave + * is active while TBA and TMA are being updated. + * + * Userspace should keep both mappings alive until + * AMDGPU_VM_OP_CLEAR_L2_TRAP succeeds. If either mapping is removed + * while the handler is active, the kernel waits for the VM to be idle, + * evicts all user queues, flushes the GPU TLB, clears the handler, and + * allows the unmap to proceed. UNMAP never returns an error for this + * condition. Queues whose trap handler VA was removed are not restarted. + * + * Returns: + * 0 on success; + * -EOPNOTSUPP if the first-level CWSR handler is unavailable; + * -EINVAL if TBA/TMA is invalid, not mapped, or not allocated + * with AMDGPU_GEM_CREATE_VM_ALWAYS_VALID; + * -ETIMEDOUT if the VM did not become idle within the wait timeout; + * negative errno if the VM reservation fails. + */ +#define AMDGPU_VM_OP_SET_L2_TRAP 3 + +/** + * AMDGPU_VM_OP_CLEAR_L2_TRAP - disable the second-level trap handler. + * + * For user queues, all active queues are evicted and the GPU TLB is + * flushed before TBA is zeroed to ensure no wave is executing inside + * the handler at the time of the clear. + * + * For kernel queues, the VM is drained via amdgpu_vm_wait_idle() before + * eviction and the clear. This ensures no kernel-queue wave is active + * while the descriptor is being zeroed. + * + * The l2trap input members are ignored for this operation. + * + * After this operation succeeds userspace may safely remove the TBA + * and TMA mappings. + * + * Returns: + * 0 on success; + * -EOPNOTSUPP if the first-level CWSR handler is unavailable; + * negative errno if the VM reservation fails. + */ +#define AMDGPU_VM_OP_CLEAR_L2_TRAP 4 + struct drm_amdgpu_vm_in { /** AMDGPU_VM_OP_* */ __u32 op; __u32 flags; + union { + struct { + /** GPU VA of second-level trap handler code buffer */ + __u64 tba_va; + /** TBA buffer size in bytes */ + __u32 tba_sz; + /** Explicit padding; tma_va starts at offset 24 */ + __u32 _pad; + /** GPU VA of second-level trap handler scratch buffer */ + __u64 tma_va; + /** TMA buffer size in bytes */ + __u32 tma_sz; + /** Padding to fix total union size at 32 bytes */ + __u32 _pad2; + } l2trap; + /** + * Padding; keeps the union at a fixed 32-byte size for + * future ops. Zero-initialise for RESERVE/UNRESERVE_VMID. + */ + __u64 _pad[4]; + }; }; struct drm_amdgpu_vm_out { @@ -1745,27 +1837,7 @@ struct drm_amdgpu_info_cwsr { __u32 min_save_area_size; }; -/* cwsr ioctl */ -#define AMDGPU_TRAP_OP_SET_L2_TRAP 1 - -struct drm_amdgpu_trap_in { - /* AMDGPU_TRAP_OP_* */ - __u32 op; - struct { - /* Level 2 trap handler base address */ - __u64 tba_va; - /* Level 2 trap handler buffer size (in bytes) */ - __u32 tba_sz; - /* Level 2 trap memory buffer address */ - __u64 tma_va; - /* Level 2 trap memory buffer size (in bytes) */ - __u32 tma_sz; - } l2trap; -}; -union drm_amdgpu_trap { - struct drm_amdgpu_trap_in in; -}; /* * Supported GPU families */ -- 2.34.1
