]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Cache ACS Capabilities register
authorManivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Fri, 2 Jan 2026 15:34:48 +0000 (21:04 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 6 Feb 2026 22:54:12 +0000 (16:54 -0600)
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
drivers/pci/pci.c
include/linux/pci.h

index 647c3c4eb482344f44f95fa2108bb56ae9a3dc38..e4c11efce34ca9a0d65c4f07765744e3ec154323 100644 (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);
 }
 
 /**
index 864775651c6fae125972cdfb062fd4d684cf294c..6195e040b29c6e403ce4e78efd6f76c0f62eff8c 100644 (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 */