summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSrinivasan Shanmugam <srinivasan.shanmugam@amd.com>2026-07-19 19:22:55 +0530
committerAlex Deucher <alexander.deucher@amd.com>2026-07-28 18:29:00 -0400
commit636df65409cd769a61031b34eb1040d95005af2b (patch)
tree4ae663bfaf32bc6ce1d46815b25efec0c38397ff /drivers/gpu
parentac9c3715159b4e8481e3f91c804f881799fd69ad (diff)
downloadlinux-636df65409cd769a61031b34eb1040d95005af2b.tar.gz
linux-636df65409cd769a61031b34eb1040d95005af2b.zip
drm/amdgpu: Allow PASID allocator to store fpriv owner
AMDGPU already has a global PASID xarray used for PASID allocation. Allow amdgpu_pasid_alloc() to optionally store the owning DRM file-private object directly. Initial callers pass NULL. A later patch in this series passes the DRM file-private object for DRM PASIDs. This prepares for using: PASID -> fpriv -> VM instead of: PASID -> VM Clear the stored owner from amdgpu_pasid_free_delayed() before waiting for outstanding fences so PASID lookups cannot observe a stale fpriv while the PASID itself is pending delayed release. v6: - Correct the PASID allocator kernel-doc to refer to the XArray cyclic allocator. - Document that PASID owner lookup may return NULL and that the returned fpriv remains valid only while the PASID lock is held. - No code changes. Retain Christian's Reviewed-by tag. v5: - Store NULL instead of xa_mk_value(0) for ownerless PASIDs. - Simplify owner clearing by unconditionally storing NULL. v4: - Add fpriv as an optional parameter to amdgpu_pasid_alloc(). - Drop separate amdgpu_pasid_set_fpriv()/clear_fpriv() helpers. - Clear PASID owner from amdgpu_pasid_free_delayed(). Cc: Alex Deucher <alexander.deucher@amd.com> Suggested-by: Christian König <christian.koenig@amd.com> Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c85
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c2
3 files changed, 82 insertions, 11 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 124fb38eb465..8a2d64f0ebc3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -51,16 +51,16 @@ struct amdgpu_pasid_cb {
/**
* amdgpu_pasid_alloc - Allocate a PASID
- * @bits: Maximum width of the PASID in bits, must be at least 1
+ * @bits: Number of PASID bits supported by the hardware
+ * @fpriv: DRM file private to associate with the PASID
*
- * Uses kernel's IDR cyclic allocator (same as PID allocation).
+ * Uses the kernel's XArray cyclic allocator.
* 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
- * memory allocation failure.
+ * Returns:
+ * Allocated PASID on success or a negative error code on failure.
*/
-int amdgpu_pasid_alloc(unsigned int bits)
+int amdgpu_pasid_alloc(unsigned int bits, struct amdgpu_fpriv *fpriv)
{
u32 pasid;
int r;
@@ -68,9 +68,9 @@ int amdgpu_pasid_alloc(unsigned int bits)
if (bits == 0)
return -EINVAL;
- r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, xa_mk_value(0),
- XA_LIMIT(1, (1U << bits) - 1),
- &amdgpu_pasid_xa_next, GFP_KERNEL);
+ r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, fpriv,
+ XA_LIMIT(1, (1U << bits) - 1),
+ &amdgpu_pasid_xa_next, GFP_KERNEL);
if (r < 0)
return r;
@@ -107,6 +107,71 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence,
}
/**
+ * amdgpu_pasid_clear_owner - Clear the owner associated with a PASID
+ * @pasid: PASID whose owner should be cleared
+ *
+ * Replace the stored owner with NULL while keeping the PASID allocated.
+ *
+ * This is used by the delayed PASID free path so that future PASID
+ * lookups cannot resolve a stale DRM file-private object while the PASID
+ * is still waiting for outstanding fences before being released.
+ */
+static void amdgpu_pasid_clear_owner(u32 pasid)
+{
+ unsigned long flags;
+
+ if (!pasid)
+ return;
+
+ xa_lock_irqsave(&amdgpu_pasid_xa, flags);
+ __xa_store(&amdgpu_pasid_xa, pasid, NULL, GFP_ATOMIC);
+ xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
+}
+
+/**
+ * amdgpu_pasid_lock - acquire the global PASID xarray lock
+ * @flags: storage for interrupt state
+ *
+ * Acquire the global PASID xarray lock with interrupts disabled.
+ * The saved interrupt state must be passed to
+ * amdgpu_pasid_unlock().
+ */
+void amdgpu_pasid_lock(unsigned long *flags)
+{
+ xa_lock_irqsave(&amdgpu_pasid_xa, *flags);
+}
+
+/**
+ * amdgpu_pasid_unlock - release the global PASID xarray lock
+ * @flags: interrupt state returned by amdgpu_pasid_lock()
+ *
+ * Release the global PASID xarray lock and restore the previous
+ * interrupt state.
+ */
+void amdgpu_pasid_unlock(unsigned long flags)
+{
+ xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
+}
+
+/**
+ * amdgpu_pasid_get_fpriv_locked - get the DRM owner of a PASID
+ * @pasid: PASID to resolve
+ *
+ * The caller must hold the PASID XArray lock.
+ *
+ * Returns:
+ * Pointer to the owning DRM file private, or %NULL if the PASID has no
+ * current owner.
+ *
+ * The returned pointer is only valid while the PASID lock remains held
+ * and must not be retained after calling amdgpu_pasid_unlock().
+ */
+struct amdgpu_fpriv *amdgpu_pasid_get_fpriv_locked(u32 pasid)
+{
+ return xa_load(&amdgpu_pasid_xa, pasid);
+}
+
+/**
* amdgpu_pasid_free_delayed - free pasid when fences signal
*
* @resv: reservation object with the fences to wait for
@@ -121,6 +186,8 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv,
struct dma_fence *fence;
int r;
+ amdgpu_pasid_clear_owner(pasid);
+
r = dma_resv_get_singleton(resv, DMA_RESV_USAGE_BOOKKEEP, &fence);
if (r)
goto fallback;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
index a57919478d3b..4b55d0d9703a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
@@ -34,6 +34,7 @@
#define AMDGPU_NUM_VMID 16
struct amdgpu_device;
+struct amdgpu_fpriv;
struct amdgpu_vm;
struct amdgpu_ring;
struct amdgpu_sync;
@@ -70,7 +71,10 @@ struct amdgpu_vmid_mgr {
bool reserved_vmid;
};
-int amdgpu_pasid_alloc(unsigned int bits);
+int amdgpu_pasid_alloc(unsigned int bits, struct amdgpu_fpriv *fpriv);
+void amdgpu_pasid_lock(unsigned long *flags);
+void amdgpu_pasid_unlock(unsigned long flags);
+struct amdgpu_fpriv *amdgpu_pasid_get_fpriv_locked(u32 pasid);
void amdgpu_pasid_free(u32 pasid);
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
u32 pasid);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 287ede40cd91..b2e2e3533c69 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1488,7 +1488,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
goto out_suspend;
}
- pasid = amdgpu_pasid_alloc(16);
+ pasid = amdgpu_pasid_alloc(16, NULL);
if (pasid < 0) {
dev_warn(adev->dev, "No more PASIDs available!");
pasid = 0;