PCI: brcmstb: Enable CRS software visibility after linkup
authorJonathan Bell <jonathan@raspberrypi.com>
Wed, 24 Jan 2024 13:55:45 +0000 (13:55 +0000)
committerDom Cobley <popcornmix@gmail.com>
Mon, 19 Feb 2024 11:35:37 +0000 (11:35 +0000)
It appears that bits in the Root Control Register are reset with
perst_n, which means the PCI layer's call to enable CRS prior to
adding/scanning the bus has no effect. Open-code the enable in
brcm_pcie_start_link as a workaround.

Without CRS visibility, configuration reads issued by the CPU don't
retire if the endpoint returns a CRS response - the RC will poll until a
(large) timeout is reached. This means the core can stall for a long
time during boot.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
drivers/pci/controller/pcie-brcmstb.c

index a7f05e0..3691e69 100644 (file)
@@ -1385,7 +1385,7 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
 {
        struct device *dev = pcie->dev;
        void __iomem *base = pcie->base;
-       u16 nlw, cls, lnksta;
+       u16 nlw, cls, lnksta, tmp16;
        bool ssc_good = false;
        int ret, i;
        u32 tmp;
@@ -1449,6 +1449,16 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
                 pci_speed_string(pcie_link_speed[cls]), nlw,
                 ssc_good ? "(SSC)" : "(!SSC)");
 
+       /*
+        * RootCtl bits are reset by perst_n, which undoes pci_enable_crs()
+        * called prior to pci_add_new_bus() during probe. Re-enable here.
+        */
+       tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCAP);
+       if (tmp16 & PCI_EXP_RTCAP_CRSVIS) {
+               tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL);
+               u16p_replace_bits(&tmp16, 1, PCI_EXP_RTCTL_CRSSVE);
+               writew(tmp16, base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL);
+       }
        return 0;
 }