diff options
author | Arik Nemtsov <arik@wizery.com> | 2014-02-10 08:34:29 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-03-09 13:16:48 -0400 |
commit | 33ea27f66afa9ca3e130bd00c595dca509152fd7 (patch) | |
tree | 6fd5a2d075e9aaef96638d4d8b04c2508100f5d8 /drivers/net/wireless | |
parent | 7bb426ea36f143459895de0cf11f0f0a7cfa396a (diff) |
iwlwifi: mvm: wait for stop sched-scan completion
cfg80211 assumes a scheduled scan is stopped synchronously. Wait for the
FW before returning to caller.
Don't do anything in the async handler in the stop-from-above flow.
There's no need to call the mac80211 sched-scan completion as the
cleanup will be automatic. Make sure the async handler is called before
the next incoming scan changes the scan_status by flushing the async
handlers after all invocations.
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/scan.c | 42 |
3 files changed, 46 insertions, 27 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 41b9e65f6a3f..fff66ab2cfda 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -1419,8 +1419,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1419 | struct cfg80211_scan_request *req) | 1419 | struct cfg80211_scan_request *req) |
1420 | { | 1420 | { |
1421 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1421 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1422 | struct iwl_notification_wait wait_scan_done; | ||
1423 | static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; | ||
1424 | int ret; | 1422 | int ret; |
1425 | 1423 | ||
1426 | if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) | 1424 | if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) |
@@ -1430,22 +1428,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1430 | 1428 | ||
1431 | switch (mvm->scan_status) { | 1429 | switch (mvm->scan_status) { |
1432 | case IWL_MVM_SCAN_SCHED: | 1430 | case IWL_MVM_SCAN_SCHED: |
1433 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | 1431 | ret = iwl_mvm_sched_scan_stop(mvm); |
1434 | scan_done_notif, | ||
1435 | ARRAY_SIZE(scan_done_notif), | ||
1436 | NULL, NULL); | ||
1437 | iwl_mvm_sched_scan_stop(mvm); | ||
1438 | ret = iwl_wait_notification(&mvm->notif_wait, | ||
1439 | &wait_scan_done, HZ); | ||
1440 | if (ret) { | 1432 | if (ret) { |
1441 | ret = -EBUSY; | 1433 | ret = -EBUSY; |
1442 | goto out; | 1434 | goto out; |
1443 | } | 1435 | } |
1444 | /* iwl_mvm_rx_scan_offload_complete_notif() will be called | ||
1445 | * soon but will not reset the scan status as it won't be | ||
1446 | * IWL_MVM_SCAN_SCHED any more since we queue the next scan | ||
1447 | * immediately (below) | ||
1448 | */ | ||
1449 | break; | 1436 | break; |
1450 | case IWL_MVM_SCAN_NONE: | 1437 | case IWL_MVM_SCAN_NONE: |
1451 | break; | 1438 | break; |
@@ -1461,7 +1448,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1461 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | 1448 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); |
1462 | out: | 1449 | out: |
1463 | mutex_unlock(&mvm->mutex); | 1450 | mutex_unlock(&mvm->mutex); |
1464 | 1451 | /* make sure to flush the Rx handler before the next scan arrives */ | |
1452 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1465 | return ret; | 1453 | return ret; |
1466 | } | 1454 | } |
1467 | 1455 | ||
@@ -1751,12 +1739,14 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | |||
1751 | struct ieee80211_vif *vif) | 1739 | struct ieee80211_vif *vif) |
1752 | { | 1740 | { |
1753 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1741 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1742 | int ret; | ||
1754 | 1743 | ||
1755 | mutex_lock(&mvm->mutex); | 1744 | mutex_lock(&mvm->mutex); |
1756 | iwl_mvm_sched_scan_stop(mvm); | 1745 | ret = iwl_mvm_sched_scan_stop(mvm); |
1757 | mutex_unlock(&mvm->mutex); | 1746 | mutex_unlock(&mvm->mutex); |
1747 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1758 | 1748 | ||
1759 | return 0; | 1749 | return ret; |
1760 | } | 1750 | } |
1761 | 1751 | ||
1762 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 1752 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3511bf79abcd..4da53c395ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -712,6 +712,11 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } | |||
712 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); | 712 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); |
713 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); | 713 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); |
714 | 714 | ||
715 | static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) | ||
716 | { | ||
717 | flush_work(&mvm->async_handlers_wk); | ||
718 | } | ||
719 | |||
715 | /* Statistics */ | 720 | /* Statistics */ |
716 | int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, | 721 | int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, |
717 | struct iwl_rx_cmd_buffer *rxb, | 722 | struct iwl_rx_cmd_buffer *rxb, |
@@ -813,7 +818,7 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | |||
813 | struct cfg80211_sched_scan_request *req); | 818 | struct cfg80211_sched_scan_request *req); |
814 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 819 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
815 | struct cfg80211_sched_scan_request *req); | 820 | struct cfg80211_sched_scan_request *req); |
816 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); | 821 | int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); |
817 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, | 822 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, |
818 | struct iwl_rx_cmd_buffer *rxb, | 823 | struct iwl_rx_cmd_buffer *rxb, |
819 | struct iwl_device_cmd *cmd); | 824 | struct iwl_device_cmd *cmd); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index b4c9fb649976..a2cd54b57e67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -519,10 +519,11 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
519 | scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | 519 | scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? |
520 | "completed" : "aborted"); | 520 | "completed" : "aborted"); |
521 | 521 | ||
522 | /* might already be something else again, don't reset if so */ | 522 | /* only call mac80211 completion if the stop was initiated by FW */ |
523 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) | 523 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { |
524 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 524 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
525 | ieee80211_sched_scan_stopped(mvm->hw); | 525 | ieee80211_sched_scan_stopped(mvm->hw); |
526 | } | ||
526 | 527 | ||
527 | return 0; | 528 | return 0; |
528 | } | 529 | } |
@@ -894,26 +895,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) | |||
894 | * microcode has notified us that a scan is completed. | 895 | * microcode has notified us that a scan is completed. |
895 | */ | 896 | */ |
896 | IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); | 897 | IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); |
897 | ret = -EIO; | 898 | ret = -ENOENT; |
898 | } | 899 | } |
899 | 900 | ||
900 | return ret; | 901 | return ret; |
901 | } | 902 | } |
902 | 903 | ||
903 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) | 904 | int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) |
904 | { | 905 | { |
905 | int ret; | 906 | int ret; |
907 | struct iwl_notification_wait wait_scan_done; | ||
908 | static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; | ||
906 | 909 | ||
907 | lockdep_assert_held(&mvm->mutex); | 910 | lockdep_assert_held(&mvm->mutex); |
908 | 911 | ||
909 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { | 912 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { |
910 | IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); | 913 | IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); |
911 | return; | 914 | return 0; |
912 | } | 915 | } |
913 | 916 | ||
917 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | ||
918 | scan_done_notif, | ||
919 | ARRAY_SIZE(scan_done_notif), | ||
920 | NULL, NULL); | ||
921 | |||
914 | ret = iwl_mvm_send_sched_scan_abort(mvm); | 922 | ret = iwl_mvm_send_sched_scan_abort(mvm); |
915 | if (ret) | 923 | if (ret) { |
916 | IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); | 924 | IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); |
917 | else | 925 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); |
918 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); | 926 | return ret; |
927 | } | ||
928 | |||
929 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); | ||
930 | |||
931 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | ||
932 | if (ret) | ||
933 | return ret; | ||
934 | |||
935 | /* | ||
936 | * Clear the scan status so the next scan requests will succeed. This | ||
937 | * also ensures the Rx handler doesn't do anything, as the scan was | ||
938 | * stopped from above. | ||
939 | */ | ||
940 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
941 | |||
942 | return 0; | ||
919 | } | 943 | } |