iwlwifi: mvm: reprobe device on firmware error during restart
authorJohannes Berg <johannes.berg@intel.com>
Thu, 4 Jul 2013 13:25:25 +0000 (15:25 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 31 Jul 2013 09:04:58 +0000 (11:04 +0200)
If we get a firmware error during restart, we currently abandon any
hope and simply fail, getting stuck until the driver is reloaded.
Unfortunately, there isn't really much else we can do since restart
will likely continue to fail, and asking mac80211 for disconnection
just causes more error.

To allow the user to at least set up the device again completely
from scratch, reprobe the device and in doing so completely destroy
any mac80211/driver state.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/ops.c

index fa1e1ce9f2bebf766b3fb2dddbafddfdf48df1d1..5d5dedddd2dc442d69eceaebdb9c95608cdbfb8f 100644 (file)
@@ -644,6 +644,22 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
        ieee80211_free_txskb(mvm->hw, skb);
 }
 
+struct iwl_mvm_reprobe {
+       struct device *dev;
+       struct work_struct work;
+};
+
+static void iwl_mvm_reprobe_wk(struct work_struct *wk)
+{
+       struct iwl_mvm_reprobe *reprobe;
+
+       reprobe = container_of(wk, struct iwl_mvm_reprobe, work);
+       if (device_reprobe(reprobe->dev))
+               dev_err(reprobe->dev, "reprobe failed!\n");
+       kfree(reprobe);
+       module_put(THIS_MODULE);
+}
+
 static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
 {
        iwl_abort_notification_waits(&mvm->notif_wait);
@@ -655,7 +671,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
         * can't recover this since we're already half suspended.
         */
        if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
-               IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n");
+               struct iwl_mvm_reprobe *reprobe;
+
+               IWL_ERR(mvm,
+                       "Firmware error during reconfiguration - reprobe!\n");
+
+               /*
+                * get a module reference to avoid doing this while unloading
+                * anyway and to avoid scheduling a work with code that's
+                * being removed.
+                */
+               if (!try_module_get(THIS_MODULE)) {
+                       IWL_ERR(mvm, "Module is being unloaded - abort\n");
+                       return;
+               }
+
+               reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC);
+               if (!reprobe) {
+                       module_put(THIS_MODULE);
+                       return;
+               }
+               reprobe->dev = mvm->trans->dev;
+               INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
+               schedule_work(&reprobe->work);
        } else if (mvm->cur_ucode == IWL_UCODE_REGULAR &&
                   iwlwifi_mod_params.restart_fw) {
                /*