Skip to content

Commit e57cf36

Browse files
microchip1kuba-moo
authored andcommitted
net: lan78xx: fix accessing the LAN7800's internal phy specific registers from the MAC driver
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: 14437e3 ("lan78xx: workaround of forced 100 Full/Half duplex mode error") Signed-off-by: Yuiko Oshino <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 5c1ebbf commit e57cf36

File tree

2 files changed

+33
-26
lines changed

2 files changed

+33
-26
lines changed

drivers/net/phy/microchip.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,37 @@ static int lan88xx_config_aneg(struct phy_device *phydev)
342342
return genphy_config_aneg(phydev);
343343
}
344344

345+
static void lan88xx_link_change_notify(struct phy_device *phydev)
346+
{
347+
int temp;
348+
349+
/* At forced 100 F/H mode, chip may fail to set mode correctly
350+
* when cable is switched between long(~50+m) and short one.
351+
* As workaround, set to 10 before setting to 100
352+
* at forced 100 F/H mode.
353+
*/
354+
if (!phydev->autoneg && phydev->speed == 100) {
355+
/* disable phy interrupt */
356+
temp = phy_read(phydev, LAN88XX_INT_MASK);
357+
temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
358+
phy_write(phydev, LAN88XX_INT_MASK, temp);
359+
360+
temp = phy_read(phydev, MII_BMCR);
361+
temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
362+
phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
363+
temp |= BMCR_SPEED100;
364+
phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
365+
366+
/* clear pending interrupt generated while workaround */
367+
temp = phy_read(phydev, LAN88XX_INT_STS);
368+
369+
/* enable phy interrupt back */
370+
temp = phy_read(phydev, LAN88XX_INT_MASK);
371+
temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
372+
phy_write(phydev, LAN88XX_INT_MASK, temp);
373+
}
374+
}
375+
345376
static struct phy_driver microchip_phy_driver[] = {
346377
{
347378
.phy_id = 0x0007c132,
@@ -359,6 +390,7 @@ static struct phy_driver microchip_phy_driver[] = {
359390

360391
.config_init = lan88xx_config_init,
361392
.config_aneg = lan88xx_config_aneg,
393+
.link_change_notify = lan88xx_link_change_notify,
362394

363395
.config_intr = lan88xx_phy_config_intr,
364396
.handle_interrupt = lan88xx_handle_interrupt,

drivers/net/usb/lan78xx.c

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,33 +2115,8 @@ static void lan78xx_remove_mdio(struct lan78xx_net *dev)
21152115
static void lan78xx_link_status_change(struct net_device *net)
21162116
{
21172117
struct phy_device *phydev = net->phydev;
2118-
int temp;
2119-
2120-
/* At forced 100 F/H mode, chip may fail to set mode correctly
2121-
* when cable is switched between long(~50+m) and short one.
2122-
* As workaround, set to 10 before setting to 100
2123-
* at forced 100 F/H mode.
2124-
*/
2125-
if (!phydev->autoneg && (phydev->speed == 100)) {
2126-
/* disable phy interrupt */
2127-
temp = phy_read(phydev, LAN88XX_INT_MASK);
2128-
temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
2129-
phy_write(phydev, LAN88XX_INT_MASK, temp);
21302118

2131-
temp = phy_read(phydev, MII_BMCR);
2132-
temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
2133-
phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
2134-
temp |= BMCR_SPEED100;
2135-
phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
2136-
2137-
/* clear pending interrupt generated while workaround */
2138-
temp = phy_read(phydev, LAN88XX_INT_STS);
2139-
2140-
/* enable phy interrupt back */
2141-
temp = phy_read(phydev, LAN88XX_INT_MASK);
2142-
temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
2143-
phy_write(phydev, LAN88XX_INT_MASK, temp);
2144-
}
2119+
phy_print_status(phydev);
21452120
}
21462121

21472122
static int irq_map(struct irq_domain *d, unsigned int irq,

0 commit comments

Comments
 (0)