static void __wl1271_op_remove_interface(struct wl1271 *wl,
                                         struct ieee80211_vif *vif,
                                         bool reset_tx_queues);
-static void wl1271_op_stop(struct ieee80211_hw *hw);
+static void wlcore_op_stop_locked(struct wl1271 *wl);
 static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 
 static int wl12xx_set_authorized(struct wl1271 *wl,
                vif = wl12xx_wlvif_to_vif(wlvif);
                __wl1271_op_remove_interface(wl, vif, false);
        }
-        wl->watchdog_recovery = false;
-       mutex_unlock(&wl->mutex);
-       wl1271_op_stop(wl->hw);
+
+       wlcore_op_stop_locked(wl);
 
        ieee80211_restart_hw(wl->hw);
 
         * to restart the HW.
         */
        wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
-       return;
+
 out_unlock:
        wl->watchdog_recovery = false;
        clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
        return 0;
 }
 
-static void wl1271_op_stop(struct ieee80211_hw *hw)
+static void wlcore_op_stop_locked(struct wl1271 *wl)
 {
-       struct wl1271 *wl = hw->priv;
        int i;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
-
-       /*
-        * Interrupts must be disabled before setting the state to OFF.
-        * Otherwise, the interrupt handler might be called and exit without
-        * reading the interrupt status.
-        */
-       wlcore_disable_interrupts(wl);
-       mutex_lock(&wl->mutex);
        if (wl->state == WL1271_STATE_OFF) {
                if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
                                        &wl->flags))
                        wlcore_enable_interrupts(wl);
 
-               mutex_unlock(&wl->mutex);
-
-               /*
-                * This will not necessarily enable interrupts as interrupts
-                * may have been disabled when op_stop was called. It will,
-                * however, balance the above call to disable_interrupts().
-                */
-               wlcore_enable_interrupts(wl);
                return;
        }
 
         * functions don't perform further work.
         */
        wl->state = WL1271_STATE_OFF;
+
+       /*
+        * Use the nosync variant to disable interrupts, so the mutex could be
+        * held while doing so without deadlocking.
+        */
+       wlcore_disable_interrupts_nosync(wl);
+
        mutex_unlock(&wl->mutex);
 
+       wlcore_synchronize_interrupts(wl);
        wl1271_flush_deferred_work(wl);
        cancel_delayed_work_sync(&wl->scan_complete_work);
        cancel_work_sync(&wl->netstack_work);
        wl->tx_res_if = NULL;
        kfree(wl->target_mem_map);
        wl->target_mem_map = NULL;
+}
+
+static void wlcore_op_stop(struct ieee80211_hw *hw)
+{
+       struct wl1271 *wl = hw->priv;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+
+       mutex_lock(&wl->mutex);
+
+       wlcore_op_stop_locked(wl);
 
        mutex_unlock(&wl->mutex);
 }
 
 static const struct ieee80211_ops wl1271_ops = {
        .start = wl1271_op_start,
-       .stop = wl1271_op_stop,
+       .stop = wlcore_op_stop,
        .add_interface = wl1271_op_add_interface,
        .remove_interface = wl1271_op_remove_interface,
        .change_interface = wl12xx_op_change_interface,