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

Reply via email to