aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtlwifi/usb.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2013-03-17 05:59:13 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-03-25 16:42:21 -0400
commit872de8ff04922e4ad95c5af39131ae9fbefe6ac5 (patch)
treed5ed761d0826faffc1afa7fc2a07dabd5a8ca586 /drivers/net/wireless/rtlwifi/usb.c
parent2ed79f38c4a2d63f8665b3e0d920d09ab5fa880b (diff)
rtlwifi: usb: use usb_alloc_coherent for RX buffers
Use dedicated DMA coherent buffers for RX urbs, to avoid allocation of large skbuffs in hard-irq context and improve performance. Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtlwifi/usb.c')
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c114
1 files changed, 67 insertions, 47 deletions
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index b5c80b5d57ef..22f29d75947e 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -324,6 +324,7 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
324 pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", 324 pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n",
325 rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); 325 rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep);
326 init_usb_anchor(&rtlusb->rx_submitted); 326 init_usb_anchor(&rtlusb->rx_submitted);
327 init_usb_anchor(&rtlusb->rx_cleanup_urbs);
327 return 0; 328 return 0;
328} 329}
329 330
@@ -405,40 +406,30 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
405 rtlusb->disableHWSM = true; 406 rtlusb->disableHWSM = true;
406} 407}
407 408
408#define __RADIO_TAP_SIZE_RSV 32
409
410static void _rtl_rx_completed(struct urb *urb); 409static void _rtl_rx_completed(struct urb *urb);
411 410
412static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw, 411static int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb,
413 struct rtl_usb *rtlusb, 412 struct urb *urb, gfp_t gfp_mask)
414 struct urb *urb,
415 gfp_t gfp_mask)
416{ 413{
417 struct sk_buff *skb;
418 struct rtl_priv *rtlpriv = rtl_priv(hw); 414 struct rtl_priv *rtlpriv = rtl_priv(hw);
415 void *buf;
419 416
420 skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV), 417 buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask,
421 gfp_mask); 418 &urb->transfer_dma);
422 if (!skb) { 419 if (!buf) {
423 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, 420 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
424 "Failed to __dev_alloc_skb!!\n"); 421 "Failed to usb_alloc_coherent!!\n");
425 return ERR_PTR(-ENOMEM); 422 return -ENOMEM;
426 } 423 }
427 424
428 /* reserve some space for mac80211's radiotap */
429 skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
430 usb_fill_bulk_urb(urb, rtlusb->udev, 425 usb_fill_bulk_urb(urb, rtlusb->udev,
431 usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), 426 usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep),
432 skb->data, min(skb_tailroom(skb), 427 buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb);
433 (int)rtlusb->rx_max_size), 428 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
434 _rtl_rx_completed, skb);
435 429
436 _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); 430 return 0;
437 return skb;
438} 431}
439 432
440#undef __RADIO_TAP_SIZE_RSV
441
442static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, 433static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
443 struct sk_buff *skb) 434 struct sk_buff *skb)
444{ 435{
@@ -558,11 +549,11 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
558 } 549 }
559} 550}
560 551
552#define __RADIO_TAP_SIZE_RSV 32
553
561static void _rtl_rx_completed(struct urb *_urb) 554static void _rtl_rx_completed(struct urb *_urb)
562{ 555{
563 struct sk_buff *skb = (struct sk_buff *)_urb->context; 556 struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context;
564 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
565 struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0];
566 struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); 557 struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
567 struct rtl_priv *rtlpriv = rtl_priv(hw); 558 struct rtl_priv *rtlpriv = rtl_priv(hw);
568 int err = 0; 559 int err = 0;
@@ -571,28 +562,42 @@ static void _rtl_rx_completed(struct urb *_urb)
571 goto free; 562 goto free;
572 563
573 if (likely(0 == _urb->status)) { 564 if (likely(0 == _urb->status)) {
574 /* If this code were moved to work queue, would CPU 565 struct sk_buff *skb;
575 * utilization be improved? NOTE: We shall allocate another skb 566 unsigned int size = _urb->actual_length;
576 * and reuse the original one. 567
568 if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) {
569 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
570 "Too short packet from bulk IN! (len: %d)\n",
571 size);
572 goto resubmit;
573 }
574
575 skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV);
576 if (!skb) {
577 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
578 "Can't allocate skb for bulk IN!\n");
579 goto resubmit;
580 }
581
582 _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
583
584 /* reserve some space for mac80211's radiotap */
585 skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
586
587 memcpy(skb_put(skb, size), _urb->transfer_buffer, size);
588
589 /* TODO: Do further processing in tasklet (queue skbs,
590 * schedule tasklet)
577 */ 591 */
578 skb_put(skb, _urb->actual_length);
579 592
580 if (likely(!rtlusb->usb_rx_segregate_hdl)) { 593 if (likely(!rtlusb->usb_rx_segregate_hdl)) {
581 struct sk_buff *_skb;
582 _rtl_usb_rx_process_noagg(hw, skb); 594 _rtl_usb_rx_process_noagg(hw, skb);
583 _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC); 595 } else {
584 if (IS_ERR(_skb)) {
585 err = PTR_ERR(_skb);
586 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
587 "Can't allocate skb for bulk IN!\n");
588 return;
589 }
590 skb = _skb;
591 } else{
592 /* TO DO */ 596 /* TO DO */
593 _rtl_rx_pre_process(hw, skb); 597 _rtl_rx_pre_process(hw, skb);
594 pr_err("rx agg not supported\n"); 598 pr_err("rx agg not supported\n");
595 } 599 }
600
596 goto resubmit; 601 goto resubmit;
597 } 602 }
598 603
@@ -608,9 +613,6 @@ static void _rtl_rx_completed(struct urb *_urb)
608 } 613 }
609 614
610resubmit: 615resubmit:
611 skb_reset_tail_pointer(skb);
612 skb_trim(skb, 0);
613
614 usb_anchor_urb(_urb, &rtlusb->rx_submitted); 616 usb_anchor_urb(_urb, &rtlusb->rx_submitted);
615 err = usb_submit_urb(_urb, GFP_ATOMIC); 617 err = usb_submit_urb(_urb, GFP_ATOMIC);
616 if (unlikely(err)) { 618 if (unlikely(err)) {
@@ -620,13 +622,31 @@ resubmit:
620 return; 622 return;
621 623
622free: 624free:
623 dev_kfree_skb_irq(skb); 625 /* On some architectures, usb_free_coherent must not be called from
626 * hardirq context. Queue urb to cleanup list.
627 */
628 usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs);
629}
630
631#undef __RADIO_TAP_SIZE_RSV
632
633static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw)
634{
635 struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
636 struct urb *urb;
637
638 usb_kill_anchored_urbs(&rtlusb->rx_submitted);
639
640 while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
641 usb_free_coherent(urb->dev, urb->transfer_buffer_length,
642 urb->transfer_buffer, urb->transfer_dma);
643 usb_free_urb(urb);
644 }
624} 645}
625 646
626static int _rtl_usb_receive(struct ieee80211_hw *hw) 647static int _rtl_usb_receive(struct ieee80211_hw *hw)
627{ 648{
628 struct urb *urb; 649 struct urb *urb;
629 struct sk_buff *skb;
630 int err; 650 int err;
631 int i; 651 int i;
632 struct rtl_priv *rtlpriv = rtl_priv(hw); 652 struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -645,11 +665,10 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
645 goto err_out; 665 goto err_out;
646 } 666 }
647 667
648 skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); 668 err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
649 if (IS_ERR(skb)) { 669 if (err < 0) {
650 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, 670 RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
651 "Failed to prep_rx_urb!!\n"); 671 "Failed to prep_rx_urb!!\n");
652 err = PTR_ERR(skb);
653 usb_free_urb(urb); 672 usb_free_urb(urb);
654 goto err_out; 673 goto err_out;
655 } 674 }
@@ -664,6 +683,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
664 683
665err_out: 684err_out:
666 usb_kill_anchored_urbs(&rtlusb->rx_submitted); 685 usb_kill_anchored_urbs(&rtlusb->rx_submitted);
686 _rtl_usb_cleanup_rx(hw);
667 return err; 687 return err;
668} 688}
669 689
@@ -705,7 +725,7 @@ static void rtl_usb_cleanup(struct ieee80211_hw *hw)
705 SET_USB_STOP(rtlusb); 725 SET_USB_STOP(rtlusb);
706 726
707 /* clean up rx stuff. */ 727 /* clean up rx stuff. */
708 usb_kill_anchored_urbs(&rtlusb->rx_submitted); 728 _rtl_usb_cleanup_rx(hw);
709 729
710 /* clean up tx stuff */ 730 /* clean up tx stuff */
711 for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { 731 for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) {