[PATCH AUTOSEL 7.0-5.10] wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211

Sasha Levin
2026-04-20T13:23:37Z

From: Ville Nummela <ville.nummela@kempower.com>

[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ]

Removing rsi_91x USB adapter could cause rtnetlink to lock up.
When rsi_mac80211_stop is called, wiphy_lock is locked. Call to
wiphy_rfkill_stop_polling would wait until the work queue has
finished, but because the work queue waits for wiphy_lock, that
would never happen.

Moving the call to rsi_disconnect avoids the lock up.

Signed-off-by: Ville Nummela <ville.nummela@kempower.com>
Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have all the information needed. Let me compile the full analysis.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

### Step 1.1: Subject Line
- **Subsystem**: `wifi: rsi_91x_usb` (USB WiFi driver for RSI 91x
chipset)
- **Action verb**: "do not pause" - indicates preventing incorrect
behavior that causes a hang
- **Summary**: Stop rfkill polling from being paused during mac80211
stop, which causes a deadlock

Record: [wifi: rsi_91x_usb] [do not pause] [Avoid deadlock by moving
rfkill stop polling out of mac80211 stop callback]

### Step 1.2: Tags
- **Signed-off-by**: Ville Nummela (author, external contributor from
Kempower)
- **Link**: `https://patch.msgid.link/20260318081912.87744-1-
ville.nummela@kempower.com`
- **Signed-off-by**: Johannes Berg (Intel, the wireless subsystem
maintainer - applied the patch)
- No Fixes: tag (expected for manual review)
- No Reported-by, Tested-by, Reviewed-by

Record: Patch authored by external contributor (Ville Nummela), applied
by the wifi subsystem maintainer (Johannes Berg). No explicit stable
nomination.

### Step 1.3: Commit Body Analysis
The message describes a **deadlock**:
1. Removing the RSI USB adapter causes rtnetlink to lock up
2. `rsi_mac80211_stop` is called with `wiphy_lock` held
3. `wiphy_rfkill_stop_polling` calls `cancel_delayed_work_sync`, which
waits for the rfkill poll work to finish
4. The rfkill poll work needs `wiphy_lock` to complete (via
`guard(wiphy)` in `cfg80211_rfkill_poll`)
5. Classic ABBA deadlock: Thread A holds wiphy_lock, waits for work;
work needs wiphy_lock

Record: Real deadlock. Trigger: USB adapter removal. Failure: system
hang (rtnetlink lockup).

### Step 1.4: Hidden Bug Fix Detection
This is explicitly a deadlock fix, not disguised. The description
clearly explains the locking inversion.

Record: Explicit deadlock fix, not hidden.

## PHASE 2: DIFF ANALYSIS

### Step 2.1: Inventory
- **Files changed**: 3
- `drivers/net/wireless/rsi/rsi_91x_mac80211.c`: +16/-1 (new function
+ remove call)
- `drivers/net/wireless/rsi/rsi_91x_usb.c`: +2/-0 (call new function)
- `drivers/net/wireless/rsi/rsi_common.h`: +1/-0 (declare new
function)
- **Total**: ~19 lines added, 1 removed
- **Functions modified**: `rsi_mac80211_stop()` (removed
`wiphy_rfkill_stop_polling` call), `rsi_disconnect()` (added call to
new function)
- **Functions added**: `rsi_mac80211_rfkill_exit()` (new helper)
- **Scope**: Small, single-subsystem, well-contained

### Step 2.2: Code Flow Change
1. **rsi_mac80211_stop()**: BEFORE: called `wiphy_rfkill_stop_polling()`
while holding `common->mutex` (and with `wiphy_lock` held by caller).
AFTER: no longer calls it.
2. **rsi_disconnect()** (USB): BEFORE: went straight to
`rsi_mac80211_detach()`. AFTER: calls `rsi_mac80211_rfkill_exit()`
first (without wiphy_lock held), then `rsi_mac80211_detach()`.
3. **New `rsi_mac80211_rfkill_exit()`**: Calls
`wiphy_rfkill_stop_polling()` without wiphy_lock held, breaking the
deadlock.

