From be80dc5c082cfbab4c9d879428df6fbb42b9e93c Mon Sep 17 00:00:00 2001 From: MilhouseVH Date: Sun, 12 Nov 2017 23:19:40 +0000 Subject: [PATCH] linux: add iwlwifi patch for new fw scan API See: https://github.com/LibreELEC/iwlwifi-firmware/pull/9 --- ...on_7_of_the_SCAN_REQ_UMAC_FW_command.patch | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 packages/linux/patches/default/linux-999.99-iwlwifi-support_version_7_of_the_SCAN_REQ_UMAC_FW_command.patch diff --git a/packages/linux/patches/default/linux-999.99-iwlwifi-support_version_7_of_the_SCAN_REQ_UMAC_FW_command.patch b/packages/linux/patches/default/linux-999.99-iwlwifi-support_version_7_of_the_SCAN_REQ_UMAC_FW_command.patch new file mode 100644 index 0000000000..90673af0fb --- /dev/null +++ b/packages/linux/patches/default/linux-999.99-iwlwifi-support_version_7_of_the_SCAN_REQ_UMAC_FW_command.patch @@ -0,0 +1,322 @@ +From ca7e685439996448a6f9179354d23ab30f9b0879 Mon Sep 17 00:00:00 2001 +From: Luca Coelho +Date: Fri, 10 Nov 2017 14:03:36 +0200 +Subject: [PATCH] iwlwifi: mvm: support version 7 of the SCAN_REQ_UMAC FW + command + +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. + +Fixes: d7a5b3e9e42e ("iwlwifi: mvm: bump API to 34 for 8000 and up") +Signed-off-by: Luca Coelho +--- + drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 59 ++++++++++++---- + drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++ + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 86 ++++++++++++++++++------ + 4 files changed, 118 insertions(+), 34 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +index 5a40092febfb..3bfc657f6b42 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h ++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +@@ -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 +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h +index 740d97093d1c..37a5c5b4eda6 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h ++++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h +@@ -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, +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +index 0e18c5066f04..4575595ab022 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +@@ -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 +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +index 774122fed454..e4fd476e9ccb 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +@@ -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 + +-- +2.14.2 +