]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
staging: mt7621-pci: properly power off dual-ported pcie phy
authorSergio Paracuellos <sergio.paracuellos@gmail.com>
Thu, 9 Apr 2020 11:16:52 +0000 (13:16 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Jun 2020 14:41:50 +0000 (16:41 +0200)
[ Upstream commit 5fcded5e857cf66c9592e4be28c4dab4520c9177 ]

Pcie phy for pcie0 and pcie1 is shared using a dual ported
one. Current code was assuming that if nothing is connected
in pcie0 it won't be also nothing connected in pcie1. This
assumtion is wrong for some devices such us 'Mikrotik rbm33g'
and 'ZyXEL LTE3301-PLUS' where only connecting a card to the
second bus on the phy is possible. For such devices kernel
hangs in the same point because of the wrong poweroff of the
phy getting the following trace:

mt7621-pci-phy 1e149000.pcie-phy: PHY for 0xbe149000 (dual port = 1)
mt7621-pci-phy 1e14a000.pcie-phy: PHY for 0xbe14a000 (dual port = 0)
mt7621-pci-phy 1e149000.pcie-phy: Xtal is 40MHz
mt7621-pci-phy 1e14a000.pcie-phy: Xtal is 40MHz
mt7621-pci 1e140000.pcie: pcie0 no card, disable it (RST & CLK)
[hangs]

The wrong assumption is located in the 'mt7621_pcie_init_ports'
function where we are just making a power off of the phy for
slots 0 and 2 if nothing is connected in them. Hence, only
poweroff the phy if nothing is connected in both slot 0 and
slot 1 avoiding the kernel to hang.

Fixes: 5737cfe87a9c ("staging: mt7621-pci: avoid to poweroff the phy for slot one")
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
Link: https://lore.kernel.org/r/20200409111652.30964-1-sergio.paracuellos@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/staging/mt7621-pci/pci-mt7621.c

index a1dafec0890a979ecb5ac740f170fcb150df7adc..6eb7436af462c805c1fff7707015658ba5827906 100644 (file)
@@ -479,17 +479,25 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
 
        mt7621_perst_gpio_pcie_deassert(pcie);
 
+       tmp = NULL;
        list_for_each_entry(port, &pcie->ports, list) {
                u32 slot = port->slot;
 
                if (!mt7621_pcie_port_is_linkup(port)) {
                        dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
                                slot);
-                       if (slot != 1)
-                               phy_power_off(port->phy);
                        mt7621_control_assert(port);
                        mt7621_pcie_port_clk_disable(port);
                        port->enabled = false;
+
+                       if (slot == 0) {
+                               tmp = port;
+                               continue;
+                       }
+
+                       if (slot == 1 && tmp && !tmp->enabled)
+                               phy_power_off(tmp->phy);
+
                }
        }