PCI: Cache ACS Capabilities register

The ACS Capability register is read-only. Cache it to allow quirks to
override it and to avoid re-reading it.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Link: https://patch.msgid.link/20260102-pci_acs-v3-2-72280b94d288@oss.qualcomm.com
This commit is contained in:
Manivannan Sadhasivam 2026-01-02 21:04:48 +05:30 committed by Bjorn Helgaas
parent c41e2fb67e
commit 8f05a5f674
2 changed files with 15 additions and 10 deletions

View File

@ -893,7 +893,6 @@ static const char *disable_acs_redir_param;
static const char *config_acs_param;
struct pci_acs {
u16 cap;
u16 ctrl;
u16 fw_ctrl;
};
@ -996,20 +995,20 @@ static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps,
static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps)
{
/* Source Validation */
caps->ctrl |= (caps->cap & PCI_ACS_SV);
caps->ctrl |= (dev->acs_capabilities & PCI_ACS_SV);
/* P2P Request Redirect */
caps->ctrl |= (caps->cap & PCI_ACS_RR);
caps->ctrl |= (dev->acs_capabilities & PCI_ACS_RR);
/* P2P Completion Redirect */
caps->ctrl |= (caps->cap & PCI_ACS_CR);
caps->ctrl |= (dev->acs_capabilities & PCI_ACS_CR);
/* Upstream Forwarding */
caps->ctrl |= (caps->cap & PCI_ACS_UF);
caps->ctrl |= (dev->acs_capabilities & PCI_ACS_UF);
/* Enable Translation Blocking for external devices and noats */
if (pci_ats_disabled() || dev->external_facing || dev->untrusted)
caps->ctrl |= (caps->cap & PCI_ACS_TB);
caps->ctrl |= (dev->acs_capabilities & PCI_ACS_TB);
}
/**
@ -1032,7 +1031,6 @@ void pci_enable_acs(struct pci_dev *dev)
if (!pos)
return;
pci_read_config_word(dev, pos + PCI_ACS_CAP, &caps.cap);
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &caps.ctrl);
caps.fw_ctrl = caps.ctrl;
@ -3515,7 +3513,7 @@ void pci_configure_ari(struct pci_dev *dev)
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
{
int pos;
u16 cap, ctrl;
u16 ctrl;
pos = pdev->acs_cap;
if (!pos)
@ -3526,8 +3524,7 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
* 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);
acs_flags &= (pdev->acs_capabilities | PCI_ACS_EC);
pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
return (ctrl & acs_flags) == acs_flags;
@ -3648,7 +3645,14 @@ bool pci_acs_path_enabled(struct pci_dev *start,
*/
void pci_acs_init(struct pci_dev *dev)
{
int pos;
dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
pos = dev->acs_cap;
if (!pos)
return;
pci_read_config_word(dev, pos + PCI_ACS_CAP, &dev->acs_capabilities);
}
/**

View File

@ -558,6 +558,7 @@ struct pci_dev {
struct pci_tsm *tsm; /* TSM operation state */
#endif
u16 acs_cap; /* ACS Capability offset */
u16 acs_capabilities; /* ACS Capabilities */
u8 supported_speeds; /* Supported Link Speeds Vector */
phys_addr_t rom; /* Physical address if not from BAR */
size_t romlen; /* Length if not from BAR */