net: lan78xx: fix accessing the LAN7800's internal phy specific registers from the...
authorYuiko Oshino <yuiko.oshino@microchip.com>
Wed, 1 Mar 2023 15:43:07 +0000 (08:43 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 3 Mar 2023 06:21:07 +0000 (22:21 -0800)
Move the LAN7800 internal phy (phy ID  0x0007c132) specific register
accesses to the phy driver (microchip.c).

Fix the error reported by Enguerrand de Ribaucourt in December 2022,
"Some operations during the cable switch workaround modify the register
LAN88XX_INT_MASK of the PHY. However, this register is specific to the
LAN8835 PHY. For instance, if a DP8322I PHY is connected to the LAN7801,
that register (0x19), corresponds to the LED and MAC address
configuration, resulting in unapropriate behavior."

I did not test with the DP8322I PHY, but I tested with an EVB-LAN7800
with the internal PHY.

Fixes: 14437e3fa284 ("lan78xx: workaround of forced 100 Full/Half duplex mode error")
Signed-off-by: Yuiko Oshino <yuiko.oshino@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230301154307.30438-1-yuiko.oshino@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/microchip.c
drivers/net/usb/lan78xx.c

index ccecee2524ce6216189cf7cabf5f7cded2205bf4..0b88635f4fbca98b7e2f9e553f69fa6f465dd770 100644 (file)
@@ -342,6 +342,37 @@ static int lan88xx_config_aneg(struct phy_device *phydev)
        return genphy_config_aneg(phydev);
 }
 
+static void lan88xx_link_change_notify(struct phy_device *phydev)
+{
+       int temp;
+
+       /* At forced 100 F/H mode, chip may fail to set mode correctly
+        * when cable is switched between long(~50+m) and short one.
+        * As workaround, set to 10 before setting to 100
+        * at forced 100 F/H mode.
+        */
+       if (!phydev->autoneg && phydev->speed == 100) {
+               /* disable phy interrupt */
+               temp = phy_read(phydev, LAN88XX_INT_MASK);
+               temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
+               phy_write(phydev, LAN88XX_INT_MASK, temp);
+
+               temp = phy_read(phydev, MII_BMCR);
+               temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
+               phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
+               temp |= BMCR_SPEED100;
+               phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
+
+               /* clear pending interrupt generated while workaround */
+               temp = phy_read(phydev, LAN88XX_INT_STS);
+
+               /* enable phy interrupt back */
+               temp = phy_read(phydev, LAN88XX_INT_MASK);
+               temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
+               phy_write(phydev, LAN88XX_INT_MASK, temp);
+       }
+}
+
 static struct phy_driver microchip_phy_driver[] = {
 {
        .phy_id         = 0x0007c132,
@@ -359,6 +390,7 @@ static struct phy_driver microchip_phy_driver[] = {
 
        .config_init    = lan88xx_config_init,
        .config_aneg    = lan88xx_config_aneg,
+       .link_change_notify = lan88xx_link_change_notify,
 
        .config_intr    = lan88xx_phy_config_intr,
        .handle_interrupt = lan88xx_handle_interrupt,
index f18ab8e220db72787bffef62c598e7c65e1e1c6e..068488890d57be2f4a1c31ae72ecef518775f110 100644 (file)
@@ -2115,33 +2115,8 @@ static void lan78xx_remove_mdio(struct lan78xx_net *dev)
 static void lan78xx_link_status_change(struct net_device *net)
 {
        struct phy_device *phydev = net->phydev;
-       int temp;
-
-       /* At forced 100 F/H mode, chip may fail to set mode correctly
-        * when cable is switched between long(~50+m) and short one.
-        * As workaround, set to 10 before setting to 100
-        * at forced 100 F/H mode.
-        */
-       if (!phydev->autoneg && (phydev->speed == 100)) {
-               /* disable phy interrupt */
-               temp = phy_read(phydev, LAN88XX_INT_MASK);
-               temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
-               phy_write(phydev, LAN88XX_INT_MASK, temp);
 
-               temp = phy_read(phydev, MII_BMCR);
-               temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
-               phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
-               temp |= BMCR_SPEED100;
-               phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
-
-               /* clear pending interrupt generated while workaround */
-               temp = phy_read(phydev, LAN88XX_INT_STS);
-
-               /* enable phy interrupt back */
-               temp = phy_read(phydev, LAN88XX_INT_MASK);
-               temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
-               phy_write(phydev, LAN88XX_INT_MASK, temp);
-       }
+       phy_print_status(phydev);
 }
 
 static int irq_map(struct irq_domain *d, unsigned int irq,