* 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 {
* 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
*/
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);
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,
}
}
}
+
+/**
+ * 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);
+}