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>
This commit is contained in:
Srinivasan Shanmugam
2026-07-19 19:22:55 +05:30
committed by Alex Deucher
parent ac9c371515
commit 636df65409
3 changed files with 82 additions and 11 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;