[PATCH 06/13] PCI: Account for ACS egress control in isolation checks

Leon Romanovsky <[email protected]> Sun, 2 Aug 2026 18:09:44 +0300
Newsgroups org.kernel.vger.linux-pci,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Leon Romanovsky <[email protected]>

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.

Signed-off-by: Leon Romanovsky <[email protected]>
---
 drivers/pci/pci.c    | 12 +++++++++++-
 drivers/pci/quirks.c | 10 ++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 154eb08036ad..bc1c3b68c131 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3620,7 +3620,8 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
 	 */
 	acs_flags &= (pdev->acs_capabilities | PCI_ACS_EC);
 
-	pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+	if (pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl))
+		return false;
 
 	/*
 	 * Direct Translated P2P routes a Translated Request to the peer
@@ -3630,6 +3631,15 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
 	if (request_redirect && (ctrl & PCI_ACS_DT) && !(ctrl & PCI_ACS_TB))
 		return false;
 
+	/*
+	 * Egress Control can override Request Redirect for peer requests.
+	 * This target-independent check cannot prove that every applicable
+	 * Egress Control Vector bit is set, so RR does not guarantee isolation
+	 * while EC is enabled.
+	 */
+	if (request_redirect && (ctrl & PCI_ACS_EC))
+		return false;
+
 	return (ctrl & acs_flags) == acs_flags;
 }
 
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index bb4c09cbbd10..ebfe902b0118 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4990,15 +4990,21 @@ 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);
+	if (pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap))
+		return 0;
 	acs_flags &= (cap | PCI_ACS_EC);
 
-	pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
+	if (pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl))
+		return 0;
 
 	/* Direct Translated P2P may bypass Request Redirect. */
 	if (request_redirect && (ctrl & PCI_ACS_DT) && !(ctrl & PCI_ACS_TB))
 		return 0;
 
+	/* Egress Control may override Request Redirect for peer requests. */
+	if (request_redirect && (ctrl & PCI_ACS_EC))
+		return 0;
+
 	return pci_acs_ctrl_enabled(acs_flags, ctrl);
 }
 

-- 
2.55.0