Commit 8fc1e8c2 authored by Emil Goode's avatar Emil Goode Committed by John W. Linville

brcmsmac: fix deadlock on missing firmware

When brcm80211 firmware is not installed networking hangs.
A deadlock happens because we call ieee80211_unregister_hw()
from the .start callback of struct ieee80211_ops. When .start
is called we are under rtnl lock and ieee80211_unregister_hw()
tries to take it again.

Function call stack:

dev_change_flags()
	__dev_change_flags()
		__dev_open()
			ASSERT_RTNL() <-- Assert rtnl lock
			ops->ndo_open()

.ndo_open = ieee80211_open,

ieee80211_open()
	ieee80211_do_open()
		drv_start()
			local->ops->start()

.start = brcms_ops_start,

brcms_ops_start()
	brcms_remove()
		ieee80211_unregister_hw()
			rtnl_lock() <-- Here we deadlock

Introduced by:
commit 25b5632f
("brcmsmac: request firmware in .start() callback")

This patch fixes the bug by removing the call to brcms_remove()
and moves the brcms_request_fw() call to the top of the .start
callback to not initiate anything unless firmware is installed.
Signed-off-by: default avatarEmil Goode <emilgoode@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent abee4c84
...@@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw) ...@@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
bool blocked; bool blocked;
int err; int err;
if (!wl->ucode.bcm43xx_bomminor) {
err = brcms_request_fw(wl, wl->wlc->hw->d11core);
if (err)
return -ENOENT;
}
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
spin_lock_bh(&wl->lock); spin_lock_bh(&wl->lock);
blocked = brcms_rfkill_set_hw_state(wl); blocked = brcms_rfkill_set_hw_state(wl);
...@@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw) ...@@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
if (!blocked) if (!blocked)
wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
if (!wl->ucode.bcm43xx_bomminor) {
err = brcms_request_fw(wl, wl->wlc->hw->d11core);
if (err) {
brcms_remove(wl->wlc->hw->d11core);
return -ENOENT;
}
}
spin_lock_bh(&wl->lock); spin_lock_bh(&wl->lock);
/* avoid acknowledging frames before a non-monitor device is added */ /* avoid acknowledging frames before a non-monitor device is added */
wl->mute_tx = true; wl->mute_tx = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment