iwlwifi: scan: support FW APIs with variable number of profiles
authorTova Mussai <tova.mussai@intel.com>
Tue, 5 Nov 2019 10:56:14 +0000 (12:56 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 27 Mar 2020 06:12:53 +0000 (08:12 +0200)
The FW changed the maximum number of scan offload profiles to 8 in new
APIs.  Support it by changing the scan_offload_profile_cfg struct to be
more dynamic, so we can reuse most of the code and only change size of
the profiles array.

Change-Id: I65210cf541af46e2675a8c764d5871f7f5b070d6
Signed-off-by: Tova Mussai <tova.mussai@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/scan.c

index 2e70e4e..3d770f4 100644 (file)
@@ -95,6 +95,7 @@ struct iwl_ssid_ie {
 #define IWL_SCAN_MAX_BLACKLIST_LEN     64
 #define IWL_SCAN_SHORT_BLACKLIST_LEN   16
 #define IWL_SCAN_MAX_PROFILES          11
+#define IWL_SCAN_MAX_PROFILES_V2       8
 #define SCAN_OFFLOAD_PROBE_REQ_SIZE    512
 #define SCAN_NUM_BAND_PROBE_DATA_V_1   2
 #define SCAN_NUM_BAND_PROBE_DATA_V_2   3
@@ -160,8 +161,7 @@ struct iwl_scan_offload_profile {
 } __packed;
 
 /**
- * struct iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1
- * @profiles:          profiles to search for match
+ * struct iwl_scan_offload_profile_cfg_data
  * @blacklist_len:     length of blacklist
  * @num_profiles:      num of profiles in the list
  * @match_notify:      clients waiting for match found notification
@@ -170,8 +170,7 @@ struct iwl_scan_offload_profile {
  * @any_beacon_notify: clients waiting for match notification without match
  * @reserved:          reserved
  */
-struct iwl_scan_offload_profile_cfg {
-       struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
+struct iwl_scan_offload_profile_cfg_data {
        u8 blacklist_len;
        u8 num_profiles;
        u8 match_notify;
@@ -181,6 +180,26 @@ struct iwl_scan_offload_profile_cfg {
        u8 reserved[2];
 } __packed;
 
+/**
+ * struct iwl_scan_offload_profile_cfg
+ * @profiles:  profiles to search for match
+ * @data:      the rest of the data for profile_cfg
+ */
+struct iwl_scan_offload_profile_cfg_v1 {
+       struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
+       struct iwl_scan_offload_profile_cfg_data data;
+} __packed; /* SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1-2*/
+
+/**
+ * struct iwl_scan_offload_profile_cfg
+ * @profiles:  profiles to search for match
+ * @data:      the rest of the data for profile_cfg
+ */
+struct iwl_scan_offload_profile_cfg {
+       struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES_V2];
+       struct iwl_scan_offload_profile_cfg_data data;
+} __packed; /* SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_3*/
+
 /**
  * struct iwl_scan_schedule_lmac - schedule of scan offload
  * @delay:             delay between iterations, in seconds.
@@ -1169,7 +1188,7 @@ struct iwl_scan_offload_profiles_query_v1 {
        u8 resume_while_scanning;
        u8 self_recovery;
        __le16 reserved;
-       struct iwl_scan_offload_profile_match_v1 matches[IWL_SCAN_MAX_PROFILES];
+       struct iwl_scan_offload_profile_match_v1 matches[0];
 } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */
 
 /**
@@ -1213,7 +1232,7 @@ struct iwl_scan_offload_profiles_query {
        u8 resume_while_scanning;
        u8 self_recovery;
        __le16 reserved;
-       struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
+       struct iwl_scan_offload_profile_match matches[0];
 } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 */
 
 /**
index 22a32eb..122ca76 100644 (file)
@@ -1709,6 +1709,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
        };
        int ret, len;
        size_t query_len, matches_len;
+       int max_profiles = iwl_umac_scan_get_max_profiles(mvm->fw);
 
        ret = iwl_mvm_send_cmd(mvm, &cmd);
        if (ret) {
@@ -1720,11 +1721,11 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
                       IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
                query_len = sizeof(struct iwl_scan_offload_profiles_query);
                matches_len = sizeof(struct iwl_scan_offload_profile_match) *
-                       IWL_SCAN_MAX_PROFILES;
+                       max_profiles;
        } else {
                query_len = sizeof(struct iwl_scan_offload_profiles_query_v1);
                matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) *
-                       IWL_SCAN_MAX_PROFILES;
+                       max_profiles;
        }
 
        len = iwl_rx_packet_payload_len(cmd.resp_pkt);
index c9c4096..7aa1350 100644 (file)
@@ -617,7 +617,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 
        hw->wiphy->max_sched_scan_reqs = 1;
        hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
-       hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
+       hw->wiphy->max_match_sets = iwl_umac_scan_get_max_profiles(mvm->fw);
        /* we create the 802.11 header and zero length SSID IE. */
        hw->wiphy->max_sched_scan_ie_len =
                SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
@@ -705,7 +705,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
                mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
                mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
-               mvm->wowlan.max_nd_match_sets = IWL_SCAN_MAX_PROFILES;
+               mvm->wowlan.max_nd_match_sets =
+                       iwl_umac_scan_get_max_profiles(mvm->fw);
                hw->wiphy->wowlan = &mvm->wowlan;
        }
 #endif
index d6ecc2d..afcf2b9 100644 (file)
@@ -2147,4 +2147,11 @@ iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm,
                              iwl_mvm_get_ctrl_pos(chandef));
 }
 
+static inline int iwl_umac_scan_get_max_profiles(const struct iwl_fw *fw)
+{
+       u8 ver = iwl_mvm_lookup_cmd_ver(fw, IWL_ALWAYS_LONG_GROUP,
+                                       SCAN_OFFLOAD_UPDATE_PROFILES_CMD);
+       return (ver == IWL_FW_CMD_VER_UNKNOWN || ver < 3) ?
+               IWL_SCAN_MAX_PROFILES : IWL_SCAN_MAX_PROFILES_V2;
+}
 #endif /* __IWL_MVM_H__ */
index 1fa7408..7a6ad1f 100644 (file)
@@ -594,11 +594,15 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
                                   struct cfg80211_sched_scan_request *req)
 {
        struct iwl_scan_offload_profile *profile;
-       struct iwl_scan_offload_profile_cfg *profile_cfg;
+       struct iwl_scan_offload_profile_cfg_v1 *profile_cfg_v1;
        struct iwl_scan_offload_blacklist *blacklist;
+       struct iwl_scan_offload_profile_cfg_data *data;
+       int max_profiles = iwl_umac_scan_get_max_profiles(mvm->fw);
+       int profile_cfg_size = sizeof(*data) +
+               sizeof(*profile) * max_profiles;
        struct iwl_host_cmd cmd = {
                .id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD,
-               .len[1] = sizeof(*profile_cfg),
+               .len[1] = profile_cfg_size,
                .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
                .dataflags[1] = IWL_HCMD_DFL_NOCOPY,
        };
@@ -606,7 +610,7 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
        int i;
        int ret;
 
-       if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES))
+       if (WARN_ON(req->n_match_sets > max_profiles))
                return -EIO;
 
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL)
@@ -618,27 +622,37 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
        if (!blacklist)
                return -ENOMEM;
 
-       profile_cfg = kzalloc(sizeof(*profile_cfg), GFP_KERNEL);
-       if (!profile_cfg) {
+       profile_cfg_v1 = kzalloc(profile_cfg_size, GFP_KERNEL);
+       if (!profile_cfg_v1) {
                ret = -ENOMEM;
                goto free_blacklist;
        }
 
        cmd.data[0] = blacklist;
        cmd.len[0] = sizeof(*blacklist) * blacklist_len;
-       cmd.data[1] = profile_cfg;
+       cmd.data[1] = profile_cfg_v1;
+
+       /* if max_profile is MAX_PROFILES_V2, we have the new API */
+       if (max_profiles == IWL_SCAN_MAX_PROFILES_V2) {
+               struct iwl_scan_offload_profile_cfg *profile_cfg =
+                       (struct iwl_scan_offload_profile_cfg *)profile_cfg_v1;
+
+               data = &profile_cfg->data;
+       } else {
+               data = &profile_cfg_v1->data;
+       }
 
        /* No blacklist configuration */
+       data->num_profiles = req->n_match_sets;
+       data->active_clients = SCAN_CLIENT_SCHED_SCAN;
+       data->pass_match = SCAN_CLIENT_SCHED_SCAN;
+       data->match_notify = SCAN_CLIENT_SCHED_SCAN;
 
-       profile_cfg->num_profiles = req->n_match_sets;
-       profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN;
-       profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN;
-       profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN;
        if (!req->n_match_sets || !req->match_sets[0].ssid.ssid_len)
-               profile_cfg->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN;
+               data->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN;
 
        for (i = 0; i < req->n_match_sets; i++) {
-               profile = &profile_cfg->profiles[i];
+               profile = &profile_cfg_v1->profiles[i];
                profile->ssid_index = i;
                /* Support any cipher and auth algorithm */
                profile->unicast_cipher = 0xff;
@@ -651,7 +665,7 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
        IWL_DEBUG_SCAN(mvm, "Sending scheduled scan profile config\n");
 
        ret = iwl_mvm_send_cmd(mvm, &cmd);
-       kfree(profile_cfg);
+       kfree(profile_cfg_v1);
 free_blacklist:
        kfree(blacklist);