1 From foo@baz Wed Aug 22 09:33:46 CEST 2018
2 From: Yuiko Oshino <yuiko.oshino@microchip.com>
3 Date: Tue, 3 Jul 2018 11:21:46 -0400
4 Subject: smsc75xx: Add workaround for gigabit link up hardware errata.
6 From: Yuiko Oshino <yuiko.oshino@microchip.com>
8 [ Upstream commit d461e3da905332189aad546b2ad9adbe6071c7cc ]
10 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.
12 Fixes: d0cad871703b898a442e4049c532ec39168e5b57 ("SMSC75XX USB 2.0 Gigabit Ethernet Devices")
13 Signed-off-by: Yuiko Oshino <yuiko.oshino@microchip.com>
14 Signed-off-by: David S. Miller <davem@davemloft.net>
15 Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
16 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
18 drivers/net/usb/smsc75xx.c | 62 +++++++++++++++++++++++++++++++++++++++++++++
19 1 file changed, 62 insertions(+)
21 --- a/drivers/net/usb/smsc75xx.c
22 +++ b/drivers/net/usb/smsc75xx.c
23 @@ -82,6 +82,9 @@ static bool turbo_mode = true;
24 module_param(turbo_mode, bool, 0644);
25 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
27 +static int smsc75xx_link_ok_nopm(struct usbnet *dev);
28 +static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
30 static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
33 @@ -852,6 +855,9 @@ static int smsc75xx_phy_initialize(struc
37 + /* phy workaround for gig link */
38 + smsc75xx_phy_gig_workaround(dev);
40 smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
41 ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
42 ADVERTISE_PAUSE_ASYM);
43 @@ -987,6 +993,62 @@ static int smsc75xx_wait_ready(struct us
47 +static int smsc75xx_phy_gig_workaround(struct usbnet *dev)
49 + struct mii_if_info *mii = &dev->mii;
50 + int ret = 0, timeout = 0;
51 + u32 buf, link_up = 0;
53 + /* Set the phy in Gig loopback */
54 + smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040);
56 + /* Wait for the link up */
58 + link_up = smsc75xx_link_ok_nopm(dev);
59 + usleep_range(10000, 20000);
61 + } while ((!link_up) && (timeout < 1000));
63 + if (timeout >= 1000) {
64 + netdev_warn(dev->net, "Timeout waiting for PHY link up\n");
69 + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
71 + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
75 + buf |= PMT_CTL_PHY_RST;
77 + ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
79 + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
85 + usleep_range(10000, 20000);
86 + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
88 + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n",
93 + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
95 + if (timeout >= 100) {
96 + netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
103 static int smsc75xx_reset(struct usbnet *dev)
105 struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);