Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: Micrel KSZ8061: fix errata solution not taking effect problem

KSZ8061 needs to write to a MMD register at driver initialization to fix
an errata. This worked in 5.0 kernel but not in newer kernels. The
issue is the main phylib code no longer resets PHY at the very beginning.
Calling phy resuming code later will reset the chip if it is already
powered down at the beginning. This wipes out the MMD register write.
Solution is to implement a phy resume function for KSZ8061 to take care
of this problem.

Fixes: 232ba3a51cc2 ("net: phy: Micrel KSZ8061: link failure after cable connect")
Signed-off-by: Tristram Ha <tristram.ha@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tristram Ha and committed by
David S. Miller
0a8d3f2e fb0aa078

+41 -1
+41 -1
drivers/net/phy/micrel.c
··· 866 866 { 867 867 int ret; 868 868 869 + /* Chip can be powered down by the bootstrap code. */ 870 + ret = phy_read(phydev, MII_BMCR); 871 + if (ret < 0) 872 + return ret; 873 + if (ret & BMCR_PDOWN) { 874 + ret = phy_write(phydev, MII_BMCR, ret & ~BMCR_PDOWN); 875 + if (ret < 0) 876 + return ret; 877 + usleep_range(1000, 2000); 878 + } 879 + 869 880 ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A); 870 881 if (ret) 871 882 return ret; ··· 2135 2124 if (ret) 2136 2125 return ret; 2137 2126 } 2127 + 2128 + /* Enable PHY Interrupts */ 2129 + if (phy_interrupt_is_valid(phydev)) { 2130 + phydev->interrupts = PHY_INTERRUPT_ENABLED; 2131 + if (phydev->drv->config_intr) 2132 + phydev->drv->config_intr(phydev); 2133 + } 2134 + 2135 + return 0; 2136 + } 2137 + 2138 + static int ksz8061_resume(struct phy_device *phydev) 2139 + { 2140 + int ret; 2141 + 2142 + /* This function can be called twice when the Ethernet device is on. */ 2143 + ret = phy_read(phydev, MII_BMCR); 2144 + if (ret < 0) 2145 + return ret; 2146 + if (!(ret & BMCR_PDOWN)) 2147 + return 0; 2148 + 2149 + genphy_resume(phydev); 2150 + usleep_range(1000, 2000); 2151 + 2152 + /* Re-program the value after chip is reset. */ 2153 + ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A); 2154 + if (ret) 2155 + return ret; 2138 2156 2139 2157 /* Enable PHY Interrupts */ 2140 2158 if (phy_interrupt_is_valid(phydev)) { ··· 5429 5389 .config_intr = kszphy_config_intr, 5430 5390 .handle_interrupt = kszphy_handle_interrupt, 5431 5391 .suspend = kszphy_suspend, 5432 - .resume = kszphy_resume, 5392 + .resume = ksz8061_resume, 5433 5393 }, { 5434 5394 .phy_id = PHY_ID_KSZ9021, 5435 5395 .phy_id_mask = 0x000ffffe,