aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/usbnet.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-06-19 17:15:53 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-22 20:34:18 -0400
commit65841fd5132c3941cdf5df09e70df3ed28323212 (patch)
tree804267b5d8b710e9939460aaaecb0803356c7843 /drivers/net/usb/usbnet.c
parent5eeb3132eb4c5e9ca92e5247fe4575fe9f8c3efe (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.c42
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}
1205EXPORT_SYMBOL_GPL(usbnet_start_xmit); 1205EXPORT_SYMBOL_GPL(usbnet_start_xmit);
1206 1206
1207static 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);