aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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]);