hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/net/phy/microchip.c
....@@ -326,6 +326,37 @@
326326 return genphy_config_aneg(phydev);
327327 }
328328
329
+static void lan88xx_link_change_notify(struct phy_device *phydev)
330
+{
331
+ int temp;
332
+
333
+ /* At forced 100 F/H mode, chip may fail to set mode correctly
334
+ * when cable is switched between long(~50+m) and short one.
335
+ * As workaround, set to 10 before setting to 100
336
+ * at forced 100 F/H mode.
337
+ */
338
+ if (!phydev->autoneg && phydev->speed == 100) {
339
+ /* disable phy interrupt */
340
+ temp = phy_read(phydev, LAN88XX_INT_MASK);
341
+ temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
342
+ phy_write(phydev, LAN88XX_INT_MASK, temp);
343
+
344
+ temp = phy_read(phydev, MII_BMCR);
345
+ temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
346
+ phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
347
+ temp |= BMCR_SPEED100;
348
+ phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
349
+
350
+ /* clear pending interrupt generated while workaround */
351
+ temp = phy_read(phydev, LAN88XX_INT_STS);
352
+
353
+ /* enable phy interrupt back */
354
+ temp = phy_read(phydev, LAN88XX_INT_MASK);
355
+ temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
356
+ phy_write(phydev, LAN88XX_INT_MASK, temp);
357
+ }
358
+}
359
+
329360 static struct phy_driver microchip_phy_driver[] = {
330361 {
331362 .phy_id = 0x0007c130,
....@@ -339,6 +370,7 @@
339370
340371 .config_init = lan88xx_config_init,
341372 .config_aneg = lan88xx_config_aneg,
373
+ .link_change_notify = lan88xx_link_change_notify,
342374
343375 .ack_interrupt = lan88xx_phy_ack_interrupt,
344376 .config_intr = lan88xx_phy_config_intr,