diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1e5a9b72650e..f95cb032394b 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -252,6 +252,70 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) | |||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | /* Submit the interrupt URB if not previously submitted, increasing refcount */ | ||
256 | int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags) | ||
257 | { | ||
258 | int ret = 0; | ||
259 | |||
260 | WARN_ON_ONCE(dev->interrupt == NULL); | ||
261 | if (dev->interrupt) { | ||
262 | mutex_lock(&dev->interrupt_mutex); | ||
263 | |||
264 | if (++dev->interrupt_count == 1) | ||
265 | ret = usb_submit_urb(dev->interrupt, mem_flags); | ||
266 | |||
267 | dev_dbg(&dev->udev->dev, "incremented interrupt URB count to %d\n", | ||
268 | dev->interrupt_count); | ||
269 | mutex_unlock(&dev->interrupt_mutex); | ||
270 | } | ||
271 | return ret; | ||
272 | } | ||
273 | EXPORT_SYMBOL_GPL(usbnet_status_start); | ||
274 | |||
275 | /* For resume; submit interrupt URB if previously submitted */ | ||
276 | static int __usbnet_status_start_force(struct usbnet *dev, gfp_t mem_flags) | ||
277 | { | ||
278 | int ret = 0; | ||
279 | |||
280 | mutex_lock(&dev->interrupt_mutex); | ||
281 | if (dev->interrupt_count) { | ||
282 | ret = usb_submit_urb(dev->interrupt, mem_flags); | ||
283 | dev_dbg(&dev->udev->dev, | ||
284 | "submitted interrupt URB for resume\n"); | ||
285 | } | ||
286 | mutex_unlock(&dev->interrupt_mutex); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | /* Kill the interrupt URB if all submitters want it killed */ | ||
291 | void usbnet_status_stop(struct usbnet *dev) | ||
292 | { | ||
293 | if (dev->interrupt) { | ||
294 | mutex_lock(&dev->interrupt_mutex); | ||
295 | WARN_ON(dev->interrupt_count == 0); | ||
296 | |||
297 | if (dev->interrupt_count && --dev->interrupt_count == 0) | ||
298 | usb_kill_urb(dev->interrupt); | ||
299 | |||
300 | dev_dbg(&dev->udev->dev, | ||
301 | "decremented interrupt URB count to %d\n", | ||
302 | dev->interrupt_count); | ||
303 | mutex_unlock(&dev->interrupt_mutex); | ||
304 | } | ||
305 | } | ||
306 | EXPORT_SYMBOL_GPL(usbnet_status_stop); | ||
307 | |||
308 | /* For suspend; always kill interrupt URB */ | ||
309 | static void __usbnet_status_stop_force(struct usbnet *dev) | ||
310 | { | ||
311 | if (dev->interrupt) { | ||
312 | mutex_lock(&dev->interrupt_mutex); | ||
313 | usb_kill_urb(dev->interrupt); | ||
314 | dev_dbg(&dev->udev->dev, "killed interrupt URB for suspend\n"); | ||
315 | mutex_unlock(&dev->interrupt_mutex); | ||
316 | } | ||
317 | } | ||
318 | |||
255 | /* Passes this packet up the stack, updating its accounting. | 319 | /* Passes this packet up the stack, updating its accounting. |
256 | * Some link protocols batch packets, so their rx_fixup paths | 320 | * Some link protocols batch packets, so their rx_fixup paths |
257 | * can return clones as well as just modify the original skb. | 321 | * can return clones as well as just modify the original skb. |
@@ -725,7 +789,7 @@ int usbnet_stop (struct net_device *net) | |||
725 | if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) | 789 | if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) |
726 | usbnet_terminate_urbs(dev); | 790 | usbnet_terminate_urbs(dev); |
727 | 791 | ||
728 | usb_kill_urb(dev->interrupt); | 792 | usbnet_status_stop(dev); |
729 | 793 | ||
730 | usbnet_purge_paused_rxq(dev); | 794 | usbnet_purge_paused_rxq(dev); |
731 | 795 | ||
@@ -787,7 +851,7 @@ int usbnet_open (struct net_device *net) | |||
787 | 851 | ||
788 | /* start any status interrupt transfer */ | 852 | /* start any status interrupt transfer */ |
789 | if (dev->interrupt) { | 853 | if (dev->interrupt) { |
790 | retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); | 854 | retval = usbnet_status_start(dev, GFP_KERNEL); |
791 | if (retval < 0) { | 855 | if (retval < 0) { |
792 | netif_err(dev, ifup, dev->net, | 856 | netif_err(dev, ifup, dev->net, |
793 | "intr submit %d\n", retval); | 857 | "intr submit %d\n", retval); |
@@ -1458,6 +1522,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1458 | dev->delay.data = (unsigned long) dev; | 1522 | dev->delay.data = (unsigned long) dev; |
1459 | init_timer (&dev->delay); | 1523 | init_timer (&dev->delay); |
1460 | mutex_init (&dev->phy_mutex); | 1524 | mutex_init (&dev->phy_mutex); |
1525 | mutex_init(&dev->interrupt_mutex); | ||
1526 | dev->interrupt_count = 0; | ||
1461 | 1527 | ||
1462 | dev->net = net; | 1528 | dev->net = net; |
1463 | strcpy (net->name, "usb%d"); | 1529 | strcpy (net->name, "usb%d"); |
@@ -1593,7 +1659,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) | |||
1593 | */ | 1659 | */ |
1594 | netif_device_detach (dev->net); | 1660 | netif_device_detach (dev->net); |
1595 | usbnet_terminate_urbs(dev); | 1661 | usbnet_terminate_urbs(dev); |
1596 | usb_kill_urb(dev->interrupt); | 1662 | __usbnet_status_stop_force(dev); |
1597 | 1663 | ||
1598 | /* | 1664 | /* |
1599 | * reattach so runtime management can use and | 1665 | * reattach so runtime management can use and |
@@ -1613,9 +1679,8 @@ int usbnet_resume (struct usb_interface *intf) | |||
1613 | int retval; | 1679 | int retval; |
1614 | 1680 | ||
1615 | if (!--dev->suspend_count) { | 1681 | if (!--dev->suspend_count) { |
1616 | /* resume interrupt URBs */ | 1682 | /* resume interrupt URB if it was previously submitted */ |
1617 | if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) | 1683 | __usbnet_status_start_force(dev, GFP_NOIO); |
1618 | usb_submit_urb(dev->interrupt, GFP_NOIO); | ||
1619 | 1684 | ||
1620 | spin_lock_irq(&dev->txq.lock); | 1685 | spin_lock_irq(&dev->txq.lock); |
1621 | while ((res = usb_get_from_anchor(&dev->deferred))) { | 1686 | while ((res = usb_get_from_anchor(&dev->deferred))) { |