Skip to content

Commit 2dcebc7

Browse files
Jacob Panjoergroedel
authored andcommitted
iommu: Move global PASID allocation from SVA to core
Intel ENQCMD requires a single PASID to be shared between multiple devices, as the PASID is stored in a single MSR register per-process and userspace can use only that one PASID. This means that the PASID allocation for any ENQCMD using device driver must always come from a shared global pool, regardless of what kind of domain the PASID will be used with. Split the code for the global PASID allocator into iommu_alloc/free_global_pasid() so that drivers can attach non-SVA domains to PASIDs as well. This patch moves global PASID allocation APIs from SVA to IOMMU APIs. Reserved PASIDs, currently only RID_PASID, are excluded from the global PASID allocation. It is expected that device drivers will use the allocated PASIDs to attach to appropriate IOMMU domains for use. Reviewed-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Signed-off-by: Jacob Pan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent 4298780 commit 2dcebc7

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

drivers/iommu/iommu-sva.c

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,30 @@
1010
#include "iommu-sva.h"
1111

1212
static DEFINE_MUTEX(iommu_sva_lock);
13-
static DEFINE_IDA(iommu_global_pasid_ida);
1413

1514
/* Allocate a PASID for the mm within range (inclusive) */
16-
static int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
15+
static int iommu_sva_alloc_pasid(struct mm_struct *mm, struct device *dev)
1716
{
17+
ioasid_t pasid;
1818
int ret = 0;
1919

20-
if (min == IOMMU_PASID_INVALID ||
21-
max == IOMMU_PASID_INVALID ||
22-
min == 0 || max < min)
23-
return -EINVAL;
24-
2520
if (!arch_pgtable_dma_compat(mm))
2621
return -EBUSY;
2722

2823
mutex_lock(&iommu_sva_lock);
2924
/* Is a PASID already associated with this mm? */
3025
if (mm_valid_pasid(mm)) {
31-
if (mm->pasid < min || mm->pasid > max)
26+
if (mm->pasid >= dev->iommu->max_pasids)
3227
ret = -EOVERFLOW;
3328
goto out;
3429
}
3530

36-
ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL);
37-
if (ret < 0)
31+
pasid = iommu_alloc_global_pasid(dev);
32+
if (pasid == IOMMU_PASID_INVALID) {
33+
ret = -ENOSPC;
3834
goto out;
39-
40-
mm->pasid = ret;
35+
}
36+
mm->pasid = pasid;
4137
ret = 0;
4238
out:
4339
mutex_unlock(&iommu_sva_lock);
@@ -64,15 +60,10 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
6460
{
6561
struct iommu_domain *domain;
6662
struct iommu_sva *handle;
67-
ioasid_t max_pasids;
6863
int ret;
6964

70-
max_pasids = dev->iommu->max_pasids;
71-
if (!max_pasids)
72-
return ERR_PTR(-EOPNOTSUPP);
73-
7465
/* Allocate mm->pasid if necessary. */
75-
ret = iommu_sva_alloc_pasid(mm, 1, max_pasids - 1);
66+
ret = iommu_sva_alloc_pasid(mm, dev);
7667
if (ret)
7768
return ERR_PTR(ret);
7869

@@ -217,5 +208,5 @@ void mm_pasid_drop(struct mm_struct *mm)
217208
if (likely(!mm_valid_pasid(mm)))
218209
return;
219210

220-
ida_free(&iommu_global_pasid_ida, mm->pasid);
211+
iommu_free_global_pasid(mm->pasid);
221212
}

drivers/iommu/iommu.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
static struct kset *iommu_group_kset;
4141
static DEFINE_IDA(iommu_group_ida);
42+
static DEFINE_IDA(iommu_global_pasid_ida);
4243

4344
static unsigned int iommu_def_domain_type __read_mostly;
4445
static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT);
@@ -3400,3 +3401,30 @@ struct iommu_domain *iommu_sva_domain_alloc(struct device *dev,
34003401

34013402
return domain;
34023403
}
3404+
3405+
ioasid_t iommu_alloc_global_pasid(struct device *dev)
3406+
{
3407+
int ret;
3408+
3409+
/* max_pasids == 0 means that the device does not support PASID */
3410+
if (!dev->iommu->max_pasids)
3411+
return IOMMU_PASID_INVALID;
3412+
3413+
/*
3414+
* max_pasids is set up by vendor driver based on number of PASID bits
3415+
* supported but the IDA allocation is inclusive.
3416+
*/
3417+
ret = ida_alloc_range(&iommu_global_pasid_ida, IOMMU_FIRST_GLOBAL_PASID,
3418+
dev->iommu->max_pasids - 1, GFP_KERNEL);
3419+
return ret < 0 ? IOMMU_PASID_INVALID : ret;
3420+
}
3421+
EXPORT_SYMBOL_GPL(iommu_alloc_global_pasid);
3422+
3423+
void iommu_free_global_pasid(ioasid_t pasid)
3424+
{
3425+
if (WARN_ON(pasid == IOMMU_PASID_INVALID))
3426+
return;
3427+
3428+
ida_free(&iommu_global_pasid_ida, pasid);
3429+
}
3430+
EXPORT_SYMBOL_GPL(iommu_free_global_pasid);

include/linux/iommu.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ enum iommu_dev_features {
197197
};
198198

199199
#define IOMMU_NO_PASID (0U) /* Reserved for DMA w/o PASID */
200+
#define IOMMU_FIRST_GLOBAL_PASID (1U) /*starting range for allocation */
200201
#define IOMMU_PASID_INVALID (-1U)
201202
typedef unsigned int ioasid_t;
202203

@@ -728,6 +729,8 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
728729
struct iommu_domain *
729730
iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid,
730731
unsigned int type);
732+
ioasid_t iommu_alloc_global_pasid(struct device *dev);
733+
void iommu_free_global_pasid(ioasid_t pasid);
731734
#else /* CONFIG_IOMMU_API */
732735

733736
struct iommu_ops {};
@@ -1089,6 +1092,13 @@ iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid,
10891092
{
10901093
return NULL;
10911094
}
1095+
1096+
static inline ioasid_t iommu_alloc_global_pasid(struct device *dev)
1097+
{
1098+
return IOMMU_PASID_INVALID;
1099+
}
1100+
1101+
static inline void iommu_free_global_pasid(ioasid_t pasid) {}
10921102
#endif /* CONFIG_IOMMU_API */
10931103

10941104
/**

0 commit comments

Comments
 (0)