From: Ping-Ke Shih pkshih@realtek.com
[ Upstream commit 58de1f91e033b1fface8d8948984583125f93736 ]
The register REG_SYS_CFG1 is used to determine chip basic information as arguments of following flows, such as download firmware and load PHY parameters, so driver read the value early (before power-on).
However, the direct IO is disallowed before power-on, or it causes wrong values, which driver recognizes a chip as a wrong type RF_1T1R, but actually RF_2T2R, causing driver warns:
rtw88_8822cs mmc1:0001:1: unsupported rf path (1)
Fix it by using indirect IO before power-on.
Reported-by: Piotr Oniszczuk piotr.oniszczuk@gmail.com Closes: https://lore.kernel.org/linux-wireless/699C22B4-A3E3-4206-97D0-22AB3348EBF6@... Suggested-by: Bitterblue Smith rtl8821cerfe2@gmail.com Tested-by: Piotr Oniszczuk piotr.oniszczuk@gmail.com Reviewed-by: Martin Blumenstingl martin.blumenstingl@googlemail.com Signed-off-by: Ping-Ke Shih pkshih@realtek.com Link: https://patch.msgid.link/20250724004815.7043-1-pkshih@realtek.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
Explanation
- Bug fixed and user impact: - The driver reads `REG_SYS_CFG1` very early to determine chip RF configuration before full power-on. In SDIO mode, doing this via direct I/O before power-on can return wrong values, making 2T2R chips look like 1T1R and leading to runtime warnings and misconfiguration (e.g., “unsupported rf path (1)”). - The early read is visible in `drivers/net/wireless/realtek/rtw88/main.c:1861`, where `hal->chip_version = rtw_read32(rtwdev, REG_SYS_CFG1);` happens during core init, before the power-on flag is set.
- What the change does: - It updates the direct/indirect access decision so that device register accesses use indirect I/O until the device is fully powered on. - Specifically, `rtw_sdio_use_direct_io()` now returns false (use indirect) when the device is not yet powered on and the target is not a bus address. This is the minimal and precise change that addresses the wrong-value read issue.
- Code path details and why it works: - Current decision helper: - `drivers/net/wireless/realtek/rtw88/sdio.c:145` defines `rtw_sdio_use_direct_io()` and is used by all bus read/write entry points (`read8/16/32`, `write8/16/32`) at `drivers/net/wireless/realtek/rtw88/sdio.c:257`, `drivers/net/wireless/realtek/rtw88/sdio.c:285`, `drivers/net/wireless/realtek/rtw88/sdio.c:313`, and for writes later in the file. - Address translation: - `drivers/net/wireless/realtek/rtw88/sdio.c:127` `rtw_sdio_to_io_address()` adds `WLAN_IOREG_OFFSET` only for direct I/O on device registers; indirect I/O passes the raw MAC register address to the indirect engine. This ensures that with the new condition pre-power-on device register accesses go through the indirect mechanism as intended. - Indirect engine: - Indirect access is orchestrated via `REG_SDIO_INDIRECT_REG_CFG` and `REG_SDIO_INDIRECT_REG_DATA` (`drivers/net/wireless/realtek/rtw88/sdio.c:159`, `drivers/net/wireless/realtek/rtw88/sdio.h:115`) and does not depend on the device power-on state for correctness, as it uses SDIO-local registers. - Power state flag: - The power-on flag used by the new check is already present and managed in the core: see `drivers/net/wireless/realtek/rtw88/main.h:371` for `RTW_FLAG_POWERON`, and it is cleared/set in the generic power flows (`drivers/net/wireless/realtek/rtw88/rtw88xxa.c:753`, `drivers/net/wireless/realtek/rtw88/rtw88xxa.c:1233`) and in MAC power flows (`drivers/net/wireless/realtek/rtw88/mac.c:309`, `drivers/net/wireless/realtek/rtw88/mac.c:325`). - Early read context: - Because `REG_SYS_CFG1` is read before `RTW_FLAG_POWERON` is set (`drivers/net/wireless/realtek/rtw88/main.c:1861`), the new guard in `rtw_sdio_use_direct_io()` affects precisely this problematic access, forcing indirect I/O and preventing the mis-detection of RF path count.
- Scope and risk: - Scope: One small conditional addition in a single function in the rtw88 SDIO HCI glue (`drivers/net/wireless/realtek/rtw88/sdio.c`). No API changes, no architectural refactoring. - Behavior change is intentionally limited to pre-power-on device register accesses; bus addresses remain direct, and after power-on existing direct/indirect policy remains unchanged. - This reduces risk of wrong reads on SDIO 2.0 paths (where prior logic allowed direct I/O pre-power-on) and aligns pre-power-on behavior across SDIO versions, improving reliability. - The indirect path is established and already used broadly (e.g., when SDIO 3.0 is supported or for unaligned accesses), so coverage/risk is low.
- Stable backport suitability: - Fixes a real, user-visible problem (incorrect RF path detection and warnings; potential malfunction). - Change is small, contained, and conforms to stable rules (bug fix, no new features or invasive changes). - Only touches the rtw88 SDIO transport, not core kernel or unrelated subsystems. - The commit message references a report, suggested fix, and testing, supporting its maturity.
- Specific code references - Decision point to force indirect before power-on: drivers/net/wireless/realtek/rtw88/sdio.c:145 - Address mapping for direct I/O: drivers/net/wireless/realtek/rtw88/sdio.c:127 - Indirect engine config/data registers: drivers/net/wireless/realtek/rtw88/sdio.c:159, drivers/net/wireless/realtek/rtw88/sdio.h:115 - Power-on flag declaration: drivers/net/wireless/realtek/rtw88/main.h:371 - Power-on flag management: drivers/net/wireless/realtek/rtw88/rtw88xxa.c:753, drivers/net/wireless/realtek/rtw88/rtw88xxa.c:1233; drivers/net/wireless/realtek/rtw88/mac.c:309, drivers/net/wireless/realtek/rtw88/mac.c:325 - Early `REG_SYS_CFG1` read (bug trigger site): drivers/net/wireless/realtek/rtw88/main.c:1861 - `WLAN_IOREG_OFFSET` definition: drivers/net/wireless/realtek/rtw88/sdio.h:11
Conclusion: This commit is a strong candidate for stable backport. It addresses a concrete and reported malfunction with a minimal, targeted change and low regression risk, confined to the rtw88 SDIO pre-power-on access path.
drivers/net/wireless/realtek/rtw88/sdio.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index cc2d4fef35879..99d7c629eac6f 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,6 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr,
static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && + !rtw_sdio_is_bus_addr(addr)) + return false; + return !rtw_sdio_is_sdio30_supported(rtwdev) || rtw_sdio_is_bus_addr(addr); }