r6040: Restore MDIO clock frequency after MAC reset
authorFlorian Fainelli <f.fainelli@gmail.com>
Thu, 9 Sep 2021 17:33:28 +0000 (10:33 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Sep 2021 09:43:09 +0000 (11:43 +0200)
commit e3f0cc1a945fcefec0c7c9d9dfd028a51daa1846 upstream.

A number of users have reported that they were not able to get the PHY
to successfully link up, especially after commit c36757eb9dee ("net:
phy: consider AN_RESTART status when reading link status") where we
stopped reading just BMSR, but we also read BMCR to determine the link
status.

Andrius at NetBSD did a wonderful job at debugging the problem
and found out that the MDIO bus clock frequency would be incorrectly set
back to its default value which would prevent the MDIO bus controller
from reading PHY registers properly. Back when we only read BMSR, if we
read all 1s, we could falsely indicate a link status, though in general
there is a cable plugged in, so this went unnoticed. After a second read
of BMCR was added, a wrong read will lead to the inability to determine
a link UP condition which is when it started to be visibly broken, even
if it was long before that.

The fix consists in restoring the value of the MD_CSR register that was
set prior to the MAC reset.

Link: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=53494
Fixes: 90f750a81a29 ("r6040: consolidate MAC reset to its own function")
Reported-by: Andrius V <vezhlys@gmail.com>
Reported-by: Darek Strugacz <darek.strugacz@op.pl>
Tested-by: Darek Strugacz <darek.strugacz@op.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/rdc/r6040.c

index 5ef5d728c2505e0977d056541552d204c108eb42..065a631238632149d8687bc6c50ca63f4fac963b 100644 (file)
 #define PHY_ST         0x8A    /* PHY status register */
 #define MAC_SM         0xAC    /* MAC status machine */
 #define  MAC_SM_RST    0x0002  /* MAC status machine reset */
+#define MD_CSC         0xb6    /* MDC speed control register */
+#define  MD_CSC_DEFAULT        0x0030
 #define MAC_ID         0xBE    /* Identifier register */
 
 #define TX_DCNT                0x80    /* TX descriptor count */
@@ -368,8 +370,9 @@ static void r6040_reset_mac(struct r6040_private *lp)
 {
        void __iomem *ioaddr = lp->base;
        int limit = MAC_DEF_TIMEOUT;
-       u16 cmd;
+       u16 cmd, md_csc;
 
+       md_csc = ioread16(ioaddr + MD_CSC);
        iowrite16(MAC_RST, ioaddr + MCR1);
        while (limit--) {
                cmd = ioread16(ioaddr + MCR1);
@@ -381,6 +384,10 @@ static void r6040_reset_mac(struct r6040_private *lp)
        iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
        iowrite16(0, ioaddr + MAC_SM);
        mdelay(5);
+
+       /* Restore MDIO clock frequency */
+       if (md_csc != MD_CSC_DEFAULT)
+               iowrite16(md_csc, ioaddr + MD_CSC);
 }
 
 static void r6040_init_mac_regs(struct net_device *dev)