Skip to content

Commit 17fce9d

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Put iopf enablement in domain attach path
Update iopf enablement in the driver to use the new method, similar to the arm-smmu-v3 driver. Enable iopf support when any domain with an iopf_handler is attached, and disable it when the domain is removed. Place all the logic for controlling the PRI and iopf queue in the domain set/remove/replace paths. Keep track of the number of domains set to the device and PASIDs that require iopf. When the first domain requiring iopf is attached, add the device to the iopf queue and enable PRI. When the last domain is removed, remove it from the iopf queue and disable PRI. Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Yi Liu <[email protected]> Tested-by: Zhangfei Gao <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 7c8896d commit 17fce9d

File tree

4 files changed

+90
-10
lines changed

4 files changed

+90
-10
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,6 +3284,9 @@ void device_block_translation(struct device *dev)
32843284
static int blocking_domain_attach_dev(struct iommu_domain *domain,
32853285
struct device *dev)
32863286
{
3287+
struct device_domain_info *info = dev_iommu_priv_get(dev);
3288+
3289+
iopf_for_domain_remove(info->domain ? &info->domain->domain : NULL, dev);
32873290
device_block_translation(dev);
32883291
return 0;
32893292
}
@@ -3494,7 +3497,15 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
34943497
if (ret)
34953498
return ret;
34963499

3497-
return dmar_domain_attach_device(to_dmar_domain(domain), dev);
3500+
ret = iopf_for_domain_set(domain, dev);
3501+
if (ret)
3502+
return ret;
3503+
3504+
ret = dmar_domain_attach_device(to_dmar_domain(domain), dev);
3505+
if (ret)
3506+
iopf_for_domain_remove(domain, dev);
3507+
3508+
return ret;
34983509
}
34993510

