Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[cascardo/linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / scan.c
index dac120f..f279fdd 100644 (file)
@@ -141,6 +141,7 @@ struct iwl_mvm_scan_params {
        struct cfg80211_match_set *match_sets;
        int n_scan_plans;
        struct cfg80211_sched_scan_plan *scan_plans;
+       u32 measurement_dwell;
 };
 
 static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
@@ -232,6 +233,27 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device)
        return IWL_SCAN_TYPE_WILD;
 }
 
+static int
+iwl_mvm_get_measurement_dwell(struct iwl_mvm *mvm,
+                             struct cfg80211_scan_request *req,
+                             struct iwl_mvm_scan_params *params)
+{
+       if (!req->duration)
+               return 0;
+
+       if (req->duration_mandatory &&
+           req->duration > scan_timing[params->type].max_out_time) {
+               IWL_DEBUG_SCAN(mvm,
+                              "Measurement scan - too long dwell %hu (max out time %u)\n",
+                              req->duration,
+                              scan_timing[params->type].max_out_time);
+               return -EOPNOTSUPP;
+       }
+
+       return min_t(u32, (u32)req->duration,
+                    scan_timing[params->type].max_out_time);
+}
+
 static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
 {
        /* require rrm scan whenever the fw supports it */
@@ -717,22 +739,6 @@ iwl_mvm_build_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        params->preq.common_data.len = cpu_to_le16(ies->common_ie_len);
 }
 
-static __le32 iwl_mvm_scan_priority(struct iwl_mvm *mvm,
-                                   enum iwl_scan_priority_ext prio)
-{
-       if (fw_has_api(&mvm->fw->ucode_capa,
-                      IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY))
-               return cpu_to_le32(prio);
-
-       if (prio <= IWL_SCAN_PRIORITY_EXT_2)
-               return cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
-
-       if (prio <= IWL_SCAN_PRIORITY_EXT_4)
-               return cpu_to_le32(IWL_SCAN_PRIORITY_MEDIUM);
-
-       return cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
-}
-
 static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
                                    struct iwl_scan_req_lmac *cmd,
                                    struct iwl_mvm_scan_params *params)
@@ -743,7 +749,7 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
        cmd->extended_dwell = scan_timing[params->type].dwell_extended;
        cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time);
        cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);
-       cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+       cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
 }
 
 static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
@@ -1033,21 +1039,24 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
                                    struct iwl_scan_req_umac *cmd,
                                    struct iwl_mvm_scan_params *params)
 {
-       cmd->extended_dwell = scan_timing[params->type].dwell_extended;
-       cmd->active_dwell = scan_timing[params->type].dwell_active;
-       cmd->passive_dwell = scan_timing[params->type].dwell_passive;
+       if (params->measurement_dwell) {
+               cmd->active_dwell = params->measurement_dwell;
+               cmd->passive_dwell = params->measurement_dwell;
+               cmd->extended_dwell = params->measurement_dwell;
+       } else {
+               cmd->active_dwell = scan_timing[params->type].dwell_active;
+               cmd->passive_dwell = scan_timing[params->type].dwell_passive;
+               cmd->extended_dwell = scan_timing[params->type].dwell_extended;
+       }
        cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented;
        cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time);
        cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);
-       cmd->scan_priority =
-               iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+       cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
 
        if (iwl_mvm_is_regular_scan(params))
-               cmd->ooc_priority =
-                       iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
        else
-               cmd->ooc_priority =
-                       iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_2);
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2);
 }
 
 static void
@@ -1067,11 +1076,11 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
        }
 }
 
-static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
+static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
                                   struct iwl_mvm_scan_params *params,
                                   struct ieee80211_vif *vif)
 {
-       int flags = 0;
+       u16 flags = 0;
 
        if (params->n_ssids == 0)
                flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
@@ -1093,6 +1102,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
        if (!iwl_mvm_is_regular_scan(params))
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
 
+       if (params->measurement_dwell)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (mvm->scan_iter_notif_enabled)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
@@ -1119,6 +1131,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        mvm->fw->ucode_capa.n_scan_channels;
        int uid, i;
        u32 ssid_bitmap = 0;
+       struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif);
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1136,8 +1149,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        mvm->scan_uid_status[uid] = type;
 
        cmd->uid = cpu_to_le32(uid);
-       cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params,
+       cmd->general_flags = cpu_to_le16(iwl_mvm_scan_umac_flags(mvm, params,
                                                                 vif));
+       cmd->scan_start_mac_id = scan_vif->id;
 
        if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
                cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
@@ -1289,6 +1303,12 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                iwl_mvm_get_scan_type(mvm,
                                      vif->type == NL80211_IFTYPE_P2P_DEVICE);
 
+       ret = iwl_mvm_get_measurement_dwell(mvm, req, &params);
+       if (ret < 0)
+               return ret;
+
+       params.measurement_dwell = ret;
+
        iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
 
        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
@@ -1315,6 +1335,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
        mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
+       mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif);
        iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
 
        queue_delayed_work(system_wq, &mvm->scan_timeout_dwork,
@@ -1437,9 +1458,12 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
        if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
                struct cfg80211_scan_info info = {
                        .aborted = aborted,
+                       .scan_start_tsf = mvm->scan_start,
                };
 
+               memcpy(info.tsf_bssid, mvm->scan_vif->bssid, ETH_ALEN);
                ieee80211_scan_completed(mvm->hw, &info);
+               mvm->scan_vif = NULL;
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
                cancel_delayed_work(&mvm->scan_timeout_dwork);
        } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
@@ -1473,6 +1497,8 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
        struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;
        u8 buf[256];
 
+       mvm->scan_start = le64_to_cpu(notif->start_tsf);
+
        IWL_DEBUG_SCAN(mvm,
                       "UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n",
                       notif->status, notif->scanned_channels,
@@ -1485,6 +1511,10 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                ieee80211_sched_scan_results(mvm->hw);
                mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
        }
+
+       IWL_DEBUG_SCAN(mvm,
+                      "UMAC Scan iteration complete: scan started at %llu (TSF)\n",
+                      mvm->scan_start);
 }
 
 static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)