diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index af1fe4696509..7d471fca2743 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -233,6 +233,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) | |||
233 | { | 233 | { |
234 | int status; | 234 | int status; |
235 | 235 | ||
236 | if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { | ||
237 | skb_queue_tail(&dev->rxq_pause, skb); | ||
238 | return; | ||
239 | } | ||
240 | |||
236 | skb->protocol = eth_type_trans (skb, dev->net); | 241 | skb->protocol = eth_type_trans (skb, dev->net); |
237 | dev->net->stats.rx_packets++; | 242 | dev->net->stats.rx_packets++; |
238 | dev->net->stats.rx_bytes += skb->len; | 243 | dev->net->stats.rx_bytes += skb->len; |
@@ -526,6 +531,41 @@ static void intr_complete (struct urb *urb) | |||
526 | } | 531 | } |
527 | 532 | ||
528 | /*-------------------------------------------------------------------------*/ | 533 | /*-------------------------------------------------------------------------*/ |
534 | void usbnet_pause_rx(struct usbnet *dev) | ||
535 | { | ||
536 | set_bit(EVENT_RX_PAUSED, &dev->flags); | ||
537 | |||
538 | if (netif_msg_rx_status(dev)) | ||
539 | devdbg(dev, "paused rx queue enabled"); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(usbnet_pause_rx); | ||
542 | |||
543 | void usbnet_resume_rx(struct usbnet *dev) | ||
544 | { | ||
545 | struct sk_buff *skb; | ||
546 | int num = 0; | ||
547 | |||
548 | clear_bit(EVENT_RX_PAUSED, &dev->flags); | ||
549 | |||
550 | while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { | ||
551 | usbnet_skb_return(dev, skb); | ||
552 | num++; | ||
553 | } | ||
554 | |||
555 | tasklet_schedule(&dev->bh); | ||
556 | |||
557 | if (netif_msg_rx_status(dev)) | ||
558 | devdbg(dev, "paused rx queue disabled, %d skbs requeued", num); | ||
559 | } | ||
560 | EXPORT_SYMBOL_GPL(usbnet_resume_rx); | ||
561 | |||
562 | void usbnet_purge_paused_rxq(struct usbnet *dev) | ||
563 | { | ||
564 | skb_queue_purge(&dev->rxq_pause); | ||
565 | } | ||
566 | EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); | ||
567 | |||
568 | /*-------------------------------------------------------------------------*/ | ||
529 | 569 | ||
530 | // unlink pending rx/tx; completion handlers do all other cleanup | 570 | // unlink pending rx/tx; completion handlers do all other cleanup |
531 | 571 | ||
@@ -623,6 +663,8 @@ int usbnet_stop (struct net_device *net) | |||
623 | 663 | ||
624 | usb_kill_urb(dev->interrupt); | 664 | usb_kill_urb(dev->interrupt); |
625 | 665 | ||
666 | usbnet_purge_paused_rxq(dev); | ||
667 | |||
626 | /* deferred work (task, timer, softirq) must also stop. | 668 | /* deferred work (task, timer, softirq) must also stop. |
627 | * can't flush_scheduled_work() until we drop rtnl (later), | 669 | * can't flush_scheduled_work() until we drop rtnl (later), |
628 | * else workers could deadlock; so make workers a NOP. | 670 | * else workers could deadlock; so make workers a NOP. |
@@ -1113,7 +1155,6 @@ static void usbnet_bh (unsigned long param) | |||
1113 | } | 1155 | } |
1114 | 1156 | ||
1115 | 1157 | ||
1116 | |||
1117 | /*------------------------------------------------------------------------- | 1158 | /*------------------------------------------------------------------------- |
1118 | * | 1159 | * |
1119 | * USB Device Driver support | 1160 | * USB Device Driver support |
@@ -1210,6 +1251,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1210 | skb_queue_head_init (&dev->rxq); | 1251 | skb_queue_head_init (&dev->rxq); |
1211 | skb_queue_head_init (&dev->txq); | 1252 | skb_queue_head_init (&dev->txq); |
1212 | skb_queue_head_init (&dev->done); | 1253 | skb_queue_head_init (&dev->done); |
1254 | skb_queue_head_init(&dev->rxq_pause); | ||
1213 | dev->bh.func = usbnet_bh; | 1255 | dev->bh.func = usbnet_bh; |
1214 | dev->bh.data = (unsigned long) dev; | 1256 | dev->bh.data = (unsigned long) dev; |
1215 | INIT_WORK (&dev->kevent, kevent); | 1257 | INIT_WORK (&dev->kevent, kevent); |