35003511
static int intel_iommu_map(struct iommu_domain *domain,
@@ -3915,6 +3926,8 @@ int intel_iommu_enable_iopf(struct device *dev)
39153926
if (!info->pri_enabled)
39163927
return -ENODEV;
39173928

3929+
/* pri_enabled is protected by the group mutex. */
3930+
iommu_group_mutex_assert(dev);
39183931
if (info->iopf_refcount) {
39193932
info->iopf_refcount++;
39203933
return 0;
@@ -3937,6 +3950,7 @@ void intel_iommu_disable_iopf(struct device *dev)
39373950
if (WARN_ON(!info->pri_enabled || !info->iopf_refcount))
39383951
return;
39393952

3953+
iommu_group_mutex_assert(dev);
39403954
if (--info->iopf_refcount)
39413955
return;
39423956

@@ -3948,8 +3962,7 @@ intel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
39483962
{
39493963
switch (feat) {
39503964
case IOMMU_DEV_FEAT_IOPF:
3951-
return intel_iommu_enable_iopf(dev);
3952-
3965+
return 0;
39533966
default:
39543967
return -ENODEV;
39553968
}
@@ -3960,7 +3973,6 @@ intel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
39603973
{
39613974
switch (feat) {
39623975
case IOMMU_DEV_FEAT_IOPF:
3963-
intel_iommu_disable_iopf(dev);
39643976
return 0;
39653977

39663978
default:
@@ -4041,6 +4053,7 @@ static int blocking_domain_set_dev_pasid(struct iommu_domain *domain,
40414053
{
40424054
struct device_domain_info *info = dev_iommu_priv_get(dev);
40434055

4056+
iopf_for_domain_remove(old, dev);
40444057
intel_pasid_tear_down_entry(info->iommu, dev, pasid, false);
40454058
domain_remove_dev_pasid(old, dev, pasid);
40464059

@@ -4114,21 +4127,27 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
41144127
if (IS_ERR(dev_pasid))
41154128
return PTR_ERR(dev_pasid);
41164129

4130+
ret = iopf_for_domain_replace(domain, old, dev);
4131+
if (ret)
4132+
goto out_remove_dev_pasid;
4133+
41174134
if (dmar_domain->use_first_level)
41184135
ret = domain_setup_first_level(iommu, dmar_domain,
41194136
dev, pasid, old);
41204137
else
41214138
ret = domain_setup_second_level(iommu, dmar_domain,
41224139
dev, pasid, old);
41234140
if (ret)
4124-
goto out_remove_dev_pasid;
4141+
goto out_unwind_iopf;
41254142

41264143
domain_remove_dev_pasid(old, dev, pasid);
41274144

41284145
intel_iommu_debugfs_create_dev_pasid(dev_pasid);
41294146

41304147
return 0;
41314148

4149+
out_unwind_iopf:
4150+
iopf_for_domain_replace(old, domain, dev);
41324151
out_remove_dev_pasid:
41334152
domain_remove_dev_pasid(domain, dev, pasid);
41344153
return ret;
@@ -4343,6 +4362,11 @@ static int identity_domain_attach_dev(struct iommu_domain *domain, struct device
43434362
if (dev_is_real_dma_subdevice(dev))
43444363
return 0;
43454364

4365+
/*
4366+
* No PRI support with the global identity domain. No need to enable or
4367+
* disable PRI in this path as the iommu has been put in the blocking
4368+
* state.
4369+
*/
43464370
if (sm_supported(iommu))
43474371
ret = intel_pasid_setup_pass_through(iommu, dev, IOMMU_NO_PASID);
43484372
else
@@ -4362,10 +4386,16 @@ static int identity_domain_set_dev_pasid(struct iommu_domain *domain,
43624386
if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
43634387
return -EOPNOTSUPP;
43644388

4365-
ret = domain_setup_passthrough(iommu, dev, pasid, old);
4389+
ret = iopf_for_domain_replace(domain, old, dev);
43664390
if (ret)
43674391
return ret;
43684392

4393+
ret = domain_setup_passthrough(iommu, dev, pasid, old);
4394+
if (ret) {
4395+
iopf_for_domain_replace(old, domain, dev);
4396+
return ret;
4397+
}
4398+
43694399
domain_remove_dev_pasid(old, dev, pasid);
43704400
return 0;
43714401
}

drivers/iommu/intel/iommu.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,39 @@ void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid);
12971297
int intel_iommu_enable_iopf(struct device *dev);
12981298
void intel_iommu_disable_iopf(struct device *dev);
12991299

1300+
static inline int iopf_for_domain_set(struct iommu_domain *domain,
1301+
struct device *dev)
1302+
{
1303+
if (!domain || !domain->iopf_handler)
1304+
return 0;
1305+
1306+
return intel_iommu_enable_iopf(dev);
1307+
}
1308+
1309+
static inline void iopf_for_domain_remove(struct iommu_domain *domain,
1310+
struct device *dev)
1311+
{
1312+
if (!domain || !domain->iopf_handler)
1313+
return;
1314+
1315+
intel_iommu_disable_iopf(dev);
1316+
}
1317+
1318+
static inline int iopf_for_domain_replace(struct iommu_domain *new,
1319+
struct iommu_domain *old,
1320+
struct device *dev)
1321+
{
1322+
int ret;
1323+
1324+
ret = iopf_for_domain_set(new, dev);
1325+
if (ret)
1326+
return ret;
1327+
1328+
iopf_for_domain_remove(old, dev);
1329+
1330+
return 0;
1331+
}
1332+
13001333
#ifdef CONFIG_INTEL_IOMMU_SVM
13011334
void intel_svm_check(struct intel_iommu *iommu);
13021335
struct iommu_domain *intel_svm_domain_alloc(struct device *dev,

drivers/iommu/intel/nested.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,23 @@ static int intel_nested_attach_dev(struct iommu_domain *domain,
5656
if (ret)
5757
goto detach_iommu;
5858

59+
ret = iopf_for_domain_set(domain, dev);
60+
if (ret)
61+
goto unassign_tag;
62+
5963
ret = intel_pasid_setup_nested(iommu, dev,
6064
IOMMU_NO_PASID, dmar_domain);
6165
if (ret)
62-
goto unassign_tag;
66+
goto disable_iopf;
6367

6468
info->domain = dmar_domain;
6569
spin_lock_irqsave(&dmar_domain->lock, flags);
6670
list_add(&info->link, &dmar_domain->devices);
6771
spin_unlock_irqrestore(&dmar_domain->lock, flags);
6872

6973
return 0;
74+
disable_iopf:
75+
iopf_for_domain_remove(domain, dev);
7076
unassign_tag:
7177
cache_tag_unassign_domain(dmar_domain, dev, IOMMU_NO_PASID);
7278
detach_iommu:
@@ -166,14 +172,20 @@ static int intel_nested_set_dev_pasid(struct iommu_domain *domain,
166172
if (IS_ERR(dev_pasid))
167173
return PTR_ERR(dev_pasid);
168174

169-
ret = domain_setup_nested(iommu, dmar_domain, dev, pasid, old);
175+
ret = iopf_for_domain_replace(domain, old, dev);
170176
if (ret)
171177
goto out_remove_dev_pasid;
172178

179+
ret = domain_setup_nested(iommu, dmar_domain, dev, pasid, old);
180+
if (ret)
181+
goto out_unwind_iopf;
182+
173183
domain_remove_dev_pasid(old, dev, pasid);
174184

175185
return 0;
176186

187+
out_unwind_iopf:
188+
iopf_for_domain_replace(old, domain, dev);
177189
out_remove_dev_pasid:
178190
domain_remove_dev_pasid(domain, dev, pasid);
179191
return ret;

drivers/iommu/intel/svm.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,23 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
164164
if (IS_ERR(dev_pasid))
165165
return PTR_ERR(dev_pasid);
166166

167+
ret = iopf_for_domain_replace(domain, old, dev);
168+
if (ret)
169+
goto out_remove_dev_pasid;
170+
167171
/* Setup the pasid table: */
168172
sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
169173
ret = __domain_setup_first_level(iommu, dev, pasid,
170174
FLPT_DEFAULT_DID, mm->pgd,
171175
sflags, old);
172176
if (ret)
173-
goto out_remove_dev_pasid;
177+
goto out_unwind_iopf;
174178

175179
domain_remove_dev_pasid(old, dev, pasid);
176180

177181
return 0;
178-
182+
out_unwind_iopf:
183+
iopf_for_domain_replace(old, domain, dev);
179184
out_remove_dev_pasid:
180185
domain_remove_dev_pasid(domain, dev, pasid);
181186
return ret;

0 commit comments

Comments
 (0)