From 636df65409cd769a61031b34eb1040d95005af2b Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Sun, 19 Jul 2026 19:22:55 +0530 Subject: [PATCH] drm/amdgpu: Allow PASID allocator to store fpriv owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Suggested-by: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 85 ++++++++++++++++++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h | 6 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +- 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; @@ -106,6 +106,71 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence, kfree(cb); } +/** + * 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 * @@ -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;