diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-03-17 05:59:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-03-25 16:42:21 -0400 |
commit | 872de8ff04922e4ad95c5af39131ae9fbefe6ac5 (patch) | |
tree | d5ed761d0826faffc1afa7fc2a07dabd5a8ca586 /drivers/net/wireless/rtlwifi/usb.c | |
parent | 2ed79f38c4a2d63f8665b3e0d920d09ab5fa880b (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.c | 114 |
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 | |||
410 | static void _rtl_rx_completed(struct urb *urb); | 409 | static void _rtl_rx_completed(struct urb *urb); |
411 | 410 | ||
412 | static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw, | 411 | static 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 | |||
442 | static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, | 433 | static 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 | |||
561 | static void _rtl_rx_completed(struct urb *_urb) | 554 | static 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 | ||
610 | resubmit: | 615 | resubmit: |
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 | ||
622 | free: | 624 | free: |
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 | |||
633 | static 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 | ||
626 | static int _rtl_usb_receive(struct ieee80211_hw *hw) | 647 | static 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 | ||
665 | err_out: | 684 | err_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++) { |