|
@@ -1804,7 +1804,34 @@ static void lan78xx_remove_mdio(struct lan78xx_net *dev)
|
|
|
|
|
|
static void lan78xx_link_status_change(struct net_device *net)
|
|
static void lan78xx_link_status_change(struct net_device *net)
|
|
{
|
|
{
|
|
- /* nothing to do */
|
|
|
|
|
|
+ struct phy_device *phydev = net->phydev;
|
|
|
|
+ int ret, 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_;
|
|
|
|
+ ret = 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_;
|
|
|
|
+ ret = phy_write(phydev, LAN88XX_INT_MASK, temp);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static int lan78xx_phy_init(struct lan78xx_net *dev)
|
|
static int lan78xx_phy_init(struct lan78xx_net *dev)
|