iwlwifi: mvm: handle pass all scan reporting
authorLuca Coelho <luciano.coelho@intel.com>
Tue, 2 Feb 2016 20:58:46 +0000 (22:58 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sat, 27 Feb 2016 19:59:53 +0000 (21:59 +0200)
The firmware doesn't send match found notifications when no matchsets
are passed.  This makes sense because if there are no matchsets,
nothing can be matched.  But the nl80211 API should report when there
are results available, even if no matchsets were passed.

To handle this, we can use the firmware's ITERATION_COMPLETE
reporting, which will send us notifications every time it completed a
scheduled scan iteration.  Then we can set a flag when we received
beacons and use that to report that results are available.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c

index d867cb478681880fa849e68bc4ae7731626587d4..bb811a29490d056930bdbf2a91b747f45e260b0e 100644 (file)
@@ -493,6 +493,12 @@ enum iwl_mvm_scan_type {
        IWL_SCAN_TYPE_FRAGMENTED,
 };
 
+enum iwl_mvm_sched_scan_pass_all_states {
+       SCHED_SCAN_PASS_ALL_DISABLED,
+       SCHED_SCAN_PASS_ALL_ENABLED,
+       SCHED_SCAN_PASS_ALL_FOUND,
+};
+
 /**
  * struct iwl_nvm_section - describes an NVM section in memory.
  *
@@ -687,6 +693,7 @@ struct iwl_mvm {
        void *scan_cmd;
        struct iwl_mcast_filter_cmd *mcast_filter_cmd;
        enum iwl_mvm_scan_type scan_type;
+       enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all;
 
        /* max number of simultaneous scans the FW supports */
        unsigned int max_scans;
index 145ec68ce6f9a398c3bed94f3f4d4f5d2eb38e64..055a8b0f7ad7e9576e8cbe65d27b6fb4e0fabd8d 100644 (file)
@@ -448,6 +448,12 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
        iwl_mvm_update_frame_stats(mvm, rate_n_flags,
                                   rx_status->flag & RX_FLAG_AMPDU_DETAILS);
 #endif
+
+       if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
+                     ieee80211_is_probe_resp(hdr->frame_control)) &&
+                    mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED))
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
+
        iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status,
                                        crypt_len, rxb);
 }
index aa6d8074f63a5871ecf8c01b57243799bbd86d67..09eb72c4ae439206aefe2fd7d223bd5d8bea6a5a 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -297,6 +299,12 @@ void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                       iwl_mvm_dump_channel_list(notif->results,
                                                 notif->scanned_channels, buf,
                                                 sizeof(buf)));
+
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) {
+               IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n");
+               ieee80211_sched_scan_results(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
+       }
 }
 
 void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
@@ -380,6 +388,7 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
 
                mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
                IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
                               aborted ? "aborted" : "completed",
@@ -533,10 +542,13 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
                IWL_DEBUG_SCAN(mvm,
                               "Sending scheduled scan with filtering, n_match_sets %d\n",
                               req->n_match_sets);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
                return false;
        }
 
        IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n");
+
+       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
        return true;
 }
 
@@ -788,6 +800,9 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
                flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
 #endif
 
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+
        if (iwl_mvm_is_regular_scan(params) &&
            vif->type != NL80211_IFTYPE_P2P_DEVICE &&
            params->type != IWL_SCAN_TYPE_FRAGMENTED)
@@ -1074,6 +1089,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
 #endif
 
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+
        if (iwl_mvm_is_regular_scan(params) &&
            vif->type != NL80211_IFTYPE_P2P_DEVICE &&
            params->type != IWL_SCAN_TYPE_FRAGMENTED)
@@ -1301,10 +1319,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                return -EBUSY;
        }
 
-       /* we don't support "match all" in the firmware */
-       if (!req->n_match_sets)
-               return -EOPNOTSUPP;
-
        ret = iwl_mvm_check_running_scans(mvm, type);
        if (ret)
                return ret;
@@ -1400,6 +1414,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        }
 
        mvm->scan_status &= ~mvm->scan_uid_status[uid];
@@ -1434,6 +1449,12 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                       iwl_mvm_dump_channel_list(notif->results,
                                                 notif->scanned_channels, buf,
                                                 sizeof(buf)));
+
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) {
+               IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n");
+               ieee80211_sched_scan_results(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
+       }
 }
 
 static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
@@ -1528,6 +1549,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
                if (uid >= 0 && !mvm->restart_fw) {
                        ieee80211_sched_scan_stopped(mvm->hw);
+                       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
                        mvm->scan_uid_status[uid] = 0;
                }
 
@@ -1549,8 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                 * restart_hw, so do not report if FW is about to be
                 * restarted.
                 */
-               if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw)
+               if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) &&
+                   !mvm->restart_fw) {
                        ieee80211_sched_scan_stopped(mvm->hw);
+                       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
+               }
        }
 }
 
@@ -1586,6 +1611,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        } else if (notify) {
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        }
 
        return ret;