usbnet: allow "minidriver" to prevent urb unlinking on usbnet_stop
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>
Thu, 30 Jul 2009 16:41:20 +0000 (19:41 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 4 Aug 2009 20:44:15 +0000 (16:44 -0400)
rndis_wlan devices freeze after running usbnet_stop several times. It appears
that firmware freezes in state where it does not respond to any RNDIS commands
and device have to be physically unplugged/replugged. This patch lets
minidrivers to disable unlink_urbs on usbnet_stop through new info flag.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/usb/usbnet.c
drivers/net/wireless/rndis_wlan.c
include/linux/usb/usbnet.h

index 25e435c..af1fe46 100644 (file)
@@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net)
                                info->description);
        }
 
-       // ensure there are no more active urbs
-       add_wait_queue (&unlink_wakeup, &wait);
-       dev->wait = &unlink_wakeup;
-       temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
-
-       // maybe wait for deletions to finish.
-       while (!skb_queue_empty(&dev->rxq)
-                       && !skb_queue_empty(&dev->txq)
-                       && !skb_queue_empty(&dev->done)) {
-               msleep(UNLINK_TIMEOUT_MS);
-               if (netif_msg_ifdown (dev))
-                       devdbg (dev, "waited for %d urb completions", temp);
+       if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) {
+               /* ensure there are no more active urbs */
+               add_wait_queue(&unlink_wakeup, &wait);
+               dev->wait = &unlink_wakeup;
+               temp = unlink_urbs(dev, &dev->txq) +
+                       unlink_urbs(dev, &dev->rxq);
+
+               /* maybe wait for deletions to finish. */
+               while (!skb_queue_empty(&dev->rxq)
+                               && !skb_queue_empty(&dev->txq)
+                               && !skb_queue_empty(&dev->done)) {
+                       msleep(UNLINK_TIMEOUT_MS);
+                       if (netif_msg_ifdown(dev))
+                               devdbg(dev, "waited for %d urb completions",
+                                       temp);
+               }
+               dev->wait = NULL;
+               remove_wait_queue(&unlink_wakeup, &wait);
        }
-       dev->wait = NULL;
-       remove_wait_queue (&unlink_wakeup, &wait);
 
        usb_kill_urb(dev->interrupt);
 
index 09c0702..76c5ec6 100644 (file)
@@ -2513,7 +2513,8 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
 
 static const struct driver_info        bcm4320b_info = {
        .description =  "Wireless RNDIS device, BCM4320b based",
-       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+                               FLAG_AVOID_UNLINK_URBS,
        .bind =         rndis_wlan_bind,
        .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
@@ -2527,7 +2528,8 @@ static const struct driver_info   bcm4320b_info = {
 
 static const struct driver_info        bcm4320a_info = {
        .description =  "Wireless RNDIS device, BCM4320a based",
-       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+                               FLAG_AVOID_UNLINK_URBS,
        .bind =         rndis_wlan_bind,
        .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
@@ -2541,7 +2543,8 @@ static const struct driver_info   bcm4320a_info = {
 
 static const struct driver_info rndis_wlan_info = {
        .description =  "Wireless RNDIS device",
-       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+                               FLAG_AVOID_UNLINK_URBS,
        .bind =         rndis_wlan_bind,
        .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
index 7c17b2e..c642f78 100644 (file)
@@ -86,6 +86,7 @@ struct driver_info {
 
 #define FLAG_FRAMING_AX 0x0040         /* AX88772/178 packets */
 #define FLAG_WLAN      0x0080          /* use "wlan%d" names */
+#define FLAG_AVOID_UNLINK_URBS 0x0100  /* don't unlink urbs at usbnet_stop() */
 
 
        /* init device ... can sleep, or cause probe() failure */