### Step 2.3: Bug Mechanism
- **Category**: Deadlock/lock ordering
- **Mechanism**: `rsi_mac80211_stop()` (called with `wiphy_lock` held)
invokes `wiphy_rfkill_stop_polling()` which calls
`cancel_delayed_work_sync()`. The work item (`cfg80211_rfkill_poll`)
needs `wiphy_lock`. Classic ABBA deadlock.
- **Fix**: Move the polling stop to `rsi_disconnect()`, before
`rsi_mac80211_detach()`, where `wiphy_lock` is NOT held.

### Step 2.4: Fix Quality
- Obviously correct: removes the deadlocking call from the locked
context, moves it to unlocked context
- Minimal/surgical: small change, well-contained within the rsi driver
- Other drivers (ath9k, rtlwifi, mt76, etc.) all call
`wiphy_rfkill_stop_polling()` from their deinit paths, NOT from
`.stop` - confirming this is the right pattern
- Regression risk: very low. The rfkill polling is stopped slightly
earlier in the teardown sequence

## PHASE 3: GIT HISTORY INVESTIGATION

### Step 3.1: Blame
- `wiphy_rfkill_stop_polling(hw->wiphy)` in `rsi_mac80211_stop()` was
added by commit `edba3532c65223` ("rsi: add support for rf-kill
functionality") by Pavani Muthyala, 2017-08-03.
- The deadlock was introduced when `cfg80211_rfkill_poll()` acquired
wiphy_lock: commit `8e2f6f2366219` ("wifi: cfg80211: lock wiphy mutex
for rfkill poll") by Johannes Berg, 2023-11-24, first in v6.7-rc4.
- `drv_stop()` has had `lockdep_assert_wiphy()` since commit
`0e8185ce1ddebf` (v6.7-rc1).

Record: Bug is a latent deadlock since v6.7 (when wiphy_lock was added
to the rfkill poll path). Buggy rfkill call in rsi since 2017, but it
only became a deadlock with v6.7.

### Step 3.2: No Fixes: tag present (expected).

### Step 3.3: File History
Recent changes to rsi files are mostly cleanups and unrelated bug fixes.
No prerequisites identified.

### Step 3.4: Author
Ville Nummela appears to be an external contributor (Kempower). This is
their first rsi commit. However, the patch was applied by Johannes Berg,
the wifi subsystem maintainer.

### Step 3.5: Dependencies
The fix is standalone. It uses only existing APIs
(`wiphy_rfkill_stop_polling`) and creates a simple wrapper function. No
dependencies on other patches.

## PHASE 4: MAILING LIST RESEARCH

Lore is protected by anti-bot measures, preventing direct access. B4 dig
could not find the commit in the local tree. The Link tag confirms the
patch was submitted and reviewed through the standard wireless-next
workflow and applied by Johannes Berg.

Record: Could not access lore discussion. Patch applied by subsystem
maintainer.

## PHASE 5: CODE SEMANTIC ANALYSIS

### Step 5.1: Functions Modified
- `rsi_mac80211_stop()` - the `.stop` mac80211 callback
- `rsi_disconnect()` - USB disconnect handler
- New: `rsi_mac80211_rfkill_exit()`

### Step 5.2: Callers
- `rsi_mac80211_stop()` is called by mac80211 via `drv_stop()`
(confirmed: `lockdep_assert_wiphy()` at driver-ops.c:39). Called when
interface goes down.
- `rsi_disconnect()` is the USB `.disconnect` callback, called by USB
subsystem on device removal.

### Step 5.3-5.4: Call Chain for Deadlock
Verified complete deadlock chain:
1. USB removal -> `rsi_disconnect()` -> `rsi_mac80211_detach()` ->
`ieee80211_unregister_hw()` -> interface shutdown -> `drv_stop()`
[acquires wiphy_lock] -> `rsi_mac80211_stop()`
2. `rsi_mac80211_stop()` -> `wiphy_rfkill_stop_polling()` ->
`rfkill_pause_polling()` ->
`cancel_delayed_work_sync(&rfkill->poll_work)`
3. Work item: `rfkill_poll()` -> `cfg80211_rfkill_poll()` ->
`guard(wiphy)(&rdev->wiphy)` [tries to acquire wiphy_lock] -> BLOCKED

### Step 5.5: Similar Patterns
All other wifi drivers (ath9k, rtlwifi, mt76, rtl818x, brcmsmac) call
`wiphy_rfkill_stop_polling()` from their deinit/disconnect path, NOT
from `.stop`. RSI was unique in calling it from `.stop`.

## PHASE 6: STABLE TREE ANALYSIS

### Step 6.1: Buggy Code in Stable
- The deadlock requires both:
- `wiphy_rfkill_stop_polling()` in `rsi_mac80211_stop()` (since 2017,
commit edba3532)
- `wiphy_lock` acquisition in `cfg80211_rfkill_poll()` (since v6.7,
commit 8e2f6f23)
- The deadlock exists in v6.7+ stable trees (6.12.y, 6.6.y if 8e2f6f23
was backported)

### Step 6.2: Backport Complications
The fix is simple and self-contained. The rsi driver code in this area
has been stable. Clean apply expected for recent stable trees.

### Step 6.3: No related fixes already in stable.

## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT

- **Subsystem**: wifi (drivers/net/wireless/rsi/) - USB WiFi driver
- **Criticality**: IMPORTANT - WiFi is commonly used, RSI chipsets are
used in embedded/IoT
- **Maintainer**: Applied by Johannes Berg (the wireless subsystem
maintainer), strong trust signal

## PHASE 8: IMPACT AND RISK ASSESSMENT

### Step 8.1: Affected Users
Users of RSI 91x USB WiFi adapters. When removing the adapter
(physically or via software), the system hangs.

### Step 8.2: Trigger Conditions
- **Trigger**: Removing RSI USB WiFi adapter (unplug or modprobe -r)
- **Frequency**: Every time the adapter is removed
- **Unprivileged**: Physical access needed, but could also be triggered
by system suspend/resume or hotplug events

### Step 8.3: Failure Mode Severity
- **Failure mode**: System hang / deadlock (rtnetlink locks up)
- **Severity**: CRITICAL - system becomes partially or fully unusable;
rtnetlink lockup affects all networking operations

### Step 8.4: Risk-Benefit
- **Benefit**: HIGH - prevents guaranteed system hang on USB adapter
removal
- **Risk**: VERY LOW - 19 lines changed, moves existing call to correct
context, pattern matches all other wifi drivers
- **Ratio**: Strongly favorable

## PHASE 9: FINAL SYNTHESIS

### Step 9.1: Evidence Summary

**FOR backporting:**
- Fixes a real, reproducible deadlock (system hang) on USB adapter
removal
- Small, surgical fix (~20 lines across 3 files in one driver)
- Obviously correct: moves `wiphy_rfkill_stop_polling()` from locked
context to unlocked context
- Pattern matches all other wifi drivers (ath9k, rtlwifi, mt76, etc.)
- Applied by wireless subsystem maintainer (Johannes Berg)
- Standalone fix with no dependencies
- Bug exists since v6.7 (when wiphy_lock was added to rfkill poll)

**AGAINST backporting:**
- No explicit stable nomination or Fixes: tag (expected for manual
review)
- Only fixes USB path (SDIO has same latent issue but wasn't addressed -
minor concern)
- Author is external contributor with no previous rsi commits (mitigated
by maintainer sign-off)

### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **YES** - clear deadlock fix, correct
locking pattern
2. Fixes a real bug? **YES** - deadlock causing system hang
3. Important issue? **YES** - deadlock = CRITICAL severity
4. Small and contained? **YES** - ~20 lines in one driver
5. No new features or APIs? **YES** - only moves existing functionality
6. Can apply to stable trees? **YES** - standalone, no dependencies

### Step 9.3: Exception Categories
Not an exception case - this is a straightforward deadlock fix.

### Step 9.4: Decision
This is a clear, small, surgical fix for a real deadlock that causes
system hang when removing an RSI USB WiFi adapter. It follows the same
pattern used by all other wifi drivers. Applied by the wifi subsystem
maintainer.

## Verification

- [Phase 1] Parsed tags: Link to patch.msgid.link, SOB by author and
Johannes Berg (maintainer)
- [Phase 2] Diff analysis: 1 line removed from `rsi_mac80211_stop()`,
16-line new function `rsi_mac80211_rfkill_exit()` added, 2 lines
calling it in `rsi_disconnect()`
- [Phase 3] git blame: `wiphy_rfkill_stop_polling` in `.stop` added by
edba3532c65223 (2017)
- [Phase 3] git show 8e2f6f2366219: confirmed `wiphy_lock` added to
`cfg80211_rfkill_poll()` in v6.7-rc4
- [Phase 3] git show 0e8185ce1ddebf: confirmed `lockdep_assert_wiphy()`
in `drv_stop()` since v6.7-rc1
- [Phase 3] git describe --contains 8e2f6f2366219: deadlock exists since
v6.7-rc4
- [Phase 4] Could not access lore (anti-bot protection); patch Link tag
confirms standard review
- [Phase 5] Verified deadlock chain: `drv_stop()` holds wiphy_lock
(driver-ops.c:39) -> `rsi_mac80211_stop()` -> `rfkill_pause_polling()`
-> `cancel_delayed_work_sync()` blocks on work item needing wiphy_lock
via `guard(wiphy)` in `cfg80211_rfkill_poll()` (core.c:224)
- [Phase 5] Confirmed all other wifi drivers (ath9k, rtlwifi, mt76,
rtl818x, brcmsmac) call `wiphy_rfkill_stop_polling()` from deinit
path, not `.stop`
- [Phase 6] Bug exists in v6.7+ trees; code in rsi driver unchanged in
affected area
- [Phase 8] Failure mode: deadlock/system hang, severity CRITICAL
- UNVERIFIED: Could not access lore discussion for reviewer feedback

**YES**

drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++-
drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++
drivers/net/wireless/rsi/rsi_common.h | 1 +
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index c7ae8031436ae..3faf2235728be 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter)
}
EXPORT_SYMBOL_GPL(rsi_mac80211_detach);

