|
@@ -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);
|
|
|
|