Replace the IDR based allocator with XArray and XArray's
internal state machine can handle memory allocation correctly.

Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 49 +++++++++++--------------
 1 file changed, 21 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index e495a8fa13fd..7b0afeddbb05 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -22,7 +22,7 @@
  */
 #include "amdgpu_ids.h"
 
-#include <linux/idr.h>
+#include <linux/xarray.h>
 #include <linux/dma-fence-array.h>
 
 
@@ -35,13 +35,12 @@
  * 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 IDR cyclic allocator
- * (similar to kernel PID allocation) which naturally delays reuse.
- * VMs are looked up from the PASID per amdgpu_device.
+ * space. Therefore PASIDs are allocated using XArray cyclic allocation
+ * which naturally delays reuse. VMs are looked up from the PASID per 
amdgpu_device.
  */
 
-static DEFINE_IDR(amdgpu_pasid_idr);
-static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
+static DEFINE_XARRAY_ALLOC(amdgpu_pasid_xa);
+static u32 amdgpu_pasid_next;
 
 /* Helper to free pasid from a fence callback */
 struct amdgpu_pasid_cb {
@@ -52,33 +51,31 @@ struct amdgpu_pasid_cb {
 /**
  * amdgpu_pasid_alloc - Allocate a PASID
  * @bits: Maximum width of the PASID in bits, must be at least 1
- *
- * Uses kernel's IDR cyclic allocator (same as PID allocation).
- * Allocates sequentially with automatic wrap-around.
- *
+
+ * Uses XArray cyclic allocator. Allocates sequentially with automatic
+ * wrap-around, delaying PASID reuse naturally.
+
  * Returns a positive integer on success. Returns %-EINVAL if bits==0.
  * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
  * memory allocation failure.
  */
 int amdgpu_pasid_alloc(unsigned int bits)
 {
-       int pasid;
+       u32 pasid;
+       int r;
 
        if (bits == 0)
                return -EINVAL;
 
-       spin_lock(&amdgpu_pasid_idr_lock);
-       /* TODO: Need to replace the idr with an xarry, and then
-        * handle the internal locking with ATOMIC safe paths.
-        */
-       pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
-                                1U << bits, GFP_ATOMIC);
-       spin_unlock(&amdgpu_pasid_idr_lock);
-
-       if (pasid >= 0)
-               trace_amdgpu_pasid_allocated(pasid);
+       r = xa_alloc_cyclic(&amdgpu_pasid_xa, &pasid, NULL,
+                           XA_LIMIT(1, (1U << bits) - 1),
+                           &amdgpu_pasid_next, GFP_KERNEL);
+       if (r < 0)
+               return r;
 
+       trace_amdgpu_pasid_allocated(pasid);
        return pasid;
+
 }
 
 /**
@@ -89,9 +86,7 @@ void amdgpu_pasid_free(u32 pasid)
 {
        trace_amdgpu_pasid_freed(pasid);
 
-       spin_lock(&amdgpu_pasid_idr_lock);
-       idr_remove(&amdgpu_pasid_idr, pasid);
-       spin_unlock(&amdgpu_pasid_idr_lock);
+       xa_erase(&amdgpu_pasid_xa, pasid);
 }
 
 static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -630,11 +625,9 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
 /**
  * amdgpu_pasid_mgr_cleanup - cleanup PASID manager
  *
- * Cleanup the IDR allocator.
+ * Cleanup the XArray allocator.
  */
 void amdgpu_pasid_mgr_cleanup(void)
 {
-       spin_lock(&amdgpu_pasid_idr_lock);
-       idr_destroy(&amdgpu_pasid_idr);
-       spin_unlock(&amdgpu_pasid_idr_lock);
+       xa_destroy(&amdgpu_pasid_xa);
 }
-- 
2.34.1

Reply via email to