Skip to content

Commit b3f6fcd

Browse files
tdavenvidiajoergroedel
authored andcommitted
iommu: Skip PASID validation for devices without PASID capability
Generally PASID support requires ACS settings that usually create single device groups, but there are some niche cases where we can get multi-device groups and still have working PASID support. The primary issue is that PCI switches are not required to treat PASID tagged TLPs specially so appropriate ACS settings are required to route all TLPs to the host bridge if PASID is going to work properly. pci_enable_pasid() does check that each device that will use PASID has the proper ACS settings to achieve this routing. However, no-PASID devices can be combined with PASID capable devices within the same topology using non-uniform ACS settings. In this case the no-PASID devices may not have strict route to host ACS flags and end up being grouped with the PASID devices. This configuration fails to allow use of the PASID within the iommu core code which wrongly checks if the no-PASID device supports PASID. Fix this by ignoring no-PASID devices during the PASID validation. They will never issue a PASID TLP anyhow so they can be ignored. Fixes: c404f55 ("iommu: Validate the PASID in iommu_attach_device_pasid()") Cc: stable@vger.kernel.org Signed-off-by: Tushar Dave <tdave@nvidia.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Vasant Hegde <vasant.hegde@amd.com> Link: https://lore.kernel.org/r/20250520011937.3230557-1-tdave@nvidia.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 82f2b0b commit b3f6fcd

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

drivers/iommu/iommu.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,10 +3366,12 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
33663366
int ret;
33673367

33683368
for_each_group_device(group, device) {
3369-
ret = domain->ops->set_dev_pasid(domain, device->dev,
3370-
pasid, old);
3371-
if (ret)
3372-
goto err_revert;
3369+
if (device->dev->iommu->max_pasids > 0) {
3370+
ret = domain->ops->set_dev_pasid(domain, device->dev,
3371+
pasid, old);
3372+
if (ret)
3373+
goto err_revert;
3374+
}
33733375
}
33743376

33753377
return 0;
@@ -3379,15 +3381,18 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
33793381
for_each_group_device(group, device) {
33803382
if (device == last_gdev)
33813383
break;
3382-
/*
3383-
* If no old domain, undo the succeeded devices/pasid.
3384-
* Otherwise, rollback the succeeded devices/pasid to the old
3385-
* domain. And it is a driver bug to fail attaching with a
3386-
* previously good domain.
3387-
*/
3388-
if (!old || WARN_ON(old->ops->set_dev_pasid(old, device->dev,
3384+
if (device->dev->iommu->max_pasids > 0) {
3385+
/*
3386+
* If no old domain, undo the succeeded devices/pasid.
3387+
* Otherwise, rollback the succeeded devices/pasid to
3388+
* the old domain. And it is a driver bug to fail
3389+
* attaching with a previously good domain.
3390+
*/
3391+
if (!old ||
3392+
WARN_ON(old->ops->set_dev_pasid(old, device->dev,
33893393
pasid, domain)))
3390-
iommu_remove_dev_pasid(device->dev, pasid, domain);
3394+
iommu_remove_dev_pasid(device->dev, pasid, domain);
3395+
}
33913396
}
33923397
return ret;
33933398
}
@@ -3398,8 +3403,10 @@ static void __iommu_remove_group_pasid(struct iommu_group *group,
33983403
{
33993404
struct group_device *device;
34003405

3401-
for_each_group_device(group, device)
3402-
iommu_remove_dev_pasid(device->dev, pasid, domain);
3406+
for_each_group_device(group, device) {
3407+
if (device->dev->iommu->max_pasids > 0)
3408+
iommu_remove_dev_pasid(device->dev, pasid, domain);
3409+
}
34033410
}
34043411

34053412
/*
@@ -3440,7 +3447,13 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
34403447

34413448
mutex_lock(&group->mutex);
34423449
for_each_group_device(group, device) {
3443-
if (pasid >= device->dev->iommu->max_pasids) {
3450+
/*
3451+
* Skip PASID validation for devices without PASID support
3452+
* (max_pasids = 0). These devices cannot issue transactions
3453+
* with PASID, so they don't affect group's PASID usage.
3454+
*/
3455+
if ((device->dev->iommu->max_pasids > 0) &&
3456+
(pasid >= device->dev->iommu->max_pasids)) {
34443457
ret = -EINVAL;
34453458
goto out_unlock;
34463459
}

0 commit comments

Comments
 (0)