diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2009-07-30 12:41:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-04 16:44:15 -0400 |
commit | 1487cd5e76337555737cbc55d7d83f41460d198f (patch) | |
tree | f6d4dbb7debf36014d25ab4b482a32683d46ede2 | |
parent | e40cbdac0629402a4cb0c3bca0cc19ab7a00e00d (diff) |
usbnet: allow "minidriver" to prevent urb unlinking on usbnet_stop
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>
-rw-r--r-- | drivers/net/usb/usbnet.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 9 | ||||
-rw-r--r-- | include/linux/usb/usbnet.h | 1 |
3 files changed, 25 insertions, 17 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 25e435c49040..af1fe4696509 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net) | |||
601 | info->description); | 601 | info->description); |
602 | } | 602 | } |
603 | 603 | ||
604 | // ensure there are no more active urbs | 604 | if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { |
605 | add_wait_queue (&unlink_wakeup, &wait); | 605 | /* ensure there are no more active urbs */ |
606 | dev->wait = &unlink_wakeup; | 606 | add_wait_queue(&unlink_wakeup, &wait); |
607 | temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); | 607 | dev->wait = &unlink_wakeup; |
608 | 608 | temp = unlink_urbs(dev, &dev->txq) + | |
609 | // maybe wait for deletions to finish. | 609 | unlink_urbs(dev, &dev->rxq); |
610 | while (!skb_queue_empty(&dev->rxq) | 610 | |
611 | && !skb_queue_empty(&dev->txq) | 611 | /* maybe wait for deletions to finish. */ |
612 | && !skb_queue_empty(&dev->done)) { | 612 | while (!skb_queue_empty(&dev->rxq) |
613 | msleep(UNLINK_TIMEOUT_MS); | 613 | && !skb_queue_empty(&dev->txq) |
614 | if (netif_msg_ifdown (dev)) | 614 | && !skb_queue_empty(&dev->done)) { |
615 | devdbg (dev, "waited for %d urb completions", temp); | 615 | msleep(UNLINK_TIMEOUT_MS); |
616 | if (netif_msg_ifdown(dev)) | ||
617 | devdbg(dev, "waited for %d urb completions", | ||
618 | temp); | ||
619 | } | ||
620 | dev->wait = NULL; | ||
621 | remove_wait_queue(&unlink_wakeup, &wait); | ||
616 | } | 622 | } |
617 | dev->wait = NULL; | ||
618 | remove_wait_queue (&unlink_wakeup, &wait); | ||
619 | 623 | ||
620 | usb_kill_urb(dev->interrupt); | 624 | usb_kill_urb(dev->interrupt); |
621 | 625 | ||
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 09c0702ae645..76c5ec6bbbc5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -2513,7 +2513,8 @@ static int rndis_wlan_stop(struct usbnet *usbdev) | |||
2513 | 2513 | ||
2514 | static const struct driver_info bcm4320b_info = { | 2514 | static const struct driver_info bcm4320b_info = { |
2515 | .description = "Wireless RNDIS device, BCM4320b based", | 2515 | .description = "Wireless RNDIS device, BCM4320b based", |
2516 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 2516 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | |
2517 | FLAG_AVOID_UNLINK_URBS, | ||
2517 | .bind = rndis_wlan_bind, | 2518 | .bind = rndis_wlan_bind, |
2518 | .unbind = rndis_wlan_unbind, | 2519 | .unbind = rndis_wlan_unbind, |
2519 | .status = rndis_status, | 2520 | .status = rndis_status, |
@@ -2527,7 +2528,8 @@ static const struct driver_info bcm4320b_info = { | |||
2527 | 2528 | ||
2528 | static const struct driver_info bcm4320a_info = { | 2529 | static const struct driver_info bcm4320a_info = { |
2529 | .description = "Wireless RNDIS device, BCM4320a based", | 2530 | .description = "Wireless RNDIS device, BCM4320a based", |
2530 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 2531 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | |
2532 | FLAG_AVOID_UNLINK_URBS, | ||
2531 | .bind = rndis_wlan_bind, | 2533 | .bind = rndis_wlan_bind, |
2532 | .unbind = rndis_wlan_unbind, | 2534 | .unbind = rndis_wlan_unbind, |
2533 | .status = rndis_status, | 2535 | .status = rndis_status, |
@@ -2541,7 +2543,8 @@ static const struct driver_info bcm4320a_info = { | |||
2541 | 2543 | ||
2542 | static const struct driver_info rndis_wlan_info = { | 2544 | static const struct driver_info rndis_wlan_info = { |
2543 | .description = "Wireless RNDIS device", | 2545 | .description = "Wireless RNDIS device", |
2544 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 2546 | .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | |
2547 | FLAG_AVOID_UNLINK_URBS, | ||
2545 | .bind = rndis_wlan_bind, | 2548 | .bind = rndis_wlan_bind, |
2546 | .unbind = rndis_wlan_unbind, | 2549 | .unbind = rndis_wlan_unbind, |
2547 | .status = rndis_status, | 2550 | .status = rndis_status, |
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 7c17b2efba86..c642f78dd9cf 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h | |||
@@ -86,6 +86,7 @@ struct driver_info { | |||
86 | 86 | ||
87 | #define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ | 87 | #define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ |
88 | #define FLAG_WLAN 0x0080 /* use "wlan%d" names */ | 88 | #define FLAG_WLAN 0x0080 /* use "wlan%d" names */ |
89 | #define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ | ||
89 | 90 | ||
90 | 91 | ||
91 | /* init device ... can sleep, or cause probe() failure */ | 92 | /* init device ... can sleep, or cause probe() failure */ |