net: asix: see 802.3 spec for phy reset
authorRobert Foss <robert.foss@collabora.com>
Mon, 29 Aug 2016 13:32:18 +0000 (09:32 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Sep 2016 04:07:06 +0000 (21:07 -0700)
From: Grant Grundler <grundler@chromium.org>

https://lkml.org/lkml/2014/11/11/947

Ben Hutchings is correct. IEEE 802.3 spec section "22.2.4.1.1 Reset" requires
up to 500ms delay. Mitigate the "max" delay by polling the phy until BCM_RESET
bit is clear.

Signed-off-by: Grant Grundler <grundler@chromium.org>
Signed-off-by: Robert Foss <robert.foss@collabora.com>
Tested-by: Robert Foss <robert.foss@collabora.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/asix_devices.c

index 083dc2ef10c8c3eee1326fa623bfc821e8b3d82e..dbcdda2ebb18d885b591e8f3f436f369e49f75fd 100644 (file)
@@ -212,6 +212,28 @@ static const struct net_device_ops ax88172_netdev_ops = {
        .ndo_set_rx_mode        = ax88172_set_multicast,
 };
 
+static void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits)
+{
+       unsigned int timeout = 5000;
+
+       asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, reset_bits);
+
+       /* give phy_id a chance to process reset */
+       udelay(500);
+
+       /* See IEEE 802.3 "22.2.4.1.1 Reset": 500ms max */
+       while (timeout--) {
+               if (asix_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR)
+                                                       & BMCR_RESET)
+                       udelay(100);
+               else
+                       return;
+       }
+
+       netdev_err(dev->net, "BMCR_RESET timeout on phy_id %d\n",
+                  dev->mii.phy_id);
+}
+
 static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret = 0;
@@ -258,7 +280,7 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
        dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */
 
-       asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+       asix_phy_reset(dev, BMCR_RESET);
        asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
                ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
        mii_nway_restart(&dev->mii);
@@ -900,8 +922,7 @@ static int ax88178_reset(struct usbnet *dev)
        } else if (data->phymode == PHY_MODE_RTL8211CL)
                rtl8211cl_phy_init(dev);
 
-       asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
-                       BMCR_RESET | BMCR_ANENABLE);
+       asix_phy_reset(dev, BMCR_RESET | BMCR_ANENABLE);
        asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
                        ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
        asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,