aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/usb/usbnet.c44
-rw-r--r--drivers/net/wireless/rndis_wlan.c13
-rw-r--r--include/linux/usb/usbnet.h6
3 files changed, 61 insertions, 2 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/*-------------------------------------------------------------------------*/
534void 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}
541EXPORT_SYMBOL_GPL(usbnet_pause_rx);
542
543void 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}
560EXPORT_SYMBOL_GPL(usbnet_resume_rx);
561
562void usbnet_purge_paused_rxq(struct usbnet *dev)
563{
564 skb_queue_purge(&dev->rxq_pause);
565}
566EXPORT_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);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 828dc1825bba..d42692dfbc67 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev,
1764 1764
1765 if (!wrqu->essid.flags || length == 0) 1765 if (!wrqu->essid.flags || length == 0)
1766 return disassociate(usbdev, 1); 1766 return disassociate(usbdev, 1);
1767 else 1767 else {
1768 /* Pause and purge rx queue, so we don't pass packets before
1769 * 'media connect'-indication.
1770 */
1771 usbnet_pause_rx(usbdev);
1772 usbnet_purge_paused_rxq(usbdev);
1773
1768 return set_essid(usbdev, &ssid); 1774 return set_essid(usbdev, &ssid);
1775 }
1769} 1776}
1770 1777
1771 1778
@@ -2328,6 +2335,8 @@ get_bssid:
2328 memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); 2335 memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
2329 wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); 2336 wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
2330 } 2337 }
2338
2339 usbnet_resume_rx(usbdev);
2331 } 2340 }
2332 2341
2333 if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { 2342 if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
@@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
2541 2550
2542 switch (msg->status) { 2551 switch (msg->status) {
2543 case RNDIS_STATUS_MEDIA_CONNECT: 2552 case RNDIS_STATUS_MEDIA_CONNECT:
2553 usbnet_pause_rx(usbdev);
2554
2544 devinfo(usbdev, "media connect"); 2555 devinfo(usbdev, "media connect");
2545 2556
2546 /* queue work to avoid recursive calls into rndis_command */ 2557 /* queue work to avoid recursive calls into rndis_command */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index de8b4b18961b..09514252d84e 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -53,6 +53,7 @@ struct usbnet {
53 struct sk_buff_head rxq; 53 struct sk_buff_head rxq;
54 struct sk_buff_head txq; 54 struct sk_buff_head txq;
55 struct sk_buff_head done; 55 struct sk_buff_head done;
56 struct sk_buff_head rxq_pause;
56 struct urb *interrupt; 57 struct urb *interrupt;
57 struct tasklet_struct bh; 58 struct tasklet_struct bh;
58 59
@@ -63,6 +64,7 @@ struct usbnet {
63# define EVENT_RX_MEMORY 2 64# define EVENT_RX_MEMORY 2
64# define EVENT_STS_SPLIT 3 65# define EVENT_STS_SPLIT 3
65# define EVENT_LINK_RESET 4 66# define EVENT_LINK_RESET 4
67# define EVENT_RX_PAUSED 5
66}; 68};
67 69
68static inline struct usb_driver *driver_of(struct usb_interface *intf) 70static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -190,6 +192,10 @@ extern void usbnet_defer_kevent (struct usbnet *, int);
190extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); 192extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
191extern void usbnet_unlink_rx_urbs(struct usbnet *); 193extern void usbnet_unlink_rx_urbs(struct usbnet *);
192 194
195extern void usbnet_pause_rx(struct usbnet *);
196extern void usbnet_resume_rx(struct usbnet *);
197extern void usbnet_purge_paused_rxq(struct usbnet *);
198
193extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); 199extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
194extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); 200extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
195extern u32 usbnet_get_link (struct net_device *net); 201extern u32 usbnet_get_link (struct net_device *net);