aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuiko Oshino <yuiko.oshino@microchip.com>2018-07-03 11:21:46 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-04 09:12:59 -0400
commitd461e3da905332189aad546b2ad9adbe6071c7cc (patch)
treebc9f0a66ea1a813de5e04a0dfe9a628c7f093582
parenta65925475571953da12a9bc2082aec29d4e2c0e7 (diff)
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: d0cad871703b898a442e4049c532ec39168e5b57 ("SMSC75XX USB 2.0 Gigabit Ethernet Devices") Signed-off-by: Yuiko Oshino <yuiko.oshino@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/smsc75xx.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 7a6a1fe79309..05553d252446 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -82,6 +82,9 @@ static bool turbo_mode = true;
82module_param(turbo_mode, bool, 0644); 82module_param(turbo_mode, bool, 0644);
83MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); 83MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
84 84
85static int smsc75xx_link_ok_nopm(struct usbnet *dev);
86static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
87
85static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, 88static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
86 u32 *data, int in_pm) 89 u32 *data, int in_pm)
87{ 90{
@@ -852,6 +855,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev)
852 return -EIO; 855 return -EIO;
853 } 856 }
854 857
858 /* phy workaround for gig link */
859 smsc75xx_phy_gig_workaround(dev);
860
855 smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 861 smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
856 ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | 862 ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
857 ADVERTISE_PAUSE_ASYM); 863 ADVERTISE_PAUSE_ASYM);
@@ -987,6 +993,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
987 return -EIO; 993 return -EIO;
988} 994}
989 995
996static 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
990static int smsc75xx_reset(struct usbnet *dev) 1052static int smsc75xx_reset(struct usbnet *dev)
991{ 1053{
992 struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); 1054 struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);