mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
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:
parent
5474e6e17a
commit
15dd29ca62
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user