diff options
author | Ming Lei <ming.lei@canonical.com> | 2012-06-19 17:15:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-22 20:34:18 -0400 |
commit | 65841fd5132c3941cdf5df09e70df3ed28323212 (patch) | |
tree | 804267b5d8b710e9939460aaaecb0803356c7843 /drivers/net/usb/usbnet.c | |
parent | 5eeb3132eb4c5e9ca92e5247fe4575fe9f8c3efe (diff) |
usbnet: handle remote wakeup asap
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>
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1e46f693eb47..aba769d77459 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -1204,6 +1204,21 @@ deferred: | |||
1204 | } | 1204 | } |
1205 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); | 1205 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); |
1206 | 1206 | ||
1207 | static void rx_alloc_submit(struct usbnet *dev, gfp_t flags) | ||
1208 | { | ||
1209 | struct urb *urb; | ||
1210 | int i; | ||
1211 | |||
1212 | /* don't refill the queue all at once */ | ||
1213 | for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { | ||
1214 | urb = usb_alloc_urb(0, flags); | ||
1215 | if (urb != NULL) { | ||
1216 | if (rx_submit(dev, urb, flags) == -ENOLINK) | ||
1217 | return; | ||
1218 | } | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1207 | /*-------------------------------------------------------------------------*/ | 1222 | /*-------------------------------------------------------------------------*/ |
1208 | 1223 | ||
1209 | // tasklet (work deferred from completions, in_irq) or timer | 1224 | // tasklet (work deferred from completions, in_irq) or timer |
@@ -1243,26 +1258,14 @@ static void usbnet_bh (unsigned long param) | |||
1243 | !timer_pending (&dev->delay) && | 1258 | !timer_pending (&dev->delay) && |
1244 | !test_bit (EVENT_RX_HALT, &dev->flags)) { | 1259 | !test_bit (EVENT_RX_HALT, &dev->flags)) { |
1245 | int temp = dev->rxq.qlen; | 1260 | int temp = dev->rxq.qlen; |
1246 | int qlen = RX_QLEN (dev); | 1261 | |
1247 | 1262 | if (temp < RX_QLEN(dev)) { | |
1248 | if (temp < qlen) { | 1263 | rx_alloc_submit(dev, GFP_ATOMIC); |
1249 | struct urb *urb; | ||
1250 | int i; | ||
1251 | |||
1252 | // don't refill the queue all at once | ||
1253 | for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { | ||
1254 | urb = usb_alloc_urb (0, GFP_ATOMIC); | ||
1255 | if (urb != NULL) { | ||
1256 | if (rx_submit (dev, urb, GFP_ATOMIC) == | ||
1257 | -ENOLINK) | ||
1258 | return; | ||
1259 | } | ||
1260 | } | ||
1261 | if (temp != dev->rxq.qlen) | 1264 | if (temp != dev->rxq.qlen) |
1262 | netif_dbg(dev, link, dev->net, | 1265 | netif_dbg(dev, link, dev->net, |
1263 | "rxqlen %d --> %d\n", | 1266 | "rxqlen %d --> %d\n", |
1264 | temp, dev->rxq.qlen); | 1267 | temp, dev->rxq.qlen); |
1265 | if (dev->rxq.qlen < qlen) | 1268 | if (dev->rxq.qlen < RX_QLEN(dev)) |
1266 | tasklet_schedule (&dev->bh); | 1269 | tasklet_schedule (&dev->bh); |
1267 | } | 1270 | } |
1268 | if (dev->txq.qlen < TX_QLEN (dev)) | 1271 | if (dev->txq.qlen < TX_QLEN (dev)) |
@@ -1572,6 +1575,13 @@ int usbnet_resume (struct usb_interface *intf) | |||
1572 | spin_unlock_irq(&dev->txq.lock); | 1575 | spin_unlock_irq(&dev->txq.lock); |
1573 | 1576 | ||
1574 | if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { | 1577 | if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { |
1578 | /* handle remote wakeup ASAP */ | ||
1579 | if (!dev->wait && | ||
1580 | netif_device_present(dev->net) && | ||
1581 | !timer_pending(&dev->delay) && | ||
1582 | !test_bit(EVENT_RX_HALT, &dev->flags)) | ||
1583 | rx_alloc_submit(dev, GFP_KERNEL); | ||
1584 | |||
1575 | if (!(dev->txq.qlen >= TX_QLEN(dev))) | 1585 | if (!(dev->txq.qlen >= TX_QLEN(dev))) |
1576 | netif_tx_wake_all_queues(dev->net); | 1586 | netif_tx_wake_all_queues(dev->net); |
1577 | tasklet_schedule (&dev->bh); | 1587 | tasklet_schedule (&dev->bh); |