[PATCH v3 10/17] PCI: Account for ACS egress control in isolation checks
From: Leon Romanovsky
Date: Tue Aug 11 2026 - 05:41:37 EST
From: Leon Romanovsky <leonro@xxxxxxxxxx>
pci_acs_enabled() treats P2P Request Redirect as effective whenever its
control bit is set. PCIe r7.0, sec 6.12.3, table 6-11 lets an enabled
Egress Control Vector override it: a clear vector bit routes the request
directly.
IOMMU grouping uses this check to prove peer requests cannot bypass the
IOMMU, but cannot know every applicable vector bit, so Request Redirect
gives no such guarantee while Egress Control is enabled.
Report Request Redirect as ineffective there, merging the devices into
one IOMMU group, and report no isolation when the register cannot be
read. Apply the same rule to the Intel SPT PCH quirk.
Unlike Direct Translated P2P this holds for an Untranslated Request too,
so it applies in both scopes. pci_enable_pasid() therefore fails on a
path where a port has Egress Control enabled, because Request Redirect
no longer shows that a Request carrying a PASID reaches the translation
agent.
Fixes: ad805758c0eb ("PCI: add ACS validation utility")
Reviewed-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxx>
---
drivers/pci/pci.c | 3 ++-
drivers/pci/pci.h | 13 +++++++++++--
drivers/pci/quirks.c | 7 +++++--
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8d165c9534ff..a633f473590f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3623,7 +3623,8 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags,
if (!pos)
return false;
- pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+ if (pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl))
+ return false;
if (pci_acs_rr_ineffective(ctrl, acs_flags, scope))
return false;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d3ea9b2bb7fc..32394e349766 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1056,6 +1056,12 @@ void pci_enable_acs(struct pci_dev *dev);
* says nothing about an Untranslated Request, so a caller asking only about
* those is unaffected.
*
+ * Egress Control can override Request Redirect for any peer Request,
+ * Untranslated ones included, so it applies in either scope. This
+ * target-independent test cannot prove that every applicable Egress Control
+ * Vector bit is set, so Request Redirect does not guarantee that the Request
+ * leaves the direct path while Egress Control is enabled.
+ *
* @ctrl is the ACS Control register, @acs_flags the controls the caller asked
* for, and @scope the Requests its answer has to cover.
*/
@@ -1065,8 +1071,11 @@ static inline bool pci_acs_rr_ineffective(u32 ctrl, u16 acs_flags,
if (!(acs_flags & PCI_ACS_RR))
return false;
- return scope == PCI_ACS_SCOPE_ALL &&
- (ctrl & PCI_ACS_DT) && !(ctrl & PCI_ACS_TB);
+ if (scope == PCI_ACS_SCOPE_ALL &&
+ (ctrl & PCI_ACS_DT) && !(ctrl & PCI_ACS_TB))
+ return true;
+
+ return ctrl & PCI_ACS_EC;
}
int pci_acs_egress_ctrl_is_set(struct pci_dev *pdev, struct pci_dev *target);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 8b50cd0e5114..cee6be63cadd 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4998,8 +4998,11 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags,
return -ENOTTY;
/* see pci_acs_flags_enabled() */
- pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
- pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
+ if (pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap))
+ return 0;
+
+ if (pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl))
+ return 0;
if (pci_acs_rr_ineffective(ctrl, acs_flags, scope))
return 0;
--
2.55.0