Search Linux Wireless

RE: [PATCH 3/4] wifi: rtw88: usb: Support RX aggregation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx> wrote:
> 
> The chips can be configured to aggregate several frames into a single
> USB transfer. Modify rtw_usb_rx_handler() to support this case.
> 
> RX aggregation improves the RX speed on certain ARM systems, like the
> NanoPi NEO Core2.
> 
> Currently none of the chips are configured to aggregate frames.
> 
> Tested with RTL8811CU and RTL8723DU.
> 
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx>
> ---
>  drivers/net/wireless/realtek/rtw88/usb.c | 57 +++++++++++++++---------
>  1 file changed, 37 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
> index 73948078068f..d61be1029a7b 100644
> --- a/drivers/net/wireless/realtek/rtw88/usb.c
> +++ b/drivers/net/wireless/realtek/rtw88/usb.c
> @@ -546,11 +546,12 @@ static void rtw_usb_rx_handler(struct work_struct *work)
>         struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work);
>         struct rtw_dev *rtwdev = rtwusb->rtwdev;
>         const struct rtw_chip_info *chip = rtwdev->chip;
> -       struct rtw_rx_pkt_stat pkt_stat;
> +       u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
>         struct ieee80211_rx_status rx_status;
> +       u32 pkt_offset, next_pkt, urb_len;
> +       struct rtw_rx_pkt_stat pkt_stat;
> +       struct sk_buff *next_skb = NULL;
>         struct sk_buff *skb;
> -       u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
> -       u32 pkt_offset;
>         u8 *rx_desc;
>         int limit;
> 
> @@ -559,29 +560,44 @@ static void rtw_usb_rx_handler(struct work_struct *work)
>                 if (!skb)
>                         break;
> 
> -               rx_desc = skb->data;
> -               chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
> -                                        &rx_status);
> -               pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
> -                            pkt_stat.shift;
> -
> -               if (pkt_stat.is_c2h) {
> -                       skb_put(skb, pkt_stat.pkt_len + pkt_offset);
> -                       rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb);
> -                       continue;
> -               }
> -
>                 if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) {
>                         dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n");
>                         dev_kfree_skb_any(skb);
>                         continue;
>                 }
> 
> -               skb_put(skb, pkt_stat.pkt_len);
> -               skb_reserve(skb, pkt_offset);
> -               rtw_rx_stats(rtwdev, pkt_stat.vif, skb);
> -               memcpy(skb->cb, &rx_status, sizeof(rx_status));
> -               ieee80211_rx_irqsafe(rtwdev->hw, skb);
> +               urb_len = skb->len;
> +
> +               do {
> +                       rx_desc = skb->data;
> +                       chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
> +                                                &rx_status);
> +                       pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
> +                                    pkt_stat.shift;
> +
> +                       next_pkt = round_up(pkt_stat.pkt_len + pkt_offset, 8);
> +
> +                       if (urb_len >= next_pkt + pkt_desc_sz)
> +                               next_skb = skb_clone(skb, GFP_KERNEL);
> +
> +                       if (pkt_stat.is_c2h) {
> +                               skb_trim(skb, pkt_stat.pkt_len + pkt_offset);
> +                               rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb);
> +                       } else {
> +                               skb_pull(skb, pkt_offset);
> +                               skb_trim(skb, pkt_stat.pkt_len);
> +                               rtw_rx_stats(rtwdev, pkt_stat.vif, skb);
> +                               memcpy(skb->cb, &rx_status, sizeof(rx_status));
> +                               ieee80211_rx_irqsafe(rtwdev->hw, skb);
> +                       }
> +
> +                       skb = next_skb;
> +                       if (skb)
> +                               skb_pull(next_skb, next_pkt);
> +
> +                       urb_len -= next_pkt;

I would like a checking to prevent underflow caused by unexpected hardware data.

> +                       next_skb = NULL;
> +               } while (skb && urb_len >= pkt_desc_sz);
>         }
>  }
> 
> @@ -625,6 +641,7 @@ static void rtw_usb_read_port_complete(struct urb *urb)
>                         if (skb)
>                                 dev_kfree_skb_any(skb);
>                 } else {
> +                       skb_put(skb, urb->actual_length);
>                         skb_queue_tail(&rtwusb->rx_queue, skb);
>                         queue_work(rtwusb->rxwq, &rtwusb->rx_work);
>                 }
> --
> 2.45.2





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux