Add SET_L2_TRAP and CLEAR_L2_TRAP operations to the VM ioctl. The second-level trap handler is set per GPUVM. All shader waves using the same GPUVM use the same second-level trap handler, regardless of the queue type.
SET_L2_TRAP sets the userspace TBA and TMA addresses for the GPUVM. The kernel checks that both address ranges are mapped in the GPUVM before using them. CLEAR_L2_TRAP clears the second-level TBA and TMA addresses from the first-level trap descriptor. Userspace must keep the TBA and TMA mappings valid after SET_L2_TRAP. The mappings can be removed after CLEAR_L2_TRAP completes successfully. Suggested-by: Christian König <[email protected]> Suggested-by: Alex Deucher <[email protected]> Cc: Felix Kuehling <[email protected]> Cc: Lancelot Six <[email protected]> Cc: James Zhu <[email protected]> Cc: Lijo Lazar <[email protected]> Cc: Samuel Pitoiset <[email protected]> Cc: Natalie Vock <[email protected]> Cc: Timur Kristóf <[email protected]> Cc: Pierre-Eric Pelloux-Prayer <[email protected]> Signed-off-by: Srinivasan Shanmugam <[email protected]> --- Changes in v3: - Remove the old TRAP UAPI cleanup from this patch because it is now done completely in patch 1. - Remove the explicit user queue evict/restore flow from SET/CLEAR. - Use the existing GPUVM fence and VM root synchronization. - Validate reserved VM ioctl input fields. - Require unused L2 trap input fields to be zero for CLEAR. - Document that userspace must keep the TBA and TMA mappings valid until CLEAR_L2_TRAP completes successfully. drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 29 ++++++++++++ include/uapi/drm/amdgpu_drm.h | 65 ++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index fe1289abb56c..3c551fe8c9fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2917,6 +2917,13 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (args->in.flags) return -EINVAL; + if (args->in.op == AMDGPU_VM_OP_SET_L2_TRAP) { + if (args->in.l2trap._pad || args->in.l2trap._pad2) + return -EINVAL; + } else if (memchr_inv(args->in._pad, 0, sizeof(args->in._pad))) { + return -EINVAL; + } + switch (args->in.op) { case AMDGPU_VM_OP_RESERVE_VMID: /* We only have requirement to reserve vmid from gfxhub */ @@ -2924,6 +2931,28 @@ 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 using this GPUVM regardless of + * queue type. + */ + if (!vm->trap_obj) + return -EOPNOTSUPP; + + return amdgpu_trap_vm_set_l2_trap(adev, vm, + 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. */ + if (!vm->trap_obj) + return -EOPNOTSUPP; + + return amdgpu_trap_vm_clear_l2_trap(adev, vm, + vm->trap_obj); default: return -EINVAL; } diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 86f957d07f4c..020edbbb01d6 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -644,10 +644,75 @@ 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 this GPUVM. + * + * The second-level trap handler is a per-GPUVM setting. All shader waves + * using this GPUVM use the same handler regardless of queue type. + * + * TBA is the GPU virtual address of the second-level trap handler code. + * TMA is the GPU virtual address of the second-level trap handler scratch + * memory. Both ranges must be non-empty and fully mapped in this GPUVM. + * + * This operation may block until outstanding GPUVM work completes. + * + * Userspace must keep the TBA and TMA mappings valid while the second-level + * trap handler is installed. + * + * Returns: + * 0 on success; + * -EOPNOTSUPP if the first-level CWSR handler is unavailable; + * -EINVAL if TBA/TMA is invalid or not mapped in this GPUVM; + * -ETIMEDOUT if outstanding GPUVM work does not complete; + * negative errno if the GPUVM reservation fails. + */ +#define AMDGPU_VM_OP_SET_L2_TRAP 3 + +/** + * AMDGPU_VM_OP_CLEAR_L2_TRAP - disable the second-level trap handler. + * + * This operation may block until outstanding GPUVM work completes. + * + * The l2trap input members must be zero for this operation. + * + * After this operation succeeds, userspace may remove the second-level + * TBA and TMA mappings. + * + * Returns: + * 0 on success; + * -EOPNOTSUPP if the first-level CWSR handler is unavailable; + * -EINVAL if the GPUVM trap state is invalid; + * -ETIMEDOUT if outstanding GPUVM work does not complete; + * negative errno if the GPUVM 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 { -- 2.34.1
