|
@@ -82,6 +82,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)
|
|
{
|
|
{
|
|
@@ -852,6 +855,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);
|
|
@@ -987,6 +993,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]);
|