Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously
@ 2026-09-03 21:24 Bitterblue Smith
  2026-09-04 22:09 ` kernel test robot
  2026-09-05  0:49 ` kernel test robot
  0 siblings, 2 replies; 3+ messages in thread
From: Bitterblue Smith @ 2026-09-03 21:24 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org; +Cc: Ping-Ke Shih, i.mafifi17

From: Mohammed Afifi <i.mafifi17@gmail.com>

In AP mode the reserved page (which contains the beacon) is downloaded
to the chip by rtw_fw_write_data_rsvd_page(). That function writes the
data via rtw_hci_write_data_rsvd_page() and then immediately polls the
hardware BCN_VALID bit to confirm the firmware accepted the beacon.

On USB, rtw_usb_write_data_rsvd_page() ends up in rtw_usb_write_port(),
which submits the URB with usb_submit_urb() and returns as soon as the
transfer is queued. The completion callback only frees the skb. As a
result the BCN_VALID poll can run while the beacon is still in flight
on the bus, and the poll times out even though the download itself is
fine.

This shows up as:

  rtw_8822bu: error beacon valid
  rtw_8822bu: failed to download drv rsvd page

The failure is intermittent because the poll retries sometimes cover
the transfer time. It occurs in bursts when something triggers repeated
beacon updates, such as stations associating and disassociating.

Fix this by adding a synchronous bulk-out helper that waits for the URB
to complete, and using it for the reserved page download. Only the
reserved page / beacon path is made synchronous; the normal data TX
path is left untouched, so throughput is unaffected.

The reserved page download runs in process context under rtwdev->mutex,
so sleeping there is safe.

Closes: https://github.com/lwfinger/rtw88/issues/451
Signed-off-by: Mohammed Afifi <i.mafifi17@gmail.com>
Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
---
 drivers/net/wireless/realtek/rtw88/usb.c | 92 +++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index c90802919473..04e3095432c3 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -394,6 +394,71 @@ static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *s
 	return ret;
 }
 
