From 18a93b2127753c6b67c1cb3d9496d13075d7b1fa Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:51 +0000 Subject: [PATCH 01/16] Revert "NVIDIA: SAUCE: PCI: Check ACS Extended flags for pci_bus_isolated()" This reverts commit 97f12f4efd338f18e2a643903014089ffcf13a37. Signed-off-by: Tushar Dave --- drivers/pci/search.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 7425680fe92d6..2be6881087b33 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -127,8 +127,6 @@ static enum pci_bus_isolation pcie_switch_isolated(struct pci_bus *bus) * traffic flowing upstream back downstream through another DSP. * * Thus any non-permissive DSP spoils the whole bus. - * PCI_ACS_UNCLAIMED_RR is not required since rejecting requests with - * error is still isolation. */ guard(rwsem_read)(&pci_bus_sem); list_for_each_entry(pdev, &bus->devices, bus_list) { @@ -138,14 +136,8 @@ static enum pci_bus_isolation pcie_switch_isolated(struct pci_bus *bus) pdev->dma_alias_mask) return PCIE_NON_ISOLATED; - if (!pci_acs_enabled(pdev, PCI_ACS_ISOLATED | - PCI_ACS_DSP_MT_RR | - PCI_ACS_USP_MT_RR)) { - /* The USP is isolated from the DSP */ - if (!pci_acs_enabled(pdev, PCI_ACS_USP_MT_RR)) - return PCIE_NON_ISOLATED; + if (!pci_acs_enabled(pdev, PCI_ACS_ISOLATED)) return PCIE_SWITCH_DSP_NON_ISOLATED; - } } return PCIE_ISOLATED; } @@ -239,13 +231,11 @@ enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) switch (type) { /* * Since PCIe links are point to point root and downstream ports are - * isolated if their own MMIO cannot be reached. The root port - * uses DSP_MT_RR for its own MMIO. + * isolated if their own MMIO cannot be reached. */ case PCI_EXP_TYPE_ROOT_PORT: case PCI_EXP_TYPE_DOWNSTREAM: - if (!pci_acs_enabled(bridge, - PCI_ACS_ISOLATED | PCI_ACS_DSP_MT_RR)) + if (!pci_acs_enabled(bridge, PCI_ACS_ISOLATED)) return PCIE_NON_ISOLATED; return PCIE_ISOLATED; From 9d299a3a2aa8ec1af32a8397a0fc07485e76a492 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:56 +0000 Subject: [PATCH 02/16] Revert "NVIDIA: SAUCE: PCI: Check ACS DSP/USP redirect bits in pci_enable_pasid()" This reverts commit 4eb81bad80e8dad1bcb4da2a849afde53b79abfc. Signed-off-by: Tushar Dave --- drivers/pci/ats.c | 4 +--- drivers/pci/pci.c | 54 ++++++----------------------------------------- 2 files changed, 8 insertions(+), 50 deletions(-) diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 00603c2c4ff0e..ec6c8dbdc5e9c 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -416,9 +416,7 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) if (!pasid) return -EINVAL; - if (!pci_acs_path_enabled(pdev, NULL, - PCI_ACS_RR | PCI_ACS_UF | PCI_ACS_USP_MT_RR | - PCI_ACS_DSP_MT_RR | PCI_ACS_UNCLAIMED_RR)) + if (!pci_acs_path_enabled(pdev, NULL, PCI_ACS_RR | PCI_ACS_UF)) return -EINVAL; pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index debbee30cab07..428f8a1493a52 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3602,52 +3602,6 @@ void pci_configure_ari(struct pci_dev *dev) } } - -/* - * The spec is not clear what it means if the capability bit is 0. One view is - * that the device acts as though the ctrl bit is zero, another view is the - * device behavior is undefined. - * - * Historically Linux has taken the position that the capability bit as 0 means - * the device supports the most favorable interpritation of the spec - ie that - * things like P2P RR are always on. As this is security sensitive we expect - * devices that do not follow this rule to be quirked. - * - * ACS Enhanced eliminated undefined areas of the spec around MMIO in root ports - * and switch ports. If those ports have no MMIO then it is not relavent. - * PCI_ACS_UNCLAIMED_RR eliminates the undefined area around an upstream switch - * window that is not fully decoded by the downstream windows. - * - * This takes the same approach with ACS Enhanced, if the device does not - * support it then we assume the ACS P2P RR has all the enhanced behaviors too. - * - * Due to ACS Enhanced bits being force set to 0 by older Linux kernels, and - * those values would break old kernels on the edge cases they cover, the only - * compatible thing for a new device to implement is ACS Enhanced supported with - * the control bits (except PCI_ACS_IORB) wired to follow ACS_RR. - */ -static u16 pci_acs_ctrl_mask(struct pci_dev *pdev, u16 hw_cap) -{ - /* - * Egress Control enables use of the Egress Control Vector which is not - * present without the cap. - */ - u16 mask = PCI_ACS_EC; - - mask = hw_cap & (PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | - PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT); - - /* - * If ACS Enhanced is supported the device reports what it is doing - * through these bits which may not be settable. - */ - if (hw_cap & PCI_ACS_ENHANCED) - mask |= PCI_ACS_IORB | PCI_ACS_DSP_MT_RB | PCI_ACS_DSP_MT_RR | - PCI_ACS_USP_MT_RB | PCI_ACS_USP_MT_RR | - PCI_ACS_UNCLAIMED_RR; - return mask; -} - static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) { int pos; @@ -3657,9 +3611,15 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) if (!pos) return false; + /* + * Except for egress control, capabilities are either required + * or only required if controllable. Features missing from the + * capability field can therefore be assumed as hard-wired enabled. + */ pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap); + acs_flags &= (cap | PCI_ACS_EC); + pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); - acs_flags &= pci_acs_ctrl_mask(pdev, cap); return (ctrl & acs_flags) == acs_flags; } From e885b4ffb1a077d905cae25c080758c5d8bb5cf0 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:56 +0000 Subject: [PATCH 03/16] Revert "NVIDIA: SAUCE: PCI: Enable ACS Enhanced bits for enable_acs and config_acs" This reverts commit 8cb4daa6aac848bfbdae349d4c4fd0e4c65a7326. Signed-off-by: Tushar Dave --- drivers/pci/pci.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 428f8a1493a52..5d92089776652 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -957,7 +957,6 @@ static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps, const char *p, const u16 acs_mask, const u16 acs_flags) { u16 flags = acs_flags; - u16 supported_flags; u16 mask = acs_mask; char *delimit; int ret = 0; @@ -1002,14 +1001,8 @@ static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps, } } - supported_flags = PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | - PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_EC | - PCI_ACS_DT; - if (caps->cap & PCI_ACS_ENHANCED) - supported_flags |= PCI_ACS_USP_MT_RR | - PCI_ACS_DSP_MT_RR | - PCI_ACS_UNCLAIMED_RR; - if (mask & ~supported_flags) { + if (mask & ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | PCI_ACS_CR | + PCI_ACS_UF | PCI_ACS_EC | PCI_ACS_DT)) { pci_err(dev, "Invalid ACS flags specified\n"); return; } @@ -1069,14 +1062,6 @@ static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps) /* Upstream Forwarding */ caps->ctrl |= (caps->cap & PCI_ACS_UF); - /* - * USP/DSP Memory Target Access Control and Unclaimed Request Redirect - */ - if (caps->cap & PCI_ACS_ENHANCED) { - caps->ctrl |= PCI_ACS_USP_MT_RR | PCI_ACS_DSP_MT_RR | - PCI_ACS_UNCLAIMED_RR; - } - /* Enable Translation Blocking for external devices and noats */ if (pci_ats_disabled() || dev->external_facing || dev->untrusted) caps->ctrl |= (caps->cap & PCI_ACS_TB); From 6789ed1843c2178c0b0ebba58280d0cb92229d62 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:56 +0000 Subject: [PATCH 04/16] Revert "NVIDIA: SAUCE: PCI: Add the ACS Enhanced Capability definitions" This reverts commit 8f5705f9f0a74d2c45b067d738b2949cfffa93de. Signed-off-by: Tushar Dave --- include/uapi/linux/pci_regs.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 58626694dac63..f9de4734c4cd1 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -1000,16 +1000,8 @@ #define PCI_ACS_UF 0x0010 /* Upstream Forwarding */ #define PCI_ACS_EC 0x0020 /* P2P Egress Control */ #define PCI_ACS_DT 0x0040 /* Direct Translated P2P */ -#define PCI_ACS_ENHANCED 0x0080 /* IORB, DSP_MT_xx, USP_MT_XX. Capability only */ -#define PCI_ACS_EGRESS_CTL_SZ GENMASK(15, 8) /* Egress Control Vector Size */ #define PCI_ACS_EGRESS_BITS 0x05 /* ACS Egress Control Vector Size */ #define PCI_ACS_CTRL 0x06 /* ACS Control Register */ -#define PCI_ACS_IORB 0x0080 /* I/O Request Blocking */ -#define PCI_ACS_DSP_MT_RB 0x0100 /* DSP Memory Target Access Control Request Blocking */ -#define PCI_ACS_DSP_MT_RR 0x0200 /* DSP Memory Target Access Control Request Redirect */ -#define PCI_ACS_USP_MT_RB 0x0400 /* USP Memory Target Access Control Request Blocking */ -#define PCI_ACS_USP_MT_RR 0x0800 /* USP Memory Target Access Control Request Redirect */ -#define PCI_ACS_UNCLAIMED_RR 0x1000 /* Unclaimed Request Redirect Control */ #define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ /* From 4912cd4ecfb461551aa4df7bb840b2b578047cd3 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:56 +0000 Subject: [PATCH 05/16] Revert "NVIDIA: SAUCE: iommu: Validate that pci_for_each_dma_alias() matches the groups" This reverts commit 9dbfd224a8b8e9c8386f849e4778bef4f77d30ab. Signed-off-by: Tushar Dave --- drivers/iommu/iommu.c | 73 +------------------------------------------ 1 file changed, 1 insertion(+), 72 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index c0430bb1c73ab..461d7a195b9f2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1582,7 +1582,7 @@ static struct iommu_group *pci_hierarchy_group(struct pci_dev *pdev) * Once a PCI bus becomes non isolating the entire downstream hierarchy of * that bus becomes a single group. */ -static struct iommu_group *__pci_device_group(struct device *dev) +struct iommu_group *pci_device_group(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct iommu_group *group; @@ -1689,77 +1689,6 @@ static struct iommu_group *__pci_device_group(struct device *dev) WARN_ON(true); return ERR_PTR(-EINVAL); } - -struct check_group_aliases_data { - struct pci_dev *pdev; - struct iommu_group *group; -}; - -static void pci_check_group(const struct check_group_aliases_data *data, - u16 alias, struct pci_dev *pdev) -{ - struct iommu_group *group; - - group = iommu_group_get(&pdev->dev); - if (!group) - return; - - if (group != data->group) - dev_err(&data->pdev->dev, - "During group construction alias processing needed dev %s alias %x to have the same group but %u != %u\n", - pci_name(pdev), alias, data->group->id, group->id); - iommu_group_put(group); -} - -static int pci_check_group_aliases(struct pci_dev *pdev, u16 alias, - void *opaque) -{ - const struct check_group_aliases_data *data = opaque; - - /* - * Sometimes when a PCIe-PCI bridge is performing transactions on behalf - * of its subordinate bus it uses devfn=0 on the subordinate bus as the - * alias. This means that 0 will alias with all devfns on the - * subordinate bus and so we expect to see those in the same group. pdev - * in this case is the bridge itself and pdev->bus is the primary bus of - * the bridge. - */ - if (pdev->bus->number != PCI_BUS_NUM(alias)) { - struct pci_dev *piter = NULL; - - for_each_pci_dev(piter) { - if (pci_domain_nr(pdev->bus) == - pci_domain_nr(piter->bus) && - PCI_BUS_NUM(alias) == pdev->bus->number) - pci_check_group(data, alias, piter); - } - } else { - pci_check_group(data, alias, pdev); - } - - return 0; -} - -struct iommu_group *pci_device_group(struct device *dev) -{ - struct iommu_group *group = __pci_device_group(dev); - - if (!IS_ERR(group)) { - struct check_group_aliases_data data = { - .pdev = to_pci_dev(dev), .group = group - }; - - /* - * The IOMMU driver should use pci_for_each_dma_alias() to - * figure out what RIDs to program and the core requires all the - * RIDs to fall within the same group. Validate that everything - * worked properly. - */ - pci_for_each_dma_alias(data.pdev, pci_check_group_aliases, - &data); - } - return group; -} EXPORT_SYMBOL_GPL(pci_device_group); /* Get the IOMMU group for device on fsl-mc bus */ From 6ede36f2fd47df84c1fbaeabdba8cd9cc3831379 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:56 +0000 Subject: [PATCH 06/16] Revert "NVIDIA: SAUCE: iommu: Compute iommu_groups properly for PCIe MFDs" This reverts commit 2bbc1b32208d4d5b39c444abf7340e379f6b59cf. Signed-off-by: Tushar Dave --- drivers/iommu/iommu.c | 169 +++++++++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 461d7a195b9f2..7a13d4d8a8892 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1389,6 +1389,85 @@ int iommu_group_id(struct iommu_group *group) } EXPORT_SYMBOL_GPL(iommu_group_id); +static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, + unsigned long *devfns); + +/* + * For multifunction devices which are not isolated from each other, find + * all the other non-isolated functions and look for existing groups. For + * each function, we also need to look for aliases to or from other devices + * that may already have a group. + */ +static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, + unsigned long *devfns) +{ + struct pci_dev *tmp = NULL; + struct iommu_group *group; + + if (!pdev->multifunction || pci_acs_enabled(pdev, PCI_ACS_ISOLATED)) + return NULL; + + for_each_pci_dev(tmp) { + if (tmp == pdev || tmp->bus != pdev->bus || + PCI_SLOT(tmp->devfn) != PCI_SLOT(pdev->devfn) || + pci_acs_enabled(tmp, PCI_ACS_ISOLATED)) + continue; + + group = get_pci_alias_group(tmp, devfns); + if (group) { + pci_dev_put(tmp); + return group; + } + } + + return NULL; +} + +/* + * Look for aliases to or from the given device for existing groups. DMA + * aliases are only supported on the same bus, therefore the search + * space is quite small (especially since we're really only looking at pcie + * device, and therefore only expect multiple slots on the root complex or + * downstream switch ports). It's conceivable though that a pair of + * multifunction devices could have aliases between them that would cause a + * loop. To prevent this, we use a bitmap to track where we've been. + */ +static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, + unsigned long *devfns) +{ + struct pci_dev *tmp = NULL; + struct iommu_group *group; + + if (test_and_set_bit(pdev->devfn & 0xff, devfns)) + return NULL; + + group = iommu_group_get(&pdev->dev); + if (group) + return group; + + for_each_pci_dev(tmp) { + if (tmp == pdev || tmp->bus != pdev->bus) + continue; + + /* We alias them or they alias us */ + if (pci_devs_are_dma_aliases(pdev, tmp)) { + group = get_pci_alias_group(tmp, devfns); + if (group) { + pci_dev_put(tmp); + return group; + } + + group = get_pci_function_alias_group(tmp, devfns); + if (group) { + pci_dev_put(tmp); + return group; + } + } + } + + return NULL; +} + /* * Generic device_group call-back function. It just allocates one * iommu-group per device. @@ -1431,88 +1510,40 @@ static struct iommu_group *pci_group_alloc_non_isolated(void) return group; } -/* - * Ignoring quirks, all functions in the MFD need to be isolated from each other - * and get their own groups, otherwise the whole MFD will share a group. Any - * function that lacks explicit ACS isolation is assumed to be able to P2P - * access any other function in the MFD. - */ -static bool pci_mfds_are_same_group(struct pci_dev *deva, struct pci_dev *devb) +static struct iommu_group *pci_get_alias_group(struct pci_dev *pdev) { - /* Are deva/devb functions in the same MFD? */ - if (PCI_SLOT(deva->devfn) != PCI_SLOT(devb->devfn)) - return false; - /* Don't understand what is happening, be conservative */ - if (deva->multifunction != devb->multifunction) - return true; - if (!deva->multifunction) - return false; - - /* Quirks can inhibit single MFD functions from combining into groups */ - if (pci_mfd_isolated(deva) || pci_mfd_isolated(devb)) - return false; - - /* Can they reach each other's MMIO through P2P? */ - return !pci_acs_enabled(deva, PCI_ACS_ISOLATED) || - !pci_acs_enabled(devb, PCI_ACS_ISOLATED); -} + struct iommu_group *group; + DECLARE_BITMAP(devfns, 256) = {}; -static bool pci_devs_are_same_group(struct pci_dev *deva, struct pci_dev *devb) -{ /* - * This is allowed to return cycles: a,b -> b,c -> c,a can be aliases. + * Look for existing groups on device aliases. If we alias another + * device or another device aliases us, use the same group. */ - if (pci_devs_are_dma_aliases(deva, devb)) - return true; - - return pci_mfds_are_same_group(deva, devb); -} - -static struct iommu_group *pci_get_alias_group(struct pci_dev *pdev) -{ - struct pci_reachable_set devfns; - const unsigned int NR_DEVFNS = sizeof(devfns.devfns) * BITS_PER_BYTE; - unsigned int devfn; + group = get_pci_alias_group(pdev, devfns); + if (group) + return group; /* - * Look for existing groups on device aliases and multi-function ACS. If - * we alias another device or another device aliases us, use the same - * group. - * - * pci_reachable_set() should return the same bitmap if called for any - * device in the set and we want all devices in the set to have the same - * group. + * Look for existing groups on non-isolated functions on the same + * slot and aliases of those funcions, if any. No need to clear + * the search bitmap, the tested devfns are still valid. */ - pci_reachable_set(pdev, &devfns, pci_devs_are_same_group); - /* start is known to have iommu_group_get() == NULL */ - __clear_bit(pdev->devfn, devfns.devfns); + group = get_pci_function_alias_group(pdev, devfns); + if (group) + return group; /* - * When MFD functions are included in the set due to ACS we assume that - * if ACS permits an internal loopback between functions it also permits - * the loopback to go downstream if any function is a bridge. + * When MFD's are included in the set due to ACS we assume that if ACS + * permits an internal loopback between functions it also permits the + * loopback to go downstream if a function is a bridge. * * It is less clear what aliases mean when applied to a bridge. For now * be conservative and also propagate the group downstream. */ - if (bitmap_empty(devfns.devfns, NR_DEVFNS)) - return NULL; - - for_each_set_bit(devfn, devfns.devfns, NR_DEVFNS) { - struct iommu_group *group; - struct pci_dev *pdev_slot; - - pdev_slot = pci_get_slot(pdev->bus, devfn); - group = iommu_group_get(&pdev_slot->dev); - pci_dev_put(pdev_slot); - if (group) { - if (WARN_ON(!(group->bus_data & - BUS_DATA_PCI_NON_ISOLATED))) - group->bus_data |= BUS_DATA_PCI_NON_ISOLATED; - return group; - } - } - return pci_group_alloc_non_isolated(); + __clear_bit(pdev->devfn & 0xFF, devfns); + if (!bitmap_empty(devfns, sizeof(devfns) * BITS_PER_BYTE)) + return pci_group_alloc_non_isolated(); + return NULL; } static struct iommu_group *pci_hierarchy_group(struct pci_dev *pdev) From c0d309c88adad1d799c275886f62901444236501 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:57 +0000 Subject: [PATCH 07/16] Revert "NVIDIA: SAUCE: PCI: Add pci_mfd_isolation()" This reverts commit 712ae82c642595229af5e2bf5a2d1a6500e56414. Signed-off-by: Tushar Dave --- drivers/pci/pci.h | 5 ---- drivers/pci/quirks.c | 58 +++++++++----------------------------------- drivers/pci/search.c | 30 ----------------------- include/linux/pci.h | 4 --- 4 files changed, 12 insertions(+), 85 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 69a7be7297282..bf23f4b96fb63 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -714,7 +714,6 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); int pci_dev_specific_enable_acs(struct pci_dev *dev); int pci_dev_specific_disable_acs_redir(struct pci_dev *dev); int pcie_failed_link_retrain(struct pci_dev *dev); -bool pci_dev_specific_mfd_isolated(struct pci_dev *dev); #else static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) @@ -733,10 +732,6 @@ static inline int pcie_failed_link_retrain(struct pci_dev *dev) { return -ENOTTY; } -static inline bool pci_dev_specific_mfd_isolated(struct pci_dev *dev) -{ - return false; -} #endif /* PCI error reporting and recovery */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f4f6a2f45733f..f1836d1d28692 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4646,8 +4646,6 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, quirk_chelsio_T5_disable_root_port_attributes); -#define PCI_ACS_QUIRK_ACS_ISOLATED BIT(16) - /* * pci_acs_ctrl_enabled - compare desired ACS controls with those provided * by a device @@ -4980,13 +4978,6 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u32 acs_flags) static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u32 acs_flags) { - /* - * The function cannot get P2P MMIO from the other functions in the MFD - * either even if the other functions do not have ACS or ACS quirks. - */ - if (acs_flags & PCI_ACS_QUIRK_ACS_ISOLATED) - return 1; - /* * SV, TB, and UF are not relevant to multifunction endpoints. * @@ -5203,7 +5194,18 @@ static const struct pci_dev_acs_enabled { { 0 } }; -static int pci_dev_call_acs_enabled(struct pci_dev *dev, u32 acs_flags) +/* + * pci_dev_specific_acs_enabled - check whether device provides ACS controls + * @dev: PCI device + * @acs_flags: Bitmask of desired ACS controls + * + * Returns: + * -ENOTTY: No quirk applies to this device; we can't tell whether the + * device provides the desired controls + * 0: Device does not provide all the desired controls + * >0: Device provides all the controls in @acs_flags + */ +int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) { const struct pci_dev_acs_enabled *i; int ret; @@ -5228,42 +5230,6 @@ static int pci_dev_call_acs_enabled(struct pci_dev *dev, u32 acs_flags) return -ENOTTY; } -/* - * pci_dev_specific_acs_enabled - check whether device provides ACS controls - * @dev: PCI device - * @acs_flags: Bitmask of desired ACS controls - * - * Returns: - * -ENOTTY: No quirk applies to this device; we can't tell whether the - * device provides the desired controls - * 0: Device does not provide all the desired controls - * >0: Device provides all the controls in @acs_flags - */ -int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) -{ - return pci_dev_call_acs_enabled(dev, acs_flags); -} - -/* - * pci_dev_specific_mfd_isolated- check whether a MFD function is isolated - * @dev: PCI device - * - * pci_dev_specific_acs_enabled() emulates the ACS flags using a quirk however - * historically Linux has not quirked every function in a MFD. - * pci_dev_specific_mfd_isolated() overrides the other function MFD checks and - * can consider a single function fully isolated from all other functions both - * for egress and ingress directions. - * - * Returns: - * false: No override, use normal PCI defined mechanisms - * true: Function is isolated from P2P to other functions in the device - */ -bool pci_dev_specific_mfd_isolated(struct pci_dev *dev) -{ - return pci_dev_call_acs_enabled(dev, PCI_ACS_QUIRK_ACS_ISOLATED | - PCI_ACS_ISOLATED) > 0; -} - /* Config space offset of Root Complex Base Address register */ #define INTEL_LPC_RCBA_REG 0xf0 /* 31:14 RCBA address */ diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 2be6881087b33..dc816dc4505c6 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -277,36 +277,6 @@ enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) } } -/* - * pci_mfd_isolated- check whether a MFD function is isolated - * @dev: PCI device - * - * True if the dev function on a MFD should be considered isolated from all - * other functions in the MFD. This is used to override ACS checks that might - * otherwise indicate the MFD function participates in an internal loopback. - * - * Returns: - * false: No override, use normal PCI defined mechanisms - * true: Function is isolated from P2P to other functions in the device - */ -bool pci_mfd_isolated(struct pci_dev *dev) -{ - /* - * For some reason AMD likes to put "dummy functions" in their PCI - * hierarchy as part of a multi function device. These are notable - * because they can't do anything. No BARs and no downstream bus. Since - * they cannot accept P2P or initiate any MMIO we consider them to be - * isolated from the rest of MFD. Since they often accompany a real PCI - * bridge with downstream devices it is important that the MFD be - * considered isolated. Annoyingly there is no ACS capability reported - * so we assume that a host bridge in a MFD with no MMIO has the special - * property of never accepting or initiating P2P operations. - */ - if (dev->class >> 8 == PCI_CLASS_BRIDGE_HOST && !pci_has_mmio(dev)) - return true; - return pci_dev_specific_mfd_isolated(dev); -} - static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { struct pci_bus *child; diff --git a/include/linux/pci.h b/include/linux/pci.h index 60e862dbb6bde..128c70a726329 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1259,7 +1259,6 @@ void pci_reachable_set(struct pci_dev *start, struct pci_reachable_set *devfns, bool (*reachable)(struct pci_dev *deva, struct pci_dev *devb)); enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus); -bool pci_mfd_isolated(struct pci_dev *dev); int pci_dev_present(const struct pci_device_id *ids); @@ -2033,9 +2032,6 @@ pci_reachable_set(struct pci_dev *start, struct pci_reachable_set *devfns, static inline enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) { return PCIE_NON_ISOLATED; } -static inline bool pci_mfd_isolated(struct pci_dev *dev) -{ return false; } - static inline int pci_dev_present(const struct pci_device_id *ids) { return 0; } From a6776892c4e8b28b1005a038e32e37f69b2fc37c Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:57 +0000 Subject: [PATCH 08/16] Revert "NVIDIA: SAUCE: PCI: Widen the acs_flags to u32 within the quirk callback" This reverts commit 25321198d083f76e87370da99da51ab3f1dc600a. Signed-off-by: Tushar Dave --- drivers/pci/quirks.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f1836d1d28692..83002b38eb64f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4657,20 +4657,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, * in @acs_ctrl_ena, i.e., the device provides all the access controls the * caller desires. Return 0 otherwise. */ -static int pci_acs_ctrl_enabled(u32 acs_ctrl_req, u32 acs_ctrl_ena) +static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena) { if ((acs_ctrl_req & acs_ctrl_ena) == acs_ctrl_req) return 1; return 0; } -static int pci_acs_ctrl_isolated(u32 acs_flags) +static int pci_acs_ctrl_isolated(u16 acs_flags) { return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } -static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u32 acs_flags); +static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags); /* * AMD has indicated that the devices below do not support peer-to-peer @@ -4697,7 +4697,7 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u32 acs_flags); * 1022:780f [AMD] FCH PCI Bridge * 1022:7809 [AMD] FCH USB OHCI Controller */ -static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags) { #ifdef CONFIG_ACPI struct acpi_table_header *header = NULL; @@ -4739,7 +4739,7 @@ static bool pci_quirk_cavium_acs_match(struct pci_dev *dev) } } -static int pci_quirk_cavium_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags) { if (!pci_quirk_cavium_acs_match(dev)) return -ENOTTY; @@ -4755,7 +4755,7 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u32 acs_flags) return pci_acs_ctrl_isolated(acs_flags); } -static int pci_quirk_xgene_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) { /* * X-Gene Root Ports matching this quirk do not allow peer-to-peer @@ -4770,7 +4770,7 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u32 acs_flags) * But the implementation could block peer-to-peer transactions between them * and provide ACS-like functionality. */ -static int pci_quirk_zhaoxin_pcie_ports_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_zhaoxin_pcie_ports_acs(struct pci_dev *dev, u16 acs_flags) { if (!pci_is_pcie(dev) || ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) && @@ -4840,7 +4840,7 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) return false; } -static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) { if (!pci_quirk_intel_pch_acs_match(dev)) return -ENOTTY; @@ -4861,7 +4861,7 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u32 acs_flags) * Port to pass traffic to another Root Port. All PCIe transactions are * terminated inside the Root Port. */ -static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) { return pci_acs_ctrl_isolated(acs_flags); } @@ -4872,12 +4872,12 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u32 acs_flags) * and validate bus numbers in requests, but does not provide an ACS * capability. */ -static int pci_quirk_nxp_rp_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_nxp_rp_acs(struct pci_dev *dev, u16 acs_flags) { return pci_acs_ctrl_isolated(acs_flags); } -static int pci_quirk_al_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) { if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) return -ENOTTY; @@ -4955,7 +4955,7 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) #define INTEL_SPT_ACS_CTRL (PCI_ACS_CAP + 4) -static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags) { int pos; u32 cap, ctrl; @@ -4976,7 +4976,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u32 acs_flags) return pci_acs_ctrl_enabled(acs_flags, ctrl); } -static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags) { /* * SV, TB, and UF are not relevant to multifunction endpoints. @@ -4992,7 +4992,7 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u32 acs_flags) PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT); } -static int pci_quirk_rciep_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_rciep_acs(struct pci_dev *dev, u16 acs_flags) { /* * Intel RCiEP's are required to allow p2p only on translated @@ -5005,7 +5005,7 @@ static int pci_quirk_rciep_acs(struct pci_dev *dev, u32 acs_flags) return pci_acs_ctrl_isolated(acs_flags); } -static int pci_quirk_brcm_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) { /* * iProc PAXB Root Ports don't advertise an ACS capability, but @@ -5025,7 +5025,7 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u32 acs_flags) * RP1000/RP2000 10G NICs(sp). * FF5xxx 40G/25G/10G NICs(aml). */ -static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u32 acs_flags) +static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u16 acs_flags) { switch (dev->device) { case 0x0100 ... 0x010F: /* EM */ @@ -5041,7 +5041,7 @@ static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u32 acs_flags) static const struct pci_dev_acs_enabled { u16 vendor; u16 device; - int (*acs_enabled)(struct pci_dev *dev, u32 acs_flags); + int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags); } pci_dev_acs_enabled[] = { { PCI_VENDOR_ID_ATI, 0x4385, pci_quirk_amd_sb_acs }, { PCI_VENDOR_ID_ATI, 0x439c, pci_quirk_amd_sb_acs }, From 5fde07f78cde22951d5dc4a5a1394a7b20859d5f Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:57 +0000 Subject: [PATCH 09/16] Revert "NVIDIA: SAUCE: PCI: Use pci_acs_ctrl_isolated() for pci_quirk_al_acs()" This reverts commit 7d21e1e81b62264042c09b5d09f3a9475ff7f07c. Signed-off-by: Tushar Dave --- drivers/pci/quirks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 83002b38eb64f..5ae759ea2eb90 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4890,7 +4890,9 @@ static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) * * Additionally, the root ports cannot send traffic to each other. */ - return pci_acs_ctrl_isolated(acs_flags); + acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); + + return acs_flags ? 0 : 1; } /* From aab8a7471e37260e0e64b87160fced648a4e2cac Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:57 +0000 Subject: [PATCH 10/16] Revert "NVIDIA: SAUCE: PCI: Use pci_quirk_mf_endpoint_acs() for pci_quirk_amd_sb_acs()" This reverts commit 7ff8d9b4792ece3e1f1e031fbca59ed7a5833d7b. Signed-off-by: Tushar Dave --- drivers/pci/quirks.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5ae759ea2eb90..789fea8d7c64a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4670,8 +4670,6 @@ static int pci_acs_ctrl_isolated(u16 acs_flags) PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } -static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags); - /* * AMD has indicated that the devices below do not support peer-to-peer * in any system where they are found in the southbridge with an AMD @@ -4714,7 +4712,10 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags) acpi_put_table(header); - return pci_quirk_mf_endpoint_acs(dev, acs_flags); + /* Filter out flags not applicable to multifunction */ + acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT); + + return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_RR | PCI_ACS_CR); #else return -ENODEV; #endif From cecb8ce8f767e7c2fe7b2d0f4d8079f0ea61f6a0 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 11/16] Revert "NVIDIA: SAUCE: PCI: Remove duplication in calling pci_acs_ctrl_enabled()" This reverts commit 11071013382c52f7d7cb632ecd1673b06d592046. Signed-off-by: Tushar Dave --- drivers/pci/quirks.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 789fea8d7c64a..aad419b819a6d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4664,12 +4664,6 @@ static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena) return 0; } -static int pci_acs_ctrl_isolated(u16 acs_flags) -{ - return pci_acs_ctrl_enabled(acs_flags, - PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); -} - /* * AMD has indicated that the devices below do not support peer-to-peer * in any system where they are found in the southbridge with an AMD @@ -4753,7 +4747,8 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags) * hardware implements and enables equivalent ACS functionality for * these flags. */ - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) @@ -4763,7 +4758,8 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) * transactions with others, allowing masking out these bits as if they * were unimplemented in the ACS capability. */ - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } /* @@ -4786,7 +4782,8 @@ static int pci_quirk_zhaoxin_pcie_ports_acs(struct pci_dev *dev, u16 acs_flags) case 0x0710 ... 0x071e: case 0x0721: case 0x0723 ... 0x0752: - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } return false; @@ -4847,7 +4844,8 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) return -ENOTTY; if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK) - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); return pci_acs_ctrl_enabled(acs_flags, 0); } @@ -4864,7 +4862,8 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) */ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) { - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } /* @@ -4875,7 +4874,8 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) */ static int pci_quirk_nxp_rp_acs(struct pci_dev *dev, u16 acs_flags) { - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) @@ -5005,7 +5005,8 @@ static int pci_quirk_rciep_acs(struct pci_dev *dev, u16 acs_flags) if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END) return -ENOTTY; - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) @@ -5016,7 +5017,8 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) * Allow each Root Port to be in a separate IOMMU group by masking * SV/RR/CR/UF bits. */ - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } /* @@ -5035,7 +5037,8 @@ static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u16 acs_flags) case 0x1001: case 0x2001: /* SP */ case 0x5010: case 0x5025: case 0x5040: /* AML */ case 0x5110: case 0x5125: case 0x5140: /* AML */ - return pci_acs_ctrl_isolated(acs_flags); + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } return false; From 02eb53f1800dd3ab802f3cb4bbe057b31d6e535b Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 12/16] Revert "NVIDIA: SAUCE: PCI: Add pci_reachable_set()" This reverts commit 3c1595166729831ded5f927937cbdece66ec91dd. Signed-off-by: Tushar Dave --- drivers/pci/search.c | 90 -------------------------------------------- include/linux/pci.h | 12 ------ 2 files changed, 102 deletions(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index dc816dc4505c6..a13fad53e44df 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -585,93 +585,3 @@ int pci_dev_present(const struct pci_device_id *ids) return 0; } EXPORT_SYMBOL(pci_dev_present); - -/** - * pci_reachable_set - Generate a bitmap of devices within a reachability set - * @start: First device in the set - * @devfns: The set of devices on the bus - * @reachable: Callback to tell if two devices can reach each other - * - * Compute a bitmap where every set bit is a device on the bus that is reachable - * from the start device, including the start device. Reachability between two - * devices is determined by a callback function. - * - * This is a non-recursive implementation that invokes the callback once per - * pair. The callback must be commutative: - * reachable(a, b) == reachable(b, a) - * reachable() can form a cyclic graph: - * reachable(a,b) == reachable(b,c) == reachable(c,a) == true - * - * Since this function is limited to a single bus the largest set can be 256 - * devices large. - */ -void pci_reachable_set(struct pci_dev *start, struct pci_reachable_set *devfns, - bool (*reachable)(struct pci_dev *deva, - struct pci_dev *devb)) -{ - struct pci_reachable_set todo_devfns = {}; - struct pci_reachable_set next_devfns = {}; - struct pci_bus *bus = start->bus; - bool again; - - /* Assume devfn of all PCI devices is bounded by MAX_NR_DEVFNS */ - static_assert(sizeof(next_devfns.devfns) * BITS_PER_BYTE >= - MAX_NR_DEVFNS); - - memset(devfns, 0, sizeof(devfns->devfns)); - __set_bit(start->devfn, devfns->devfns); - __set_bit(start->devfn, next_devfns.devfns); - - down_read(&pci_bus_sem); - while (true) { - unsigned int devfna; - unsigned int i; - - /* - * For each device that hasn't been checked compare every - * device on the bus against it. - */ - again = false; - for_each_set_bit(devfna, next_devfns.devfns, MAX_NR_DEVFNS) { - struct pci_dev *deva = NULL; - struct pci_dev *devb; - - list_for_each_entry(devb, &bus->devices, bus_list) { - if (devb->devfn == devfna) - deva = devb; - - if (test_bit(devb->devfn, devfns->devfns)) - continue; - - if (!deva) { - deva = devb; - list_for_each_entry_continue( - deva, &bus->devices, bus_list) - if (deva->devfn == devfna) - break; - } - - if (!reachable(deva, devb)) - continue; - - __set_bit(devb->devfn, todo_devfns.devfns); - again = true; - } - } - - if (!again) - break; - - /* - * Every new bit adds a new deva to check, reloop the whole - * thing. Expect this to be rare. - */ - for (i = 0; i != ARRAY_SIZE(devfns->devfns); i++) { - devfns->devfns[i] |= todo_devfns.devfns[i]; - next_devfns.devfns[i] = todo_devfns.devfns[i]; - todo_devfns.devfns[i] = 0; - } - } - up_read(&pci_bus_sem); -} -EXPORT_SYMBOL_GPL(pci_reachable_set); diff --git a/include/linux/pci.h b/include/linux/pci.h index 128c70a726329..c91f91355351e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -834,10 +834,6 @@ struct pci_dynids { struct list_head list; /* For IDs added at runtime */ }; -struct pci_reachable_set { - DECLARE_BITMAP(devfns, 256); -}; - enum pci_bus_isolation { /* * The bus is off a root port and the root port has isolated ACS flags @@ -1255,9 +1251,6 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from); -void pci_reachable_set(struct pci_dev *start, struct pci_reachable_set *devfns, - bool (*reachable)(struct pci_dev *deva, - struct pci_dev *devb)); enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus); int pci_dev_present(const struct pci_device_id *ids); @@ -2024,11 +2017,6 @@ static inline struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from) { return NULL; } -static inline void -pci_reachable_set(struct pci_dev *start, struct pci_reachable_set *devfns, - bool (*reachable)(struct pci_dev *deva, struct pci_dev *devb)) -{ } - static inline enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) { return PCIE_NON_ISOLATED; } From a7f84350b578fefa6563eff9769e3720a5e3889b Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 13/16] Revert "NVIDIA: SAUCE: iommu: Organize iommu_group by member size" This reverts commit b48d6bedb2064f2e5bb02d03d6ee3572c3530a92. Signed-off-by: Tushar Dave --- drivers/iommu/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 7a13d4d8a8892..12f0cc6684f7b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -58,13 +58,13 @@ struct iommu_group { void *iommu_data; void (*iommu_data_release)(void *iommu_data); char *name; + int id; struct iommu_domain *default_domain; struct iommu_domain *blocking_domain; struct iommu_domain *domain; struct list_head entry; - void *owner; unsigned int owner_cnt; - int id; + void *owner; /* Used by the device_group() callbacks */ u32 bus_data; From f17333e159baac239a473d4e0622c1410ceaaab9 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 14/16] Revert "NVIDIA: SAUCE: iommu: Compute iommu_groups properly for PCIe switches" This reverts commit 6dc364981fe81d3e91883b20f7e98d23bc407e54. Signed-off-by: Tushar Dave --- drivers/iommu/iommu.c | 264 ++++++++++-------------------------------- include/linux/pci.h | 3 - 2 files changed, 60 insertions(+), 207 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 12f0cc6684f7b..415683c37606a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -65,16 +65,8 @@ struct iommu_group { struct list_head entry; unsigned int owner_cnt; void *owner; - - /* Used by the device_group() callbacks */ - u32 bus_data; }; -/* - * Everything downstream of this group should share it. - */ -#define BUS_DATA_PCI_NON_ISOLATED BIT(0) - struct group_device { struct list_head list; struct device *dev; @@ -1468,6 +1460,25 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, return NULL; } +struct group_for_pci_data { + struct pci_dev *pdev; + struct iommu_group *group; +}; + +/* + * DMA alias iterator callback, return the last seen device. Stop and return + * the IOMMU group if we find one along the way. + */ +static int get_pci_alias_or_group(struct pci_dev *pdev, u16 alias, void *opaque) +{ + struct group_for_pci_data *data = opaque; + + data->pdev = pdev; + data->group = iommu_group_get(&pdev->dev); + + return data->group != NULL; +} + /* * Generic device_group call-back function. It just allocates one * iommu-group per device. @@ -1499,226 +1510,71 @@ struct iommu_group *generic_single_device_group(struct device *dev) } EXPORT_SYMBOL_GPL(generic_single_device_group); -static struct iommu_group *pci_group_alloc_non_isolated(void) -{ - struct iommu_group *group; - - group = iommu_group_alloc(); - if (IS_ERR(group)) - return group; - group->bus_data |= BUS_DATA_PCI_NON_ISOLATED; - return group; -} - -static struct iommu_group *pci_get_alias_group(struct pci_dev *pdev) -{ - struct iommu_group *group; - DECLARE_BITMAP(devfns, 256) = {}; - - /* - * Look for existing groups on device aliases. If we alias another - * device or another device aliases us, use the same group. - */ - group = get_pci_alias_group(pdev, devfns); - if (group) - return group; - - /* - * Look for existing groups on non-isolated functions on the same - * slot and aliases of those funcions, if any. No need to clear - * the search bitmap, the tested devfns are still valid. - */ - group = get_pci_function_alias_group(pdev, devfns); - if (group) - return group; - - /* - * When MFD's are included in the set due to ACS we assume that if ACS - * permits an internal loopback between functions it also permits the - * loopback to go downstream if a function is a bridge. - * - * It is less clear what aliases mean when applied to a bridge. For now - * be conservative and also propagate the group downstream. - */ - __clear_bit(pdev->devfn & 0xFF, devfns); - if (!bitmap_empty(devfns, sizeof(devfns) * BITS_PER_BYTE)) - return pci_group_alloc_non_isolated(); - return NULL; -} - -static struct iommu_group *pci_hierarchy_group(struct pci_dev *pdev) -{ - /* - * SRIOV functions may resid on a virtual bus, jump directly to the PFs - * bus in all cases. - */ - struct pci_bus *bus = pci_physfn(pdev)->bus; - struct iommu_group *group; - - /* Nothing upstream of this */ - if (pci_is_root_bus(bus)) - return NULL; - - /* - * !self is only for SRIOV virtual busses which should have been - * excluded above. - */ - if (WARN_ON(!bus->self)) - return ERR_PTR(-EINVAL); - - group = iommu_group_get(&bus->self->dev); - if (!group) { - /* - * If the upstream bridge needs the same group as pdev then - * there is no way for it's pci_device_group() to discover it. - */ - dev_err(&pdev->dev, - "PCI device is probing out of order, upstream bridge device of %s is not probed yet\n", - pci_name(bus->self)); - return ERR_PTR(-EPROBE_DEFER); - } - if (group->bus_data & BUS_DATA_PCI_NON_ISOLATED) - return group; - iommu_group_put(group); - return NULL; -} - /* - * For legacy PCI we have two main considerations when forming groups: - * - * 1) In PCI we can loose the RID inside the fabric, or some devices will use - * the wrong RID. The PCI core calls this aliasing, but from an IOMMU - * perspective it means that a PCI device may have multiple RIDs and a - * single RID may represent many PCI devices. This effectively means all the - * aliases must share a translation, thus group, because the IOMMU cannot - * tell devices apart. - * - * 2) PCI permits a bus segment to claim an address even if the transaction - * originates from an end point not the CPU. When it happens it is called - * peer to peer. Claiming a transaction in the middle of the bus hierarchy - * bypasses the IOMMU translation. The IOMMU subsystem rules require these - * devices to be placed in the same group because they lack isolation from - * each other. In PCI Express the ACS system can be used to inhibit this and - * force transactions to go to the IOMMU. - * - * From a PCI perspective any given PCI bus is either isolating or - * non-isolating. Isolating means downstream originated transactions always - * progress toward the CPU and do not go to other devices on the bus - * segment, while non-isolating means downstream originated transactions can - * progress back downstream through another device on the bus segment. - * - * Beyond buses a multi-function device or bridge can also allow - * transactions to loop back internally from one function to another. - * - * Once a PCI bus becomes non isolating the entire downstream hierarchy of - * that bus becomes a single group. + * Use standard PCI bus topology, isolation features, and DMA alias quirks + * to find or create an IOMMU group for a device. */ struct iommu_group *pci_device_group(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct iommu_group *group; - struct pci_dev *real_pdev; + struct group_for_pci_data data; + struct pci_bus *bus; + struct iommu_group *group = NULL; + u64 devfns[4] = { 0 }; if (WARN_ON(!dev_is_pci(dev))) return ERR_PTR(-EINVAL); /* - * Arches can supply a completely different PCI device that actually - * does DMA. + * Find the upstream DMA alias for the device. A device must not + * be aliased due to topology in order to have its own IOMMU group. + * If we find an alias along the way that already belongs to a + * group, use it. */ - real_pdev = pci_real_dma_dev(pdev); - if (real_pdev != pdev) { - group = iommu_group_get(&real_pdev->dev); - if (!group) { - /* - * The real_pdev has not had an iommu probed to it. We - * can't create a new group here because there is no way - * for pci_device_group(real_pdev) to pick it up. - */ - dev_err(dev, - "PCI device is probing out of order, real device of %s is not probed yet\n", - pci_name(real_pdev)); - return ERR_PTR(-EPROBE_DEFER); - } - return group; - } + if (pci_for_each_dma_alias(pdev, get_pci_alias_or_group, &data)) + return data.group; - if (pdev->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT) - return iommu_group_alloc(); + pdev = data.pdev; - /* Anything upstream of this enforcing non-isolated? */ - group = pci_hierarchy_group(pdev); - if (group) - return group; + /* + * Continue upstream from the point of minimum IOMMU granularity + * due to aliases to the point where devices are protected from + * peer-to-peer DMA by PCI ACS. Again, if we find an existing + * group, use it. + */ + for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { + if (!bus->self) + continue; - switch (pci_bus_isolated(pci_physfn(pdev)->bus)) { - case PCIE_ISOLATED: - /* Check multi-function groups and same-bus devfn aliases */ - group = pci_get_alias_group(pdev); + if (pci_acs_path_enabled(bus->self, NULL, PCI_ACS_ISOLATED)) + break; + + pdev = bus->self; + + group = iommu_group_get(&pdev->dev); if (group) return group; - - /* No shared group found, allocate new */ - return iommu_group_alloc(); + } /* - * On legacy PCI there is no RID at an electrical level. On PCI-X the - * RID of the bridge may be used in some cases instead of the - * downstream's RID. This creates aliasing problems. PCI/PCI-X doesn't - * provide isolation either. The end result is that as soon as we hit a - * PCI/PCI-X bus we switch to non-isolated for the whole downstream for - * both aliasing and isolation reasons. The bridge has to be included in - * the group because of the aliasing. + * Look for existing groups on device aliases. If we alias another + * device or another device aliases us, use the same group. */ - case PCI_BRIDGE_NON_ISOLATED: - /* A PCIe switch where the USP has MMIO and is not isolated. */ - case PCIE_NON_ISOLATED: - group = iommu_group_get(&pdev->bus->self->dev); - if (WARN_ON(!group)) - return ERR_PTR(-EINVAL); - /* - * No need to be concerned with aliases here since we are going - * to put the entire downstream tree in the bridge/USP's group. - */ - group->bus_data |= BUS_DATA_PCI_NON_ISOLATED; + group = get_pci_alias_group(pdev, (unsigned long *)devfns); + if (group) return group; /* - * It is a PCI bus and the upstream bridge/port does not alias or allow - * P2P. - */ - case PCI_BUS_NON_ISOLATED: - /* - * It is a PCIe switch and the DSP cannot reach the USP. The DSP's - * are not isolated from each other and share a group. + * Look for existing groups on non-isolated functions on the same + * slot and aliases of those funcions, if any. No need to clear + * the search bitmap, the tested devfns are still valid. */ - case PCIE_SWITCH_DSP_NON_ISOLATED: { - struct pci_dev *piter = NULL; + group = get_pci_function_alias_group(pdev, (unsigned long *)devfns); + if (group) + return group; - /* - * All the downstream devices on the bus share a group. If this - * is a PCIe switch then they will all be DSPs - */ - for_each_pci_dev(piter) { - if (piter->bus != pdev->bus) - continue; - group = iommu_group_get(&piter->dev); - if (group) { - pci_dev_put(piter); - if (WARN_ON(!(group->bus_data & - BUS_DATA_PCI_NON_ISOLATED))) - group->bus_data |= - BUS_DATA_PCI_NON_ISOLATED; - return group; - } - } - return pci_group_alloc_non_isolated(); - } - default: - break; - } - WARN_ON(true); - return ERR_PTR(-EINVAL); + /* No shared group found, allocate new */ + return iommu_group_alloc(); } EXPORT_SYMBOL_GPL(pci_device_group); diff --git a/include/linux/pci.h b/include/linux/pci.h index c91f91355351e..6cf1b88b6205b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2026,9 +2026,6 @@ static inline int pci_dev_present(const struct pci_device_id *ids) #define no_pci_devices() (1) #define pci_dev_put(dev) do { } while (0) -static inline struct pci_dev *pci_real_dma_dev(struct pci_dev *dev) -{ return dev; } - static inline void pci_set_master(struct pci_dev *dev) { } static inline void pci_clear_master(struct pci_dev *dev) { } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } From ab7fdccc131e29d52b88fe8c17e9d026c1c7a104 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 15/16] Revert "NVIDIA: SAUCE: PCI: Add pci_bus_isolation()" This reverts commit 91219dd9d6638b894244e2ac0155c24617ebf698. Signed-off-by: Tushar Dave --- drivers/pci/search.c | 164 ------------------------------------------- include/linux/pci.h | 31 -------- 2 files changed, 195 deletions(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a13fad53e44df..53840634fbfc2 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -113,170 +113,6 @@ 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; -} - -/** - * 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; - - /* - * This bus was created by pci_register_host_bridge(). The spec provides - * no way to tell what kind of bus this is, for PCIe we expect this to - * be internal to the root complex and not covered by any spec behavior. - * Linux has historically been optimistic about this bus and treated it - * as isolating. Given that the behavior of the root complex and the ACS - * behavior of RCiEP's is explicitly not specified we hope that the - * implementation is directing everything that reaches the root bus to - * the IOMMU. - */ - if (pci_is_root_bus(bus)) - return PCIE_ISOLATED; - - /* - * bus->self is only NULL for SRIOV VFs, it represents a "virtual" bus - * within Linux to hold any bus numbers consumed by VF RIDs. Caller must - * use pci_physfn() to get the bus for calling this function. - */ - if (WARN_ON(!bridge)) - return PCI_BRIDGE_NON_ISOLATED; - - /* - * The bridge is not a PCIe bridge therefore this bus is PCI/PCI-X. - * - * PCI does not have anything like ACS. Any down stream device can bus - * master an address that any other downstream device can claim. No - * isolation is possible. - */ - if (!pci_is_pcie(bridge)) { - if (bridge->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS) - type = PCI_EXP_TYPE_PCI_BRIDGE; - else - return PCI_BRIDGE_NON_ISOLATED; - } else { - type = pci_pcie_type(bridge); - } - - switch (type) { - /* - * Since PCIe links are point to point root and downstream ports are - * isolated if their own MMIO cannot be reached. - */ - case PCI_EXP_TYPE_ROOT_PORT: - case PCI_EXP_TYPE_DOWNSTREAM: - if (!pci_acs_enabled(bridge, PCI_ACS_ISOLATED)) - return PCIE_NON_ISOLATED; - return PCIE_ISOLATED; - - /* - * bus is the interior bus of a PCI-E switch where ACS rules apply. - */ - case PCI_EXP_TYPE_UPSTREAM: - return pcie_switch_isolated(bus); - - /* - * PCIe to PCI/PCI-X - this bus is PCI. - */ - case PCI_EXP_TYPE_PCI_BRIDGE: - /* - * A PCIe express bridge will use the subordinate bus number - * with a 0 devfn as the RID in some cases. This causes all - * subordinate devfns to alias with 0, which is the same - * grouping as PCI_BUS_NON_ISOLATED. The RID of the bridge - * itself is only used by the bridge. - * - * However, if the bridge has MMIO then we will assume the MMIO - * is not isolated due to no ACS controls on this bridge type. - */ - if (pci_has_mmio(bridge)) - return PCI_BRIDGE_NON_ISOLATED; - return PCI_BUS_NON_ISOLATED; - - /* - * PCI/PCI-X to PCIe - this bus is PCIe. We already know there must be a - * PCI bus upstream of this bus, so just return non-isolated. If - * upstream is PCI-X the PCIe RID should be preserved, but for PCI the - * RID will be lost. - */ - case PCI_EXP_TYPE_PCIE_BRIDGE: - return PCI_BRIDGE_NON_ISOLATED; - - default: - return PCI_BRIDGE_NON_ISOLATED; - } -} - static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { struct pci_bus *child; diff --git a/include/linux/pci.h b/include/linux/pci.h index 6cf1b88b6205b..4b30e824eaf76 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -834,32 +834,6 @@ struct pci_dynids { struct list_head list; /* For IDs added at runtime */ }; -enum pci_bus_isolation { - /* - * The bus is off a root port and the root port has isolated ACS flags - * or the bus is part of a PCIe switch and the switch has isolated ACS - * flags. - */ - PCIE_ISOLATED, - /* - * The switch's DSP's are not isolated from each other but are isolated - * from the USP. - */ - PCIE_SWITCH_DSP_NON_ISOLATED, - /* The above and the USP's MMIO is not isolated. */ - PCIE_NON_ISOLATED, - /* - * A PCI/PCI-X bus, no isolation. This is like - * PCIE_SWITCH_DSP_NON_ISOLATED in that the upstream bridge is isolated - * from the bus. The bus itself may also have a shared alias of devfn=0. - */ - PCI_BUS_NON_ISOLATED, - /* - * The above and the bridge's MMIO is not isolated and the bridge's RID - * may be an alias. - */ - PCI_BRIDGE_NON_ISOLATED, -}; /* * PCI Error Recovery System (PCI-ERS). If a PCI device driver provides @@ -1251,8 +1225,6 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from); -enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus); - int pci_dev_present(const struct pci_device_id *ids); int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, @@ -2017,9 +1989,6 @@ static inline struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from) { return NULL; } -static inline enum pci_bus_isolation pci_bus_isolated(struct pci_bus *bus) -{ return PCIE_NON_ISOLATED; } - static inline int pci_dev_present(const struct pci_device_id *ids) { return 0; } From 65e9cb376edb806579a396f5c5936b950466dcb0 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Mon, 25 Aug 2025 18:31:58 +0000 Subject: [PATCH 16/16] Revert "NVIDIA: SAUCE: PCI: Move REQ_ACS_FLAGS into pci_regs.h as PCI_ACS_ISOLATED" This reverts commit 273d22387420018421cce94319ae47cf729e185a. Signed-off-by: Tushar Dave --- drivers/iommu/iommu.c | 16 +++++++++++++--- include/uapi/linux/pci_regs.h | 10 ---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 415683c37606a..b0c4f8446d0c2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1384,6 +1384,16 @@ EXPORT_SYMBOL_GPL(iommu_group_id); static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, unsigned long *devfns); +/* + * To consider a PCI device isolated, we require ACS to support Source + * Validation, Request Redirection, Completer Redirection, and Upstream + * Forwarding. This effectively means that devices cannot spoof their + * requester ID, requests and completions cannot be redirected, and all + * transactions are forwarded upstream, even as it passes through a + * bridge where the target device is downstream. + */ +#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) + /* * For multifunction devices which are not isolated from each other, find * all the other non-isolated functions and look for existing groups. For @@ -1396,13 +1406,13 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, struct pci_dev *tmp = NULL; struct iommu_group *group; - if (!pdev->multifunction || pci_acs_enabled(pdev, PCI_ACS_ISOLATED)) + if (!pdev->multifunction || pci_acs_enabled(pdev, REQ_ACS_FLAGS)) return NULL; for_each_pci_dev(tmp) { if (tmp == pdev || tmp->bus != pdev->bus || PCI_SLOT(tmp->devfn) != PCI_SLOT(pdev->devfn) || - pci_acs_enabled(tmp, PCI_ACS_ISOLATED)) + pci_acs_enabled(tmp, REQ_ACS_FLAGS)) continue; group = get_pci_alias_group(tmp, devfns); @@ -1546,7 +1556,7 @@ struct iommu_group *pci_device_group(struct device *dev) if (!bus->self) continue; - if (pci_acs_path_enabled(bus->self, NULL, PCI_ACS_ISOLATED)) + if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; pdev = bus->self; diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index f9de4734c4cd1..3445c4970e4d8 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -1004,16 +1004,6 @@ #define PCI_ACS_CTRL 0x06 /* ACS Control Register */ #define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ -/* - * To consider a PCI device isolated, we require ACS to support Source - * Validation, Request Redirection, Completer Redirection, and Upstream - * Forwarding. This effectively means that devices cannot spoof their - * requester ID, requests and completions cannot be redirected, and all - * transactions are forwarded upstream, even as it passes through a - * bridge where the target device is downstream. - */ -#define PCI_ACS_ISOLATED (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) - /* SATA capability */ #define PCI_SATA_REGS 4 /* SATA REGs specifier */ #define PCI_SATA_REGS_MASK 0xF /* location - BAR#/inline */