| Message ID | SI2PR01MB439314CABFD64FC0586F2FF8DCB62@SI2PR01MB4393.apcprd01.prod.exchangelabs.com |
|---|---|
| State | New |
| Headers | show |
| Series | PCI: Add support for ACS Enhanced Capability | expand |
> The enhanced ACS controls introduced by PCIe Gen 5 ensures better device > isolation. On devices that support the PCI_ACS_ECAP capability, the > controls are required to be enabled properly: > - ACS I/O Request Blocking needs to be enabled to avoid unintended > upstream I/O requests. > - ACS DSP and USP Memory Target Access Control needs to be set with > Request Redirect or Request Blocking to ensure the Downstream and > Upstream Port memory resource ranges are not accessed by upstream > memory requests. > - ACS Unclaimed Request Redirect needs to be enabled to ensure accesses to > areas that lies within a Switch's Upstream Port memory apertures but not > within any Downstream Port memory apertures get redirected. > > To maintain compatibility with legacy devices that lack PCI_ACS_ECAP > support, pci_acs_enabled() skips checking for the capability. > > Signed-off-by: Wei Wang <wei.w.wang@hotmail.com> Sashiko has reviewed this patch and found no issues. It looks great!
On Thu, 3 Sep 2026, Wei Wang wrote: > The enhanced ACS controls introduced by PCIe Gen 5 ensures better device > isolation. On devices that support the PCI_ACS_ECAP capability, the > controls are required to be enabled properly: > - ACS I/O Request Blocking needs to be enabled to avoid unintended > upstream I/O requests. > - ACS DSP and USP Memory Target Access Control needs to be set with > Request Redirect or Request Blocking to ensure the Downstream and > Upstream Port memory resource ranges are not accessed by upstream > memory requests. > - ACS Unclaimed Request Redirect needs to be enabled to ensure accesses to > areas that lies within a Switch's Upstream Port memory apertures but not > within any Downstream Port memory apertures get redirected. > > To maintain compatibility with legacy devices that lack PCI_ACS_ECAP > support, pci_acs_enabled() skips checking for the capability. > > Signed-off-by: Wei Wang <wei.w.wang@hotmail.com> > Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> > --- > drivers/pci/pci.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 65 insertions(+) > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 50a3b61f9898..b951195d5adc 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -3648,6 +3648,57 @@ void pci_configure_ari(struct pci_dev *dev) > } > } > > +static bool pci_dev_has_memory_bars(struct pci_dev *pdev) > +{ > + int i; > + > + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { > + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) > + return true; > + } > + > + return false; > +} > + > +static bool pci_acs_ecap_enabled(struct pci_dev *pdev, u16 ctrl) > +{ > + struct pci_dev *upstream_pdev; > + > + /* > + * For ACS DSP/USP Memory Target Access Control, either Request > + * Redirect or Request Blocking must be enabled to enforce isolation. > + * According to PCIe spec 7.0, the DSP Memory Target Access is > + * applicable to both Root Ports and Switch Downstream Ports that have > + * applicable Memory BAR space to protect. So if the device does not > + * have a Memory BAR, it skips the check. > + */ > + if (pci_dev_has_memory_bars(pdev) && > + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RB && > + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RR) > + return false; > + > + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) { > + upstream_pdev = pci_upstream_bridge(pdev); > + > + /* > + * The USP Memory Target Access is only applicable to > + * downstream ports that have applicable Memory BAR space in > + * the Switch Upstream Port to protect. > + */ > + if (upstream_pdev && pci_dev_has_memory_bars(upstream_pdev) && > + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RB && > + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RR) > + return false; > + > + /* PCI_ACS_URRC is applicable to Downstream Ports only. */ > + if (!(ctrl & PCI_ACS_URRC)) > + return false; > + } > + > + /* PCI_ACS_IB is applicable to both Root and Downstream Ports. */ > + return !!(ctrl & PCI_ACS_IB); When the return type is bool, !!() construct is unnecessary. > +} > + > static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) > { > int pos; > @@ -3665,6 +3716,18 @@ 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 (acs_flags & PCI_ACS_ECAP) { > + if (!pci_acs_ecap_enabled(pdev, ctrl)) > + return false; > + /* > + * The check for the required controls in PCI_ACS_ECAP has > + * passed. Clear the ECAP flag and continue to check the > + * basic ACS controls. > + */ > + acs_flags &= ~PCI_ACS_ECAP; > + } > + > return (ctrl & acs_flags) == acs_flags; > } > > @@ -3723,6 +3786,8 @@ bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) > */ > case PCI_EXP_TYPE_DOWNSTREAM: > case PCI_EXP_TYPE_ROOT_PORT: > + /* PCI_ACS_ECAP applies to Root and Downstream Ports only */ > + acs_flags |= PCI_ACS_ECAP; > return pci_acs_flags_enabled(pdev, acs_flags); > /* > * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be >
On 9/3/26 7:09 PM, Ilpo Järvinen wrote: > On Thu, 3 Sep 2026, Wei Wang wrote: > >> The enhanced ACS controls introduced by PCIe Gen 5 ensures better device >> isolation. On devices that support the PCI_ACS_ECAP capability, the >> controls are required to be enabled properly: >> - ACS I/O Request Blocking needs to be enabled to avoid unintended >> upstream I/O requests. >> - ACS DSP and USP Memory Target Access Control needs to be set with >> Request Redirect or Request Blocking to ensure the Downstream and >> Upstream Port memory resource ranges are not accessed by upstream >> memory requests. >> - ACS Unclaimed Request Redirect needs to be enabled to ensure accesses to >> areas that lies within a Switch's Upstream Port memory apertures but not >> within any Downstream Port memory apertures get redirected. >> >> To maintain compatibility with legacy devices that lack PCI_ACS_ECAP >> support, pci_acs_enabled() skips checking for the capability. >> >> Signed-off-by: Wei Wang <wei.w.wang@hotmail.com> >> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> >> --- >> drivers/pci/pci.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 65 insertions(+) >> >> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c >> index 50a3b61f9898..b951195d5adc 100644 >> --- a/drivers/pci/pci.c >> +++ b/drivers/pci/pci.c >> @@ -3648,6 +3648,57 @@ void pci_configure_ari(struct pci_dev *dev) >> } >> } >> >> +static bool pci_dev_has_memory_bars(struct pci_dev *pdev) >> +{ >> + int i; >> + >> + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { >> + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) >> + return true; >> + } >> + >> + return false; >> +} >> + >> +static bool pci_acs_ecap_enabled(struct pci_dev *pdev, u16 ctrl) >> +{ >> + struct pci_dev *upstream_pdev; >> + >> + /* >> + * For ACS DSP/USP Memory Target Access Control, either Request >> + * Redirect or Request Blocking must be enabled to enforce isolation. >> + * According to PCIe spec 7.0, the DSP Memory Target Access is >> + * applicable to both Root Ports and Switch Downstream Ports that have >> + * applicable Memory BAR space to protect. So if the device does not >> + * have a Memory BAR, it skips the check. >> + */ >> + if (pci_dev_has_memory_bars(pdev) && >> + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RB && >> + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RR) >> + return false; >> + >> + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) { >> + upstream_pdev = pci_upstream_bridge(pdev); >> + >> + /* >> + * The USP Memory Target Access is only applicable to >> + * downstream ports that have applicable Memory BAR space in >> + * the Switch Upstream Port to protect. >> + */ >> + if (upstream_pdev && pci_dev_has_memory_bars(upstream_pdev) && >> + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RB && >> + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RR) >> + return false; >> + >> + /* PCI_ACS_URRC is applicable to Downstream Ports only. */ >> + if (!(ctrl & PCI_ACS_URRC)) >> + return false; >> + } >> + >> + /* PCI_ACS_IB is applicable to both Root and Downstream Ports. */ >> + return !!(ctrl & PCI_ACS_IB); > > When the return type is bool, !!() construct is unnecessary. Good catch, thanks. The compiler already does the conversion for bool.
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 50a3b61f9898..b951195d5adc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3648,6 +3648,57 @@ void pci_configure_ari(struct pci_dev *dev) } } +static bool pci_dev_has_memory_bars(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) + return true; + } + + return false; +} + +static bool pci_acs_ecap_enabled(struct pci_dev *pdev, u16 ctrl) +{ + struct pci_dev *upstream_pdev; + + /* + * For ACS DSP/USP Memory Target Access Control, either Request + * Redirect or Request Blocking must be enabled to enforce isolation. + * According to PCIe spec 7.0, the DSP Memory Target Access is + * applicable to both Root Ports and Switch Downstream Ports that have + * applicable Memory BAR space to protect. So if the device does not + * have a Memory BAR, it skips the check. + */ + if (pci_dev_has_memory_bars(pdev) && + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RB && + FIELD_GET(PCI_ACS_DMAC_MASK, ctrl) != PCI_ACS_MAC_RR) + return false; + + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) { + upstream_pdev = pci_upstream_bridge(pdev); + + /* + * The USP Memory Target Access is only applicable to + * downstream ports that have applicable Memory BAR space in + * the Switch Upstream Port to protect. + */ + if (upstream_pdev && pci_dev_has_memory_bars(upstream_pdev) && + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RB && + FIELD_GET(PCI_ACS_UMAC_MASK, ctrl) != PCI_ACS_MAC_RR) + return false; + + /* PCI_ACS_URRC is applicable to Downstream Ports only. */ + if (!(ctrl & PCI_ACS_URRC)) + return false; + } + + /* PCI_ACS_IB is applicable to both Root and Downstream Ports. */ + return !!(ctrl & PCI_ACS_IB); +} + static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) { int pos; @@ -3665,6 +3716,18 @@ 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 (acs_flags & PCI_ACS_ECAP) { + if (!pci_acs_ecap_enabled(pdev, ctrl)) + return false; + /* + * The check for the required controls in PCI_ACS_ECAP has + * passed. Clear the ECAP flag and continue to check the + * basic ACS controls. + */ + acs_flags &= ~PCI_ACS_ECAP; + } + return (ctrl & acs_flags) == acs_flags; } @@ -3723,6 +3786,8 @@ bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) */ case PCI_EXP_TYPE_DOWNSTREAM: case PCI_EXP_TYPE_ROOT_PORT: + /* PCI_ACS_ECAP applies to Root and Downstream Ports only */ + acs_flags |= PCI_ACS_ECAP; return pci_acs_flags_enabled(pdev, acs_flags); /* * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be