* [PATCH wireless-next] wifi: rtw88: usb: do not log transfers lost to a mode switch
@ 2026-08-12 12:28 Mehmet Fide
2026-08-12 17:01 ` Bitterblue Smith
2026-08-12 17:32 ` [PATCH rtw-next v2] " Mehmet Fide
0 siblings, 2 replies; 4+ messages in thread
From: Mehmet Fide @ 2026-08-12 12:28 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: Bitterblue Smith, linux-kernel
An RTL8822BU or RTL8822CU is asked to come back as a USB 3 device by
rtw_usb_switch_mode_new(), added in commit 315c23a64e99 ("wifi: rtw88:
usb: Support USB 3 with RTL8822CU/RTL8822BU"). The chip powers off its
MAC and leaves the bus while the last control transfers of that sequence
are still in flight, so they complete with -EPROTO and the driver reports
them as errors:
rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
rtw_8822bu 1-1:1.0: write register 0xc4 failed with -71
usb 1-1: USB disconnect, device number 2
usbcore: registered new interface driver rtw_8822bu
rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
Register 0xc4 is REG_PAD_CTRL2 and the access losing the race is the
rtw_write32_set() that ends the switch sequence, a few milliseconds before
the disconnect. Which transfer gets caught varies from boot to boot: 0xc4
is in the "always on" section, so every write to it is followed by a second
one from rtw_usb_reg_sec(), and sometimes that is the one that fails:
rtw_8822bu 1-1:1.0: rtw_usb_reg_sec: reg 0x4e0, usb write 1 fail, status: -71
Nothing is wrong here. The device re-enumerates, probes again and registers
normally, which is why rtw_usb_probe() already treats a non-zero return
from rtw_usb_switch_mode() as "Not a fail". On a USB 2 only port the
switch can never succeed, so the message returns on every boot and
everyone using such a port has to work out that it is harmless.
Mark the window in which the chip is expected to leave the bus and skip the
error reports for transfers that fall into it. The flag is never cleared
because the switch always ends in a re-probe with a fresh struct rtw_usb.
Tested with an RTL8822BU (0x7392:0xb822) on a USB 2 root port of a TI AM62,
where the message appears exactly once per boot. With the patch both lines
are gone while the disconnect, the re-enumeration and the second firmware
load are unchanged. The tested build was 6.12.103 carrying the same change;
the hunks differ only in context.
Signed-off-by: Mehmet Fide <mehmet.fide@gmail.com>
---
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -64,7 +64,7 @@
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
t_reg, 0, data, t_len, 500);
- if (status != t_len && status != -ENODEV)
+ if (status != t_len && status != -ENODEV && !rtwusb->switching_mode)
rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n",
__func__, t_reg, t_len, status);
}
@@ -90,7 +90,7 @@
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
RTW_USB_VENQT_CMD_IDX, data, len, 1000);
- if (ret < 0 && ret != -ENODEV && count++ < 4)
+ if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
rtw_err(rtwdev, "read register 0x%x failed with %d\n",
addr, ret);
@@ -140,7 +140,7 @@
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, data, len, 500);
- if (ret < 0 && ret != -ENODEV && count++ < 4)
+ if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
rtw_err(rtwdev, "write register 0x%x failed with %d\n",
addr, ret);
@@ -1111,6 +1111,7 @@
static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
{
+ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
enum usb_device_speed cur_speed;
u8 id = rtwdev->chip->id;
bool can_switch;
@@ -1151,6 +1152,11 @@
rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
+ /* From here the chip powers off its MAC and re-enumerates, so it can
+ * leave the bus while a control transfer is still in flight.
+ */
+ rtwusb->switching_mode = true;
+
rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
usleep_range(1000, 1001);
rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
--- a/drivers/net/wireless/realtek/rtw88/usb.h
+++ b/drivers/net/wireless/realtek/rtw88/usb.h
@@ -85,6 +85,9 @@
struct sk_buff_head rx_free_queue;
struct work_struct rx_work;
struct work_struct rx_urb_work;
+
+ /* the chip is re-enumerating, control transfers are expected to fail */
+ bool switching_mode;
};
static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH wireless-next] wifi: rtw88: usb: do not log transfers lost to a mode switch
2026-08-12 12:28 [PATCH wireless-next] wifi: rtw88: usb: do not log transfers lost to a mode switch Mehmet Fide
@ 2026-08-12 17:01 ` Bitterblue Smith
2026-08-12 17:32 ` [PATCH rtw-next v2] " Mehmet Fide
1 sibling, 0 replies; 4+ messages in thread
From: Bitterblue Smith @ 2026-08-12 17:01 UTC (permalink / raw)
To: Mehmet Fide, Ping-Ke Shih, linux-wireless; +Cc: linux-kernel
On 12/08/2026 15:28, Mehmet Fide wrote:
> An RTL8822BU or RTL8822CU is asked to come back as a USB 3 device by
> rtw_usb_switch_mode_new(), added in commit 315c23a64e99 ("wifi: rtw88:
> usb: Support USB 3 with RTL8822CU/RTL8822BU"). The chip powers off its
> MAC and leaves the bus while the last control transfers of that sequence
> are still in flight, so they complete with -EPROTO and the driver reports
> them as errors:
>
> rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
> rtw_8822bu 1-1:1.0: write register 0xc4 failed with -71
> usb 1-1: USB disconnect, device number 2
> usbcore: registered new interface driver rtw_8822bu
> rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
>
> Register 0xc4 is REG_PAD_CTRL2 and the access losing the race is the
> rtw_write32_set() that ends the switch sequence, a few milliseconds before
> the disconnect. Which transfer gets caught varies from boot to boot: 0xc4
> is in the "always on" section, so every write to it is followed by a second
> one from rtw_usb_reg_sec(), and sometimes that is the one that fails:
>
> rtw_8822bu 1-1:1.0: rtw_usb_reg_sec: reg 0x4e0, usb write 1 fail, status: -71
>
> Nothing is wrong here. The device re-enumerates, probes again and registers
> normally, which is why rtw_usb_probe() already treats a non-zero return
> from rtw_usb_switch_mode() as "Not a fail". On a USB 2 only port the
> switch can never succeed, so the message returns on every boot and
> everyone using such a port has to work out that it is harmless.
>
> Mark the window in which the chip is expected to leave the bus and skip the
> error reports for transfers that fall into it. The flag is never cleared
> because the switch always ends in a re-probe with a fresh struct rtw_usb.
>
> Tested with an RTL8822BU (0x7392:0xb822) on a USB 2 root port of a TI AM62,
> where the message appears exactly once per boot. With the patch both lines
> are gone while the disconnect, the re-enumeration and the second firmware
> load are unchanged. The tested build was 6.12.103 carrying the same change;
> the hunks differ only in context.
>
> Signed-off-by: Mehmet Fide <mehmet.fide@gmail.com>
I guess this is one way to do it.
I was going to do this the same way I did for rtw89, along with some
other changes, like retry control messages up to 10 times and do both
reads and writes from a single function. But I got busy with life stuff
and haven't started.
By the way, RTL8812AU and RTL8814AU (handled by rtw_usb_switch_mode_old())
have the same problem.
Your patch looks funny. Please generate patches using "git format-patch",
and use the rtw-next branch from https://github.com/pkshih/rtw.
> ---
> --- a/drivers/net/wireless/realtek/rtw88/usb.c
> +++ b/drivers/net/wireless/realtek/rtw88/usb.c
> @@ -64,7 +64,7 @@
> RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
> t_reg, 0, data, t_len, 500);
>
> - if (status != t_len && status != -ENODEV)
> + if (status != t_len && status != -ENODEV && !rtwusb->switching_mode)
> rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n",
> __func__, t_reg, t_len, status);
> }
> @@ -90,7 +90,7 @@
> ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
> RTW_USB_VENQT_CMD_IDX, data, len, 1000);
> - if (ret < 0 && ret != -ENODEV && count++ < 4)
> + if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
> rtw_err(rtwdev, "read register 0x%x failed with %d\n",
> addr, ret);
>
> @@ -140,7 +140,7 @@
> ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
> addr, 0, data, len, 500);
> - if (ret < 0 && ret != -ENODEV && count++ < 4)
> + if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
> rtw_err(rtwdev, "write register 0x%x failed with %d\n",
> addr, ret);
>
> @@ -1111,6 +1111,7 @@
>
> static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
> {
> + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
> enum usb_device_speed cur_speed;
> u8 id = rtwdev->chip->id;
> bool can_switch;
> @@ -1151,6 +1152,11 @@
> rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
> rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
>
> + /* From here the chip powers off its MAC and re-enumerates, so it can
> + * leave the bus while a control transfer is still in flight.
> + */
> + rtwusb->switching_mode = true;
> +
> rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
> usleep_range(1000, 1001);
> rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
> --- a/drivers/net/wireless/realtek/rtw88/usb.h
> +++ b/drivers/net/wireless/realtek/rtw88/usb.h
> @@ -85,6 +85,9 @@
> struct sk_buff_head rx_free_queue;
> struct work_struct rx_work;
> struct work_struct rx_urb_work;
> +
> + /* the chip is re-enumerating, control transfers are expected to fail */
> + bool switching_mode;
> };
>
> static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH rtw-next v2] wifi: rtw88: usb: do not log transfers lost to a mode switch
2026-08-12 12:28 [PATCH wireless-next] wifi: rtw88: usb: do not log transfers lost to a mode switch Mehmet Fide
2026-08-12 17:01 ` Bitterblue Smith
@ 2026-08-12 17:32 ` Mehmet Fide
2026-08-13 0:41 ` Ping-Ke Shih
1 sibling, 1 reply; 4+ messages in thread
From: Mehmet Fide @ 2026-08-12 17:32 UTC (permalink / raw)
To: Bitterblue Smith, Ping-Ke Shih, linux-wireless; +Cc: linux-kernel
An RTL8822BU or RTL8822CU is asked to come back as a USB 3 device by
rtw_usb_switch_mode_new(). The chip powers off its MAC and leaves the bus
while the last control transfers of that sequence are still in flight, so
they complete with -EPROTO and the driver reports them as errors:
rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
rtw_8822bu 1-1:1.0: write register 0xc4 failed with -71
usb 1-1: USB disconnect, device number 2
usbcore: registered new interface driver rtw_8822bu
rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
Register 0xc4 is REG_PAD_CTRL2 and the access losing the race is the
rtw_write32_set() that ends the switch sequence, a few milliseconds before
the disconnect. Which transfer gets caught varies from boot to boot: 0xc4
is in the "always on" section, so every write to it is followed by a second
one from rtw_usb_reg_sec(), and sometimes that is the one that fails:
rtw_8822bu 1-1:1.0: rtw_usb_reg_sec: reg 0x4e0, usb write 1 fail, status: -71
Nothing is wrong here. The device re-enumerates, probes again and registers
normally, which is why rtw_usb_probe() already treats a non-zero return
from rtw_usb_switch_mode() as "Not a fail". On a USB 2 only port the
switch can never succeed, so the message returns on every boot and
everyone using such a port has to work out that it is harmless.
Mark the window in which the chip is expected to leave the bus and skip the
error reports for transfers that fall into it. rtw_usb_switch_mode_old()
disconnects the same way for RTL8812AU and RTL8814AU, so mark it there too.
The flag is never cleared because the switch always ends in a re-probe with
a fresh struct rtw_usb.
Tested with an RTL8822BU (0x7392:0xb822) on a USB 2 root port of a TI AM62,
where the message appears exactly once per boot. With the patch both lines
are gone while the disconnect, the re-enumeration and the second firmware
load are unchanged.
Signed-off-by: Mehmet Fide <mehmet.fide@gmail.com>
---
v2:
- regenerated with git format-patch on top of rtw-next, as asked
- also mark the window in rtw_usb_switch_mode_old(), which disconnects
the same way for RTL8812AU and RTL8814AU
drivers/net/wireless/realtek/rtw88/usb.c | 13 ++++++++++---
drivers/net/wireless/realtek/rtw88/usb.h | 3 +++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 64e1c3420..b60e58b35 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -64,7 +64,7 @@ static void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data)
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
t_reg, 0, data, t_len, 500);
- if (status != t_len && status != -ENODEV)
+ if (status != t_len && status != -ENODEV && !rtwusb->switching_mode)
rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n",
__func__, t_reg, t_len, status);
}
@@ -90,7 +90,7 @@ static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len)
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
RTW_USB_VENQT_CMD_IDX, data, len, 1000);
- if (ret < 0 && ret != -ENODEV && count++ < 4)
+ if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
rtw_err(rtwdev, "read register 0x%x failed with %d\n",
addr, ret);
@@ -140,7 +140,7 @@ static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, data, len, 500);
- if (ret < 0 && ret != -ENODEV && count++ < 4)
+ if (ret < 0 && ret != -ENODEV && !rtwusb->switching_mode && count++ < 4)
rtw_err(rtwdev, "write register 0x%x failed with %d\n",
addr, ret);
@@ -1098,6 +1098,7 @@ static int rtw_usb_switch_mode_old(struct rtw_dev *rtwdev)
rtw_write8(rtwdev, REG_ACLK_MON, 0x1);
rtw_write8(rtwdev, 0x3d, 0x3);
/* usb disconnect */
+ rtwusb->switching_mode = true;
rtw_write8(rtwdev, REG_SYS_PW_CTRL + 1, 0x80);
return 1;
}
@@ -1111,6 +1112,7 @@ static int rtw_usb_switch_mode_old(struct rtw_dev *rtwdev)
static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
{
+ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
enum usb_device_speed cur_speed;
u8 id = rtwdev->chip->id;
bool can_switch;
@@ -1151,6 +1153,11 @@ static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
+ /* From here the chip powers off its MAC and re-enumerates, so it can
+ * leave the bus while a control transfer is still in flight.
+ */
+ rtwusb->switching_mode = true;
+
rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
usleep_range(1000, 1001);
rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h
index 9b695b688..9d2825368 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.h
+++ b/drivers/net/wireless/realtek/rtw88/usb.h
@@ -85,6 +85,9 @@ struct rtw_usb {
struct sk_buff_head rx_free_queue;
struct work_struct rx_work;
struct work_struct rx_urb_work;
+
+ /* the chip is re-enumerating, control transfers are expected to fail */
+ bool switching_mode;
};
static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [PATCH rtw-next v2] wifi: rtw88: usb: do not log transfers lost to a mode switch
2026-08-12 17:32 ` [PATCH rtw-next v2] " Mehmet Fide
@ 2026-08-13 0:41 ` Ping-Ke Shih
0 siblings, 0 replies; 4+ messages in thread
From: Ping-Ke Shih @ 2026-08-13 0:41 UTC (permalink / raw)
To: Mehmet Fide, Bitterblue Smith, linux-wireless@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Mehmet Fide <mehmet.fide@gmail.com> wrote:
> An RTL8822BU or RTL8822CU is asked to come back as a USB 3 device by
> rtw_usb_switch_mode_new(). The chip powers off its MAC and leaves the bus
> while the last control transfers of that sequence are still in flight, so
> they complete with -EPROTO and the driver reports them as errors:
>
> rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
> rtw_8822bu 1-1:1.0: write register 0xc4 failed with -71
> usb 1-1: USB disconnect, device number 2
> usbcore: registered new interface driver rtw_8822bu
> rtw_8822bu 1-1:1.0: Firmware version 27.2.0, H2C version 13
>
> Register 0xc4 is REG_PAD_CTRL2 and the access losing the race is the
> rtw_write32_set() that ends the switch sequence, a few milliseconds before
> the disconnect. Which transfer gets caught varies from boot to boot: 0xc4
> is in the "always on" section, so every write to it is followed by a second
> one from rtw_usb_reg_sec(), and sometimes that is the one that fails:
>
> rtw_8822bu 1-1:1.0: rtw_usb_reg_sec: reg 0x4e0, usb write 1 fail, status: -71
How about changing to use WARN_ONCE()?
[...]
> @@ -1098,6 +1098,7 @@ static int rtw_usb_switch_mode_old(struct rtw_dev *rtwdev)
> rtw_write8(rtwdev, REG_ACLK_MON, 0x1);
> rtw_write8(rtwdev, 0x3d, 0x3);
> /* usb disconnect */
> + rtwusb->switching_mode = true;
> rtw_write8(rtwdev, REG_SYS_PW_CTRL + 1, 0x80);
> return 1;
> }
[...]
> @@ -1151,6 +1153,11 @@ static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
> rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
> rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
>
> + /* From here the chip powers off its MAC and re-enumerates, so it can
> + * leave the bus while a control transfer is still in flight.
> + */
> + rtwusb->switching_mode = true;
> +
> rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
> usleep_range(1000, 1001);
> rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
If WARN_ONCE isn't suitable, move these two assignments to caller.
I think only set `rtwusb->switching_mode = true` only if the return
value is 1.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-13 0:41 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 12:28 [PATCH wireless-next] wifi: rtw88: usb: do not log transfers lost to a mode switch Mehmet Fide
2026-08-12 17:01 ` Bitterblue Smith
2026-08-12 17:32 ` [PATCH rtw-next v2] " Mehmet Fide
2026-08-13 0:41 ` Ping-Ke Shih
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.