]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
PCI/ASPM: Cache L0s/L1 Supported so advertised link states can be overridden
authorBjorn Helgaas <bhelgaas@google.com>
Mon, 10 Nov 2025 22:22:25 +0000 (16:22 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 13 Nov 2025 00:47:16 +0000 (18:47 -0600)
Defective devices sometimes advertise support for ASPM L0s or L1 states
even if they don't work correctly.

Cache the L0s Supported and L1 Supported bits early in enumeration so
HEADER quirks can override the ASPM states advertised in Link Capabilities
before pcie_aspm_cap_init() enables ASPM.

Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Lukas Wunner <lukas@wunner.de>
Link: https://patch.msgid.link/20251110222929.2140564-2-helgaas@kernel.org
drivers/pci/pcie/aspm.c
drivers/pci/probe.c
include/linux/pci.h

index 7cc8281e70119b52cf214fc4701740c0cb3e53f1..15d50c089070377b52b77a4bbd13b1bdf16addd1 100644 (file)
@@ -830,7 +830,6 @@ static void pcie_aspm_override_default_link_state(struct pcie_link_state *link)
 static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
 {
        struct pci_dev *child = link->downstream, *parent = link->pdev;
-       u32 parent_lnkcap, child_lnkcap;
        u16 parent_lnkctl, child_lnkctl;
        struct pci_bus *linkbus = parent->subordinate;
 
@@ -845,9 +844,8 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
         * If ASPM not supported, don't mess with the clocks and link,
         * bail out now.
         */
-       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
-       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
-       if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS))
+       if (!(parent->aspm_l0s_support && child->aspm_l0s_support) &&
+           !(parent->aspm_l1_support && child->aspm_l1_support))
                return;
 
        /* Configure common clock before checking latencies */
@@ -859,8 +857,6 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
         * read-only Link Capabilities may change depending on common clock
         * configuration (PCIe r5.0, sec 7.5.3.6).
         */
-       pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
-       pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
        pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
        pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
 
@@ -880,7 +876,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
         * given link unless components on both sides of the link each
         * support L0s.
         */
-       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
+       if (parent->aspm_l0s_support && child->aspm_l0s_support)
                link->aspm_support |= PCIE_LINK_STATE_L0S;
 
        if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
@@ -889,7 +885,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
                link->aspm_enabled |= PCIE_LINK_STATE_L0S_DW;
 
        /* Setup L1 state */
-       if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
+       if (parent->aspm_l1_support && child->aspm_l1_support)
                link->aspm_support |= PCIE_LINK_STATE_L1;
 
        if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
index c83e75a0ec1263298aeac7f84bcf5513b003496c..de72ceaea28562458a1e875e5d75f04bfc3d4ff4 100644 (file)
@@ -1663,6 +1663,13 @@ void set_pcie_port_type(struct pci_dev *pdev)
        if (reg32 & PCI_EXP_LNKCAP_DLLLARC)
                pdev->link_active_reporting = 1;
 
+#ifdef CONFIG_PCIEASPM
+       if (reg32 & PCI_EXP_LNKCAP_ASPM_L0S)
+               pdev->aspm_l0s_support = 1;
+       if (reg32 & PCI_EXP_LNKCAP_ASPM_L1)
+               pdev->aspm_l1_support = 1;
+#endif
+
        parent = pci_upstream_bridge(pdev);
        if (!parent)
                return;
index d1fdf81fbe1e427aecbc951fa3fdf65c20450b05..bf97d49c23cf54cdcd5e20d8d61351e067820e5a 100644 (file)
@@ -412,6 +412,8 @@ struct pci_dev {
        u16             l1ss;           /* L1SS Capability pointer */
 #ifdef CONFIG_PCIEASPM
        struct pcie_link_state  *link_state;    /* ASPM link state */
+       unsigned int    aspm_l0s_support:1;     /* ASPM L0s support */
+       unsigned int    aspm_l1_support:1;      /* ASPM L1 support */
        unsigned int    ltr_path:1;     /* Latency Tolerance Reporting
                                           supported from root to here */
 #endif