smsc75xx: Add workaround for gigabit link up hardware errata.
[ Upstream commit d461e3da905332189aad546b2ad9adbe6071c7cc ]
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: d0cad87170
("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>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1acb2ad5d9
commit
c7fda06308
1 changed files with 62 additions and 0 deletions
|
@ -81,6 +81,9 @@ static bool turbo_mode = true;
|
||||||
module_param(turbo_mode, bool, 0644);
|
module_param(turbo_mode, bool, 0644);
|
||||||
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
|
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
|
||||||
|
|
||||||
|
static int smsc75xx_link_ok_nopm(struct usbnet *dev);
|
||||||
|
static int smsc75xx_phy_gig_workaround(struct usbnet *dev);
|
||||||
|
|
||||||
static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
||||||
u32 *data, int in_pm)
|
u32 *data, int in_pm)
|
||||||
{
|
{
|
||||||
|
@ -840,6 +843,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* phy workaround for gig link */
|
||||||
|
smsc75xx_phy_gig_workaround(dev);
|
||||||
|
|
||||||
smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
|
smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
|
||||||
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
|
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
|
||||||
ADVERTISE_PAUSE_ASYM);
|
ADVERTISE_PAUSE_ASYM);
|
||||||
|
@ -978,6 +984,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int smsc75xx_phy_gig_workaround(struct usbnet *dev)
|
||||||
|
{
|
||||||
|
struct mii_if_info *mii = &dev->mii;
|
||||||
|
int ret = 0, timeout = 0;
|
||||||
|
u32 buf, link_up = 0;
|
||||||
|
|
||||||
|
/* Set the phy in Gig loopback */
|
||||||
|
smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040);
|
||||||
|
|
||||||
|
/* Wait for the link up */
|
||||||
|
do {
|
||||||
|
link_up = smsc75xx_link_ok_nopm(dev);
|
||||||
|
usleep_range(10000, 20000);
|
||||||
|
timeout++;
|
||||||
|
} while ((!link_up) && (timeout < 1000));
|
||||||
|
|
||||||
|
if (timeout >= 1000) {
|
||||||
|
netdev_warn(dev->net, "Timeout waiting for PHY link up\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* phy reset */
|
||||||
|
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf |= PMT_CTL_PHY_RST;
|
||||||
|
|
||||||
|
ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = 0;
|
||||||
|
do {
|
||||||
|
usleep_range(10000, 20000);
|
||||||
|
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
timeout++;
|
||||||
|
} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
|
||||||
|
|
||||||
|
if (timeout >= 100) {
|
||||||
|
netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int smsc75xx_reset(struct usbnet *dev)
|
static int smsc75xx_reset(struct usbnet *dev)
|
||||||
{
|
{
|
||||||
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
|
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue