Commit df3d8f46 authored by Bitterblue Smith's avatar Bitterblue Smith Committed by Ping-Ke Shih
Browse files

wifi: rtw88: usb: Support RX aggregation



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 of RTL8811CU on certain ARM
systems, like the NanoPi NEO Core2. It also improves the RX speed of
RTL8822CU on some x86_64 systems.

Currently none of the chips are configured to aggregate frames.

Tested with RTL8822CU, RTL8811CU, and RTL8723DU.

Reviewed-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Tested-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarBitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/f845826d-de71-492d-9a22-e48c07989a1f@gmail.com
parent 38ea04a7
Loading
Loading
Loading
Loading
+40 −21
Original line number Diff line number Diff line
@@ -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;
	struct sk_buff *skb;
	u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
	u32 pkt_offset;
	u8 *rx_desc;
	int limit;

@@ -559,32 +560,49 @@ static void rtw_usb_rx_handler(struct work_struct *work)
		if (!skb)
			break;

		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;
		}

		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;

		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;
		}
			next_pkt = round_up(pkt_stat.pkt_len + pkt_offset, 8);

		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);
			if (urb_len >= next_pkt + pkt_desc_sz)
				next_skb = skb_clone(skb, GFP_KERNEL);
			else
				next_skb = NULL;

		rtw_update_rx_freq_for_invalid(rtwdev, skb, &rx_status, &pkt_stat);
			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_update_rx_freq_for_invalid(rtwdev, skb,
							       &rx_status,
							       &pkt_stat);
				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(skb, next_pkt);

			urb_len -= next_pkt;
		} while (skb);
	}
}

static void rtw_usb_read_port_complete(struct urb *urb);
@@ -627,6 +645,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);
		}