mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-29 20:58:57 -04:00
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:
committed by
Alex Deucher
parent
ac9c371515
commit
636df65409
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user