]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amdgpu: prevent immediate PASID reuse case
authorEric Huang <jinhuieric.huang@amd.com>
Mon, 16 Mar 2026 15:01:30 +0000 (11:01 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 23 Mar 2026 18:48:06 +0000 (14:48 -0400)
PASID resue could cause interrupt issue when process
immediately runs into hw state left by previous
process exited with the same PASID, it's possible that
page faults are still pending in the IH ring buffer when
the process exits and frees up its PASID. To prevent the
case, it uses idr cyclic allocator same as kernel pid's.

Signed-off-by: Eric Huang <jinhuieric.huang@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 8f1de51f49be692de137c8525106e0fce2d1912d)
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c

index 64c519cd739572d6e481861218a380569259d208..d88523568b625fae3d1bc77bc9120e5a650ec214 100644 (file)
  * PASIDs are global address space identifiers that can be shared
  * between the GPU, an IOMMU and the driver. VMs on different devices
  * may use the same PASID if they share the same address
- * space. Therefore PASIDs are allocated using a global IDA. VMs are
- * looked up from the PASID per amdgpu_device.
+ * space. Therefore PASIDs are allocated using IDR cyclic allocator
+ * (similar to kernel PID allocation) which naturally delays reuse.
+ * VMs are looked up from the PASID per amdgpu_device.
  */
-static DEFINE_IDA(amdgpu_pasid_ida);
+
+static DEFINE_IDR(amdgpu_pasid_idr);
+static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
 
 /* Helper to free pasid from a fence callback */
 struct amdgpu_pasid_cb {
@@ -50,8 +53,8 @@ struct amdgpu_pasid_cb {
  * amdgpu_pasid_alloc - Allocate a PASID
  * @bits: Maximum width of the PASID in bits, must be at least 1
  *
- * Allocates a PASID of the given width while keeping smaller PASIDs
- * available if possible.
+ * Uses kernel's IDR cyclic allocator (same as PID allocation).
+ * Allocates sequentially with automatic wrap-around.
  *
  * Returns a positive integer on success. Returns %-EINVAL if bits==0.
  * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
@@ -59,14 +62,15 @@ struct amdgpu_pasid_cb {
  */
 int amdgpu_pasid_alloc(unsigned int bits)
 {
-       int pasid = -EINVAL;
+       int pasid;
 
-       for (bits = min(bits, 31U); bits > 0; bits--) {
-               pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1),
-                                       (1U << bits) - 1, GFP_KERNEL);
-               if (pasid != -ENOSPC)
-                       break;
-       }
+       if (bits == 0)
+               return -EINVAL;
+
+       spin_lock(&amdgpu_pasid_idr_lock);
+       pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
+                                1U << bits, GFP_KERNEL);
+       spin_unlock(&amdgpu_pasid_idr_lock);
 
        if (pasid >= 0)
                trace_amdgpu_pasid_allocated(pasid);
@@ -81,7 +85,10 @@ int amdgpu_pasid_alloc(unsigned int bits)
 void amdgpu_pasid_free(u32 pasid)
 {
        trace_amdgpu_pasid_freed(pasid);
-       ida_free(&amdgpu_pasid_ida, pasid);
+
+       spin_lock(&amdgpu_pasid_idr_lock);
+       idr_remove(&amdgpu_pasid_idr, pasid);
+       spin_unlock(&amdgpu_pasid_idr_lock);
 }
 
 static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -616,3 +623,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
                }
        }
 }
+
+/**
+ * amdgpu_pasid_mgr_cleanup - cleanup PASID manager
+ *
+ * Cleanup the IDR allocator.
+ */
+void amdgpu_pasid_mgr_cleanup(void)
+{
+       spin_lock(&amdgpu_pasid_idr_lock);
+       idr_destroy(&amdgpu_pasid_idr);
+       spin_unlock(&amdgpu_pasid_idr_lock);
+}
index b3649cd3af5699ef7331eedee54b042cdcdd99d7..a57919478d3bd7512e2dd1e9d2fc9b2612758009 100644 (file)
@@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bits);
 void amdgpu_pasid_free(u32 pasid);
 void amdgpu_pasid_free_delayed(struct dma_resv *resv,
                               u32 pasid);
+void amdgpu_pasid_mgr_cleanup(void);
 
 bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
                               struct amdgpu_vmid *id);
index c60cbce356cfefa9eddf4dcdf40709e2d493c078..d54afeb7b2a79d42c94d079b33171884fc5df409 100644 (file)
@@ -2898,6 +2898,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
        xa_destroy(&adev->vm_manager.pasids);
 
        amdgpu_vmid_mgr_fini(adev);
+       amdgpu_pasid_mgr_cleanup();
 }
 
 /**