]>
Commit | Line | Data |
---|---|---|
ba4a4fdd GKH |
1 | From foo@baz Wed Aug 22 10:28:26 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. | |
5 | ||
6 | From: Yuiko Oshino <yuiko.oshino@microchip.com> | |
7 | ||
8 | [ Upstream commit d461e3da905332189aad546b2ad9adbe6071c7cc ] | |
9 | ||
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. | |
11 | ||
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> | |
17 | --- | |
18 | drivers/net/usb/smsc75xx.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ | |
19 | 1 file changed, 62 insertions(+) | |
20 | ||
21 | --- a/drivers/net/usb/smsc75xx.c | |
22 | +++ b/drivers/net/usb/smsc75xx.c | |
23 | @@ -81,6 +81,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"); | |
26 | ||
27 | +static int smsc75xx_link_ok_nopm(struct usbnet *dev); | |
28 | +static int smsc75xx_phy_gig_workaround(struct usbnet *dev); | |
29 | + | |
30 | static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, | |
31 | u32 *data, int in_pm) | |
32 | { | |
33 | @@ -840,6 +843,9 @@ static int smsc75xx_phy_initialize(struc | |
34 | return -EIO; | |
35 | } | |
36 | ||
37 | + /* phy workaround for gig link */ | |
38 | + smsc75xx_phy_gig_workaround(dev); | |
39 | + | |
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 | @@ -978,6 +984,62 @@ static int smsc75xx_wait_ready(struct us | |
44 | return -EIO; | |
45 | } | |
46 | ||
47 | +static int smsc75xx_phy_gig_workaround(struct usbnet *dev) | |
48 | +{ | |
49 | + struct mii_if_info *mii = &dev->mii; | |
50 | + int ret = 0, timeout = 0; | |
51 | + u32 buf, link_up = 0; | |
52 | + | |
53 | + /* Set the phy in Gig loopback */ | |
54 | + smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040); | |
55 | + | |
56 | + /* Wait for the link up */ | |
57 | + do { | |
58 | + link_up = smsc75xx_link_ok_nopm(dev); | |
59 | + usleep_range(10000, 20000); | |
60 | + timeout++; | |
61 | + } while ((!link_up) && (timeout < 1000)); | |
62 | + | |
63 | + if (timeout >= 1000) { | |
64 | + netdev_warn(dev->net, "Timeout waiting for PHY link up\n"); | |
65 | + return -EIO; | |
66 | + } | |
67 | + | |
68 | + /* phy reset */ | |
69 | + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); | |
70 | + if (ret < 0) { | |
71 | + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); | |
72 | + return ret; | |
73 | + } | |
74 | + | |
75 | + buf |= PMT_CTL_PHY_RST; | |
76 | + | |
77 | + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); | |
78 | + if (ret < 0) { | |
79 | + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret); | |
80 | + return ret; | |
81 | + } | |
82 | + | |
83 | + timeout = 0; | |
84 | + do { | |
85 | + usleep_range(10000, 20000); | |
86 | + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); | |
87 | + if (ret < 0) { | |
88 | + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", | |
89 | + ret); | |
90 | + return ret; | |
91 | + } | |
92 | + timeout++; | |
93 | + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); | |
94 | + | |
95 | + if (timeout >= 100) { | |
96 | + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); | |
97 | + return -EIO; | |
98 | + } | |
99 | + | |
100 | + return 0; | |
101 | +} | |
102 | + | |
103 | static int smsc75xx_reset(struct usbnet *dev) | |
104 | { | |
105 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); |