iwlwifi: mvm: support version 7 of the SCAN_REQ_UMAC FW command
authorLuca Coelho <luciano.coelho@intel.com>
Fri, 10 Nov 2017 12:03:36 +0000 (14:03 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Wed, 15 Nov 2017 16:38:42 +0000 (18:38 +0200)
Newer firmware versions (such as iwlwifi-8000C-34.ucode) have
introduced an API change in the SCAN_REQ_UMAC command that is not
backwards compatible.  The driver needs to detect and use the new API
format when the firmware reports it, otherwise the scan command will
not work properly, causing a command timeout.

Fix this by adding a TLV that tells the driver that the new API is in
use and use the correct structures for it.

This fixes https://bugzilla.kernel.org/show_bug.cgi?id=197591

Fixes: d7a5b3e9e42e ("iwlwifi: mvm: bump API to 34 for 8000 and up")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
drivers/net/wireless/intel/iwlwifi/fw/file.h
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/scan.c

index 5a40092febfb611c8dc06d9b13288027f453f83e..3bfc657f6b4214da88f63a8bab326855dea2afca 100644 (file)
@@ -531,6 +531,8 @@ struct iwl_scan_config_v1 {
 } __packed; /* SCAN_CONFIG_DB_CMD_API_S */
 
 #define SCAN_TWO_LMACS 2
+#define SCAN_LB_LMAC_IDX 0
+#define SCAN_HB_LMAC_IDX 1
 
 struct iwl_scan_config {
        __le32 flags;
@@ -578,6 +580,7 @@ enum iwl_umac_scan_general_flags {
        IWL_UMAC_SCAN_GEN_FLAGS_MATCH                   = BIT(9),
        IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL          = BIT(10),
        IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED        = BIT(11),
+       IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL          = BIT(13),
 };
 
 /**
@@ -631,12 +634,17 @@ struct iwl_scan_req_umac_tail {
  * @uid: scan id, &enum iwl_umac_scan_uid_offsets
  * @ooc_priority: out of channel priority - &enum iwl_scan_priority
  * @general_flags: &enum iwl_umac_scan_general_flags
- * @reserved2: for future use and alignment
  * @scan_start_mac_id: report the scan start TSF time according to this mac TSF
  * @extended_dwell: dwell time for channels 1, 6 and 11
  * @active_dwell: dwell time for active scan
  * @passive_dwell: dwell time for passive scan
  * @fragmented_dwell: dwell time for fragmented passive scan
+ * @adwell_default_n_aps: for adaptive dwell the default number of APs
+ *     per channel
+ * @adwell_default_n_aps_social: for adaptive dwell the default
+ *     number of APs per social (1,6,11) channel
+ * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added
+ *     to total scan time
  * @max_out_time: max out of serving channel time, per LMAC - for CDB there
  *     are 2 LMACs
  * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs
@@ -644,6 +652,8 @@ struct iwl_scan_req_umac_tail {
  * @channel_flags: &enum iwl_scan_channel_flags
  * @n_channels: num of channels in scan request
  * @reserved: for future use and alignment
+ * @reserved2: for future use and alignment
+ * @reserved3: for future use and alignment
  * @data: &struct iwl_scan_channel_cfg_umac and
  *     &struct iwl_scan_req_umac_tail
  */
@@ -651,41 +661,64 @@ struct iwl_scan_req_umac {
        __le32 flags;
        __le32 uid;
        __le32 ooc_priority;
-       /* SCAN_GENERAL_PARAMS_API_S_VER_4 */
        __le16 general_flags;
-       u8 reserved2;
+       u8 reserved;
        u8 scan_start_mac_id;
-       u8 extended_dwell;
-       u8 active_dwell;
-       u8 passive_dwell;
-       u8 fragmented_dwell;
        union {
                struct {
+                       u8 extended_dwell;
+                       u8 active_dwell;
+                       u8 passive_dwell;
+                       u8 fragmented_dwell;
                        __le32 max_out_time;
                        __le32 suspend_time;
                        __le32 scan_priority;
-                       /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */
+                       /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
                        u8 channel_flags;
                        u8 n_channels;
-                       __le16 reserved;
+                       __le16 reserved2;
                        u8 data[];
                } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
                struct {
+                       u8 extended_dwell;
+                       u8 active_dwell;
+                       u8 passive_dwell;
+                       u8 fragmented_dwell;
                        __le32 max_out_time[SCAN_TWO_LMACS];
                        __le32 suspend_time[SCAN_TWO_LMACS];
                        __le32 scan_priority;
-                       /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */
+                       /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
                        u8 channel_flags;
                        u8 n_channels;
-                       __le16 reserved;
+                       __le16 reserved2;
                        u8 data[];
                } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */
+               struct {
+                       u8 active_dwell;
+                       u8 passive_dwell;
+                       u8 fragmented_dwell;
+                       u8 adwell_default_n_aps;
+                       u8 adwell_default_n_aps_social;
+                       u8 reserved3;
+                       __le16 adwell_max_budget;
+                       __le32 max_out_time[SCAN_TWO_LMACS];
+                       __le32 suspend_time[SCAN_TWO_LMACS];
+                       __le32 scan_priority;
+                       /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
+                       u8 channel_flags;
+                       u8 n_channels;
+                       __le16 reserved2;
+                       u8 data[];
+               } v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */
        };
 } __packed;
 
-#define IWL_SCAN_REQ_UMAC_SIZE sizeof(struct iwl_scan_req_umac)
+#define IWL_SCAN_REQ_UMAC_SIZE_V7 sizeof(struct iwl_scan_req_umac)
+#define IWL_SCAN_REQ_UMAC_SIZE_V6 (sizeof(struct iwl_scan_req_umac) - \
+                                  2 * sizeof(u8) - sizeof(__le16))
 #define IWL_SCAN_REQ_UMAC_SIZE_V1 (sizeof(struct iwl_scan_req_umac) - \
-                                  2 * sizeof(__le32))
+                                  2 * sizeof(__le32) - 2 * sizeof(u8) - \
+                                  sizeof(__le16))
 
 /**
  * struct iwl_umac_scan_abort
index 740d97093d1c5c8992b5f09f4274b445639de20b..37a5c5b4eda6ca48eb24c6978c8aeba640e1886d 100644 (file)
@@ -264,6 +264,7 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_STA_TYPE              = (__force iwl_ucode_tlv_api_t)30,
        IWL_UCODE_TLV_API_NAN2_VER2             = (__force iwl_ucode_tlv_api_t)31,
        /* API Set 1 */
