On Mon, 30 Jun 2025 19:28:32 -0300 Jason Gunthorpe <jgg@xxxxxxxxxx> wrote: > diff --git a/drivers/pci/search.c b/drivers/pci/search.c > index 53840634fbfc2b..540a503b499e3f 100644 > --- a/drivers/pci/search.c > +++ b/drivers/pci/search.c > @@ -113,6 +113,156 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, > return ret; > } > > +static enum pci_bus_isolation pcie_switch_isolated(struct pci_bus *bus) > +{ > + struct pci_dev *pdev; > + > + /* > + * Within a PCIe switch we have an interior bus that has the Upstream > + * port as the bridge and a set of Downstream port bridging to the > + * egress ports. > + * > + * Each DSP has an ACS setting which controls where its traffic is > + * permitted to go. Any DSP with a permissive ACS setting can send > + * traffic flowing upstream back downstream through another DSP. > + * > + * Thus any non-permissive DSP spoils the whole bus. > + */ > + guard(rwsem_read)(&pci_bus_sem); > + list_for_each_entry(pdev, &bus->devices, bus_list) { > + /* Don't understand what this is, be conservative */ > + if (!pci_is_pcie(pdev) || > + pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM || > + pdev->dma_alias_mask) > + return PCIE_NON_ISOLATED; > + > + if (!pci_acs_enabled(pdev, PCI_ACS_ISOLATED)) > + return PCIE_SWITCH_DSP_NON_ISOLATED; > + } > + return PCIE_ISOLATED; > +} > + > +static bool pci_has_mmio(struct pci_dev *pdev) > +{ > + unsigned int i; > + > + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { > + struct resource *res = pci_resource_n(pdev, i); > + > + if (resource_size(res) && resource_type(res) == IORESOURCE_MEM) > + return true; > + } > + return false; > +} Maybe the intent is to make this as generic as possible, but it seems to only be used for bridge devices, so technically it could get away with testing only the first two resources, right? > + > +/** > + * pci_bus_isolated - Determine how isolated connected devices are > + * @bus: The bus to check > + * > + * Isolation is the ability of devices to talk to each other. Full isolation > + * means that a device can only communicate with the IOMMU and can not do peer > + * to peer within the fabric. > + * > + * We consider isolation on a bus by bus basis. If the bus will permit a > + * transaction originated downstream to complete on anything other than the > + * IOMMU then the bus is not isolated. > + * > + * Non-isolation includes all the downstream devices on this bus, and it may > + * include the upstream bridge or port that is creating this bus. > + * > + * The various cases are returned in an enum. > + * > + * Broadly speaking this function evaluates the ACS settings in a PCI switch to > + * determine if a PCI switch is configured to have full isolation. > + * > + * Old PCI/PCI-X busses cannot have isolation due to their physical properties, > + * but they do have some aliasing properties that effect group creation. > + * > + * pci_bus_isolated() does not consider loopback internal to devices, like > + * multi-function devices performing a self-loopback. The caller must check > + * this separately. It does not considering alasing within the bus. > + * > + * It does not currently support the ACS P2P Egress Control Vector, Linux does > + * not yet have any way to enable this feature. EC will create subsets of the > + * bus that are isolated from other subsets. > + */ > +enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) > +{ > + struct pci_dev *bridge = bus->self; > + int type; > + > + /* Consider virtual busses isolated */ > + if (!bridge) > + return PCIE_ISOLATED; > + if (pci_is_root_bus(bus)) > + return PCIE_ISOLATED; How do we know the root bus isn't conventional? I suppose this is only called by IOMMU code, but QEMU can make some pretty weird configurations. Thanks, Alex