+struct rtw_usb_write_data_sync_cb {
+	struct completion done;
+	int status;
+};
+
+static void rtw_usb_write_port_sync_complete(struct urb *urb)
+{
+	struct rtw_usb_write_data_sync_cb *cb = urb->context;
+
+	cb->status = urb->status;
+	complete(&cb->done);
+}
+
+/* Synchronous bulk-out that returns only after the data has actually been
+ * transferred to the device. Required for the reserved-page / beacon
+ * download: the caller polls the hardware BCN_VALID bit immediately after
+ * this returns, so the bytes must be on the chip by then. The normal async
+ * TX path races that poll, which shows up as intermittent
+ * "error beacon valid" / "failed to download drv rsvd page" in AP mode,
+ * more often on 5 GHz where the larger beacon takes longer to transfer.
+ */
+static int rtw_usb_write_port_sync(struct rtw_dev *rtwdev, u8 qsel,
+				   struct sk_buff *skb)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_device *usbd = rtwusb->udev;
+	struct rtw_usb_write_data_sync_cb cb;
+	int ep = qsel_to_ep(rtwusb, qsel);
+	unsigned int pipe;
+	struct urb *urb;
+	int ret;
+
+	if (ep < 0)
+		return ep;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	init_completion(&cb.done);
+	cb.status = -EINPROGRESS;
+
+	pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]);
+	usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len,
+			  rtw_usb_write_port_sync_complete, &cb);
+	urb->transfer_flags |= URB_ZERO_PACKET;
+
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret)
+		goto out;
+
+	/* 5 s matches the vendor driver's bulk-out timeout */
+	if (!wait_for_completion_timeout(&cb.done, msecs_to_jiffies(5000))) {
+		usb_kill_urb(urb);
+		ret = -ETIMEDOUT;
+	} else {
+		ret = cb.status;
+	}
+
+out:
+	usb_free_urb(urb);
+
+	return ret;
+}
+
 static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list)
 {
 	struct rtw_dev *rtwdev = rtwusb->rtwdev;
@@ -543,13 +608,38 @@ static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
 {
 	const struct rtw_chip_info *chip = rtwdev->chip;
 	struct rtw_tx_pkt_info pkt_info = {0};
+	struct rtw_tx_desc *pkt_desc;
+	struct sk_buff *skb;
+	int ret;
 
 	pkt_info.tx_pkt_size = size;
 	pkt_info.qsel = TX_DESC_QSEL_BEACON;
 	pkt_info.offset = chip->tx_pkt_desc_sz;
 	pkt_info.ls = true;
 
-	return rtw_usb_write_data(rtwdev, &pkt_info, buf);
+	skb = dev_alloc_skb(chip->tx_pkt_desc_sz + size);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_reserve(skb, chip->tx_pkt_desc_sz);
+	skb_put_data(skb, buf, size);
+	pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
+	memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
+	rtw_tx_fill_tx_desc(rtwdev, &pkt_info, pkt_desc);
+	rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, pkt_desc);
+
+	/* Download the beacon/reserved page synchronously so that the caller's
+	 * subsequent BCN_VALID poll observes the completed transfer instead of
+	 * racing the async TX path.
+	 */
+	ret = rtw_usb_write_port_sync(rtwdev, pkt_info.qsel, skb);
+	if (ret)
+		rtw_err(rtwdev, "failed to download rsvd page over USB, ret=%d\n",
+			ret);
+
+	dev_kfree_skb_any(skb);
+
+	return ret;
 }
 
 static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously
  2026-09-03 21:24 [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously Bitterblue Smith
@ 2026-09-04 22:09 ` kernel test robot
  2026-09-05  0:49 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2026-09-04 22:09 UTC (permalink / raw)
  To: Bitterblue Smith, linux-wireless@vger.kernel.org
  Cc: llvm, oe-kbuild-all, Ping-Ke Shih, i.mafifi17

Hi Bitterblue,

kernel test robot noticed the following build errors:

[auto build test ERROR on wireless-next/main]
[also build test ERROR on wireless/main linus/master v7.3-rc1 next-20260903]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bitterblue-Smith/wifi-rtw88-usb-Download-the-reserved-page-synchronously/20260904-002447
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
patch link:    https://lore.kernel.org/r/fd7bbc79-03f9-4932-ada8-f555392d4485%40gmail.com
patch subject: [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260905/202609050523.VXiKq456-lkp@intel.com/config)
compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project 0edd1b088cc36b4faee80358c925a91e16006258)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260905/202609050523.VXiKq456-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202609050523.VXiKq456-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/net/wireless/realtek/rtw88/usb.c:623:41: error: incompatible pointer types passing 'struct rtw_tx_desc *' to parameter of type 'struct sk_buff *' [-Wincompatible-pointer-types]
     623 |         rtw_tx_fill_tx_desc(rtwdev, &pkt_info, pkt_desc);
         |                                                ^~~~~~~~
   drivers/net/wireless/realtek/rtw88/tx.h:99:55: note: passing argument to parameter 'skb' here
      99 |                          struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb);
         |                                                                            ^
>> drivers/net/wireless/realtek/rtw88/usb.c:624:49: error: incompatible pointer types passing 'struct rtw_tx_desc *' to parameter of type 'u8 *' (aka 'unsigned char *') [-Wincompatible-pointer-types]
     624 |         rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, pkt_desc);
         |                                                        ^~~~~~~~
   drivers/net/wireless/realtek/rtw88/tx.h:136:17: note: passing argument to parameter 'txdesc' here
     136 |                                                u8 *txdesc)
         |                                                    ^
   2 errors generated.


vim +623 drivers/net/wireless/realtek/rtw88/usb.c

   600	
   601	static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
   602						u32 size)
   603	{
   604		const struct rtw_chip_info *chip = rtwdev->chip;
   605		struct rtw_tx_pkt_info pkt_info = {0};
   606		struct rtw_tx_desc *pkt_desc;
   607		struct sk_buff *skb;
   608		int ret;
   609	
   610		pkt_info.tx_pkt_size = size;
   611		pkt_info.qsel = TX_DESC_QSEL_BEACON;
   612		pkt_info.offset = chip->tx_pkt_desc_sz;
   613		pkt_info.ls = true;
   614	
   615		skb = dev_alloc_skb(chip->tx_pkt_desc_sz + size);
   616		if (!skb)
   617			return -ENOMEM;
   618	
   619		skb_reserve(skb, chip->tx_pkt_desc_sz);
   620		skb_put_data(skb, buf, size);
   621		pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
   622		memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
 > 623		rtw_tx_fill_tx_desc(rtwdev, &pkt_info, pkt_desc);
 > 624		rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, pkt_desc);
   625	
   626		/* Download the beacon/reserved page synchronously so that the caller's
   627		 * subsequent BCN_VALID poll observes the completed transfer instead of
   628		 * racing the async TX path.
   629		 */
   630		ret = rtw_usb_write_port_sync(rtwdev, pkt_info.qsel, skb);
   631		if (ret)
   632			rtw_err(rtwdev, "failed to download rsvd page over USB, ret=%d\n",
   633				ret);
   634	
   635		dev_kfree_skb_any(skb);
   636	
   637		return ret;
   638	}
   639	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously
  2026-09-03 21:24 [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously Bitterblue Smith
  2026-09-04 22:09 ` kernel test robot
@ 2026-09-05  0:49 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2026-09-05  0:49 UTC (permalink / raw)
  To: Bitterblue Smith, linux-wireless@vger.kernel.org
  Cc: oe-kbuild-all, Ping-Ke Shih, i.mafifi17

Hi Bitterblue,

kernel test robot noticed the following build errors:

[auto build test ERROR on wireless-next/main]
[also build test ERROR on wireless/main linus/master v7.3-rc1 next-20260904]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bitterblue-Smith/wifi-rtw88-usb-Download-the-reserved-page-synchronously/20260904-002447
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
patch link:    https://lore.kernel.org/r/fd7bbc79-03f9-4932-ada8-f555392d4485%40gmail.com
patch subject: [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20260905/202609050825.gGIFwsGa-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260905/202609050825.gGIFwsGa-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202609050825.gGIFwsGa-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/net/wireless/realtek/rtw88/usb.c: In function 'rtw_usb_write_data_rsvd_page':
>> drivers/net/wireless/realtek/rtw88/usb.c:623:48: error: passing argument 3 of 'rtw_tx_fill_tx_desc' from incompatible pointer type [-Wincompatible-pointer-types]
     623 |         rtw_tx_fill_tx_desc(rtwdev, &pkt_info, pkt_desc);
         |                                                ^~~~~~~~
         |                                                |
         |                                                struct rtw_tx_desc *
   In file included from drivers/net/wireless/realtek/rtw88/usb.c:12:
   drivers/net/wireless/realtek/rtw88/tx.h:99:76: note: expected 'struct sk_buff *' but argument is of type 'struct rtw_tx_desc *'
      99 |                          struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb);
         |                                                            ~~~~~~~~~~~~~~~~^~~
>> drivers/net/wireless/realtek/rtw88/usb.c:624:56: error: passing argument 3 of 'rtw_tx_fill_txdesc_checksum' from incompatible pointer type [-Wincompatible-pointer-types]
     624 |         rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, pkt_desc);
         |                                                        ^~~~~~~~
         |                                                        |
         |                                                        struct rtw_tx_desc *
   drivers/net/wireless/realtek/rtw88/tx.h:136:52: note: expected 'u8 *' {aka 'unsigned char *'} but argument is of type 'struct rtw_tx_desc *'
     136 |                                                u8 *txdesc)
         |                                                ~~~~^~~~~~


