aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-07-04 09:25:25 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-07-31 05:04:58 -0400
commitac1ed4163b5a523728fa0e8c27c1ff4d182f40fd (patch)
treecdff0b9ff46398eac0d26c7e1fdace3d0595466a /drivers/net/wireless/iwlwifi
parent58fa2aad295579a0fcab699eb76bff79eb8df3a8 (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.c40
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
647struct iwl_mvm_reprobe {
648 struct device *dev;
649 struct work_struct work;
650};
651
652static 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
647static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) 663static 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 /*