diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
33 files changed, 1698 insertions, 800 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c index ef50ccabcc73..458b97930059 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c @@ -32,7 +32,7 @@ static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) { size = sizeof(cmd); - cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, + cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm, phyctxt->channel->band)); } else { size = IWL_BINDING_CMD_SIZE_V1; @@ -164,3 +164,11 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; } + +u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band) +{ + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) || + band == NL80211_BAND_2GHZ) + return IWL_LMAC_24G_INDEX; + return IWL_LMAC_5G_INDEX; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index c604f9f39b24..243eccc68cb0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2021 Intel Corporation + * Copyright (C) 2013-2014, 2018-2023 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -109,10 +109,6 @@ #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 20 #define IWL_MVM_USE_NSSN_SYNC 0 -#define IWL_MVM_PHY_FILTER_CHAIN_A 0 -#define IWL_MVM_PHY_FILTER_CHAIN_B 0 -#define IWL_MVM_PHY_FILTER_CHAIN_C 0 -#define IWL_MVM_PHY_FILTER_CHAIN_D 0 #define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false #define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40 /* 20016 pSec is 6 meter RTT, meaning 3 meter range */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 37aa4676dc94..f6488b4bbe68 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1380,6 +1380,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) return __iwl_mvm_suspend(hw, wowlan, false); } +struct iwl_multicast_key_data { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 len; + u8 flags; + u8 id; + u8 ipn[6]; +}; + /* converted data from the different status responses */ struct iwl_wowlan_status_data { u64 replay_ctr; @@ -1398,7 +1406,8 @@ struct iwl_wowlan_status_data { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 len; u8 flags; - } gtk; + u8 id; + } gtk[WOWLAN_GTK_KEYS_NUM]; struct { /* @@ -1428,12 +1437,7 @@ struct iwl_wowlan_status_data { } tkip, aes; } ptk; - struct { - u64 ipn; - u8 key[WOWLAN_KEY_MAX_SIZE]; - u8 len; - u8 flags; - } igtk; + struct iwl_multicast_key_data igtk; u8 *wake_packet; }; @@ -1758,7 +1762,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, s8 new_key_id = -1; if (status->num_of_gtk_rekeys) - new_key_id = status->gtk.flags & + new_key_id = status->gtk[0].flags & IWL_WOWLAN_GTK_IDX_MASK; /* Don't install a new key's value to an old key */ @@ -1777,20 +1781,18 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - void *last_gtk; - u32 cipher; - bool find_phase, unhandled_cipher; + u32 gtk_cipher, igtk_cipher; + bool unhandled_cipher, igtk_support; int num_keys; }; -static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) +static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) { struct iwl_mvm_d3_gtk_iter_data *data = _data; - struct iwl_wowlan_status_data *status = data->status; if (data->unhandled_cipher) return; @@ -1805,51 +1807,230 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_TKIP: /* we support these */ + data->gtk_cipher = key->cipher; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: + /* we support these */ + if (data->igtk_support && + (key->keyidx == 4 || key->keyidx == 5)) { + data->igtk_cipher = key->cipher; + } else { + data->unhandled_cipher = true; + return; + } break; default: - /* everything else (even CMAC for MFP) - disconnect from AP */ + /* everything else - disconnect from AP */ data->unhandled_cipher = true; return; } data->num_keys++; +} - /* - * pairwise key - update sequence counters only; - * note that this assumes no TDLS sessions are active - */ - if (sta) { - if (data->find_phase) - return; +static void +iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, + struct ieee80211_key_seq *seq, u32 cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn)); + memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn)); + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn)); + memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn)); + break; + } +} - switch (key->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: +static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm_d3_gtk_iter_data *data = _data; + struct iwl_wowlan_status_data *status = data->status; + s8 keyidx; + + if (data->unhandled_cipher) + return; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + /* ignore WEP completely, nothing to do */ + return; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (sta) { atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn); iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key); - break; - case WLAN_CIPHER_SUITE_TKIP: + return; + } + fallthrough; + case WLAN_CIPHER_SUITE_TKIP: + if (sta) { atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn); iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq); - break; + return; } + keyidx = key->keyidx; + /* The current key is always sent by the FW, even if it wasn't + * rekeyed during D3. + * We remove an existing key if it has the same index as + * a new key + */ + if (status->num_of_gtk_rekeys && + ((status->gtk[0].len && keyidx == status->gtk[0].id) || + (status->gtk[1].len && keyidx == status->gtk[1].id))) { + ieee80211_remove_key(key); + } else { + iwl_mvm_set_key_rx_seq(key, data->status, false); + } + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (key->keyidx == 4 || key->keyidx == 5) { + /* remove rekeyed key */ + if (status->num_of_gtk_rekeys) { + ieee80211_remove_key(key); + } else { + struct ieee80211_key_seq seq; - /* that's it for this key */ - return; + iwl_mvm_d3_set_igtk_bigtk_ipn(&status->igtk, + &seq, + key->cipher); + ieee80211_set_key_rx_seq(key, 0, &seq); + } + } } +} - if (data->find_phase) { - data->last_gtk = key; - data->cipher = key->cipher; - return; +static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, + struct ieee80211_vif *vif, + struct iwl_mvm *mvm, u32 gtk_cipher) +{ + int i; + struct ieee80211_key_conf *key; + struct { + struct ieee80211_key_conf conf; + u8 key[32]; + } conf = { + .conf.cipher = gtk_cipher, + }; + + BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); + BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key)); + + switch (gtk_cipher) { + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + conf.conf.keylen = WLAN_KEY_LEN_CCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; + break; + case WLAN_CIPHER_SUITE_TKIP: + conf.conf.keylen = WLAN_KEY_LEN_TKIP; + break; + default: + WARN_ON(1); + } + + for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { + if (!status->gtk[i].len) + continue; + + conf.conf.keyidx = status->gtk[i].id; + IWL_DEBUG_WOWLAN(mvm, + "Received from FW GTK cipher %d, key index %d\n", + conf.conf.cipher, conf.conf.keyidx); + memcpy(conf.conf.key, status->gtk[i].key, + sizeof(status->gtk[i].key)); + + key = ieee80211_gtk_rekey_add(vif, &conf.conf); + if (IS_ERR(key)) + return false; + iwl_mvm_set_key_rx_seq_idx(key, status, i); } - if (data->status->num_of_gtk_rekeys) - ieee80211_remove_key(key); + return true; +} + +static bool +iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, + struct ieee80211_vif *vif, u32 cipher, + struct iwl_multicast_key_data *key_data) +{ + struct ieee80211_key_conf *key_config; + struct { + struct ieee80211_key_conf conf; + u8 key[WOWLAN_KEY_MAX_SIZE]; + } conf = { + .conf.cipher = cipher, + .conf.keyidx = key_data->id, + }; + struct ieee80211_key_seq seq; + + if (!key_data->len) + return true; + + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher); + + switch (cipher) { + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; + break; + default: + WARN_ON(1); + } + BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); + memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - if (data->last_gtk == key) - iwl_mvm_set_key_rx_seq(key, data->status, false); + key_config = ieee80211_gtk_rekey_add(vif, &conf.conf); + if (IS_ERR(key_config)) + return false; + ieee80211_set_key_rx_seq(key_config, 0, &seq); + return true; +} + +static int iwl_mvm_lookup_wowlan_status_ver(struct iwl_mvm *mvm) +{ + u8 notif_ver; + + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) + return 6; + + /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0); + if (!notif_ver) + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 7); + + return notif_ver; } static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, @@ -1871,71 +2052,41 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (status->wakeup_reasons & disconnection_reasons) return false; + if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || + iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + 0)) + gtkdata.igtk_support = true; + /* find last GTK that we used initially, if any */ - gtkdata.find_phase = true; ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_d3_update_keys, >kdata); + iwl_mvm_d3_find_last_keys, >kdata); /* not trying to keep connections with MFP/unhandled ciphers */ if (gtkdata.unhandled_cipher) return false; if (!gtkdata.num_keys) goto out; - if (!gtkdata.last_gtk) - return false; /* * invalidate all other GTKs that might still exist and update * the one that we used */ - gtkdata.find_phase = false; ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_d3_update_keys, >kdata); - IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", - status->num_of_gtk_rekeys); if (status->num_of_gtk_rekeys) { - struct ieee80211_key_conf *key; - struct { - struct ieee80211_key_conf conf; - u8 key[32]; - } conf = { - .conf.cipher = gtkdata.cipher, - .conf.keyidx = - status->gtk.flags & IWL_WOWLAN_GTK_IDX_MASK, - }; - __be64 replay_ctr; + __be64 replay_ctr = cpu_to_be64(status->replay_ctr); - IWL_DEBUG_WOWLAN(mvm, - "Received from FW GTK cipher %d, key index %d\n", - conf.conf.cipher, conf.conf.keyidx); + IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", + status->num_of_gtk_rekeys); - BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); - BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk.key)); - - memcpy(conf.conf.key, status->gtk.key, sizeof(status->gtk.key)); - - switch (gtkdata.cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf.conf.keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; - break; - } - - key = ieee80211_gtk_rekey_add(vif, &conf.conf); - if (IS_ERR(key)) + if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) return false; - iwl_mvm_set_key_rx_seq(key, status, true); - replay_ctr = cpu_to_be64(status->replay_ctr); + if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, + gtkdata.igtk_cipher, + &status->igtk)) + return false; ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); @@ -1955,60 +2106,70 @@ out: static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status, struct iwl_wowlan_gtk_status_v2 *data) { - BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key)); + BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data->key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + sizeof(data->tkip_mic_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); - status->gtk.len = data->key_len; - status->gtk.flags = data->key_flags; + status->gtk[0].len = data->key_len; + status->gtk[0].flags = data->key_flags; - memcpy(status->gtk.key, data->key, sizeof(data->key)); + memcpy(status->gtk[0].key, data->key, sizeof(data->key)); /* if it's as long as the TKIP encryption key, copy MIC key */ - if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) - memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + if (status->gtk[0].len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, data->tkip_mic_key, sizeof(data->tkip_mic_key)); } static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, struct iwl_wowlan_gtk_status_v3 *data) { - /* The parts we need are identical in v2 and v3 */ -#define CHECK(_f) do { \ - BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) != \ - offsetof(struct iwl_wowlan_gtk_status_v3, _f)); \ - BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\ - offsetofend(struct iwl_wowlan_gtk_status_v3, _f)); \ -} while (0) + int data_idx, status_idx = 0; - CHECK(key); - CHECK(key_len); - CHECK(key_flags); - CHECK(tkip_mic_key); -#undef CHECK + BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data[0].key)); + BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + + sizeof(data[0].tkip_mic_key) > + sizeof(status->gtk[0].key)); + BUILD_BUG_ON(ARRAY_SIZE(status->gtk) < WOWLAN_GTK_KEYS_NUM); + for (data_idx = 0; data_idx < ARRAY_SIZE(status->gtk); data_idx++) { + if (!(data[data_idx].key_len)) + continue; + status->gtk[status_idx].len = data[data_idx].key_len; + status->gtk[status_idx].flags = data[data_idx].key_flags; + status->gtk[status_idx].id = status->gtk[status_idx].flags & + IWL_WOWLAN_GTK_IDX_MASK; + + memcpy(status->gtk[status_idx].key, data[data_idx].key, + sizeof(data[data_idx].key)); - iwl_mvm_convert_gtk_v2(status, (void *)data); + /* if it's as long as the TKIP encryption key, copy MIC key */ + if (status->gtk[status_idx].len == + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(status->gtk[status_idx].key + + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + data[data_idx].tkip_mic_key, + sizeof(data[data_idx].tkip_mic_key)); + status_idx++; + } } static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { - const u8 *ipn = data->ipn; - BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key)); + if (!data->key_len) + return; + status->igtk.len = data->key_len; status->igtk.flags = data->key_flags; + status->igtk.id = u32_get_bits(data->key_flags, + IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) + + WOWLAN_IGTK_MIN_INDEX; memcpy(status->igtk.key, data->key, sizeof(data->key)); - - status->igtk.ipn = ((u64)ipn[5] << 0) | - ((u64)ipn[4] << 8) | - ((u64)ipn[3] << 16) | - ((u64)ipn[2] << 24) | - ((u64)ipn[1] << 32) | - ((u64)ipn[0] << 40); + memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn)); } static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, @@ -2031,7 +2192,7 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, } iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); - iwl_mvm_convert_gtk_v3(status, &data->gtk[0]); + iwl_mvm_convert_gtk_v3(status, data->gtk); iwl_mvm_convert_igtk(status, &data->igtk[0]); status->replay_ctr = le64_to_cpu(data->replay_ctr); @@ -2139,14 +2300,9 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) len = iwl_rx_packet_payload_len(cmd.resp_pkt); /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, - WOWLAN_GET_STATUSES, 0); - if (!notif_ver) - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - WOWLAN_GET_STATUSES, 7); + notif_ver = iwl_mvm_lookup_wowlan_status_ver(mvm); - if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { + if (notif_ver < 7) { struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data; status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len); @@ -2154,29 +2310,29 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + sizeof(v6->gtk.tkip_mic_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); /* copy GTK info to the right place */ - memcpy(status->gtk.key, v6->gtk.decrypt_key, + memcpy(status->gtk[0].key, v6->gtk.decrypt_key, sizeof(v6->gtk.decrypt_key)); - memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, v6->gtk.tkip_mic_key, sizeof(v6->gtk.tkip_mic_key)); iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc); /* hardcode the key length to 16 since v6 only supports 16 */ - status->gtk.len = 16; + status->gtk[0].len = 16; /* * The key index only uses 2 bits (values 0 to 3) and * we always set bit 7 which means this is the * currently used key. */ - status->gtk.flags = v6->gtk.key_index | BIT(7); + status->gtk[0].flags = v6->gtk.key_index | BIT(7); } else if (notif_ver == 7) { struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data; @@ -2210,7 +2366,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); - iwl_mvm_convert_gtk_v3(status, &v12->gtk[0]); + iwl_mvm_convert_gtk_v3(status, v12->gtk); iwl_mvm_convert_igtk(status, &v12->igtk[0]); status->tid_tear_down = v12->tid_tear_down; @@ -2732,17 +2888,13 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, if (wowlan_info_ver < 2) { struct iwl_wowlan_info_notif_v1 *notif_v1 = (void *)pkt->data; - notif = kmemdup(notif_v1, - offsetofend(struct iwl_wowlan_info_notif, - received_beacons), - GFP_ATOMIC); - + notif = kmemdup(notif_v1, sizeof(*notif), GFP_ATOMIC); if (!notif) return false; notif->tid_tear_down = notif_v1->tid_tear_down; notif->station_id = notif_v1->station_id; - + memset_after(notif, 0, station_id); } else { notif = (void *)pkt->data; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 3613b1fdc5d9..cb4ecad6103f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -554,7 +554,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, char buf[20]; int len; - len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); + len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_ap_addr); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -567,7 +567,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, bool ret; mutex_lock(&mvm->mutex); - ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); + ret = mac_pton(buf, mvmvif->uapsd_misbehaving_ap_addr); mutex_unlock(&mvm->mutex); return ret ? count : -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 84a488538427..cf27f106d4d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -15,6 +15,7 @@ #include "iwl-io.h" #include "debugfs.h" #include "iwl-modparams.h" +#include "iwl-drv.h" #include "fw/error-dump.h" #include "fw/api/phy-ctxt.h" @@ -391,13 +392,14 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, +static ssize_t iwl_dbgfs_rs_data_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, + char __user *user_buf, size_t count, loff_t *ppos) { - struct ieee80211_sta *sta = file->private_data; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw; - struct iwl_mvm *mvm = lq_sta->pers.drv; + struct iwl_lq_sta_rs_fw *lq_sta = &mvm_link_sta->lq_sta.rs_fw; static const size_t bufsz = 2048; char *buff; int desc = 0; @@ -407,8 +409,6 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, if (!buff) return -ENOMEM; - mutex_lock(&mvm->mutex); - desc += scnprintf(buff + desc, bufsz - desc, "sta_id %d\n", lq_sta->pers.sta_id); desc += scnprintf(buff + desc, bufsz - desc, @@ -429,18 +429,19 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, lq_sta->last_rate_n_flags); if (desc < bufsz - 1) buff[desc++] = '\n'; - mutex_unlock(&mvm->mutex); ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); return ret; } -static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta, +static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i; u16 amsdu_len; @@ -448,36 +449,39 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta, return -EINVAL; /* only change from debug set <-> debug unset */ - if (amsdu_len && mvmsta->orig_amsdu_len) + if (amsdu_len && mvm_link_sta->orig_amsdu_len) return -EBUSY; if (amsdu_len) { - mvmsta->orig_amsdu_len = sta->cur->max_amsdu_len; - sta->deflink.agg.max_amsdu_len = amsdu_len; - sta->deflink.agg.max_amsdu_len = amsdu_len; - for (i = 0; i < ARRAY_SIZE(sta->deflink.agg.max_tid_amsdu_len); i++) - sta->deflink.agg.max_tid_amsdu_len[i] = amsdu_len; + mvm_link_sta->orig_amsdu_len = link_sta->agg.max_amsdu_len; + link_sta->agg.max_amsdu_len = amsdu_len; + link_sta->agg.max_amsdu_len = amsdu_len; + for (i = 0; i < ARRAY_SIZE(link_sta->agg.max_tid_amsdu_len); i++) + link_sta->agg.max_tid_amsdu_len[i] = amsdu_len; } else { - sta->deflink.agg.max_amsdu_len = mvmsta->orig_amsdu_len; - mvmsta->orig_amsdu_len = 0; + link_sta->agg.max_amsdu_len = mvm_link_sta->orig_amsdu_len; + mvm_link_sta->orig_amsdu_len = 0; } + ieee80211_sta_recalc_aggregates(link_sta->sta); + return count; } -static ssize_t iwl_dbgfs_amsdu_len_read(struct file *file, +static ssize_t iwl_dbgfs_amsdu_len_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, char __user *user_buf, size_t count, loff_t *ppos) { - struct ieee80211_sta *sta = file->private_data; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - char buf[32]; int pos; - pos = scnprintf(buf, sizeof(buf), "current %d ", sta->cur->max_amsdu_len); + pos = scnprintf(buf, sizeof(buf), "current %d ", + link_sta->agg.max_amsdu_len); pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n", - mvmsta->orig_amsdu_len); + mvm_link_sta->orig_amsdu_len); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -712,6 +716,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, struct iwl_mvm *mvm = file->private_data; char *buff, *pos, *endpos; static const size_t bufsz = 1024; + char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; int ret; buff = kmalloc(bufsz, GFP_KERNEL); @@ -722,7 +727,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, endpos = pos + bufsz; pos += scnprintf(pos, endpos - pos, "FW prefix: %s\n", - mvm->trans->cfg->fw_name_pre); + iwl_drv_get_fwname_pre(mvm->trans, _fw_name_pre)); pos += scnprintf(pos, endpos - pos, "FW: %s\n", mvm->fwrt.fw->human_readable); pos += scnprintf(pos, endpos - pos, "Device: %s\n", @@ -1596,17 +1601,127 @@ static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm, #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) -#define MVM_DEBUGFS_WRITE_STA_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta) -#define MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta) +static ssize_t +_iwl_dbgfs_link_sta_wrap_write(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char *, + size_t, loff_t *), + struct file *file, + char *buf, size_t buf_size, loff_t *ppos) +{ + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; + ssize_t ret; -#define MVM_DEBUGFS_ADD_STA_FILE_ALIAS(alias, name, parent, mode) do { \ - debugfs_create_file(alias, mode, parent, sta, \ - &iwl_dbgfs_##name##_ops); \ - } while (0) -#define MVM_DEBUGFS_ADD_STA_FILE(name, parent, mode) \ - MVM_DEBUGFS_ADD_STA_FILE_ALIAS(#name, name, parent, mode) + mutex_lock(&mvm->mutex); + + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { + mutex_unlock(&mvm->mutex); + return -ENODEV; + } + + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, buf, buf_size, ppos); + + mutex_unlock(&mvm->mutex); + + return ret; +} + +static ssize_t +_iwl_dbgfs_link_sta_wrap_read(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char __user *, + size_t, loff_t *), + struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; + ssize_t ret; + + mutex_lock(&mvm->mutex); + + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { + mutex_unlock(&mvm->mutex); + return -ENODEV; + } + + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, user_buf, count, ppos); + + mutex_unlock(&mvm->mutex); + + return ret; +} + +#define MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, buflen) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + char buf[buflen] = {}; \ + size_t buf_size = min(count, sizeof(buf) - 1); \ + \ + if (copy_from_user(buf, user_buf, sizeof(buf))) \ + return -EFAULT; \ + \ + return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \ + file, \ + buf, buf_size, ppos); \ +} \ + +#define MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + return _iwl_dbgfs_link_sta_wrap_read(iwl_dbgfs_##name##_read, \ + file, \ + user_buf, count, ppos); \ +} \ + +#define MVM_DEBUGFS_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(name) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(alias, name, parent, mode) \ + debugfs_create_file(alias, mode, parent, link_sta, \ + &iwl_dbgfs_link_sta_##name##_ops) +#define MVM_DEBUGFS_ADD_LINK_STA_FILE(name, parent, mode) \ + MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(#name, name, parent, mode) static ssize_t iwl_dbgfs_prph_reg_read(struct file *file, @@ -1891,7 +2006,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); MVM_DEBUGFS_READ_FILE_OPS(nic_temp); MVM_DEBUGFS_READ_FILE_OPS(stations); -MVM_DEBUGFS_READ_FILE_OPS(rs_data); +MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(rs_data); MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); @@ -1921,7 +2036,7 @@ MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); MVM_DEBUGFS_READ_FILE_OPS(wifi_6e_enable); #endif -MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16); +MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(amsdu_len, 16); MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32); @@ -2068,17 +2183,18 @@ static const struct file_operations iwl_dbgfs_mem_ops = { .llseek = default_llseek, }; -void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir) +void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct dentry *dir) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); if (iwl_mvm_has_tlc_offload(mvm)) { - MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400); + MVM_DEBUGFS_ADD_LINK_STA_FILE(rs_data, dir, 0400); } - MVM_DEBUGFS_ADD_STA_FILE(amsdu_len, dir, 0600); + + MVM_DEBUGFS_ADD_LINK_STA_FILE(amsdu_len, dir, 0600); } void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 3963a0d4ed04..233ae81884a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -72,15 +72,24 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->cfg.assoc && - !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; struct ieee80211_sta *sta; + u8 sta_id; rcu_read_lock(); - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (!IS_ERR_OR_NULL(sta) && sta->mfp) - expected_tk_len = 0; + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(addr, link_conf->bssid, ETH_ALEN)) + continue; + + sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (!IS_ERR_OR_NULL(sta) && sta->mfp) + expected_tk_len = 0; + break; + } rcu_read_unlock(); } @@ -518,20 +527,30 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->cfg.assoc && - !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN)) + continue; + + target->sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return PTR_ERR_OR_ZERO(sta); + } - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) - FTM_PUT_FLAG(PMF); - + if (sta->mfp && (peer->ftm.trigger_based || + peer->ftm.non_trigger_based)) + FTM_PUT_FLAG(PMF); + break; + } rcu_read_unlock(); - - target->sta_id = mvmvif->deflink.ap_sta_id; } else { target->sta_id = IWL_MVM_INVALID_STA; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 1b6fb73ddfc7..b49781d1a07a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -104,7 +104,8 @@ iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, static int iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + struct ieee80211_bss_conf *link_conf) { u32 cmd_id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -119,7 +120,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | IWL_TOF_RESPONDER_CMD_VALID_BSSID | IWL_TOF_RESPONDER_CMD_VALID_STA_ID), - .sta_id = mvmvif->deflink.bcast_sta.sta_id, + .sta_id = mvmvif->link[link_conf->link_id]->bcast_sta.sta_id, }; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6); int err; @@ -386,7 +387,8 @@ int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, return -EINVAL; } -int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_ftm_responder_params *params; @@ -395,11 +397,11 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_phy_ctxt *phy_ctxt; int ret; - params = vif->bss_conf.ftmr_params; + params = bss_conf->ftmr_params; lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) + if (WARN_ON_ONCE(!bss_conf->ftm_responder)) return -EINVAL; if (vif->p2p || vif->type != NL80211_IFTYPE_AP || @@ -409,7 +411,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } rcu_read_lock(); - pctx = rcu_dereference(vif->bss_conf.chanctx_conf); + pctx = rcu_dereference(bss_conf->chanctx_conf); /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care * about changes in the ctx after releasing the lock because the driver * is still protected by the mutex. */ @@ -424,7 +426,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (ret) return ret; - ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); + ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def, bss_conf); if (ret) return ret; @@ -446,13 +448,14 @@ void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm, } void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { - if (!vif->bss_conf.ftm_responder) + if (!bss_conf->ftm_responder) return; iwl_mvm_ftm_responder_clear(mvm, vif); - iwl_mvm_ftm_start_responder(mvm, vif); + iwl_mvm_ftm_start_responder(mvm, vif, bss_conf); } void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index b35c96cf7ad2..1f5db65a088d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -433,7 +433,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, /* if reached this point, Alive notification was received */ iwl_mei_alive_notif(true); - ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait); + ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait, + &mvm->fw->ucode_capa); if (ret) { IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); iwl_fw_set_current_image(&mvm->fwrt, old_type); @@ -477,40 +478,13 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, return 0; } -#ifdef CONFIG_ACPI static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, struct iwl_phy_specific_cfg *phy_filters) { - /* - * TODO: read specific phy config from BIOS - * ACPI table for this feature has not been defined yet, - * so for now we use hardcoded values. - */ - - if (IWL_MVM_PHY_FILTER_CHAIN_A) { - phy_filters->filter_cfg_chain_a = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_A); - } - if (IWL_MVM_PHY_FILTER_CHAIN_B) { - phy_filters->filter_cfg_chain_b = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_B); - } - if (IWL_MVM_PHY_FILTER_CHAIN_C) { - phy_filters->filter_cfg_chain_c = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_C); - } - if (IWL_MVM_PHY_FILTER_CHAIN_D) { - phy_filters->filter_cfg_chain_d = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); - } -} -#else /* CONFIG_ACPI */ - -static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, - struct iwl_phy_specific_cfg *phy_filters) -{ -} +#ifdef CONFIG_ACPI + *phy_filters = mvm->phy_filters; #endif /* CONFIG_ACPI */ +} #if defined(CONFIG_ACPI) && defined(CONFIG_EFI) static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) @@ -559,7 +533,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) u32 cmd_id = PHY_CONFIGURATION_CMD; struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; - struct iwl_phy_specific_cfg phy_filters = {}; u8 cmd_ver; size_t cmd_size; @@ -590,11 +563,8 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, IWL_FW_CMD_VER_UNKNOWN); - if (cmd_ver == 3) { - iwl_mvm_phy_filter_init(mvm, &phy_filters); - memcpy(&phy_cfg_cmd.phy_specific_cfg, &phy_filters, - sizeof(struct iwl_phy_specific_cfg)); - } + if (cmd_ver >= 3) + iwl_mvm_phy_filter_init(mvm, &phy_cfg_cmd.phy_specific_cfg); IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg); @@ -1091,7 +1061,7 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { }, { .ident = "LENOVO", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Lenovo"), + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), }, }, { .ident = "DELL", @@ -1104,7 +1074,26 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), }, }, - + { .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "MSI", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), + }, + }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, /* keep last */ {} }; @@ -1162,7 +1151,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) if (ret == 0) return; - if (!dmi_check_system(dmi_tas_approved_list)) { + if (!iwl_mvm_is_vendor_in_approved_list()) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", dmi_get_system_info(DMI_SYS_VENDOR)); @@ -1176,6 +1165,10 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) "Unable to add US/Canada to TAS block list, disabling TAS\n"); return; } + } else { + IWL_DEBUG_RADIO(mvm, + "System vendor '%s' is in the approved list.\n", + dmi_get_system_info(DMI_SYS_VENDOR)); } /* v4 is the same size as v3, so no need to differentiate here */ @@ -1356,6 +1349,8 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) /* we don't fail if the table is not available */ } } + + iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); } #else /* CONFIG_ACPI */ @@ -1571,6 +1566,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + iwl_mvm_lari_cfg(mvm); + /* Init RSS configuration */ ret = iwl_configure_rxq(&mvm->fwrt); if (ret) @@ -1591,6 +1588,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL); } + for (i = 0; i < IWL_MVM_FW_MAX_LINK_ID + 1; i++) + RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); + memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map)); mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; @@ -1610,7 +1610,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) * internal aux station for all aux activities that don't * requires a dedicated data queue. */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { /* * In old version the aux station uses mac id like other * station and not lmac id @@ -1678,7 +1678,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - iwl_mvm_lari_cfg(mvm); /* * RTNL is not taken during Ct-kill, but we don't need to scan/Tx * anyway, so don't init MCC. @@ -1699,9 +1698,11 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); - iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr, - IWL_TIME_SYNC_PROTOCOL_TM | - IWL_TIME_SYNC_PROTOCOL_FTM); + + if (mvm->time_sync.active) + iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr, + IWL_TIME_SYNC_PROTOCOL_TM | + IWL_TIME_SYNC_PROTOCOL_FTM); } if (!mvm->ptp_data.ptp_clock) @@ -1727,8 +1728,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) iwl_mvm_tas_init(mvm); iwl_mvm_leds_sync(mvm); - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) { + if (iwl_rfi_supported(mvm)) { if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE) iwl_rfi_send_config_cmd(mvm, NULL); } @@ -1778,7 +1778,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL); } - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { /* * Add auxiliary station for scanning. * Newer versions of this command implies that the fw uses diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index eb828de40a3c..ace82e2c5bd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -63,6 +63,9 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmvif); if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) return -EINVAL; + + rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id], + link_conf); } /* Update SF - Disable if needed. if this fails, SF might still be on @@ -73,6 +76,7 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd.link_id = cpu_to_le32(link_info->fw_link_id); cmd.mac_id = cpu_to_le32(mvmvif->id); + cmd.spec_link_id = link_conf->link_id; /* P2P-Device already has a valid PHY context during add */ phyctxt = link_info->phy_ctxt; if (phyctxt) @@ -85,6 +89,8 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } @@ -114,22 +120,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!link_info->phy_ctxt) return 0; - /* check there aren't too many active links */ - if (!link_info->active && active) { - int i, count = 0; - - /* link with phy_ctxt is active in FW */ - for_each_mvm_vif_valid_link(mvmvif, i) - if (mvmvif->link[i]->phy_ctxt) - count++; - - /* FIXME: IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM should be - * defined per HW - */ - if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM) - return -EINVAL; - } - /* Catch early if driver tries to activate or deactivate a link * twice. */ @@ -161,10 +151,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); - /* TODO: set a value to cmd.listen_lmac when system requiremens - * will define it - */ - iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf, &cmd.cck_rates, &cmd.ofdm_rates); @@ -177,7 +163,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &cmd.protection_flags, ht_flag, LINK_PROT_FLG_TGG_PROTECT); - iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, &cmd.ac[0], + iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac, &cmd.qos_flags); @@ -202,7 +188,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* TODO how to set ndp_fdbk_buff_th_exp? */ - if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif, + if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id], &cmd.trig_based_txf[0])) { flags |= LINK_FLG_MU_EDCA_CW; flags_mask |= LINK_FLG_MU_EDCA_CW; @@ -239,6 +225,8 @@ send_cmd: cmd.modify_mask = cpu_to_le32(changes); cmd.flags = cpu_to_le32(flags); cmd.flags_mask = cpu_to_le32(flags_mask); + cmd.spec_link_id = link_conf->link_id; + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE)) @@ -260,9 +248,12 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)) return -EINVAL; + RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], + NULL); cmd.link_id = cpu_to_le32(link_info->fw_link_id); iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id); link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; + cmd.spec_link_id = link_conf->link_id; ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index cc90f2884cff..7369a45f7f2b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -470,19 +470,24 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_ac_qos *ac, __le32 *qos_flags) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = + mvmvif->link[link_conf->link_id]; int i; + if (!mvm_link) + return; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i); u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i); ac[ucode_ac].cw_min = - cpu_to_le16(mvmvif->deflink.queue_params[i].cw_min); + cpu_to_le16(mvm_link->queue_params[i].cw_min); ac[ucode_ac].cw_max = - cpu_to_le16(mvmvif->deflink.queue_params[i].cw_max); + cpu_to_le16(mvm_link->queue_params[i].cw_max); ac[ucode_ac].edca_txop = - cpu_to_le16(mvmvif->deflink.queue_params[i].txop * 32); - ac[ucode_ac].aifsn = mvmvif->deflink.queue_params[i].aifs; + cpu_to_le16(mvm_link->queue_params[i].txop * 32); + ac[ucode_ac].aifsn = mvm_link->queue_params[i].aifs; ac[ucode_ac].fifos_mask = BIT(txf); } @@ -558,7 +563,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cmd->filter_flags = 0; - iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, &cmd->ac[0], + iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, cmd->ac, &cmd->qos_flags); /* The fw does not distinguish between ht and fat */ @@ -629,17 +634,17 @@ __le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm, IEEE80211_P2P_OPPPS_CTWINDOW_MASK); } -__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { - __le32 twt_policy = cpu_to_le32(0); + u32 twt_policy = 0; if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) - twt_policy |= cpu_to_le32(TWT_SUPPORTED); + twt_policy |= TWT_SUPPORTED; if (vif->bss_conf.twt_protected) - twt_policy |= cpu_to_le32(PROTECTED_TWT_SUPPORTED); + twt_policy |= PROTECTED_TWT_SUPPORTED; if (vif->bss_conf.twt_broadcast) - twt_policy |= cpu_to_le32(BROADCAST_TWT_SUPPORTED); + twt_policy |= BROADCAST_TWT_SUPPORTED; return twt_policy; } @@ -711,7 +716,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); ctxt_sta->data_policy |= - iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif); + cpu_to_le32(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif)); } @@ -888,7 +893,7 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, u8 rate; u32 i; - if (link_id == IEEE80211_LINK_UNSPECIFIED && vif->valid_links) { + if (link_id == IEEE80211_LINK_UNSPECIFIED && ieee80211_vif_is_mld(vif)) { for (i = 0; i < ARRAY_SIZE(mvmvif->link); i++) { if (!mvmvif->link[i]) continue; @@ -1111,6 +1116,10 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, beacon_cmd.flags = cpu_to_le16(flags); beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); + + if (WARN_ON(!mvmvif->link[link_conf->link_id])) + return -EINVAL; + if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12) beacon_cmd.link_id = cpu_to_le32(mvmvif->link[link_conf->link_id]->fw_link_id); @@ -1555,21 +1564,38 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx; u32 rx_missed_bcon, rx_missed_bcon_since_rx; struct ieee80211_vif *vif; - u32 id = le32_to_cpu(mb->mac_id); + /* Id can be mac/link id depending on the notification version */ + u32 id = le32_to_cpu(mb->link_id); union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; u32 mac_type; + u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + MISSED_BEACONS_NOTIFICATION, + 0); + + rcu_read_lock(); + + /* before version four the ID in the notification refers to mac ID */ + if (notif_ver < 4) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + } else { + struct ieee80211_bss_conf *bss_conf = + iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, true); + + if (!bss_conf) + goto out; + + vif = bss_conf->vif; + } IWL_DEBUG_INFO(mvm, - "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", - le32_to_cpu(mb->mac_id), + "missed bcn %s_id=%u, consecutive=%u (%u, %u, %u)\n", + notif_ver < 4 ? "mac" : "link", + id, le32_to_cpu(mb->consec_missed_beacons), le32_to_cpu(mb->consec_missed_beacons_since_last_rx), le32_to_cpu(mb->num_recvd_beacons), le32_to_cpu(mb->num_expected_beacons)); - rcu_read_lock(); - - vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); if (!vif) goto out; @@ -1730,20 +1756,47 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; struct ieee80211_vif *csa_vif, *vif; - struct iwl_mvm_vif *mvmvif; - u32 id_n_color, csa_id, mac_id; + struct iwl_mvm_vif *mvmvif, *csa_mvmvif; + u32 id_n_color, csa_id; + /* save mac_id or link_id to use later to cancel csa if needed */ + u32 id; + u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, + CHANNEL_SWITCH_START_NOTIF, 0); + bool csa_active; - id_n_color = le32_to_cpu(notif->id_and_color); - mac_id = id_n_color & FW_CTXT_ID_MSK; + rcu_read_lock(); - if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER)) - return; + if (notif_ver < 3) { + struct iwl_channel_switch_start_notif_v1 *notif = (void *)pkt->data; + u32 mac_id; + + id_n_color = le32_to_cpu(notif->id_and_color); + mac_id = id_n_color & FW_CTXT_ID_MSK; + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, mac_id, true); + if (!vif) + goto out_unlock; + + id = mac_id; + csa_active = vif->bss_conf.csa_active; + } else { + struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; + u32 link_id = le32_to_cpu(notif->link_id); + struct ieee80211_bss_conf *bss_conf = + iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, link_id, true); + + if (!bss_conf) + goto out_unlock; + + id = link_id; + vif = bss_conf->vif; + csa_active = bss_conf->csa_active; + } - rcu_read_lock(); - vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]); mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (notif_ver >= 3) + id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); switch (vif->type) { case NL80211_IFTYPE_AP: @@ -1752,7 +1805,8 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, csa_vif != vif)) goto out_unlock; - csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); + csa_mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); + csa_id = FW_CMD_ID_AND_COLOR(csa_mvmvif->id, csa_mvmvif->color); if (WARN(csa_id != id_n_color, "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", csa_id, id_n_color)) @@ -1777,9 +1831,9 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, */ if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF, - 0) && !vif->bss_conf.csa_active) { + 0) && !csa_active) { IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n"); - iwl_mvm_cancel_channel_switch(mvm, vif, mac_id); + iwl_mvm_cancel_channel_switch(mvm, vif, id); break; } @@ -1802,7 +1856,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_channel_switch_error_notif *notif = (void *)pkt->data; struct ieee80211_vif *vif; - u32 id = le32_to_cpu(notif->mac_id); + u32 id = le32_to_cpu(notif->link_id); u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask); rcu_read_lock(); @@ -1812,7 +1866,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, return; } - IWL_DEBUG_INFO(mvm, "FW reports CSA error: mac_id=%u, csa_err_mask=%u\n", + IWL_DEBUG_INFO(mvm, "FW reports CSA error: id=%u, csa_err_mask=%u\n", id, csa_err_mask); if (csa_err_mask & (CS_ERR_COUNT_ERROR | CS_ERR_LONG_DELAY_AFTER_CS | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 0f01b62357c6..ce7905faa08f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -108,7 +108,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mcc_update_resp *resp; + struct iwl_mcc_update_resp_v8 *resp; u8 resp_ver; IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); @@ -138,7 +138,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, resp->channels, __le16_to_cpu(resp->mcc), __le16_to_cpu(resp->geo_info), - __le16_to_cpu(resp->cap), resp_ver); + le32_to_cpu(resp->cap), resp_ver); /* Store the return source id */ src_id = resp->source_id; if (IS_ERR_OR_NULL(regd)) { @@ -245,12 +245,21 @@ static const u8 tm_if_types_ext_capa_sta[] = { /* Additional interface types for which extended capabilities are * specified separately */ + +#define IWL_MVM_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \ + IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \ + __bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \ + IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \ + __bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)) + static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { { .iftype = NL80211_IFTYPE_STATION, .extended_capabilities = he_if_types_ext_capa_sta, .extended_capabilities_mask = he_if_types_ext_capa_sta, .extended_capabilities_len = sizeof(he_if_types_ext_capa_sta), + /* relevant only if EHT is supported */ + .eml_capabilities = IWL_MVM_EMLSR_CAPA, }, { .iftype = NL80211_IFTYPE_STATION, @@ -258,7 +267,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { .extended_capabilities_mask = tm_if_types_ext_capa_sta, .extended_capabilities_len = sizeof(tm_if_types_ext_capa_sta), /* relevant only if EHT is supported */ - .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP, + .eml_capabilities = IWL_MVM_EMLSR_CAPA, }, }; @@ -1029,6 +1038,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; mvmvif->link[link_id]->phy_ctxt = NULL; mvmvif->link[link_id]->active = 0; + mvmvif->link[link_id]->igtk = NULL; } probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data, @@ -1233,7 +1243,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) /* async_handlers_wk is now blocked */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) + if (!iwl_mvm_has_new_station_api(mvm->fw)) iwl_mvm_rm_aux_sta(mvm); iwl_mvm_stop_device(mvm); @@ -1478,21 +1488,37 @@ iwl_mvm_chandef_get_primary_80(struct cfg80211_chan_def *chandef) return (control_start - data_start) / 80; } -/* - * Returns true if addding the interface is done - * (either with success or failure) - * - * FIXME: remove this again and merge it in - */ -static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - int *ret) +static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; lockdep_assert_held(&mvm->mutex); + ret = iwl_mvm_alloc_bcast_sta(mvm, vif); + if (ret) { + IWL_ERR(mvm, "Failed to allocate bcast sta\n"); + return ret; + } + + /* Only queue for this station is the mcast queue, + * which shouldn't be in TFD mask anyway + */ + return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0, + vif->type, + IWL_STA_MULTICAST); +} + +static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; + + mutex_lock(&mvm->mutex); + mvmvif->mvm = mvm; /* the first link always points to the default one */ @@ -1510,12 +1536,18 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, mvmvif->deflink.beacon_stats.num_beacons; /* Allocate resources for the MAC context, and add it to the fw */ - *ret = iwl_mvm_mac_ctxt_init(mvm, vif); - if (*ret) - return true; + ret = iwl_mvm_mac_ctxt_init(mvm, vif); + if (ret) + goto out; rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); + /* Currently not much to do for NAN */ + if (vif->type == NL80211_IFTYPE_NAN) { + ret = 0; + goto out; + } + /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 @@ -1530,50 +1562,12 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) { iwl_mvm_vif_dbgfs_register(mvm, vif); - return true; + ret = 0; + goto out; } mvmvif->features |= hw->netdev_features; - return false; -} - -static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_alloc_bcast_sta(mvm, vif); - if (ret) { - IWL_ERR(mvm, "Failed to allocate bcast sta\n"); - return ret; - } - - /* - * Only queue for this station is the mcast queue, - * which shouldn't be in TFD mask anyway - */ - return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0, - vif->type, - IWL_STA_MULTICAST); -} - -static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - mutex_lock(&mvm->mutex); - - /* Common for MLD and non-MLD API */ - if (iwl_mvm_mac_add_interface_common(mvm, hw, vif, &ret)) - goto out; - ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_unlock; @@ -2246,7 +2240,7 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm, * is enabled or not */ bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, + const struct iwl_mvm_vif_link_info *link_info, struct iwl_he_backoff_conf *trig_based_txf) { int i; @@ -2254,11 +2248,11 @@ bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, bool mu_edca_enabled = true; for (i = 0; i < IEEE80211_NUM_ACS; i++) { - struct ieee80211_he_mu_edca_param_ac_rec *mu_edca = - &mvmvif->deflink.queue_params[i].mu_edca_param_rec; + const struct ieee80211_he_mu_edca_param_ac_rec *mu_edca = + &link_info->queue_params[i].mu_edca_param_rec; u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i); - if (!mvmvif->deflink.queue_params[i].mu_edca) { + if (!link_info->queue_params[i].mu_edca) { mu_edca_enabled = false; break; } @@ -2285,8 +2279,7 @@ bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * so take it from one of them. */ sband = mvm->hw->wiphy->bands[NL80211_BAND_2GHZ]; - own_he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); return (own_he_cap && (own_he_cap->he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_ACK_EN)); @@ -2405,7 +2398,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, rcu_read_unlock(); - if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif, + if (iwl_mvm_set_fw_mu_edca_params(mvm, &mvmvif->deflink, &sta_ctxt_cmd.trig_based_txf[0])) flags |= STA_CTXT_HE_MU_EDCA_CW; @@ -2898,7 +2891,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); - iwl_mvm_ftm_restart_responder(mvm, vif); + iwl_mvm_ftm_restart_responder(mvm, vif, &vif->bss_conf); goto out_unlock; @@ -3040,7 +3033,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, IWL_WARN(mvm, "Failed updating beacon data\n"); if (changes & BSS_CHANGED_FTM_RESPONDER) { - int ret = iwl_mvm_ftm_start_responder(mvm, vif); + int ret = iwl_mvm_ftm_start_responder(mvm, vif, &vif->bss_conf); if (ret) IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", @@ -3054,7 +3047,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u64 changes) { - struct iwl_mvm_bss_info_changed_ops callbacks = { + static const struct iwl_mvm_bss_info_changed_ops callbacks = { .bss_info_changed_sta = iwl_mvm_bss_info_changed_station, .bss_info_changed_ap_ibss = iwl_mvm_bss_info_changed_ap_ibss, }; @@ -3067,7 +3060,7 @@ void iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - struct iwl_mvm_bss_info_changed_ops *callbacks, + const struct iwl_mvm_bss_info_changed_ops *callbacks, u64 changes) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3468,8 +3461,7 @@ static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm, sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (he_cap) { /* we know that ours is writable */ @@ -3564,7 +3556,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct iwl_mvm_sta_state_ops callbacks = { + static const struct iwl_mvm_sta_state_ops callbacks = { .add_sta = iwl_mvm_add_sta, .update_sta = iwl_mvm_update_sta, .rm_sta = iwl_mvm_rm_sta, @@ -3607,7 +3599,8 @@ static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; /* Beacon interval check - firmware will crash if the beacon * interval is less than 16. We can't avoid connecting at all, @@ -3616,14 +3609,11 @@ static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm, * wpa_s will blocklist the AP... */ - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_link_sta *link_sta = - link_sta_dereference_protected(sta, i); + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); - if (!link_conf || !link_sta) + if (!link_conf) continue; if (link_conf->beacon_int < IWL_MVM_MIN_BEACON_INTERVAL_TU) { @@ -3645,24 +3635,23 @@ static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw, bool is_sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_link_sta *link_sta = - link_sta_dereference_protected(sta, i); + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); - if (!link_conf || !link_sta || !mvmvif->link[i]) + if (!link_conf || !mvmvif->link[link_id]) continue; link_conf->he_support = link_sta->he_cap.has_he; if (is_sta) { - mvmvif->link[i]->he_ru_2mhz_block = false; + mvmvif->link[link_id]->he_ru_2mhz_block = false; if (link_sta->he_cap.has_he) - iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif, i, + iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif, + link_id, link_conf); } } @@ -3672,9 +3661,10 @@ static int iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_link_sta *link_sta; unsigned int i; int ret; @@ -3699,15 +3689,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, NL80211_TDLS_SETUP); } - for (i = 0; i < ARRAY_SIZE(sta->link); i++) { - struct ieee80211_link_sta *link_sta; - - link_sta = link_sta_dereference_protected(sta, i); - if (!link_sta) - continue; - + for_each_sta_active_link(vif, sta, link_sta, i) link_sta->agg.max_rc_amsdu_len = 1; - } + ieee80211_sta_recalc_aggregates(sta); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) @@ -3721,11 +3705,12 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; lockdep_assert_held(&mvm->mutex); @@ -3751,14 +3736,13 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, if (!mvm->mld_api_is_used) goto out; - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); if (WARN_ON(!link_conf)) return -EINVAL; - if (!mvmvif->link[i]) + if (!mvmvif->link[link_id]) continue; iwl_mvm_link_changed(mvm, vif, link_conf, @@ -3778,7 +3762,7 @@ static int iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -3813,11 +3797,10 @@ static int iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - int ret; lockdep_assert_held(&mvm->mutex); @@ -3836,10 +3819,7 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, mvmvif->authorized = 0; /* disable beacon filtering */ - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); - WARN_ON(ret && - !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, - &mvm->status)); + iwl_mvm_disable_beacon_filter(mvm, vif, 0); } return 0; @@ -3851,11 +3831,12 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_link_sta *link_sta; unsigned int link_id; int ret; @@ -3889,12 +3870,15 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, * from the AP now. */ iwl_mvm_reset_cca_40mhz_workaround(mvm, vif); + + /* Also free dup data just in case any assertions below fail */ + kfree(mvm_sta->dup_data); } mutex_lock(&mvm->mutex); /* this would be a mac80211 bug ... but don't crash */ - for_each_mvm_vif_valid_link(mvmvif, link_id) { + for_each_sta_active_link(vif, sta, link_sta, link_id) { if (WARN_ON_ONCE(!mvmvif->link[link_id]->phy_ctxt)) { mutex_unlock(&mvm->mutex); return test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, @@ -4538,7 +4522,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id) return -EINVAL; } - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12) { + if (iwl_mvm_has_new_station_api(mvm->fw)) { ret = iwl_mvm_add_aux_sta(mvm, lmac_id); WARN(ret, "Failed to allocate aux station"); } @@ -4578,7 +4562,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, int duration, enum ieee80211_roc_type type) { - struct iwl_mvm_roc_ops ops = { + static const struct iwl_mvm_roc_ops ops = { .add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20, .switch_phy_ctxt = iwl_mvm_roc_switch_binding, }; @@ -4590,7 +4574,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type, - struct iwl_mvm_roc_ops *ops) + const struct iwl_mvm_roc_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -4613,7 +4597,7 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_STATION: - lmac_id = iwl_mvm_get_lmac_id(mvm->fw, channel->band); + lmac_id = iwl_mvm_get_lmac_id(mvm, channel->band); /* Use aux roc framework (HS20) */ ret = ops->add_aux_sta_for_hs20(mvm, lmac_id); @@ -5097,7 +5081,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, static int iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm, struct ieee80211_vif_chanctx_switch *vifs, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { int ret; @@ -5156,7 +5140,7 @@ out: static int iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm, struct ieee80211_vif_chanctx_switch *vifs, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { int ret; @@ -5199,7 +5183,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -5228,7 +5212,7 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct iwl_mvm_switch_vif_chanctx_ops ops = { + static const struct iwl_mvm_switch_vif_chanctx_ops ops = { .__assign_vif_chanctx = __iwl_mvm_assign_vif_chanctx, .__unassign_vif_chanctx = __iwl_mvm_unassign_vif_chanctx, }; @@ -5669,6 +5653,30 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, iwl_trans_wait_tx_queues_empty(mvm->trans, msk); } +void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int i; + + mutex_lock(&mvm->mutex); + for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) { + struct iwl_mvm_sta *mvmsta; + struct ieee80211_sta *tmp; + + tmp = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (tmp != sta) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + if (iwl_mvm_flush_sta(mvm, mvmsta, false)) + IWL_ERR(mvm, "flush request fail\n"); + } + mutex_unlock(&mvm->mutex); +} + int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { @@ -6159,10 +6167,6 @@ static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - if (iwl_mvm_has_new_tx_csum(mvm)) - return iwl_mvm_tx_csum_bz(mvm, head, true) == - iwl_mvm_tx_csum_bz(mvm, skb, true); - /* For now don't aggregate IPv6 in AMSDU */ if (skb->protocol != htons(ETH_P_IP)) return false; @@ -6225,6 +6229,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, .flush = iwl_mvm_mac_flush, + .flush_sta = iwl_mvm_mac_flush_sta, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, .set_key = iwl_mvm_mac_set_key, @@ -6282,7 +6287,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate, #ifdef CONFIG_IWLWIFI_DEBUGFS - .sta_add_debugfs = iwl_mvm_sta_add_debugfs, + .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, #endif .set_hw_timestamp = iwl_mvm_set_hw_timestamp, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 8853821b3716..2c9f2f71b083 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation */ #include <linux/kernel.h> #include <net/mac80211.h> @@ -42,7 +42,7 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, * Of course the same can be done during add as well, but we must do * it during remove, since we don't have the mvmvif->ap_sta pointer. */ - if (!sta && (keyconf->link_id >= 0 || !vif->valid_links)) + if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif))) return BIT(link_info->ap_sta_id); /* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */ @@ -51,10 +51,10 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, return iwl_mvm_sta_fw_id_mask(mvm, sta, keyconf->link_id); } -static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf) +u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u32 flags = 0; @@ -164,13 +164,9 @@ static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd); } -int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf) +int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, + struct ieee80211_key_conf *keyconf) { - u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); - u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); struct iwl_sec_key_cmd cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), @@ -179,9 +175,14 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, .u.add.key_flags = cpu_to_le32(key_flags), .u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)), }; + int max_key_len = sizeof(cmd.u.add.key); int ret; - if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key))) + if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || + keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) + max_key_len -= IWL_SEC_WEP_KEY_OFFSET; + + if (WARN_ON(keyconf->keylen > max_key_len)) return -EINVAL; if (WARN_ON(!sta_mask)) @@ -223,6 +224,58 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, return ret; } +int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf) +{ + u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); + u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = NULL; + int ret; + + if (keyconf->keyidx == 4 || keyconf->keyidx == 5) { + unsigned int link_id = 0; + + /* set to -1 for non-MLO right now */ + if (keyconf->link_id >= 0) + link_id = keyconf->link_id; + + mvm_link = mvmvif->link[link_id]; + if (WARN_ON(!mvm_link)) + return -EINVAL; + + if (mvm_link->igtk) { + IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n", + mvm_link->igtk->keyidx); + ret = iwl_mvm_sec_key_del(mvm, vif, sta, + mvm_link->igtk); + if (ret) + IWL_ERR(mvm, + "failed to remove old IGTK (ret=%d)\n", + ret); + } + + WARN_ON(mvm_link->igtk); + } + + ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); + if (ret) + return ret; + + if (mvm_link) + mvm_link->igtk = keyconf; + + /* We don't really need this, but need it to be not invalid, + * and if we switch links multiple times it might go to be + * invalid when removed. + */ + keyconf->hw_key_idx = 0; + + return 0; +} + static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -231,11 +284,31 @@ static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, { u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; if (WARN_ON(!sta_mask)) return -EINVAL; + if (keyconf->keyidx == 4 || keyconf->keyidx == 5) { + struct iwl_mvm_vif_link_info *mvm_link; + unsigned int link_id = 0; + + /* set to -1 for non-MLO right now */ + if (keyconf->link_id >= 0) + link_id = keyconf->link_id; + + mvm_link = mvmvif->link[link_id]; + if (WARN_ON(!mvm_link)) + return -EINVAL; + + if (mvm_link->igtk == keyconf) { + /* no longer in HW - mark for later */ + mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; + mvm_link->igtk = NULL; + } + } + ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx, flags); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 1717fb52dc12..f313a8d771e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation */ #include "mvm.h" @@ -50,7 +50,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, * the association response successfully, so just skip all that * and enable both when we have MLO. */ - if (vif->valid_links) { + if (ieee80211_vif_is_mld(vif)) { iwl_mvm_mld_set_he_support(mvm, vif, cmd); cmd->eht_support = cpu_to_le32(1); return; @@ -96,6 +96,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, u32 action, bool force_assoc_off) { struct iwl_mac_config_cmd cmd = {}; + u16 esr_transition_timeout; WARN_ON(vif->type != NL80211_IFTYPE_STATION); @@ -115,16 +116,16 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->cfg.assoc && !force_assoc_off) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - cmd.client.is_assoc = cpu_to_le32(1); + cmd.client.is_assoc = 1; if (!mvmvif->authorized && fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO)) cmd.client.data_policy |= - cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE); + cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE); } else { - cmd.client.is_assoc = cpu_to_le32(0); + cmd.client.is_assoc = 0; /* Allow beacons to pass through as long as we are not * associated, or we do not have dtim period information. @@ -132,14 +133,25 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON); } - cmd.client.assoc_id = cpu_to_le32(vif->cfg.aid); + cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid); + if (ieee80211_vif_is_mld(vif)) { + esr_transition_timeout = + u16_get_bits(vif->cfg.eml_cap, + IEEE80211_EML_CAP_TRANSITION_TIMEOUT); + + cmd.client.esr_transition_timeout = + min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU, + esr_transition_timeout); + cmd.client.medium_sync_delay = + cpu_to_le16(vif->cfg.eml_med_sync_delay); + } if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) cmd.client.data_policy |= - iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif); + cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif)); return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index fbc2d5ed1006..8b6c641772ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022-2023 Intel Corporation */ #include "mvm.h" @@ -215,6 +215,53 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static unsigned int iwl_mvm_mld_count_active_links(struct ieee80211_vif *vif) +{ + unsigned int n_active = 0; + int i; + + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + struct ieee80211_bss_conf *link_conf; + + link_conf = link_conf_dereference_protected(vif, i); + if (link_conf && + rcu_access_pointer(link_conf->chanctx_conf)) + n_active++; + } + + return n_active; +} + +static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int link_id, ret = 0; + + mvmvif->esr_active = true; + + /* Disable SMPS overrideing by user */ + vif->driver_flags |= IEEE80211_VIF_DISABLE_SMPS_OVERRIDE; + + iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, + IEEE80211_SMPS_OFF); + + for_each_mvm_vif_valid_link(mvmvif, link_id) { + struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; + + if (!link->phy_ctxt) + continue; + + ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2); + if (ret) + break; + + link->phy_ctxt->rlc_disabled = true; + } + + return ret; +} + static int __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -224,10 +271,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, { u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); unsigned int link_id = link_conf->link_id; int ret; + /* if the assigned one was not counted yet, count it now */ + if (!rcu_access_pointer(link_conf->chanctx_conf)) + n_active++; + + if (n_active > iwl_mvm_max_active_links(mvm, vif)) + return -EOPNOTSUPP; + if (WARN_ON_ONCE(!mvmvif->link[link_id])) return -EINVAL; @@ -243,6 +298,15 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, } } + if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { + mvmvif->link[link_id]->listen_lmac = true; + ret = iwl_mvm_esr_mode_active(mvm, vif); + if (ret) { + IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret); + return ret; + } + } + mvmvif->link[link_id]->phy_ctxt = phy_ctxt; if (switching_chanctx) { @@ -326,14 +390,62 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + int link_id, ret = 0; + + mvmvif->esr_active = false; + + vif->driver_flags &= ~IEEE80211_VIF_DISABLE_SMPS_OVERRIDE; + + iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, + IEEE80211_SMPS_AUTOMATIC); + + for_each_vif_active_link(vif, link_conf, link_id) { + struct ieee80211_chanctx_conf *chanctx_conf; + struct iwl_mvm_phy_ctxt *phy_ctxt; + u8 static_chains, dynamic_chains; + + mvmvif->link[link_id]->listen_lmac = false; + + rcu_read_lock(); + + chanctx_conf = rcu_dereference(link_conf->chanctx_conf); + phy_ctxt = mvmvif->link[link_id]->phy_ctxt; + + if (!chanctx_conf || !phy_ctxt) { + rcu_read_unlock(); + continue; + } + + phy_ctxt->rlc_disabled = false; + static_chains = chanctx_conf->rx_chains_static; + dynamic_chains = chanctx_conf->rx_chains_dynamic; + + rcu_read_unlock(); + + ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains, + dynamic_chains); + if (ret) + break; + } + + return ret; +} + static void __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx, bool switching_chanctx) + { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); unsigned int link_id = link_conf->link_id; /* shouldn't happen, but verify link_id is valid before accessing */ @@ -352,6 +464,14 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, mvmvif->ap_ibss_active = false; } + if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { + int ret = iwl_mvm_esr_mode_inactive(mvm, vif); + + if (ret) + IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n", + ret); + } + if (vif->type == NL80211_IFTYPE_MONITOR) iwl_mvm_mld_rm_snif_sta(mvm, vif); @@ -422,7 +542,7 @@ static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); - iwl_mvm_ftm_restart_responder(mvm, vif); + iwl_mvm_ftm_restart_responder(mvm, vif, link_conf); goto out_unlock; @@ -492,7 +612,7 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct iwl_mvm_sta_state_ops callbacks = { + static const struct iwl_mvm_sta_state_ops callbacks = { .add_sta = iwl_mvm_mld_add_sta, .update_sta = iwl_mvm_mld_update_sta, .rm_sta = iwl_mvm_mld_rm_sta, @@ -697,7 +817,11 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm, if (link_conf->he_support) link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; - if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | + if (changes & BSS_CHANGED_ERP_SLOT) + link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO; + + if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT | + BSS_CHANGED_HT | BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS | BSS_CHANGED_HE_BSS_COLOR) && iwl_mvm_link_changed(mvm, vif, link_conf, @@ -711,7 +835,7 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm, /* FIXME: need to decide if we need FTM responder per link */ if (changes & BSS_CHANGED_FTM_RESPONDER) { - int ret = iwl_mvm_ftm_start_responder(mvm, vif); + int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf); if (ret) IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", @@ -779,7 +903,7 @@ iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct iwl_mvm_switch_vif_chanctx_ops ops = { + static const struct iwl_mvm_switch_vif_chanctx_ops ops = { .__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx, .__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx, }; @@ -816,8 +940,12 @@ iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; - mvmvif->deflink.queue_params[ac] = *params; + if (!mvm_link) + return -EINVAL; + + mvm_link->queue_params[ac] = *params; /* No need to update right away, we'll get BSS_CHANGED_QOS * The exception is P2P_DEVICE interface which needs immediate update. @@ -871,7 +999,7 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type) { - struct iwl_mvm_roc_ops ops = { + static const struct iwl_mvm_roc_ops ops = { .add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta, .switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx, }; @@ -886,32 +1014,16 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {}; + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 removed = old_links & ~new_links; u16 added = new_links & ~old_links; int err, i; - if (hweight16(new_links) > 2) { + if (hweight16(new_links) > 1 && + n_active > iwl_mvm_max_active_links(mvm, vif)) return -EOPNOTSUPP; - } else if (hweight16(new_links) > 1) { - unsigned int n_active = 0; - - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - struct ieee80211_bss_conf *link_conf; - - link_conf = link_conf_dereference_protected(vif, i); - if (link_conf && - rcu_access_pointer(link_conf->chanctx_conf)) - n_active++; - } - - if (vif->type == NL80211_IFTYPE_AP && - n_active > mvm->fw->ucode_capa.num_beacons) - return -EOPNOTSUPP; - else if (n_active > 1) - return -EOPNOTSUPP; - } for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { int r; @@ -955,9 +1067,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, goto out_err; kfree(mvmvif->link[i]); mvmvif->link[i] = NULL; - } - - if (added & BIT(i)) { + } else if (added & BIT(i)) { struct ieee80211_bss_conf *link_conf; link_conf = link_conf_dereference_protected(vif, i); @@ -974,6 +1084,9 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, } } + if (err) + goto out_err; + err = 0; if (new_links == 0) { mvmvif->link[0] = &mvmvif->deflink; @@ -1036,6 +1149,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, .flush = iwl_mvm_mac_flush, + .flush_sta = iwl_mvm_mac_flush_sta, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, .set_key = iwl_mvm_mac_set_key, @@ -1092,7 +1206,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .abort_pmsr = iwl_mvm_abort_pmsr, #ifdef CONFIG_IWLWIFI_DEBUGFS - .sta_add_debugfs = iwl_mvm_sta_add_debugfs, + .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, #endif .set_hw_timestamp = iwl_mvm_set_hw_timestamp, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 0bfdf4462755..524852cf5cd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022-2023 Intel Corporation */ #include "mvm.h" #include "time-sync.h" @@ -71,6 +71,11 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm, cmd.station_type = cpu_to_le32(sta->type); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) && + sta->type == STATION_TYPE_BCAST_MGMT) + cmd.mfp = cpu_to_le32(1); + if (addr) { memcpy(cmd.peer_mld_address, addr, ETH_ALEN); memcpy(cmd.peer_link_address, addr, ETH_ALEN); @@ -128,11 +133,11 @@ static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm, /* * Adds an internal sta to the FW table with its queues */ -static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta, - const u8 *addr, int link_id, - u16 *queue, u8 tid, - unsigned int *_wdg_timeout) +int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, int link_id, + u16 *queue, u8 tid, + unsigned int *_wdg_timeout) { int ret, txq; unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : @@ -364,6 +369,9 @@ int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (WARN_ON(!link)) + return -EIO; + switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: @@ -393,6 +401,9 @@ int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (WARN_ON(!link)) + return -EIO; + return iwl_mvm_mld_rm_int_sta(mvm, &link->mcast_sta, true, 0, &link->cab_queue); } @@ -442,6 +453,11 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC) cmd.assoc_id = cpu_to_le32(sta->aid); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) && + (sta->mfp || mvm_sta->sta_state < IEEE80211_STA_AUTHORIZED)) + cmd.mfp = cpu_to_le32(1); + switch (link_sta->rx_nss) { case 1: cmd.mimo = cpu_to_le32(0); @@ -667,15 +683,15 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ret = iwl_mvm_mld_alloc_sta_links(mvm, vif, sta); if (ret) return ret; - } - spin_lock_init(&mvm_sta->lock); + spin_lock_init(&mvm_sta->lock); - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); - else ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA, STATION_TYPE_PEER); + } else { + ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); + } + if (ret) goto err; @@ -728,7 +744,7 @@ int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_link_sta *link_sta; unsigned int link_id; - int ret = 0; + int ret = -EINVAL; lockdep_assert_held(&mvm->mutex); @@ -791,8 +807,6 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); - kfree(mvm_sta->dup_data); - /* flush its queues here since we are freeing mvm_sta */ for_each_sta_active_link(vif, sta, link_sta, link_id) { struct iwl_mvm_link_sta *mvm_link_sta = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6e7470d3a826..b83df0631279 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -104,6 +104,7 @@ struct iwl_mvm_phy_ctxt { /* track for RLC config command */ u32 center_freq1; + bool rlc_disabled; }; struct iwl_mvm_time_event_data { @@ -300,6 +301,8 @@ struct iwl_probe_resp_data { * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked * @queue_params: QoS params for this MAC * @mgmt_queue: queue number for unbufferable management frames + * @igtk: the current IGTK programmed into the firmware + * @listen_lmac: indicates this link is allocated to the listen LMAC */ struct iwl_mvm_vif_link_info { u8 bssid[ETH_ALEN]; @@ -317,8 +320,11 @@ struct iwl_mvm_vif_link_info { enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; struct iwl_probe_resp_data __rcu *probe_resp_data; + struct ieee80211_key_conf *igtk; + bool he_ru_2mhz_block; bool active; + bool listen_lmac; u16 cab_queue; /* Assigned while mac80211 has the link in a channel context, @@ -370,6 +376,7 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; + bool esr_active; u8 low_latency: 6; u8 low_latency_actual: 1; @@ -415,7 +422,7 @@ struct iwl_mvm_vif { #endif /* FW identified misbehaving AP */ - u8 uapsd_misbehaving_bssid[ETH_ALEN]; + u8 uapsd_misbehaving_ap_addr[ETH_ALEN] __aligned(2); struct delayed_work uapsd_nonagg_detected_wk; bool csa_countdown; @@ -1003,6 +1010,8 @@ struct iwl_mvm { struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER]; + struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_MVM_FW_MAX_LINK_ID + 1]; + /* -1 for always, 0 for never, >0 for that many times */ s8 fw_restart; u8 *error_recovery_buf; @@ -1174,6 +1183,10 @@ struct iwl_mvm { __le16 cur_aid; u8 cur_bssid[ETH_ALEN]; +#ifdef CONFIG_ACPI + struct iwl_phy_specific_cfg phy_filters; +#endif + unsigned long last_6ghz_passive_scan_jiffies; unsigned long last_reset_or_resume_time_jiffies; @@ -1302,6 +1315,19 @@ iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu) lockdep_is_held(&mvm->mutex)); } +static inline struct ieee80211_bss_conf * +iwl_mvm_rcu_fw_link_id_to_link_conf(struct iwl_mvm *mvm, u8 link_id, bool rcu) +{ + if (WARN_ON(link_id >= ARRAY_SIZE(mvm->link_id_to_link_conf))) + return NULL; + + if (rcu) + return rcu_dereference(mvm->link_id_to_link_conf[link_id]); + + return rcu_dereference_protected(mvm->link_id_to_link_conf[link_id], + lockdep_is_held(&mvm->mutex)); +} + static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, @@ -1415,6 +1441,12 @@ static inline bool iwl_mvm_has_mld_api(const struct iwl_fw *fw) IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT); } +static inline bool iwl_mvm_has_new_station_api(const struct iwl_fw *fw) +{ + return iwl_mvm_has_mld_api(fw) || + iwl_fw_lookup_cmd_ver(fw, ADD_STA, 0) >= 12; +} + static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm) { /* TODO - replace with TLV once defined */ @@ -1516,17 +1548,30 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); } -static inline bool iwl_mvm_has_new_tx_csum(struct iwl_mvm *mvm) +static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans) +{ + if ((CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) && + !CSR_HW_RFID_IS_CDB(trans->hw_rf_id)) + /* Step A doesn't support eSR */ + return CSR_HW_RFID_STEP(trans->hw_rf_id); + + return false; +} + +static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { - if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) - return false; + struct iwl_trans *trans = mvm->fwrt.trans; + + if (vif->type == NL80211_IFTYPE_AP) + return mvm->fw->ucode_capa.num_beacons; - if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ && - CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && - mvm->trans->hw_rev_step <= SILICON_B_STEP) - return false; + if (iwl_mvm_is_esr_supported(trans) || + (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && + CSR_HW_RFID_IS_CDB(trans->hw_rf_id))) + return IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM; - return true; + return 1; } extern const u8 iwl_mvm_ac_to_tx_fifo[]; @@ -1606,7 +1651,6 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, struct ieee80211_sta *sta, unsigned int tid); -u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu); #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_mvm_get_tx_fail_reason(u32 status); @@ -1741,6 +1785,8 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef); u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); +int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic); /* MAC (virtual interface) programming */ @@ -1758,7 +1804,7 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct iwl_ac_qos *ac, __le32 *qos_flags); bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, + const struct iwl_mvm_vif_link_info *link_info, struct iwl_he_backoff_conf *trig_based_txf); void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, @@ -1774,8 +1820,8 @@ void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm, int iwl_mvm_get_mac_type(struct ieee80211_vif *vif); __le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); +u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off); @@ -1826,6 +1872,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, /* Bindings */ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band); /* Links */ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1873,7 +1920,7 @@ void iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - struct iwl_mvm_bss_info_changed_ops *callbacks, + const struct iwl_mvm_bss_info_changed_ops *callbacks, u64 changes); void iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, @@ -1907,7 +1954,7 @@ struct iwl_mvm_roc_ops { int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type, - struct iwl_mvm_roc_ops *ops); + const struct iwl_mvm_roc_ops *ops); int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /*Session Protection */ @@ -2204,7 +2251,7 @@ static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {} #endif /* Location Aware Regulatory */ -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); @@ -2224,9 +2271,11 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); /* FTM responder */ -int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, @@ -2322,10 +2371,10 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir); +void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct dentry *dir); #endif /* new MLD related APIs */ @@ -2346,7 +2395,14 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 old_sta_mask, u32 new_sta_mask); - +int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, + struct ieee80211_key_conf *keyconf); +u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf); + +bool iwl_rfi_supported(struct iwl_mvm *mvm); int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_table); struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm); @@ -2405,7 +2461,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode, - struct iwl_mvm_switch_vif_chanctx_ops *ops); + const struct iwl_mvm_switch_vif_chanctx_ops *ops); /* Channel info utils */ static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) @@ -2603,6 +2659,8 @@ void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_prep_tx_info *info); void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); +void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 6d18a1fd649b..f67ab8ee18c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -404,7 +404,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret < 0 ? ret : 0; } -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id) { @@ -412,7 +412,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, }; - struct iwl_mcc_update_resp *resp_cp; + struct iwl_mcc_update_resp_v8 *resp_cp; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, @@ -420,7 +420,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .data = { &mcc_update_cmd }, }; - int ret; + int ret, resp_ver; u32 status; int resp_len, n_channels; u16 mcc; @@ -439,25 +439,70 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, pkt = cmd.resp_pkt; + resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + MCC_UPDATE_CMD, 0); + /* Extract MCC response */ - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { - struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; - - n_channels = __le32_to_cpu(mcc_resp->n_channels); - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); - resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + if (resp_ver >= 8) { + struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp_v8->n_channels); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp_v8, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; + } + resp_cp->status = mcc_resp_v8->status; + resp_cp->mcc = mcc_resp_v8->mcc; + resp_cp->cap = mcc_resp_v8->cap; + resp_cp->source_id = mcc_resp_v8->source_id; + resp_cp->time = mcc_resp_v8->time; + resp_cp->geo_info = mcc_resp_v8->geo_info; + resp_cp->n_channels = mcc_resp_v8->n_channels; + memcpy(resp_cp->channels, mcc_resp_v8->channels, + n_channels * sizeof(__le32)); + } else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { + struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp_v4->n_channels); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp_v4, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); goto exit; } + + resp_cp->status = mcc_resp_v4->status; + resp_cp->mcc = mcc_resp_v4->mcc; + resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap)); + resp_cp->source_id = mcc_resp_v4->source_id; + resp_cp->time = mcc_resp_v4->time; + resp_cp->geo_info = mcc_resp_v4->geo_info; + resp_cp->n_channels = mcc_resp_v4->n_channels; + memcpy(resp_cp->channels, mcc_resp_v4->channels, + n_channels * sizeof(__le32)); } else { struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp_v3, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } + resp_len = struct_size(resp_cp, channels, n_channels); resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); @@ -466,7 +511,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_cp->status = mcc_resp_v3->status; resp_cp->mcc = mcc_resp_v3->mcc; - resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); + resp_cp->cap = cpu_to_le32(mcc_resp_v3->cap); resp_cp->source_id = mcc_resp_v3->source_id; resp_cp->time = mcc_resp_v3->time; resp_cp->geo_info = mcc_resp_v3->geo_info; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index a8bd0f5f795c..dfb16ca5b438 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -198,6 +198,10 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT)) + enabled |= IWL_D3_PROTO_OFFLOAD_BTM; + if (!disable_offloading) common->enabled = cpu_to_le32(enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 32625bfacaae..5336a4afde4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -192,8 +192,7 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, WARN_ON(!(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)); sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (he_cap) { /* we know that ours is writable */ @@ -449,7 +448,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(ADD_STA_KEY), HCMD_NAME(ADD_STA), HCMD_NAME(REMOVE_STA), - HCMD_NAME(FW_GET_ITEM_CMD), HCMD_NAME(TX_CMD), HCMD_NAME(SCD_QUEUE_CFG), HCMD_NAME(TXPATH_FLUSH), @@ -512,7 +510,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(REPLY_BEACON_FILTERING_CMD), HCMD_NAME(D3_CONFIG_CMD), HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), - HCMD_NAME(OFFLOADS_QUERY_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), @@ -1604,7 +1601,9 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue; - if (unlikely(pkt_len < rx_h->min_size)) + if (IWL_FW_CHECK(mvm, pkt_len < rx_h->min_size, + "unexpected notification 0x%04x size %d, need %d\n", + rx_h->cmd_id, pkt_len, rx_h->min_size)) return; if (rx_h->context == RX_HANDLER_SYNC) { @@ -1743,8 +1742,11 @@ static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode, else set_bit(IWL_MVM_TXQ_STATE_STOP_FULL, &mvmtxq->state); - if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) + if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) { + local_bh_disable(); iwl_mvm_mac_itxq_xmit(mvm->hw, txq); + local_bh_enable(); + } } out: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 3ab6fb83a175..a5b432bc9e2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -151,7 +151,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { - cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, + cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm, chandef->chan->band)); /* Set the channel info data */ @@ -163,15 +163,18 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, chains_static, chains_dynamic); } -static int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, - struct iwl_mvm_phy_ctxt *ctxt, - u8 chains_static, u8 chains_dynamic) +int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic) { struct iwl_rlc_config_cmd cmd = { .phy_id = cpu_to_le32(ctxt->id), }; - if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, RLC_CONFIG_CMD), 0) < 2) + if (ctxt->rlc_disabled) + return 0; + + if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, + RLC_CONFIG_CMD), 0) < 2) return 0; BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_DRIVER_FORCE != diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index ac1dae52556f..9131b5f1bc76 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -237,8 +237,8 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, - ETH_ALEN)) + if (ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr)) return false; /* @@ -327,12 +327,11 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm, if (WARN_ON(!dtimper_tu)) return; - /* configure skip over dtim up to 306TU - 314 msec */ - skip = max_t(u8, 1, 306 / dtimper_tu); + /* configure skip over dtim up to 900 TU DTIM interval */ + skip = max_t(u8, 1, 900 / dtimper_tu); } - /* the firmware really expects "look at every X DTIMs", so add 1 */ - cmd->skip_dtim_periods = 1 + skip; + cmd->skip_dtim_periods = skip; cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); } @@ -502,9 +501,9 @@ void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid, - ETH_ALEN)) - eth_zero_addr(mvmvif->uapsd_misbehaving_bssid); + if (!ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr)) + eth_zero_addr(mvmvif->uapsd_misbehaving_ap_addr); } static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, @@ -512,14 +511,23 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, { u8 *ap_sta_id = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; - /* The ap_sta_id is not expected to change during current association - * so no explicit protection is needed - */ - if (mvmvif->deflink.ap_sta_id == *ap_sta_id) - memcpy(mvmvif->uapsd_misbehaving_bssid, - vif->bss_conf.bssid, - ETH_ALEN); + rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; + + /* The ap_sta_id is not expected to change during current + * association so no explicit protection is needed + */ + if (link_info->ap_sta_id == *ap_sta_id) { + ether_addr_copy(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr); + break; + } + } + rcu_read_unlock(); } void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, @@ -647,30 +655,32 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, return; /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { + if (bss_mvmvif && vifs->bss_active && !vifs->p2p_active && + !vifs->ap_active) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { + if (p2p_mvmvif && vifs->p2p_active && !vifs->bss_active && + !vifs->ap_active) { p2p_mvmvif->pm_enabled = true; return; } - if (vifs->bss_active && vifs->p2p_active) + if (p2p_mvmvif && bss_mvmvif && vifs->bss_active && vifs->p2p_active) client_same_channel = iwl_mvm_have_links_same_channel(bss_mvmvif, p2p_mvmvif); - if (vifs->bss_active && vifs->ap_active) + if (bss_mvmvif && ap_mvmvif && vifs->bss_active && vifs->ap_active) ap_same_channel = iwl_mvm_have_links_same_channel(bss_mvmvif, ap_mvmvif); /* clients are not stand alone: enable PM if DCM */ if (!(client_same_channel || ap_same_channel)) { - if (vifs->bss_active) + if (bss_mvmvif && vifs->bss_active) bss_mvmvif->pm_enabled = true; - if (vifs->p2p_active) + if (p2p_mvmvif && vifs->p2p_active) p2p_mvmvif->pm_enabled = true; return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index bb77bc9aa821..2ecd32bed752 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2020 - 2021 Intel Corporation + * Copyright (C) 2020 - 2022 Intel Corporation */ #include "mvm.h" @@ -70,6 +70,16 @@ static const struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { PHY_BAND_6, PHY_BAND_6,}}, }; +bool iwl_rfi_supported(struct iwl_mvm *mvm) +{ + /* The feature depends on a platform bugfix, so for now + * it's always disabled. + * When the platform support detection is implemented we should + * check FW TLV and platform support instead. + */ + return false; +} + int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_table) { int ret; @@ -81,7 +91,7 @@ int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_t .len[0] = sizeof(cmd), }; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) + if (!iwl_rfi_supported(mvm)) return -EOPNOTSUPP; lockdep_assert_held(&mvm->mutex); @@ -113,7 +123,7 @@ struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm) .flags = CMD_WANT_SKB, }; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) + if (!iwl_rfi_supported(mvm)) return ERR_PTR(-EOPNOTSUPP); mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index c3a00bfbeef2..6cba8a353b53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include "rs.h" #include "fw-api.h" @@ -63,12 +63,11 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta) static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband) + const struct ieee80211_sta_he_cap *sband_he_cap) { struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; - const struct ieee80211_sta_he_cap *sband_he_cap; bool vht_ena = vht_cap->vht_supported; u16 flags = 0; @@ -94,8 +93,6 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm, IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - sband_he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); if (sband_he_cap && !(sband_he_cap->he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) @@ -197,16 +194,14 @@ static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs) static void rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, struct iwl_tlc_config_cmd_v4 *cmd) { const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); - u16 tx_mcs_80 = - le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80); - u16 tx_mcs_160 = - le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160); + u16 tx_mcs_80 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_80); + u16 tx_mcs_160 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_160); int i; u8 nss = link_sta->rx_nss; @@ -289,7 +284,8 @@ rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw, static void rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, const struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, + const struct ieee80211_sta_eht_cap *sband_eht_cap, struct iwl_tlc_config_cmd_v4 *cmd) { /* peer RX mcs capa */ @@ -297,7 +293,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, &link_sta->eht_cap.eht_mcs_nss_supp; /* our TX mcs capa */ const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs = - &sband->iftype_data->eht_cap.eht_mcs_nss_supp; + &sband_eht_cap->eht_mcs_nss_supp; enum IWL_TLC_MCS_PER_BW bw; struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20; @@ -316,7 +312,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, } /* nic is 20Mhz only */ - if (!(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[0] & + if (!(sband_he_cap->he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { mcs_tx_20 = eht_tx_mcs->only_20mhz; } else { @@ -370,6 +366,8 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, static void rs_fw_set_supp_rates(struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, + const struct ieee80211_sta_eht_cap *sband_eht_cap, struct iwl_tlc_config_cmd_v4 *cmd) { int i; @@ -388,12 +386,13 @@ static void rs_fw_set_supp_rates(struct ieee80211_vif *vif, cmd->mode = IWL_TLC_MNG_MODE_NON_HT; /* HT/VHT rates */ - if (link_sta->eht_cap.has_eht) { + if (link_sta->eht_cap.has_eht && sband_he_cap && sband_eht_cap) { cmd->mode = IWL_TLC_MNG_MODE_EHT; - rs_fw_eht_set_enabled_rates(vif, link_sta, sband, cmd); - } else if (he_cap->has_he) { + rs_fw_eht_set_enabled_rates(vif, link_sta, sband_he_cap, + sband_eht_cap, cmd); + } else if (he_cap->has_he && sband_he_cap) { cmd->mode = IWL_TLC_MNG_MODE_HE; - rs_fw_he_set_enabled_rates(link_sta, sband, cmd); + rs_fw_he_set_enabled_rates(link_sta, sband_he_cap, cmd); } else if (vht_cap->vht_supported) { cmd->mode = IWL_TLC_MNG_MODE_VHT; rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd); @@ -479,7 +478,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate); } - if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) { + if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) { u16 size = le32_to_cpu(notif->amsdu_size); int i; @@ -489,7 +488,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, * so also check with orig_amsdu_len which holds the * original data before debugfs changed the value */ - WARN_ON(mvmsta->orig_amsdu_len < size); + WARN_ON(mvm_link_sta->orig_amsdu_len < size); goto out; } @@ -524,6 +523,7 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, { const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; + const struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; if (WARN_ON_ONCE(!link_conf->chandef.chan)) return IEEE80211_MAX_MPDU_LEN_VHT_3895; @@ -538,8 +538,18 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, default: return IEEE80211_MAX_MPDU_LEN_VHT_3895; } - } else - if (vht_cap->vht_supported) { + } else if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ && + eht_cap->has_eht) { + switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0], + IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) { + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454: + return IEEE80211_MAX_MPDU_LEN_VHT_11454; + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991: + return IEEE80211_MAX_MPDU_LEN_VHT_7991; + default: + return IEEE80211_MAX_MPDU_LEN_VHT_3895; + } + } else if (vht_cap->vht_supported) { switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: return IEEE80211_MAX_MPDU_LEN_VHT_11454; @@ -576,13 +586,17 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta); + const struct ieee80211_sta_he_cap *sband_he_cap = + ieee80211_get_he_iftype_cap_vif(sband, vif); + const struct ieee80211_sta_eht_cap *sband_eht_cap = + ieee80211_get_eht_iftype_cap_vif(sband, vif); struct iwl_mvm_link_sta *mvm_link_sta; struct iwl_lq_sta_rs_fw *lq_sta; struct iwl_tlc_config_cmd_v4 cfg_cmd = { .max_ch_width = mvmsta->authorized ? rs_fw_bw_from_sta_bw(link_sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ, .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, vif, link_sta, - sband)), + sband_he_cap)), .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), .sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta), .max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ? @@ -592,6 +606,21 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, int cmd_ver; int ret; + /* Enable external EHT LTF only for GL device and if there's + * mutual support by AP and client + */ + if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && + sband_eht_cap && + sband_eht_cap->eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && + link_sta->eht_cap.has_eht && + link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) { + IWL_DEBUG_RATE(mvm, "Set support for Extra EHT LTF\n"); + cfg_cmd.flags |= + cpu_to_le16(IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK); + } + rcu_read_lock(); mvm_link_sta = rcu_dereference(mvmsta->link[link_id]); if (WARN_ON_ONCE(!mvm_link_sta)) { @@ -609,7 +638,9 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm); #endif - rs_fw_set_supp_rates(vif, link_sta, sband, &cfg_cmd); + rs_fw_set_supp_rates(vif, link_sta, sband, + sband_he_cap, sband_eht_cap, + &cfg_cmd); /* * since TLC offload works with one mode we can assume diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index a4c1e3bf4ff1..481d68cbbbd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2005 - 2014, 2018 - 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014, 2018 - 2023 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH *****************************************************************************/ @@ -1070,10 +1070,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->bw = RATE_MCS_CHAN_WIDTH_20; - WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX || - rate->index > IWL_RATE_MCS_9_INDEX); + if (WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX)) + rate->index = rs_ht_to_legacy[IWL_RATE_MCS_0_INDEX]; + else if (WARN_ON_ONCE(rate->index > IWL_RATE_MCS_9_INDEX)) + rate->index = rs_ht_to_legacy[IWL_RATE_MCS_9_INDEX]; + else + rate->index = rs_ht_to_legacy[rate->index]; - rate->index = rs_ht_to_legacy[rate->index]; rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ @@ -2691,6 +2694,8 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, return; lq_sta = mvm_sta; + + spin_lock_bh(&lq_sta->pers.lock); iwl_mvm_hwrate_to_tx_rate_v1(lq_sta->last_rate_n_flags, info->band, &info->control.rates[0]); info->control.rates[0].count = 1; @@ -2705,6 +2710,7 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, iwl_mvm_hwrate_to_tx_rate_v1(last_ucode_rate, info->band, &txrc->reported_rate); } + spin_unlock_bh(&lq_sta->pers.lock); } static void *rs_drv_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, @@ -3261,11 +3267,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* If it's locked we are in middle of init flow * just wait for next tx status to update the lq_sta data */ - if (!spin_trylock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock)) + if (!spin_trylock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock)) return; __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); - spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); + spin_unlock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); } #ifdef CONFIG_MAC80211_DEBUGFS @@ -4114,9 +4120,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, } else { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - spin_lock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); + spin_lock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); rs_drv_rate_init(mvm, sta, band); - spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); + spin_unlock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index b38b24246675..542c192698a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -213,8 +213,12 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm, }; u16 thr; - if (ieee80211_is_data_qos(hdr->frame_control)) - ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)]; + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 tid = ieee80211_get_tid(hdr); + + if (tid < IWL_MAX_TID_COUNT) + ac = tid_to_mac80211_ac[tid]; + } mvmsta = iwl_mvm_sta_from_mac80211(sta); mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index e1d02c260e69..8d1e44fd9de7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -279,7 +279,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_hdr *hdr, struct iwl_rx_mpdu_desc *desc, - u32 status) + u32 status, + struct ieee80211_rx_status *stats) { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; @@ -308,8 +309,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && - !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) + !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) { + stats->flag |= RX_FLAG_DECRYPTED; return 0; + } if (!sta) return -1; @@ -378,7 +381,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (unlikely(ieee80211_is_mgmt(hdr->frame_control) && !ieee80211_has_protected(hdr->frame_control))) - return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status); + return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status, stats); if (!ieee80211_has_protected(hdr->frame_control) || (status & IWL_RX_MPDU_STATUS_SEC_MASK) == @@ -484,7 +487,7 @@ static void iwl_mvm_rx_csum(struct iwl_mvm *mvm, } /* - * returns true if a packet is a duplicate and should be dropped. + * returns true if a packet is a duplicate or invalid tid and should be dropped. * Updates AMSDU PN tracking info */ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, @@ -513,11 +516,14 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, return false; } - if (ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) { /* frame has qos control */ tid = ieee80211_get_tid(hdr); - else + if (tid >= IWL_MAX_TID_COUNT) + return true; + } else { tid = IWL_MAX_TID_COUNT; + } /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ sub_frame_idx = desc->amsdu_info & @@ -691,6 +697,11 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) rcu_read_lock(); sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + goto out; + } + mvmsta = iwl_mvm_sta_from_mac80211(sta); /* SN is set to the last expired frame + 1 */ @@ -712,6 +723,8 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) entries[index].e.reorder_time + 1 + RX_REORDER_BUF_TIMEOUT_MQ); } + +out: spin_unlock(&buf->lock); } @@ -978,10 +991,12 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); rcu_read_unlock(); - if (WARN(tid != baid_data->tid || - !(sta_mask & baid_data->sta_mask), - "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n", - baid, baid_data->sta_mask, baid_data->tid, sta_mask, tid)) + if (IWL_FW_CHECK(mvm, + tid != baid_data->tid || + !(sta_mask & baid_data->sta_mask), + "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n", + baid, baid_data->sta_mask, baid_data->tid, + sta_mask, tid)) return false; nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK; @@ -1766,6 +1781,15 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT)) { + usig->common |= + cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED); + usig->common |= + LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_VALIDATE, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); + } + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE); eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK, @@ -1775,9 +1799,9 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm, eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT); eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_B0, + eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC, + eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); iwl_mvm_decode_eht_ru(mvm, rx_status, eht); @@ -2512,7 +2536,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); /* Unblock BCAST / MCAST station */ iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false); - cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); + cancel_delayed_work(&mvm->cs_tx_unblock_dwork); } } @@ -2626,6 +2650,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK); phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); phy_data.with_data = false; + phy_data.rx_vec[0] = desc->rx_vec[0]; + phy_data.rx_vec[1] = desc->rx_vec[1]; if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, RX_NO_DATA_NOTIF, 0) < 2) { @@ -2644,7 +2670,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, sizeof(struct iwl_rx_no_data_ver_3))) /* invalid len for ver 3 */ return; - memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec)); + phy_data.rx_vec[2] = desc->rx_vec[2]; + phy_data.rx_vec[3] = desc->rx_vec[3]; } else { if (format == RATE_MCS_EHT_MSK) /* no support for EHT before version 3 API */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 175615755d9d..c1d9ce753468 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -647,7 +647,7 @@ static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm, NL80211_BAND_2GHZ, no_cck); - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { tx_cmd[0].sta_id = mvm->aux_sta.sta_id; tx_cmd[1].sta_id = mvm->aux_sta.sta_id; @@ -1084,7 +1084,7 @@ static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); /* This function should not be called when using ADD_STA ver >=12 */ - WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12); + WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw)); cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; @@ -1135,7 +1135,7 @@ static void iwl_mvm_fill_scan_config_v2(struct iwl_mvm *mvm, void *config, memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); /* This function should not be called when using ADD_STA ver >=12 */ - WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12); + WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw)); cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; @@ -1250,7 +1250,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) memset(&cfg, 0, sizeof(cfg)); - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { cfg.bcast_sta_id = mvm->aux_sta.sta_id; } else if (iwl_fw_lookup_cmd_ver(mvm->fw, SCAN_CFG_CMD, 0) < 5) { /* @@ -1627,11 +1627,11 @@ iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, } static void -iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, +iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm, struct ieee80211_channel **channels, - struct iwl_scan_channel_params_v6 *cp, + struct iwl_scan_channel_params_v7 *cp, int n_channels, u32 flags, - enum nl80211_iftype vif_type) + enum nl80211_iftype vif_type, u32 version) { int i; @@ -1641,14 +1641,19 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, u32 n_aps_flag = iwl_mvm_scan_ch_n_aps_flag(vif_type, channels[i]->hw_value); + u8 iwl_band = iwl_mvm_phy_band_from_nl80211(band); cfg->flags = cpu_to_le32(flags | n_aps_flag); cfg->v2.channel_num = channels[i]->hw_value; - cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); if (cfg80211_channel_is_psc(channels[i])) cfg->flags = 0; cfg->v2.iter_count = 1; cfg->v2.iter_interval = 0; + if (version < 17) + cfg->v2.band = iwl_band; + else + cfg->flags |= cpu_to_le32((iwl_band << + IWL_CHAN_CFG_FLAGS_BAND_POS)); } } @@ -1723,14 +1728,15 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm *mvm, pp->bssid_num = idex_b; } -/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v6 */ +/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v7 */ static u32 -iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, +iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, u32 n_channels, struct iwl_scan_probe_params_v4 *pp, - struct iwl_scan_channel_params_v6 *cp, - enum nl80211_iftype vif_type) + struct iwl_scan_channel_params_v7 *cp, + enum nl80211_iftype vif_type, + u32 version) { int i; struct cfg80211_scan_6ghz_params *scan_6ghz_params = @@ -1745,6 +1751,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, u8 j, k, s_max = 0, b_max = 0, n_used_bssid_entries; bool force_passive, found = false, allow_passive = true, unsolicited_probe_on_chan = false, psc_no_listen = false; + s8 psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; /* * Avoid performing passive scan on non PSC channels unless the @@ -1756,9 +1763,14 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, continue; cfg->v1.channel_num = params->channels[i]->hw_value; - cfg->v2.band = 2; - cfg->v2.iter_count = 1; - cfg->v2.iter_interval = 0; + if (version < 17) + cfg->v2.band = PHY_BAND_6; + else + cfg->flags |= cpu_to_le32(PHY_BAND_6 << + IWL_CHAN_CFG_FLAGS_BAND_POS); + + cfg->v5.iter_count = 1; + cfg->v5.iter_interval = 0; /* * The optimize the scan time, i.e., reduce the scan dwell time @@ -1769,9 +1781,22 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, */ n_used_bssid_entries = 3; for (j = 0; j < params->n_6ghz_params; j++) { + s8 tmp_psd_20; + if (!(scan_6ghz_params[j].channel_idx == i)) continue; + /* Use the highest PSD value allowed as advertised by + * APs for this channel + */ + tmp_psd_20 = scan_6ghz_params[j].psd_20; + if (tmp_psd_20 != + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED && + (psd_20 == + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED || + psd_20 < tmp_psd_20)) + psd_20 = tmp_psd_20; + found = false; unsolicited_probe_on_chan |= scan_6ghz_params[j].unsolicited_probe; @@ -1875,6 +1900,9 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, flags |= bssid_bitmap | (s_ssid_bitmap << 16); cfg->flags |= cpu_to_le32(flags); + if (version >= 17) + cfg->v5.psd_20 = psd_20; + ch_cnt++; } @@ -2292,11 +2320,12 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } static void -iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, struct iwl_scan_general_params_v11 *gp, - u16 gen_flags, u8 gen_flags2) + u16 gen_flags, u8 gen_flags2, + u32 version) { struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); @@ -2313,7 +2342,23 @@ iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; - gp->scan_start_mac_id = scan_vif->id; + if (version < 12) { + gp->scan_start_mac_or_link_id = scan_vif->id; + } else { + struct iwl_mvm_vif_link_info *link_info; + u8 link_id = 0; + + /* Use one of the active link (if any). In the future it would + * be possible that the link ID would be part of the scan + * request coming from upper layers so we would need to use it. + */ + if (vif->active_links) + link_id = ffs(vif->active_links) - 1; + + link_info = scan_vif->link[link_id]; + if (!WARN_ON(!link_info)) + gp->scan_start_mac_or_link_id = link_info->fw_link_id; + } } static void @@ -2352,21 +2397,22 @@ iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, } static void -iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_ch_p_v7(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_channel_params_v6 *cp, - u32 channel_cfg_flags) + struct iwl_scan_channel_params_v7 *cp, + u32 channel_cfg_flags, + u32 version) { cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); cp->count = params->n_channels; cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; - iwl_mvm_umac_scan_cfg_channels_v6(mvm, params->channels, cp, + iwl_mvm_umac_scan_cfg_channels_v7(mvm, params->channels, cp, params->n_channels, channel_cfg_flags, - vif->type); + vif->type, version); if (params->enable_6ghz_passive) { struct ieee80211_supported_band *sband = @@ -2383,11 +2429,19 @@ iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm, if (!cfg80211_channel_is_psc(channel)) continue; - cfg->flags = 0; - cfg->v2.channel_num = channel->hw_value; - cfg->v2.band = PHY_BAND_6; - cfg->v2.iter_count = 1; - cfg->v2.iter_interval = 0; + cfg->v5.channel_num = channel->hw_value; + cfg->v5.iter_count = 1; + cfg->v5.iter_interval = 0; + + if (version < 17) { + cfg->flags = 0; + cfg->v2.band = PHY_BAND_6; + } else { + cfg->flags = cpu_to_le32(PHY_BAND_6 << + IWL_CHAN_CFG_FLAGS_BAND_POS); + cfg->v5.psd_20 = + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; + } cp->count++; } } @@ -2408,9 +2462,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif, &scan_p->general_params, - gen_flags, 0); + gen_flags, 0, 12); ret = iwl_mvm_fill_scan_sched_params(params, scan_p->periodic_params.schedule, @@ -2430,9 +2484,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, int type, int uid, u32 version) { - struct iwl_scan_req_umac_v15 *cmd = mvm->scan_cmd; - struct iwl_scan_req_params_v15 *scan_p = &cmd->scan_params; - struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params; + struct iwl_scan_req_umac_v17 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params; + struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params; int ret; u16 gen_flags; @@ -2451,9 +2505,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, else gen_flags2 = 0; - iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif, &scan_p->general_params, - gen_flags, gen_flags2); + gen_flags, gen_flags2, version); ret = iwl_mvm_fill_scan_sched_params(params, scan_p->periodic_params.schedule, @@ -2462,11 +2516,13 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, return ret; if (!params->scan_6ghz) { - iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, - &bitmap_ssid); - iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif, - &scan_p->channel_params, bitmap_ssid); - + iwl_mvm_scan_umac_fill_probe_p_v4(params, + &scan_p->probe_params, + &bitmap_ssid); + iwl_mvm_scan_umac_fill_ch_p_v7(mvm, params, vif, + &scan_p->channel_params, + bitmap_ssid, + version); return 0; } else { pb->preq = params->preq; @@ -2478,9 +2534,10 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); - cp->count = iwl_mvm_umac_scan_cfg_channels_v6_6g(mvm, params, + cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params, params->n_channels, - pb, cp, vif->type); + pb, cp, vif->type, + version); if (!cp->count) { mvm->scan_uid_status[uid] = 0; return -EINVAL; @@ -2507,6 +2564,20 @@ static int iwl_mvm_scan_umac_v15(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 15); } +static int iwl_mvm_scan_umac_v16(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 16); +} + +static int iwl_mvm_scan_umac_v17(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 17); +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -2622,6 +2693,8 @@ struct iwl_scan_umac_handler { static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(17), + IWL_SCAN_UMAC_HANDLER(16), IWL_SCAN_UMAC_HANDLER(15), IWL_SCAN_UMAC_HANDLER(14), IWL_SCAN_UMAC_HANDLER(12), @@ -3210,7 +3283,9 @@ static size_t iwl_scan_req_umac_get_size(u8 scan_ver) return sizeof(struct iwl_scan_req_umac_v12); case 14: case 15: - return sizeof(struct iwl_scan_req_umac_v15); + case 16: + case 17: + return sizeof(struct iwl_scan_req_umac_v17); } return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 98f330fcf678..30d4233595e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation + * Copyright (C) 2013-2014, 2018-2019, 2022-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #include "mvm.h" @@ -180,9 +180,6 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, struct ieee80211_sta *sta, }; int ret = 0; - if (mvm->cfg->disable_dummy_notification) - sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); - /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5469d634e289..3b9a343d4f67 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2015, 2018-2022 Intel Corporation + * Copyright (C) 2012-2015, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -60,22 +60,27 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, if (WARN_ON(!link_sta)) return 0; - if (link_sta->ht_cap.ht_supported) + /* Note that we always use only legacy & highest supported PPDUs, so + * of Draft P802.11be D.30 Table 10-12a--Fields used for calculating + * the maximum A-MPDU size of various PPDU types in different bands, + * we only need to worry about the highest supported PPDU type here. + */ + + if (link_sta->ht_cap.ht_supported) { + agg_size = link_sta->ht_cap.ampdu_factor; mpdu_dens = link_sta->ht_cap.ampdu_density; + } - if (link_conf->chandef.chan->band == - NL80211_BAND_6GHZ) { + if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { + /* overwrite HT values on 6 GHz */ mpdu_dens = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); agg_size = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); } else if (link_sta->vht_cap.vht_supported) { - agg_size = link_sta->vht_cap.cap & - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; - agg_size >>= - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; - } else if (link_sta->ht_cap.ht_supported) { - agg_size = link_sta->ht_cap.ampdu_factor; + /* if VHT supported overwrite HT value */ + agg_size = u32_get_bits(link_sta->vht_cap.cap, + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); } /* D6.0 10.12.2 A-MPDU length limit rules @@ -91,10 +96,13 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, u8_get_bits(link_sta->he_cap.he_cap_elem.mac_cap_info[3], IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); + if (link_sta->eht_cap.has_eht) + agg_size += u8_get_bits(link_sta->eht_cap.eht_cap_elem.mac_cap_info[1], + IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK); + /* Limit to max A-MPDU supported by FW */ - if (agg_size > (STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT)) - agg_size = (STA_FLG_MAX_AGG_SIZE_4M >> - STA_FLG_MAX_AGG_SIZE_SHIFT); + agg_size = min_t(u32, agg_size, + STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT); *_agg_size = agg_size; return mpdu_dens; @@ -281,7 +289,7 @@ static void iwl_mvm_rx_agg_session_expired(struct timer_list *t) * A-MDPU and hence the timer continues to run. Then, the * timer expires and sta is NULL. */ - if (!sta) + if (IS_ERR_OR_NULL(sta)) goto unlock; mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -1679,7 +1687,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12 && + if (iwl_mvm_has_new_station_api(mvm->fw) && sta->type == IWL_STA_AUX_ACTIVITY) cmd.mac_id_n_color = cpu_to_le32(mac_id); else @@ -1859,6 +1867,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, ret = iwl_mvm_sta_init(mvm, vif, sta, sta_id, sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK); + if (ret) + goto err; update_fw: ret = iwl_mvm_sta_send_to_fw(mvm, sta, sta_update, sta_flags); @@ -2070,13 +2080,6 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cancel_delayed_work(&mvm->tdls_cs.dwork); } - /* - * Make sure that the tx response code sees the station as -EBUSY and - * calls the drain worker. - */ - spin_lock_bh(&mvm_sta->lock); - spin_unlock_bh(&mvm_sta->lock); - return false; } @@ -2089,9 +2092,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (iwl_mvm_has_new_rx_api(mvm)) - kfree(mvm_sta->dup_data); - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); if (ret) return ret; @@ -2885,7 +2885,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } if (iwl_mvm_has_new_rx_api(mvm) && start) { - u16 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]); + u32 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]); /* sparse doesn't like the __align() so don't check */ #ifndef __CHECKER__ @@ -3785,6 +3785,9 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, u8 sta_id = mvmvif->deflink.ap_sta_id; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) + return NULL; + return sta->addr; } @@ -3822,6 +3825,11 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { addr = iwl_mvm_get_mac_addr(mvm, vif, sta); + if (!addr) { + IWL_ERR(mvm, "Failed to find mac address\n"); + return -EINVAL; + } + /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); @@ -4301,16 +4309,27 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u16 queue; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_key_conf *keyconf; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + bool mld = iwl_mvm_has_mld_api(mvm->fw); + u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK; ret = iwl_mvm_allocate_int_sta(mvm, sta, 0, - NL80211_IFTYPE_UNSPECIFIED, - IWL_STA_LINK); + NL80211_IFTYPE_UNSPECIFIED, type); if (ret) return ret; - ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, mvmvif->color, - addr, sta, &queue, - IWL_MVM_TX_FIFO_BE); + if (mld) + ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, sta, addr, + mvmvif->deflink.fw_link_id, + &queue, + IWL_MAX_TID_COUNT, + &wdg_timeout); + else + ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, + mvmvif->color, addr, sta, + &queue, + IWL_MVM_TX_FIFO_BE); if (ret) goto out; @@ -4323,9 +4342,23 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, keyconf->cipher = cipher; memcpy(keyconf->key, key, key_len); keyconf->keylen = key_len; + keyconf->flags = IEEE80211_KEY_FLAG_PAIRWISE; + + if (mld) { + /* The MFP flag is set according to the station mfp field. Since + * we don't have a station, set it manually. + */ + u32 key_flags = + iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) | + IWL_SEC_KEY_FLAG_MFP; + u32 sta_mask = BIT(sta->sta_id); + + ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); + } else { + ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false, + 0, NULL, 0, 0, true); + } - ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false, - 0, NULL, 0, 0, true); kfree(keyconf); return 0; out: @@ -4335,10 +4368,10 @@ out: void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 mac_id) + u32 id) { struct iwl_cancel_channel_switch_cmd cancel_channel_switch_cmd = { - .mac_id = cpu_to_le32(mac_id), + .id = cpu_to_le32(id), }; int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index a61d4f88125f..7364346a1209 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -336,6 +336,9 @@ struct iwl_mvm_rxq_dup_data { * @sta_id: the index of the station in the fw * @lq_sta: holds rate scaling data, either for the case when RS is done in * the driver - %rs_drv or in the FW - %rs_fw. + * @orig_amsdu_len: used to save the original amsdu_len when it is changed via + * debugfs. If it's set to 0, it means that it is it's not set via + * debugfs. * @avg_energy: energy as reported by FW statistics notification */ struct iwl_mvm_link_sta { @@ -346,6 +349,8 @@ struct iwl_mvm_link_sta { struct iwl_lq_sta rs_drv; } lq_sta; + u16 orig_amsdu_len; + u8 avg_energy; }; @@ -365,6 +370,7 @@ struct iwl_mvm_link_sta { * and from Tx response flow, it needs a spinlock. * @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data. * @tid_to_baid: a simple map of TID to baid + * @vif: a vif pointer * @reserved_queue: the queue reserved for this STA for DQA purposes * Every STA has is given one reserved queue to allow it to operate. If no * such queue can be guaranteed, the STA addition will fail. @@ -374,10 +380,8 @@ struct iwl_mvm_link_sta { * @amsdu_enabled: bitmap of TX AMSDU allowed TIDs. * In case TLC offload is not active it is either 0xFFFF or 0. * @max_amsdu_len: max AMSDU length - * @orig_amsdu_len: used to save the original amsdu_len when it is changed via - * debugfs. If it's set to 0, it means that it is it's not set via - * debugfs. * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) + * @sleeping: sta sleep transitions in power management * @sleep_tx_count: the number of frames that we told the firmware to let out * even when that station is asleep. This is useful in case the queue * gets empty before all the frames were sent, which can happen when @@ -427,7 +431,6 @@ struct iwl_mvm_sta { bool disable_tx; u16 amsdu_enabled; u16 max_amsdu_len; - u16 orig_amsdu_len; bool sleeping; u8 agg_tids; u8 sleep_tx_count; @@ -580,7 +583,7 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 *key, u32 key_len); void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 mac_id); + u32 id); /* Queues */ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, @@ -616,7 +619,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state, - struct iwl_mvm_sta_state_ops *callbacks); + const struct iwl_mvm_sta_state_ops *callbacks); /* New MLD STA related APIs */ /* STA */ @@ -646,6 +649,11 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, u16 old_links, u16 new_links); u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int filter_link_id); +int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, int link_id, + u16 *queue, u8 tid, + unsigned int *_wdg_timeout); /* Queues */ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 6b7b6250f1bb..5f0e7144a951 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -103,7 +103,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) /* In newer version of this command an aux station is added only * in cases of dedicated tx queue and need to be removed in end * of use */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12) + if (iwl_mvm_has_new_station_api(mvm->fw)) iwl_mvm_rm_aux_sta(mvm); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 10d7178f1071..36d70d589aed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #include <linux/ieee80211.h> #include <linux/etherdevice.h> #include <linux/tcp.h> +#include <net/gso.h> #include <net/ip.h> #include <net/ipv6.h> @@ -40,13 +41,14 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, #define OPT_HDR(type, skb, off) \ (type *)(skb_network_header(skb) + (off)) -static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_tx_info *info, bool amsdu) +static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_tx_info *info, + bool amsdu) { struct ieee80211_hdr *hdr = (void *)skb->data; + u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u16 offload_assist = 0; #if IS_ENABLED(CONFIG_INET) - u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u8 protocol = 0; /* Do not compute checksum if already computed */ @@ -118,6 +120,8 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, else udp_hdr(skb)->check = 0; +out: +#endif /* * mac header len should include IV, size is in words unless * the IV is added by the firmware like in WEP. @@ -130,8 +134,6 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, mh_len /= 2; offload_assist |= mh_len << TX_CMD_OFFLD_MH_SIZE; -out: -#endif if (amsdu) offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); else if (ieee80211_hdrlen(hdr->frame_control) % 4) @@ -141,54 +143,6 @@ out: return offload_assist; } -u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu) -{ - struct ieee80211_hdr *hdr = (void *)skb->data; - u32 offload_assist = IWL_TX_CMD_OFFLD_BZ_PARTIAL_CSUM; - unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); - unsigned int csum_start = skb_checksum_start_offset(skb); - - offload_assist |= u32_encode_bits(hdrlen / 2, - IWL_TX_CMD_OFFLD_BZ_MH_LEN); - if (amsdu) - offload_assist |= IWL_TX_CMD_OFFLD_BZ_AMSDU; - else if (hdrlen % 4) - /* padding is inserted later in transport */ - offload_assist |= IWL_TX_CMD_OFFLD_BZ_MH_PAD; - - if (skb->ip_summed != CHECKSUM_PARTIAL) - return offload_assist; - - offload_assist |= IWL_TX_CMD_OFFLD_BZ_ENABLE_CSUM | - IWL_TX_CMD_OFFLD_BZ_ZERO2ONES; - - /* - * mac80211 will always calculate checksum in software for - * non-fast-xmit, and so we can only do offloaded checksum - * for fast-xmit frames. In this case, we always have the - * RFC 1042 header present. skb_checksum_start_offset() - * returns the offset from the beginning, but the hardware - * needs it from after the header & SNAP header. - */ - csum_start -= hdrlen + 8; - - offload_assist |= u32_encode_bits(csum_start, - IWL_TX_CMD_OFFLD_BZ_START_OFFS); - offload_assist |= u32_encode_bits(csum_start + skb->csum_offset, - IWL_TX_CMD_OFFLD_BZ_RESULT_OFFS); - - return offload_assist; -} - -static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_tx_info *info, - bool amsdu) -{ - if (!iwl_mvm_has_new_tx_csum(mvm)) - return iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu); - return iwl_mvm_tx_csum_bz(mvm, skb, amsdu); -} - /* * Sets most of the Tx cmd's fields */ @@ -288,7 +242,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->sta_id = sta_id; tx_cmd->offload_assist = - cpu_to_le16(iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu)); + cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu)); } static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm, @@ -308,6 +262,54 @@ static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm, return BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; } +static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info) +{ + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + u32 result; + + /* + * we only care about legacy/HT/VHT so far, so we can + * build in v1 and use iwl_new_rate_from_v1() + */ + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + u8 nss = ieee80211_rate_get_vht_nss(rate); + + result = RATE_MCS_VHT_MSK_V1; + result |= u32_encode_bits(mcs, RATE_VHT_MCS_RATE_CODE_MSK); + result |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + result |= RATE_MCS_SGI_MSK_V1; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); + else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + result |= u32_encode_bits(2, RATE_MCS_CHAN_WIDTH_MSK_V1); + else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) + result |= u32_encode_bits(3, RATE_MCS_CHAN_WIDTH_MSK_V1); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + result = RATE_MCS_HT_MSK_V1; + result |= u32_encode_bits(rate->idx, + RATE_HT_MCS_RATE_CODE_MSK_V1 | + RATE_HT_MCS_NSS_MSK_V1); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + result |= RATE_MCS_SGI_MSK_V1; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); + if (info->flags & IEEE80211_TX_CTL_LDPC) + result |= RATE_MCS_LDPC_MSK_V1; + if (u32_get_bits(info->flags, IEEE80211_TX_CTL_STBC)) + result |= RATE_MCS_STBC_MSK; + } else { + return 0; + } + + if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6) + return iwl_new_rate_from_v1(result); + return result; +} + static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc) @@ -317,8 +319,15 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, u32 rate_flags = 0; bool is_cck; - /* info->control is only relevant for non HW rate control */ - if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { + if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) { + u32 result = iwl_mvm_get_inject_tx_rate(mvm, info); + + if (result) + return result; + rate_idx = info->control.rates[0].idx; + } else if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { + /* info->control is only relevant for non HW rate control */ + /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS && !ieee80211_is_data(fc), @@ -398,7 +407,8 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, * table is controlled by LINK_QUALITY commands */ - if (ieee80211_is_data(fc) && sta) { + if (likely(ieee80211_is_data(fc) && sta && + !(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT))) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { @@ -556,9 +566,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, cmd->rate_n_flags = cpu_to_le32(rate_n_flags); } else { struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; - u16 offload_assist = iwl_mvm_tx_csum_pre_bz(mvm, skb, - info, - amsdu); + u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, + info, amsdu); cmd->offload_assist = cpu_to_le16(offload_assist); @@ -749,6 +758,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) } link = mvmvif->link[link_id]; + if (WARN_ON(!link)) + return -1; if (!ieee80211_is_data(hdr->frame_control)) sta_id = link->bcast_sta.sta_id; @@ -840,7 +851,7 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, band = mvmsta->vif->bss_conf.chandef.chan->band; } - lmac = iwl_mvm_get_lmac_id(mvm->fw, band); + lmac = iwl_mvm_get_lmac_id(mvm, band); } else if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) { /* for real MLO restrict to both LMACs if they exist */ @@ -1875,7 +1886,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (WARN_ON_ONCE(!sta || !sta->wme)) { + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta) || !sta->wme)) { rcu_read_unlock(); return; } @@ -2065,7 +2076,8 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) u16 tfd_cnt; int i; - if (unlikely(sizeof(*ba_res) > pkt_len)) + if (IWL_FW_CHECK(mvm, sizeof(*ba_res) > pkt_len, + "short BA notification (%d)\n", pkt_len)) return; sta_id = ba_res->sta_id; @@ -2077,7 +2089,13 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) (void *)(uintptr_t)ba_res->reduced_txp; tfd_cnt = le16_to_cpu(ba_res->tfd_cnt); - if (!tfd_cnt || struct_size(ba_res, tfd, tfd_cnt) > pkt_len) + if (!tfd_cnt) + return; + + if (IWL_FW_CHECK(mvm, + struct_size(ba_res, tfd, tfd_cnt) > pkt_len, + "short BA notification (tfds:%d, size:%d)\n", + tfd_cnt, pkt_len)) return; rcu_read_lock(); @@ -2135,7 +2153,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) rcu_read_lock(); mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); - if (WARN_ON_ONCE(!mvmsta)) { + if (IWL_FW_CHECK(mvm, !mvmsta, + "invalid STA ID %d in BA notif\n", + sta_id)) { rcu_read_unlock(); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index af31b09c3966..48016b4343d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -312,6 +312,10 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, smps_mode = IEEE80211_SMPS_DYNAMIC; } + /* SMPS is disabled in eSR */ + if (mvmvif->esr_active) + smps_mode = IEEE80211_SMPS_OFF; + ieee80211_request_smps(vif, link_id, smps_mode); } @@ -413,16 +417,20 @@ static void iwl_mvm_diversity_iter(void *_data, u8 *mac, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_diversity_iter_data *data = _data; - int i; + int i, link_id; - if (mvmvif->deflink.phy_ctxt != data->ctxt) - return; + for_each_mvm_vif_valid_link(mvmvif, link_id) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; - for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { - if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_STATIC || - mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { - data->result = false; - break; + if (link_info->phy_ctxt != data->ctxt) + continue; + + for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { + if (link_info->smps_requests[i] == IEEE80211_SMPS_STATIC || + link_info->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { + data->result = false; + break; + } } } } |