iommu: Warn on premature unblock during DMA aliased sibling reset

When two aliased siblings are in the same iommu_group, they might share the
same RID. The reset functions don't support this case, though it is unclear
whether there is a real case of having an ATS capable device on a PCI/PCI-X
bus.

Theoretically, however, if two aliased devices are resetting concurrently,
one might be unblocked prematurely in the middle of the reset by the other
sibling who completes the reset first.

This isn't a regression from this series but it's better to spit a warning,
so we can know if such use case is common enough for us to make subsequent
patches for its coverage.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Nicolin Chen 2026-04-24 18:15:27 -07:00 committed by Joerg Roedel
parent 5474e6e17a
commit 15dd29ca62

View File

@ -4105,6 +4105,41 @@ int pci_dev_reset_iommu_prepare(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare);
static int __group_device_cmp_dma_alias(struct pci_dev *dev, u16 alias,
void *data)
{
return alias == *(u16 *)data;
}
static int group_device_cmp_dma_alias(struct pci_dev *dev, u16 alias,
void *data)
{
return pci_for_each_dma_alias(data, __group_device_cmp_dma_alias,
&alias);
}
static bool group_device_dma_alias_is_blocked(struct iommu_group *group,
struct group_device *gdev)
{
struct group_device *sibling;
lockdep_assert_held(&group->mutex);
if (!dev_is_pci(gdev->dev))
return false;
for_each_group_device(group, sibling) {
if (sibling == gdev || !sibling->blocked ||
!dev_is_pci(sibling->dev))
continue;
if (pci_for_each_dma_alias(to_pci_dev(gdev->dev),
group_device_cmp_dma_alias,
to_pci_dev(sibling->dev)))
return true;
}
return false;
}
/**
* pci_dev_reset_iommu_done() - Restore IOMMU after a PCI device reset is done
* @pdev: PCI device that has finished a reset routine
@ -4144,6 +4179,20 @@ void pci_dev_reset_iommu_done(struct pci_dev *pdev)
if (WARN_ON(!group->blocking_domain))
return;
if (group_device_dma_alias_is_blocked(group, gdev)) {
/*
* FIXME: DMA aliased devices share the same RID, which would be
* convoluted to handle, as "gdev->blocked" is not sufficient:
* - "blocked" state is effectively shared across these devices
* - if the core skipped the blocking on the second device, the
* IOMMU driver's attachment state would diverge from the HW
* state
* For now, just warn and see whether real ATS use cases hit it.
*/
pci_warn(pdev,
"DMA-aliased sibling may be prematurely unblocked\n");
}
/*
* Re-attach RID domain back to group->domain
*