Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / drivers / net / usb / usbnet.c
index 34e425264a7a20f841487c3a949deb3b7abbaf20..1e5a9b72650e9946e23040f1169421bf87d18317 100644 (file)
@@ -938,6 +938,27 @@ static const struct ethtool_ops usbnet_ethtool_ops = {
 
 /*-------------------------------------------------------------------------*/
 
+static void __handle_link_change(struct usbnet *dev)
+{
+       if (!test_bit(EVENT_DEV_OPEN, &dev->flags))
+               return;
+
+       if (!netif_carrier_ok(dev->net)) {
+               /* kill URBs for reading packets to save bus bandwidth */
+               unlink_urbs(dev, &dev->rxq);
+
+               /*
+                * tx_timeout will unlink URBs for sending packets and
+                * tx queue is stopped by netcore after link becomes off
+                */
+       } else {
+               /* submitting URBs for reading packets */
+               tasklet_schedule(&dev->bh);
+       }
+
+       clear_bit(EVENT_LINK_CHANGE, &dev->flags);
+}
+
 /* work that cannot be done in interrupt context uses keventd.
  *
  * NOTE:  with 2.5 we could do more of this using completion callbacks,
@@ -1035,8 +1056,14 @@ skip_reset:
                } else {
                        usb_autopm_put_interface(dev->intf);
                }
+
+               /* handle link change from link resetting */
+               __handle_link_change(dev);
        }
 
+       if (test_bit (EVENT_LINK_CHANGE, &dev->flags))
+               __handle_link_change(dev);
+
        if (dev->flags)
                netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
 }
@@ -1286,6 +1313,7 @@ static void usbnet_bh (unsigned long param)
        // or are we maybe short a few urbs?
        } else if (netif_running (dev->net) &&
                   netif_device_present (dev->net) &&
+                  netif_carrier_ok(dev->net) &&
                   !timer_pending (&dev->delay) &&
                   !test_bit (EVENT_RX_HALT, &dev->flags)) {
                int     temp = dev->rxq.qlen;
@@ -1663,6 +1691,8 @@ void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset)
 
        if (need_reset && link)
                usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+       else
+               usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
 }
 EXPORT_SYMBOL(usbnet_link_change);