usbnet: handle remote wakeup asap
authorMing Lei <ming.lei@canonical.com>
Tue, 19 Jun 2012 21:15:53 +0000 (21:15 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 23 Jun 2012 00:34:18 +0000 (17:34 -0700)
If usbnet is resumed by remote wakeup, generally there are
some packets comming to be handled, so allocate and submit
rx URBs in usbnet_resume to avoid delays introduced by tasklet.
Otherwise, usbnet may have been runtime suspended before the
usbnet_bh is executed to schedule Rx URBs.

Without the patch, usbnet can't recieve any packets from peer
in runtime suspend state if runtime PM is enabled and
autosuspend_delay is set as zero.

Signed-off-by: Ming Lei <ming.lei@canonical.com>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/usbnet.c

index 1e46f693eb47e4e946eb3063ab6d7bc0b4852bb0..aba769d77459b61e6cc42deff0a101acd709af89 100644 (file)
@@ -1204,6 +1204,21 @@ deferred:
 }
 EXPORT_SYMBOL_GPL(usbnet_start_xmit);
 
+static void rx_alloc_submit(struct usbnet *dev, gfp_t flags)
+{
+       struct urb      *urb;
+       int             i;
+
+       /* don't refill the queue all at once */
+       for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
+               urb = usb_alloc_urb(0, flags);
+               if (urb != NULL) {
+                       if (rx_submit(dev, urb, flags) == -ENOLINK)
+                               return;
+               }
+       }
+}
+
 /*-------------------------------------------------------------------------*/
 
 // tasklet (work deferred from completions, in_irq) or timer
@@ -1243,26 +1258,14 @@ static void usbnet_bh (unsigned long param)
                   !timer_pending (&dev->delay) &&
                   !test_bit (EVENT_RX_HALT, &dev->flags)) {
                int     temp = dev->rxq.qlen;
-               int     qlen = RX_QLEN (dev);
-
-               if (temp < qlen) {
-                       struct urb      *urb;
-                       int             i;
-
-                       // don't refill the queue all at once
-                       for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
-                               urb = usb_alloc_urb (0, GFP_ATOMIC);
-                               if (urb != NULL) {
-                                       if (rx_submit (dev, urb, GFP_ATOMIC) ==
-                                           -ENOLINK)
-                                               return;
-                               }
-                       }
+
+               if (temp < RX_QLEN(dev)) {
+                       rx_alloc_submit(dev, GFP_ATOMIC);
                        if (temp != dev->rxq.qlen)
                                netif_dbg(dev, link, dev->net,
                                          "rxqlen %d --> %d\n",
                                          temp, dev->rxq.qlen);
-                       if (dev->rxq.qlen < qlen)
+                       if (dev->rxq.qlen < RX_QLEN(dev))
                                tasklet_schedule (&dev->bh);
                }
                if (dev->txq.qlen < TX_QLEN (dev))
@@ -1572,6 +1575,13 @@ 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) &&
+                               !timer_pending(&dev->delay) &&
+                               !test_bit(EVENT_RX_HALT, &dev->flags))
+                                       rx_alloc_submit(dev, GFP_KERNEL);
+
                        if (!(dev->txq.qlen >= TX_QLEN(dev)))
                                netif_tx_wake_all_queues(dev->net);
                        tasklet_schedule (&dev->bh);