diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-03-17 05:59:24 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-03-25 16:42:22 -0400 |
commit | 29bb7013a53d8fc43f79f39d22a15ba8d3e77d9b (patch) | |
tree | 824374b426f7e3c2d4a5679b0176fa4add44f996 | |
parent | d7d0f081c48951018133cac38c8c0796f37db727 (diff) |
rtlwifi: usb: defer rx processing to tasklet
Move processing of received packets to tasklet from hard-irq context.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.c | 60 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.h | 4 |
3 files changed, 51 insertions, 15 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index b6222eedb835..710f7904ecdf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | |||
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
434 | (u32)hdr->addr1[2], (u32)hdr->addr1[3], | 434 | (u32)hdr->addr1[2], (u32)hdr->addr1[3], |
435 | (u32)hdr->addr1[4], (u32)hdr->addr1[5]); | 435 | (u32)hdr->addr1[4], (u32)hdr->addr1[5]); |
436 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); | 436 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); |
437 | ieee80211_rx_irqsafe(hw, skb); | 437 | ieee80211_rx(hw, skb); |
438 | } | 438 | } |
439 | 439 | ||
440 | void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) | 440 | void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 8df5836cc99c..a7b54f631293 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -308,6 +308,8 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static void _rtl_rx_work(unsigned long param); | ||
312 | |||
311 | static int _rtl_usb_init_rx(struct ieee80211_hw *hw) | 313 | static int _rtl_usb_init_rx(struct ieee80211_hw *hw) |
312 | { | 314 | { |
313 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 315 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
@@ -325,6 +327,11 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw) | |||
325 | rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); | 327 | rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); |
326 | init_usb_anchor(&rtlusb->rx_submitted); | 328 | init_usb_anchor(&rtlusb->rx_submitted); |
327 | init_usb_anchor(&rtlusb->rx_cleanup_urbs); | 329 | init_usb_anchor(&rtlusb->rx_cleanup_urbs); |
330 | |||
331 | skb_queue_head_init(&rtlusb->rx_queue); | ||
332 | rtlusb->rx_work_tasklet.func = _rtl_rx_work; | ||
333 | rtlusb->rx_work_tasklet.data = (unsigned long)rtlusb; | ||
334 | |||
328 | return 0; | 335 | return 0; |
329 | } | 336 | } |
330 | 337 | ||
@@ -515,7 +522,7 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, | |||
515 | } | 522 | } |
516 | 523 | ||
517 | if (likely(rtl_action_proc(hw, skb, false))) | 524 | if (likely(rtl_action_proc(hw, skb, false))) |
518 | ieee80211_rx_irqsafe(hw, skb); | 525 | ieee80211_rx(hw, skb); |
519 | else | 526 | else |
520 | dev_kfree_skb_any(skb); | 527 | dev_kfree_skb_any(skb); |
521 | } | 528 | } |
@@ -534,7 +541,31 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
534 | while (!skb_queue_empty(&rx_queue)) { | 541 | while (!skb_queue_empty(&rx_queue)) { |
535 | _skb = skb_dequeue(&rx_queue); | 542 | _skb = skb_dequeue(&rx_queue); |
536 | _rtl_usb_rx_process_agg(hw, _skb); | 543 | _rtl_usb_rx_process_agg(hw, _skb); |
537 | ieee80211_rx_irqsafe(hw, _skb); | 544 | ieee80211_rx(hw, _skb); |
545 | } | ||
546 | } | ||
547 | |||
548 | #define __RX_SKB_MAX_QUEUED 32 | ||
549 | |||
550 | static void _rtl_rx_work(unsigned long param) | ||
551 | { | ||
552 | struct rtl_usb *rtlusb = (struct rtl_usb *)param; | ||
553 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); | ||
554 | struct sk_buff *skb; | ||
555 | |||
556 | while ((skb = skb_dequeue(&rtlusb->rx_queue))) { | ||
557 | if (unlikely(IS_USB_STOP(rtlusb))) { | ||
558 | dev_kfree_skb_any(skb); | ||
559 | continue; | ||
560 | } | ||
561 | |||
562 | if (likely(!rtlusb->usb_rx_segregate_hdl)) { | ||
563 | _rtl_usb_rx_process_noagg(hw, skb); | ||
564 | } else { | ||
565 | /* TO DO */ | ||
566 | _rtl_rx_pre_process(hw, skb); | ||
567 | pr_err("rx agg not supported\n"); | ||
568 | } | ||
538 | } | 569 | } |
539 | } | 570 | } |
540 | 571 | ||
@@ -552,6 +583,7 @@ static void _rtl_rx_completed(struct urb *_urb) | |||
552 | 583 | ||
553 | if (likely(0 == _urb->status)) { | 584 | if (likely(0 == _urb->status)) { |
554 | struct sk_buff *skb; | 585 | struct sk_buff *skb; |
586 | unsigned int qlen; | ||
555 | unsigned int size = _urb->actual_length; | 587 | unsigned int size = _urb->actual_length; |
556 | 588 | ||
557 | if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) { | 589 | if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) { |
@@ -561,6 +593,14 @@ static void _rtl_rx_completed(struct urb *_urb) | |||
561 | goto resubmit; | 593 | goto resubmit; |
562 | } | 594 | } |
563 | 595 | ||
596 | qlen = skb_queue_len(&rtlusb->rx_queue); | ||
597 | if (qlen >= __RX_SKB_MAX_QUEUED) { | ||
598 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
599 | "Pending RX skbuff queue full! (qlen: %d)\n", | ||
600 | qlen); | ||
601 | goto resubmit; | ||
602 | } | ||
603 | |||
564 | skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV); | 604 | skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV); |
565 | if (!skb) { | 605 | if (!skb) { |
566 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | 606 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
@@ -575,17 +615,8 @@ static void _rtl_rx_completed(struct urb *_urb) | |||
575 | 615 | ||
576 | memcpy(skb_put(skb, size), _urb->transfer_buffer, size); | 616 | memcpy(skb_put(skb, size), _urb->transfer_buffer, size); |
577 | 617 | ||
578 | /* TODO: Do further processing in tasklet (queue skbs, | 618 | skb_queue_tail(&rtlusb->rx_queue, skb); |
579 | * schedule tasklet) | 619 | tasklet_schedule(&rtlusb->rx_work_tasklet); |
580 | */ | ||
581 | |||
582 | if (likely(!rtlusb->usb_rx_segregate_hdl)) { | ||
583 | _rtl_usb_rx_process_noagg(hw, skb); | ||
584 | } else { | ||
585 | /* TO DO */ | ||
586 | _rtl_rx_pre_process(hw, skb); | ||
587 | pr_err("rx agg not supported\n"); | ||
588 | } | ||
589 | 620 | ||
590 | goto resubmit; | 621 | goto resubmit; |
591 | } | 622 | } |
@@ -626,6 +657,9 @@ static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw) | |||
626 | 657 | ||
627 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | 658 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); |
628 | 659 | ||
660 | tasklet_kill(&rtlusb->rx_work_tasklet); | ||
661 | skb_queue_purge(&rtlusb->rx_queue); | ||
662 | |||
629 | while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { | 663 | while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { |
630 | usb_free_coherent(urb->dev, urb->transfer_buffer_length, | 664 | usb_free_coherent(urb->dev, urb->transfer_buffer_length, |
631 | urb->transfer_buffer, urb->transfer_dma); | 665 | urb->transfer_buffer, urb->transfer_dma); |
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index 22d7c68258ec..685273ca9561 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h | |||
@@ -136,12 +136,14 @@ struct rtl_usb { | |||
136 | void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); | 136 | void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); |
137 | 137 | ||
138 | /* Rx */ | 138 | /* Rx */ |
139 | u8 in_ep_nums ; | 139 | u8 in_ep_nums; |
140 | u32 in_ep; /* Bulk IN endpoint number */ | 140 | u32 in_ep; /* Bulk IN endpoint number */ |
141 | u32 rx_max_size; /* Bulk IN max buffer size */ | 141 | u32 rx_max_size; /* Bulk IN max buffer size */ |
142 | u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ | 142 | u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ |
143 | struct usb_anchor rx_submitted; | 143 | struct usb_anchor rx_submitted; |
144 | struct usb_anchor rx_cleanup_urbs; | 144 | struct usb_anchor rx_cleanup_urbs; |
145 | struct tasklet_struct rx_work_tasklet; | ||
146 | struct sk_buff_head rx_queue; | ||
145 | void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, | 147 | void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, |
146 | struct sk_buff_head *); | 148 | struct sk_buff_head *); |
147 | void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); | 149 | void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); |