+/**
+ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling
+ * when the device is removed.
+ * @adapter: Pointer to the adapter structure.
+ *
+ * Return: None.
+ */
+void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter)
+{
+ struct ieee80211_hw *hw = adapter->hw;
+
+ if (hw)
+ wiphy_rfkill_stop_polling(hw->wiphy);
+}
+EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit);
+
/**
* rsi_indicate_tx_status() - This function indicates the transmit status.
* @adapter: Pointer to the adapter structure.
@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend)
rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n");
mutex_lock(&common->mutex);
common->iface_down = true;
- wiphy_rfkill_stop_polling(hw->wiphy);

/* Block all rx frames */
rsi_send_rx_filter_frame(common, 0xffff);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index d83204701e27e..8765cac6f875b 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction)
if (!adapter)
return;

+ rsi_mac80211_rfkill_exit(adapter);
+
rsi_mac80211_detach(adapter);

if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 &&
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 7aa5124575cfe..591602beeec68 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -79,6 +79,7 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
}

void rsi_mac80211_detach(struct rsi_hw *hw);
+void rsi_mac80211_rfkill_exit(struct rsi_hw *hw);
u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
struct rsi_hw *rsi_91x_init(u16 oper_mode);
void rsi_91x_deinit(struct rsi_hw *adapter);
--
2.53.0