]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.152/smsc75xx-add-workaround-for-gigabit-link-up-hardware-errata.patch
Linux 4.4.152
[thirdparty/kernel/stable-queue.git] / releases / 4.4.152 / smsc75xx-add-workaround-for-gigabit-link-up-hardware-errata.patch
CommitLineData
ba4a4fdd
GKH
1From foo@baz Wed Aug 22 10:28:26 CEST 2018
2From: Yuiko Oshino <yuiko.oshino@microchip.com>
3Date: Tue, 3 Jul 2018 11:21:46 -0400
4Subject: smsc75xx: Add workaround for gigabit link up hardware errata.
5
6From: Yuiko Oshino <yuiko.oshino@microchip.com>
7
8[ Upstream commit d461e3da905332189aad546b2ad9adbe6071c7cc ]
9
10In 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
12Fixes: d0cad871703b898a442e4049c532ec39168e5b57 ("SMSC75XX USB 2.0 Gigabit Ethernet Devices")
13Signed-off-by: Yuiko Oshino <yuiko.oshino@microchip.com>
14Signed-off-by: David S. Miller <davem@davemloft.net>
15Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
16Signed-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]);