]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: keystone: Fix race condition when initializing PHYs
authorSiddharth Vadapalli <s-vadapalli@ti.com>
Wed, 27 Sep 2023 04:18:45 +0000 (09:48 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Jan 2024 22:52:52 +0000 (14:52 -0800)
[ Upstream commit c12ca110c613a81cb0f0099019c839d078cd0f38 ]

The PCI driver invokes the PHY APIs using the ks_pcie_enable_phy()
function. The PHY in this case is the Serdes. It is possible that the
PCI instance is configured for two lane operation across two different
Serdes instances, using one lane of each Serdes.

In such a configuration, if the reference clock for one Serdes is
provided by the other Serdes, it results in a race condition. After the
Serdes providing the reference clock is initialized by the PCI driver by
invoking its PHY APIs, it is not guaranteed that this Serdes remains
powered on long enough for the PHY APIs based initialization of the
dependent Serdes. In such cases, the PLL of the dependent Serdes fails
to lock due to the absence of the reference clock from the former Serdes
which has been powered off by the PM Core.

Fix this by obtaining reference to the PHYs before invoking the PHY
initialization APIs and releasing reference after the initialization is
complete.

Link: https://lore.kernel.org/linux-pci/20230927041845.1222080-1-s-vadapalli@ti.com
Fixes: 49229238ab47 ("PCI: keystone: Cleanup PHY handling")
Signed-off-by: Siddharth Vadapalli <s-vadapalli@ti.com>
Signed-off-by: Krzysztof WilczyƄski <kwilczynski@kernel.org>
Acked-by: Ravi Gunasekaran <r-gunasekaran@ti.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/pci/controller/dwc/pci-keystone.c

index eacdcb0a87719003f6fbc103b0454435ebc1d5ef..09379e5f7724a2193019225a9e52df29cf4b8498 100644 (file)
@@ -1200,7 +1200,16 @@ static int ks_pcie_probe(struct platform_device *pdev)
                goto err_link;
        }
 
+       /* Obtain references to the PHYs */
+       for (i = 0; i < num_lanes; i++)
+               phy_pm_runtime_get_sync(ks_pcie->phy[i]);
+
        ret = ks_pcie_enable_phy(ks_pcie);
+
+       /* Release references to the PHYs */
+       for (i = 0; i < num_lanes; i++)
+               phy_pm_runtime_put_sync(ks_pcie->phy[i]);
+
        if (ret) {
                dev_err(dev, "failed to enable phy\n");
                goto err_link;