+       IWL_UCODE_TLV_API_ADAPTIVE_DWELL        = (__force iwl_ucode_tlv_api_t)32,
        IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE   = (__force iwl_ucode_tlv_api_t)34,
        IWL_UCODE_TLV_API_NEW_RX_STATS          = (__force iwl_ucode_tlv_api_t)35,
        IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL     = (__force iwl_ucode_tlv_api_t)37,
index 0e18c5066f04e2102114ebff9e433984fe880f60..4575595ab022600ff7d33da2d789c54f84a0e951 100644 (file)
@@ -1142,6 +1142,12 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
                            IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
 }
 
+static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm)
+{
+       return fw_has_api(&mvm->fw->ucode_capa,
+                         IWL_UCODE_TLV_API_ADAPTIVE_DWELL);
+}
+
 static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
 {
        /* For now we only use this mode to differentiate between
index 774122fed454fbb4d1d109a18a53634baf6f83e2..e4fd476e9ccb0888d572ee296a4947c9fd3903ca 100644 (file)
@@ -130,6 +130,19 @@ struct iwl_mvm_scan_params {
        u32 measurement_dwell;
 };
 
+static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm)
+{
+       struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
+
+       if (iwl_mvm_is_adaptive_dwell_supported(mvm))
+               return (void *)&cmd->v7.data;
+
+       if (iwl_mvm_has_new_tx_api(mvm))
+               return (void *)&cmd->v6.data;
+
+       return (void *)&cmd->v1.data;
+}
+
 static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
 {
        if (mvm->scan_rx_ant != ANT_NONE)
@@ -1075,25 +1088,57 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
 {
        struct iwl_mvm_scan_timing_params *timing = &scan_timing[params->type];
 
+       if (iwl_mvm_is_regular_scan(params))
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
+       else
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2);
+
+       if (iwl_mvm_is_adaptive_dwell_supported(mvm)) {
+               if (params->measurement_dwell) {
+                       cmd->v7.active_dwell = params->measurement_dwell;
+                       cmd->v7.passive_dwell = params->measurement_dwell;
+               } else {
+                       cmd->v7.active_dwell = IWL_SCAN_DWELL_ACTIVE;
+                       cmd->v7.passive_dwell = IWL_SCAN_DWELL_PASSIVE;
+               }
+               cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
+
+               cmd->v7.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
+               cmd->v7.max_out_time[SCAN_LB_LMAC_IDX] =
+                       cpu_to_le32(timing->max_out_time);
+               cmd->v7.suspend_time[SCAN_LB_LMAC_IDX] =
+                       cpu_to_le32(timing->suspend_time);
+               if (iwl_mvm_is_cdb_supported(mvm)) {
+                       cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] =
+                               cpu_to_le32(timing->max_out_time);
+                       cmd->v7.suspend_time[SCAN_HB_LMAC_IDX] =
+                               cpu_to_le32(timing->suspend_time);
+               }
+
+               return;
+       }
+
        if (params->measurement_dwell) {
-               cmd->active_dwell = params->measurement_dwell;
-               cmd->passive_dwell = params->measurement_dwell;
-               cmd->extended_dwell = params->measurement_dwell;
+               cmd->v1.active_dwell = params->measurement_dwell;
+               cmd->v1.passive_dwell = params->measurement_dwell;
+               cmd->v1.extended_dwell = params->measurement_dwell;
        } else {
-               cmd->active_dwell = IWL_SCAN_DWELL_ACTIVE;
-               cmd->passive_dwell = IWL_SCAN_DWELL_PASSIVE;
-               cmd->extended_dwell = IWL_SCAN_DWELL_EXTENDED;
+               cmd->v1.active_dwell = IWL_SCAN_DWELL_ACTIVE;
+               cmd->v1.passive_dwell = IWL_SCAN_DWELL_PASSIVE;
+               cmd->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED;
        }
-       cmd->fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
+       cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
 
        if (iwl_mvm_has_new_tx_api(mvm)) {
                cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
-               cmd->v6.max_out_time[0] = cpu_to_le32(timing->max_out_time);
-               cmd->v6.suspend_time[0] = cpu_to_le32(timing->suspend_time);
+               cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] =
+                       cpu_to_le32(timing->max_out_time);
+               cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] =
+                       cpu_to_le32(timing->suspend_time);
                if (iwl_mvm_is_cdb_supported(mvm)) {
-                       cmd->v6.max_out_time[1] =
+                       cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] =
                                cpu_to_le32(timing->max_out_time);
-                       cmd->v6.suspend_time[1] =
+                       cmd->v6.suspend_time[SCAN_HB_LMAC_IDX] =
                                cpu_to_le32(timing->suspend_time);
                }
        } else {
@@ -1102,11 +1147,6 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
                cmd->v1.scan_priority =
                        cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
        }
-
-       if (iwl_mvm_is_regular_scan(params))
-               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
-       else
-               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2);
 }
 
 static void
@@ -1178,8 +1218,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                             int type)
 {
        struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
-       void *cmd_data = iwl_mvm_has_new_tx_api(mvm) ?
-                        (void *)&cmd->v6.data : (void *)&cmd->v1.data;
+       void *cmd_data = iwl_mvm_get_scan_req_umac_data(mvm);
        struct iwl_scan_req_umac_tail *sec_part = cmd_data +
                sizeof(struct iwl_scan_channel_cfg_umac) *
                        mvm->fw->ucode_capa.n_scan_channels;
@@ -1216,7 +1255,10 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
                                IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
 
-       if (iwl_mvm_has_new_tx_api(mvm)) {
+       if (iwl_mvm_is_adaptive_dwell_supported(mvm)) {
+               cmd->v7.channel_flags = channel_flags;
+               cmd->v7.n_channels = params->n_channels;
+       } else if (iwl_mvm_has_new_tx_api(mvm)) {
                cmd->v6.channel_flags = channel_flags;
                cmd->v6.n_channels = params->n_channels;
        } else {
@@ -1661,8 +1703,10 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
 {
        int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1;
 
-       if (iwl_mvm_has_new_tx_api(mvm))
-               base_size = IWL_SCAN_REQ_UMAC_SIZE;
+       if (iwl_mvm_is_adaptive_dwell_supported(mvm))
+               base_size = IWL_SCAN_REQ_UMAC_SIZE_V7;
+       else if (iwl_mvm_has_new_tx_api(mvm))
+               base_size = IWL_SCAN_REQ_UMAC_SIZE_V6;
 
        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
                return base_size +