[PATCH RESEND rtw-next v2 2/2] wifi: rtw88: 8822c: ignore nrx values without CCK PD registers
From: Zeshan Ahmed Nobin
Date: Sun Nov 08 2026 - 13:30:36 EST
rtw8822c_phy_cck_pd_set() reads nrx, the number of CCK RX paths minus
one, from a 2-bit register field. The driver only ever sets it to 0 or
1, for one or two RX paths (see rtw8822c_config_cck_rx_path()), and
rtw8822c_cck_pd_reg[] only has registers for those two values; its
entries for nrx 2 and 3 are all zero.
A device that stops responding can return any value. On USB, a failed
read returns whatever an earlier read left in the buffer, so bw can be
0 or 1 while nrx is 2 or 3. When the level then changes,
rtw8822c_phy_cck_pd_set_reg() gets past its WARN_ON(), which only
checks nrx against RTW_RF_PATH_MAX, and calls rtw_read32_mask() and
rtw_write32_mask() on register 0x0 with a zero mask. Both compute
__ffs(0), which is undefined, and the write puts back whatever was read
from register 0x0.
Return early when rtw8822c_cck_pd_reg[] has no registers for nrx; bw
has already been checked at that point.
The fix and this message were drafted with an AI coding assistant
(Claude Opus 5.5 by Anthropic), then reviewed and tested by the
submitter.
Reported-by: Luka Gejak <luka.gejak@xxxxxxxxx>
Closes: https://lore.kernel.org/linux-wireless/f6a7d3272fe7635c6a83698dfab5d85500437ca6@xxxxxxxxx/
Fixes: 479c4ee931a6 ("rtw88: add dynamic cck pd mechanism")
Signed-off-by: Zeshan Ahmed Nobin <zeshanahmednobin@xxxxxxxxx>
---
Notes:
Testing, only on an RTL8822CE (PCIe). There a failed read gives all
ones, so bw is 3 as well and patch 1 returns first. A debug-only change
forced nrx to 2 on a working chip instead:
- With this patch, in 12 s the function ran 6 times and returned early
each time. rtw8822c_phy_cck_pd_set_reg() was never called with nrx 2,
and there was no UBSAN report.
- With the new check skipped, rtw8822c_phy_cck_pd_set_reg() ran with
nrx 2, and UBSAN reported "shift exponent 64 is too large for 32-bit
type 'unsigned int'" in rtw_read32_mask() and rtw_write32_mask().
- Not tested on USB hardware.
- Build-tested on rtw-next (dc16902cad9c) with W=1: no warnings.
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 6343568285bc..acd192684bb1 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -4413,6 +4413,14 @@ static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
if (bw >= ARRAY_SIZE(dm_info->cck_pd_lv))
return;
+ /*
+ * rtw8822c_cck_pd_reg[] only has registers for one and two RX paths
+ * (nrx 0 and 1); its entries for nrx 2 and 3 are all zero. A device
+ * that stops responding can still return those values.
+ */
+ if (!rtw8822c_cck_pd_reg[bw][nrx].mask_pd)
+ return;
+
rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d) bw=%d nr=%d cck_fa_avg=%d\n",
dm_info->cck_pd_lv[bw][nrx], new_lvl, bw, nrx,
dm_info->cck_fa_avg);
--
2.43.0