iwlwifi: mvm: abort scan on sched_scan request
authorArik Nemtsov <arik@wizery.com>
Mon, 10 Feb 2014 10:49:39 +0000 (12:49 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 9 Mar 2014 17:16:48 +0000 (19:16 +0200)
A scheduled scan is a more persistent setting and should take priority
over temporary regular scans. Abort the regular when a sched_scan
request arrives and then request the sched_scan.

The kernel API allows sending a sched_scan without canceling a regular
scan in progress, so this is our way to abstract the FW's limitations.

Make the scan-cancel Rx handler async and flush after invocation to
ensure new scans can't creep in before it.

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>
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/scan.c

index fff66ab2cfda0eb304a5a55418b7451bd96143fc..a6df00d675b7586b586f0dadeecc1c71a68c7a16 100644 (file)
@@ -1708,9 +1708,26 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
-       if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
-               IWL_DEBUG_SCAN(mvm,
-                              "SCHED SCAN request during internal scan - abort\n");
+       switch (mvm->scan_status) {
+       case IWL_MVM_SCAN_OS:
+               IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
+               ret = iwl_mvm_cancel_scan(mvm);
+               if (ret) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+
+               /*
+                * iwl_mvm_rx_scan_complete() will be called soon but will
+                * not reset the scan status as it won't be IWL_MVM_SCAN_OS
+                * any more since we queue the next scan immediately (below).
+                * We make sure it is called before the next scan starts by
+                * flushing the async-handlers work.
+                */
+               break;
+       case IWL_MVM_SCAN_NONE:
+               break;
+       default:
                ret = -EBUSY;
                goto out;
        }
@@ -1732,6 +1749,8 @@ err:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 out:
        mutex_unlock(&mvm->mutex);
+       /* make sure to flush the Rx handler before the next scan arrives */
+       iwl_mvm_wait_for_async_handlers(mvm);
        return ret;
 }
 
index 4da53c395ad306f00de3f5f1af77fac1e92bd3a9..e5c1db97acf405d535cee2e802932c9fb5701c07 100644 (file)
@@ -804,7 +804,7 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                             struct iwl_device_cmd *cmd);
 int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                             struct iwl_device_cmd *cmd);
-void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
+int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
 
 /* Scheduled scan */
 int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
index 05f6355720637f4993be79fd64f5d41e240a9112..39279e1d6ad4e1f7d59ae5f4b26612adc904b2bd 100644 (file)
@@ -226,7 +226,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
 
        RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
-       RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+       RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
        RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
                   iwl_mvm_rx_scan_offload_complete_notif, true),
        RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results,
index a2cd54b57e678b68471c5b8277b573445b4543b4..945398ba39b4271cc87ae333411f5c987831958c 100644 (file)
@@ -402,10 +402,13 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scan_complete_notif *notif = (void *)pkt->data;
 
+       lockdep_assert_held(&mvm->mutex);
+
        IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
                       notif->status, notif->scanned_channels);
 
-       mvm->scan_status = IWL_MVM_SCAN_NONE;
+       if (mvm->scan_status == IWL_MVM_SCAN_OS)
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
        ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
@@ -466,7 +469,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
        };
 }
 
-void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
+int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
 {
        struct iwl_notification_wait wait_scan_abort;
        static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
@@ -474,13 +477,13 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
        int ret;
 
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
-               return;
+               return 0;
 
        if (iwl_mvm_is_radio_killed(mvm)) {
                ieee80211_scan_completed(mvm->hw, true);
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
                mvm->scan_status = IWL_MVM_SCAN_NONE;
-               return;
+               return 0;
        }
 
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
@@ -495,14 +498,11 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
                goto out_remove_notif;
        }
 
-       ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ);
-       if (ret)
-               IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
-
-       return;
+       return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ);
 
 out_remove_notif:
        iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
+       return ret;
 }
 
 int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
This page took 0.032195 seconds and 5 git commands to generate.