|
@@ -752,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
|
|
|
// precondition: never called in_interrupt
|
|
|
static void usbnet_terminate_urbs(struct usbnet *dev)
|
|
|
{
|
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
int temp;
|
|
|
|
|
|
/* ensure there are no more active urbs */
|
|
|
- add_wait_queue(&unlink_wakeup, &wait);
|
|
|
+ add_wait_queue(&dev->wait, &wait);
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
- dev->wait = &unlink_wakeup;
|
|
|
temp = unlink_urbs(dev, &dev->txq) +
|
|
|
unlink_urbs(dev, &dev->rxq);
|
|
|
|
|
@@ -773,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
|
|
|
"waited for %d urb completions\n", temp);
|
|
|
}
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
- dev->wait = NULL;
|
|
|
- remove_wait_queue(&unlink_wakeup, &wait);
|
|
|
+ remove_wait_queue(&dev->wait, &wait);
|
|
|
}
|
|
|
|
|
|
int usbnet_stop (struct net_device *net)
|
|
|
{
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
struct driver_info *info = dev->driver_info;
|
|
|
- int retval;
|
|
|
+ int retval, pm;
|
|
|
|
|
|
clear_bit(EVENT_DEV_OPEN, &dev->flags);
|
|
|
netif_stop_queue (net);
|
|
@@ -791,6 +788,8 @@ int usbnet_stop (struct net_device *net)
|
|
|
net->stats.rx_packets, net->stats.tx_packets,
|
|
|
net->stats.rx_errors, net->stats.tx_errors);
|
|
|
|
|
|
+ /* to not race resume */
|
|
|
+ pm = usb_autopm_get_interface(dev->intf);
|
|
|
/* allow minidriver to stop correctly (wireless devices to turn off
|
|
|
* radio etc) */
|
|
|
if (info->stop) {
|
|
@@ -817,6 +816,9 @@ int usbnet_stop (struct net_device *net)
|
|
|
dev->flags = 0;
|
|
|
del_timer_sync (&dev->delay);
|
|
|
tasklet_kill (&dev->bh);
|
|
|
+ if (!pm)
|
|
|
+ usb_autopm_put_interface(dev->intf);
|
|
|
+
|
|
|
if (info->manage_power &&
|
|
|
!test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
|
|
|
info->manage_power(dev, 0);
|
|
@@ -1437,11 +1439,12 @@ static void usbnet_bh (unsigned long param)
|
|
|
/* restart RX again after disabling due to high error rate */
|
|
|
clear_bit(EVENT_RX_KILL, &dev->flags);
|
|
|
|
|
|
- // waiting for all pending urbs to complete?
|
|
|
- if (dev->wait) {
|
|
|
- if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
|
|
|
- wake_up (dev->wait);
|
|
|
- }
|
|
|
+ /* waiting for all pending urbs to complete?
|
|
|
+ * only then can we forgo submitting anew
|
|
|
+ */
|
|
|
+ if (waitqueue_active(&dev->wait)) {
|
|
|
+ if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
|
|
|
+ wake_up_all(&dev->wait);
|
|
|
|
|
|
// or are we maybe short a few urbs?
|
|
|
} else if (netif_running (dev->net) &&
|
|
@@ -1580,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
|
|
|
dev->driver_name = name;
|
|
|
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
|
|
|
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
|
|
|
+ init_waitqueue_head(&dev->wait);
|
|
|
skb_queue_head_init (&dev->rxq);
|
|
|
skb_queue_head_init (&dev->txq);
|
|
|
skb_queue_head_init (&dev->done);
|
|
@@ -1791,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)
|
|
|
spin_unlock_irq(&dev->txq.lock);
|
|
|
|
|
|
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
|
|
|
- /* handle remote wakeup ASAP */
|
|
|
- if (!dev->wait &&
|
|
|
- netif_device_present(dev->net) &&
|
|
|
+ /* handle remote wakeup ASAP
|
|
|
+ * we cannot race against stop
|
|
|
+ */
|
|
|
+ if (netif_device_present(dev->net) &&
|
|
|
!timer_pending(&dev->delay) &&
|
|
|
!test_bit(EVENT_RX_HALT, &dev->flags))
|
|
|
rx_alloc_submit(dev, GFP_NOIO);
|