diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-07-04 09:25:25 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-07-31 05:04:58 -0400 |
commit | ac1ed4163b5a523728fa0e8c27c1ff4d182f40fd (patch) | |
tree | cdff0b9ff46398eac0d26c7e1fdace3d0595466a /drivers/net/wireless/iwlwifi | |
parent | 58fa2aad295579a0fcab699eb76bff79eb8df3a8 (diff) |
iwlwifi: mvm: reprobe device on firmware error during restart
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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fa1e1ce9f2be..5d5dedddd2dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -644,6 +644,22 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
644 | ieee80211_free_txskb(mvm->hw, skb); | 644 | ieee80211_free_txskb(mvm->hw, skb); |
645 | } | 645 | } |
646 | 646 | ||
647 | struct iwl_mvm_reprobe { | ||
648 | struct device *dev; | ||
649 | struct work_struct work; | ||
650 | }; | ||
651 | |||
652 | static void iwl_mvm_reprobe_wk(struct work_struct *wk) | ||
653 | { | ||
654 | struct iwl_mvm_reprobe *reprobe; | ||
655 | |||
656 | reprobe = container_of(wk, struct iwl_mvm_reprobe, work); | ||
657 | if (device_reprobe(reprobe->dev)) | ||
658 | dev_err(reprobe->dev, "reprobe failed!\n"); | ||
659 | kfree(reprobe); | ||
660 | module_put(THIS_MODULE); | ||
661 | } | ||
662 | |||
647 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | 663 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) |
648 | { | 664 | { |
649 | iwl_abort_notification_waits(&mvm->notif_wait); | 665 | iwl_abort_notification_waits(&mvm->notif_wait); |
@@ -655,7 +671,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
655 | * can't recover this since we're already half suspended. | 671 | * can't recover this since we're already half suspended. |
656 | */ | 672 | */ |
657 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 673 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
658 | IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); | 674 | struct iwl_mvm_reprobe *reprobe; |
675 | |||
676 | IWL_ERR(mvm, | ||
677 | "Firmware error during reconfiguration - reprobe!\n"); | ||
678 | |||
679 | /* | ||
680 | * get a module reference to avoid doing this while unloading | ||
681 | * anyway and to avoid scheduling a work with code that's | ||
682 | * being removed. | ||
683 | */ | ||
684 | if (!try_module_get(THIS_MODULE)) { | ||
685 | IWL_ERR(mvm, "Module is being unloaded - abort\n"); | ||
686 | return; | ||
687 | } | ||
688 | |||
689 | reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); | ||
690 | if (!reprobe) { | ||
691 | module_put(THIS_MODULE); | ||
692 | return; | ||
693 | } | ||
694 | reprobe->dev = mvm->trans->dev; | ||
695 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); | ||
696 | schedule_work(&reprobe->work); | ||
659 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && | 697 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && |
660 | iwlwifi_mod_params.restart_fw) { | 698 | iwlwifi_mod_params.restart_fw) { |
661 | /* | 699 | /* |