/*-------------------------------------------------------------------------*/
+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,
} 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);
}
// 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;
netif_device_attach (net);
if (dev->driver_info->flags & FLAG_LINK_INTR)
- netif_carrier_off(net);
+ usbnet_link_change(dev, 0, 0);
return 0;
}
EXPORT_SYMBOL(usbnet_manage_power);
+void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset)
+{
+ /* update link after link is reseted */
+ if (link && !need_reset)
+ netif_carrier_on(dev->net);
+ else
+ netif_carrier_off(dev->net);
+
+ if (need_reset && link)
+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+ else
+ usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
+}
+EXPORT_SYMBOL(usbnet_link_change);
+
/*-------------------------------------------------------------------------*/
static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
u16 value, u16 index, void *data, u16 size)