Skip to content

Commit d461e3d

Browse files
microchip1davem330
authored andcommitted
smsc75xx: Add workaround for gigabit link up hardware errata.
In certain conditions, the device may not be able to link in gigabit mode. This software workaround ensures that the device will not enter the failure state. Fixes: d0cad87 ("SMSC75XX USB 2.0 Gigabit Ethernet Devices") Signed-off-by: Yuiko Oshino <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a659254 commit d461e3d

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

drivers/net/usb/smsc75xx.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ static bool turbo_mode = true;
8282
module_param(turbo_mode, bool, 0644);
8383
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
8484

85+
static int smsc75xx_link_ok_nopm(struct usbnet *dev);
86+
static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
87+
8588
static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
8689
u32 *data, int in_pm)
8790
{
@@ -852,6 +855,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev)
852855
return -EIO;
853856
}
854857

858+
/* phy workaround for gig link */
859+
smsc75xx_phy_gig_workaround(dev);
860+
855861
smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
856862
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
857863
ADVERTISE_PAUSE_ASYM);
@@ -987,6 +993,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
987993
return -EIO;
988994
}
989995

996+
static int smsc75xx_phy_gig_workaround(struct usbnet *dev)
997+
{
998+
struct mii_if_info *mii = &dev->mii;
999+
int ret = 0, timeout = 0;
1000+
u32 buf, link_up = 0;
1001+
1002+
/* Set the phy in Gig loopback */
1003+
smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040);
1004+
1005+
/* Wait for the link up */
1006+
do {
1007+
link_up = smsc75xx_link_ok_nopm(dev);
1008+
usleep_range(10000, 20000);
1009+
timeout++;
1010+
} while ((!link_up) && (timeout < 1000));
1011+
1012+
if (timeout >= 1000) {
1013+
netdev_warn(dev->net, "Timeout waiting for PHY link up\n");
1014+
return -EIO;
1015+
}
1016+
1017+
/* phy reset */
1018+
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1019+
if (ret < 0) {
1020+
netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
1021+
return ret;
1022+
}
1023+
1024+
buf |= PMT_CTL_PHY_RST;
1025+
1026+
ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
1027+
if (ret < 0) {
1028+
netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
1029+
return ret;
1030+
}
1031+
1032+
timeout = 0;
1033+
do {
1034+
usleep_range(10000, 20000);
1035+
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
1036+
if (ret < 0) {
1037+
netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n",
1038+
ret);
1039+
return ret;
1040+
}
1041+
timeout++;
1042+
} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
1043+
1044+
if (timeout >= 100) {
1045+
netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
1046+
return -EIO;
1047+
}
1048+
1049+
return 0;
1050+
}
1051+
9901052
static int smsc75xx_reset(struct usbnet *dev)
9911053
{
9921054
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);

0 commit comments

Comments
 (0)