vim +/rtw_tx_fill_tx_desc +623 drivers/net/wireless/realtek/rtw88/usb.c

   600	
   601	static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
   602						u32 size)
   603	{
   604		const struct rtw_chip_info *chip = rtwdev->chip;
   605		struct rtw_tx_pkt_info pkt_info = {0};
   606		struct rtw_tx_desc *pkt_desc;
   607		struct sk_buff *skb;
   608		int ret;
   609	
   610		pkt_info.tx_pkt_size = size;
   611		pkt_info.qsel = TX_DESC_QSEL_BEACON;
   612		pkt_info.offset = chip->tx_pkt_desc_sz;
   613		pkt_info.ls = true;
   614	
   615		skb = dev_alloc_skb(chip->tx_pkt_desc_sz + size);
   616		if (!skb)
   617			return -ENOMEM;
   618	
   619		skb_reserve(skb, chip->tx_pkt_desc_sz);
   620		skb_put_data(skb, buf, size);
   621		pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
   622		memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
 > 623		rtw_tx_fill_tx_desc(rtwdev, &pkt_info, pkt_desc);
 > 624		rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, pkt_desc);
   625	
   626		/* Download the beacon/reserved page synchronously so that the caller's
   627		 * subsequent BCN_VALID poll observes the completed transfer instead of
   628		 * racing the async TX path.
   629		 */
   630		ret = rtw_usb_write_port_sync(rtwdev, pkt_info.qsel, skb);
   631		if (ret)
   632			rtw_err(rtwdev, "failed to download rsvd page over USB, ret=%d\n",
   633				ret);
   634	
   635		dev_kfree_skb_any(skb);
   636	
   637		return ret;
   638	}
   639	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-05  0:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 21:24 [PATCH rtw-next] wifi: rtw88: usb: Download the reserved page synchronously Bitterblue Smith
2026-09-04 22:09 ` kernel test robot
2026-09-05  0:49 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox