diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/ops.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index af79a14063a9..2fcc8ef88a68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -275,6 +275,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
275 | CMD(BEACON_NOTIFICATION), | 275 | CMD(BEACON_NOTIFICATION), |
276 | CMD(BEACON_TEMPLATE_CMD), | 276 | CMD(BEACON_TEMPLATE_CMD), |
277 | CMD(STATISTICS_NOTIFICATION), | 277 | CMD(STATISTICS_NOTIFICATION), |
278 | CMD(REDUCE_TX_POWER_CMD), | ||
278 | CMD(TX_ANT_CONFIGURATION_CMD), | 279 | CMD(TX_ANT_CONFIGURATION_CMD), |
279 | CMD(D3_CONFIG_CMD), | 280 | CMD(D3_CONFIG_CMD), |
280 | CMD(PROT_OFFLOAD_CONFIG_CMD), | 281 | CMD(PROT_OFFLOAD_CONFIG_CMD), |
@@ -301,6 +302,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
301 | CMD(MCAST_FILTER_CMD), | 302 | CMD(MCAST_FILTER_CMD), |
302 | CMD(REPLY_BEACON_FILTERING_CMD), | 303 | CMD(REPLY_BEACON_FILTERING_CMD), |
303 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 304 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
305 | CMD(MAC_PM_POWER_TABLE), | ||
304 | }; | 306 | }; |
305 | #undef CMD | 307 | #undef CMD |
306 | 308 | ||
@@ -340,6 +342,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
340 | mvm->fw = fw; | 342 | mvm->fw = fw; |
341 | mvm->hw = hw; | 343 | mvm->hw = hw; |
342 | 344 | ||
345 | mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; | ||
346 | |||
343 | mutex_init(&mvm->mutex); | 347 | mutex_init(&mvm->mutex); |
344 | spin_lock_init(&mvm->async_handlers_lock); | 348 | spin_lock_init(&mvm->async_handlers_lock); |
345 | INIT_LIST_HEAD(&mvm->time_event_list); | 349 | INIT_LIST_HEAD(&mvm->time_event_list); |
@@ -431,6 +435,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
431 | if (err) | 435 | if (err) |
432 | goto out_unregister; | 436 | goto out_unregister; |
433 | 437 | ||
438 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD) | ||
439 | mvm->pm_ops = &pm_mac_ops; | ||
440 | else | ||
441 | mvm->pm_ops = &pm_legacy_ops; | ||
442 | |||
443 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); | ||
444 | |||
434 | return op_mode; | 445 | return op_mode; |
435 | 446 | ||
436 | out_unregister: | 447 | out_unregister: |
@@ -638,6 +649,22 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
638 | ieee80211_free_txskb(mvm->hw, skb); | 649 | ieee80211_free_txskb(mvm->hw, skb); |
639 | } | 650 | } |
640 | 651 | ||
652 | struct iwl_mvm_reprobe { | ||
653 | struct device *dev; | ||
654 | struct work_struct work; | ||
655 | }; | ||
656 | |||
657 | static void iwl_mvm_reprobe_wk(struct work_struct *wk) | ||
658 | { | ||
659 | struct iwl_mvm_reprobe *reprobe; | ||
660 | |||
661 | reprobe = container_of(wk, struct iwl_mvm_reprobe, work); | ||
662 | if (device_reprobe(reprobe->dev)) | ||
663 | dev_err(reprobe->dev, "reprobe failed!\n"); | ||
664 | kfree(reprobe); | ||
665 | module_put(THIS_MODULE); | ||
666 | } | ||
667 | |||
641 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | 668 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) |
642 | { | 669 | { |
643 | iwl_abort_notification_waits(&mvm->notif_wait); | 670 | iwl_abort_notification_waits(&mvm->notif_wait); |
@@ -649,9 +676,30 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
649 | * can't recover this since we're already half suspended. | 676 | * can't recover this since we're already half suspended. |
650 | */ | 677 | */ |
651 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 678 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
652 | IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); | 679 | struct iwl_mvm_reprobe *reprobe; |
653 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && | 680 | |
654 | iwlwifi_mod_params.restart_fw) { | 681 | IWL_ERR(mvm, |
682 | "Firmware error during reconfiguration - reprobe!\n"); | ||
683 | |||
684 | /* | ||
685 | * get a module reference to avoid doing this while unloading | ||
686 | * anyway and to avoid scheduling a work with code that's | ||
687 | * being removed. | ||
688 | */ | ||
689 | if (!try_module_get(THIS_MODULE)) { | ||
690 | IWL_ERR(mvm, "Module is being unloaded - abort\n"); | ||
691 | return; | ||
692 | } | ||
693 | |||
694 | reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); | ||
695 | if (!reprobe) { | ||
696 | module_put(THIS_MODULE); | ||
697 | return; | ||
698 | } | ||
699 | reprobe->dev = mvm->trans->dev; | ||
700 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); | ||
701 | schedule_work(&reprobe->work); | ||
702 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { | ||
655 | /* | 703 | /* |
656 | * This is a bit racy, but worst case we tell mac80211 about | 704 | * This is a bit racy, but worst case we tell mac80211 about |
657 | * a stopped/aborted (sched) scan when that was already done | 705 | * a stopped/aborted (sched) scan when that was already done |
@@ -669,6 +717,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
669 | break; | 717 | break; |
670 | } | 718 | } |
671 | 719 | ||
720 | if (mvm->restart_fw > 0) | ||
721 | mvm->restart_fw--; | ||
672 | ieee80211_restart_hw(mvm->hw); | 722 | ieee80211_restart_hw(mvm->hw); |
673 | } | 723 | } |
674 | } | 724 | } |
@@ -678,6 +728,8 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | |||
678 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 728 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
679 | 729 | ||
680 | iwl_mvm_dump_nic_error_log(mvm); | 730 | iwl_mvm_dump_nic_error_log(mvm); |
731 | if (!mvm->restart_fw) | ||
732 | iwl_mvm_dump_sram(mvm); | ||
681 | 733 | ||
682 | iwl_mvm_nic_restart(mvm); | 734 | iwl_mvm_nic_restart(mvm); |
683 | } | 735 | } |