Skip to content

Commit 3c863ff

Browse files
NTManalexdeucher
authored andcommitted
drm/amdgpu: replace PASID IDR with XArray
Replace the PASID IDR + spinlock with XArray as noted in the TODO left by commit ea56aa2 ("drm/amdgpu: fix the idr allocation flags"). The IDR conversion still has an IRQ safety issue: amdgpu_pasid_free() can be called from hardirq context via the fence signal path, but amdgpu_pasid_idr_lock is taken with plain spin_lock() in process context, creating a potential deadlock: CPU0 ---- spin_lock(&amdgpu_pasid_idr_lock) // process context, IRQs on <Interrupt> spin_lock(&amdgpu_pasid_idr_lock) // deadlock The hardirq call chain is: sdma_v6_0_process_trap_irq -> amdgpu_fence_process -> dma_fence_signal -> drm_sched_job_done -> dma_fence_signal -> amdgpu_pasid_free_cb -> amdgpu_pasid_free Use XArray with XA_FLAGS_LOCK_IRQ (all xa operations use IRQ-safe locking internally) and XA_FLAGS_ALLOC1 (zero is not a valid PASID). Both xa_alloc_cyclic() and xa_erase() then handle locking consistently, fixing the IRQ safety issue and removing the need for an explicit spinlock. v8: squash in irq safe fix Reviewed-by: Christian König <christian.koenig@amd.com> Suggested-by: Lijo Lazar <lijo.lazar@amd.com> Fixes: ea56aa2 ("drm/amdgpu: fix the idr allocation flags") Fixes: 8f1de51 ("drm/amdgpu: prevent immediate PASID reuse case") Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 1d4ade3 commit 3c863ff

1 file changed

Lines changed: 19 additions & 20 deletions

File tree

drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323
#include "amdgpu_ids.h"
2424

25-
#include <linux/idr.h>
25+
#include <linux/xarray.h>
2626
#include <linux/dma-fence-array.h>
2727

2828

@@ -40,8 +40,8 @@
4040
* VMs are looked up from the PASID per amdgpu_device.
4141
*/
4242

43-
static DEFINE_IDR(amdgpu_pasid_idr);
44-
static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
43+
static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1);
44+
static u32 amdgpu_pasid_xa_next;
4545

4646
/* Helper to free pasid from a fence callback */
4747
struct amdgpu_pasid_cb {
@@ -62,36 +62,37 @@ struct amdgpu_pasid_cb {
6262
*/
6363
int amdgpu_pasid_alloc(unsigned int bits)
6464
{
65-
int pasid;
65+
u32 pasid;
66+
int r;
6667

6768
if (bits == 0)
6869
return -EINVAL;
6970

70-
spin_lock(&amdgpu_pasid_idr_lock);
71-
/* TODO: Need to replace the idr with an xarry, and then
72-
* handle the internal locking with ATOMIC safe paths.
73-
*/
74-
pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
75-
1U << bits, GFP_ATOMIC);
76-
spin_unlock(&amdgpu_pasid_idr_lock);
77-
78-
if (pasid >= 0)
79-
trace_amdgpu_pasid_allocated(pasid);
71+
r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, xa_mk_value(0),
72+
XA_LIMIT(1, (1U << bits) - 1),
73+
&amdgpu_pasid_xa_next, GFP_KERNEL);
74+
if (r < 0)
75+
return r;
8076

77+
trace_amdgpu_pasid_allocated(pasid);
8178
return pasid;
8279
}
8380

8481
/**
8582
* amdgpu_pasid_free - Free a PASID
8683
* @pasid: PASID to free
84+
*
85+
* Called in IRQ context.
8786
*/
8887
void amdgpu_pasid_free(u32 pasid)
8988
{
89+
unsigned long flags;
90+
9091
trace_amdgpu_pasid_freed(pasid);
9192

92-
spin_lock(&amdgpu_pasid_idr_lock);
93-
idr_remove(&amdgpu_pasid_idr, pasid);
94-
spin_unlock(&amdgpu_pasid_idr_lock);
93+
xa_lock_irqsave(&amdgpu_pasid_xa, flags);
94+
__xa_erase(&amdgpu_pasid_xa, pasid);
95+
xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
9596
}
9697

9798
static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -634,7 +635,5 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
634635
*/
635636
void amdgpu_pasid_mgr_cleanup(void)
636637
{
637-
spin_lock(&amdgpu_pasid_idr_lock);
638-
idr_destroy(&amdgpu_pasid_idr);
639-
spin_unlock(&amdgpu_pasid_idr_lock);
638+
xa_destroy(&amdgpu_pasid_xa);
640639
}

0 commit comments

Comments
 (0)