3.14-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Emil Goode <emilgo...@gmail.com>

commit 8fc1e8c240aab968db658b2d8d079b4391207a36 upstream.

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 25b5632fb35ca61b8ae3eee235edcdc2883f7a5e
("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: Emil Goode <emilgo...@gmail.com>
Signed-off-by: John W. Linville <linvi...@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c |   14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80
        bool blocked;
        int err;
 
+       if (!wl->ucode.bcm43xx_bomminor) {
+               err = brcms_request_fw(wl, wl->wlc->hw->d11core);
+               if (err)
+                       return -ENOENT;
+       }
+
        ieee80211_wake_queues(hw);
        spin_lock_bh(&wl->lock);
        blocked = brcms_rfkill_set_hw_state(wl);
@@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80
        if (!blocked)
                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);
        /* avoid acknowledging frames before a non-monitor device is added */
        wl->mute_tx = true;


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to