[PATCH v3] PCI: Fix up L1SS capability for Intel Apollo Lake PCIe bridge

From: Ron Lee
Date: Mon Feb 06 2023 - 09:35:56 EST


On Google Coral and Reef family Chromebooks with Intel Apollo Lake
SoC, the PCIe bridge lost its L1 PM Substates capability after resumed
from D3cold. This patch save the capability header and the pointer
offset to the L1SS capability after this bridge initialized, and
recover them every time resuming from D3cold.

Link:https://lore.kernel.org/linux-pci/CAFJ_xbq0cxcH-cgpXLU4Mjk30+muWyWm1aUZGK7iG53yaLBaQg@xxxxxxxxxxxxxx/T/#u
Signed-off-by: Ron Lee <ron.lee@xxxxxxxxx>
---
Change from v2: traverse the capability link list to find the L1SS capability header
and pointer offset to the L1SS capability, save them after the bridge initialized and
restore them after resuming from D3cold.

drivers/pci/quirks.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 285acc4aaccc..4e1c8c4c7e9a 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -5992,3 +5992,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
#endif
+
+#ifdef CONFIG_PCIEASPM
+static u16 pos_to_l1ss;
+static u32 l1ss_header;
+static void chromeos_save_apl_pci_l1ss_capability(struct pci_dev *pdev)
+{
+ u32 header;
+ int pos = PCI_CFG_SPACE_SIZE;
+
+ while (pos) {
+ pci_read_config_dword(pdev, pos, &header);
+ if (PCI_EXT_CAP_NEXT(header) == pdev->l1ss)
+ pos_to_l1ss = pos;
+ else if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_L1SS)
+ l1ss_header = header;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ }
+}
+
+static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *pdev)
+{
+ u32 header;
+
+ if (!pos_to_l1ss || !l1ss_header)
+ return;
+
+ pci_info(pdev, "Fixup L1SS Capability\n");
+ /* Fixup the header of L1SS Capability if missing */
+ pci_read_config_dword(pdev, pdev->l1ss, &header);
+ if (PCI_EXT_CAP_ID(header) != PCI_EXT_CAP_ID_L1SS)
+ pci_write_config_dword(pdev, pdev->l1ss, l1ss_header);
+
+ /* Fixup the link to L1SS Capability if missing*/
+ pci_read_config_dword(pdev, pos_to_l1ss, &header);
+ if (PCI_EXT_CAP_NEXT(header) != pdev->l1ss)
+ pci_write_config_dword(pdev, pos_to_l1ss, pdev->l1ss << 20);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
+#endif
--
2.17.1