1d1e879ecSMiri Korenblit // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2d1e879ecSMiri Korenblit /* 3d1e879ecSMiri Korenblit * Copyright (C) 2024-2025 Intel Corporation 4d1e879ecSMiri Korenblit */ 5d1e879ecSMiri Korenblit 6d1e879ecSMiri Korenblit #include <linux/ieee80211.h> 7d1e879ecSMiri Korenblit #include <kunit/static_stub.h> 8d1e879ecSMiri Korenblit 9d1e879ecSMiri Korenblit #include "sta.h" 10d1e879ecSMiri Korenblit #include "hcmd.h" 11d1e879ecSMiri Korenblit #include "iface.h" 12d1e879ecSMiri Korenblit #include "mlo.h" 13d1e879ecSMiri Korenblit #include "key.h" 14d1e879ecSMiri Korenblit #include "agg.h" 15d1e879ecSMiri Korenblit #include "tlc.h" 16d1e879ecSMiri Korenblit #include "fw/api/sta.h" 17d1e879ecSMiri Korenblit #include "fw/api/mac.h" 18d1e879ecSMiri Korenblit #include "fw/api/rx.h" 19d1e879ecSMiri Korenblit 20d1e879ecSMiri Korenblit int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld, 21d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta) 22d1e879ecSMiri Korenblit { 23d1e879ecSMiri Korenblit struct iwl_mld_link_sta *mld_link_sta; 24d1e879ecSMiri Korenblit 25d1e879ecSMiri Korenblit /* This function should only be used with the wiphy lock held, 26d1e879ecSMiri Korenblit * In other cases, it is not guaranteed that the link_sta will exist 27d1e879ecSMiri Korenblit * in the driver too, and it is checked here. 28d1e879ecSMiri Korenblit */ 29d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 30d1e879ecSMiri Korenblit 31d1e879ecSMiri Korenblit /* This is not meant to be called with a NULL pointer */ 32d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 33d1e879ecSMiri Korenblit return -ENOENT; 34d1e879ecSMiri Korenblit 35d1e879ecSMiri Korenblit mld_link_sta = iwl_mld_link_sta_from_mac80211(link_sta); 36d1e879ecSMiri Korenblit if (!mld_link_sta) { 37d1e879ecSMiri Korenblit WARN_ON(!iwl_mld_error_before_recovery(mld)); 38d1e879ecSMiri Korenblit return -ENOENT; 39d1e879ecSMiri Korenblit } 40d1e879ecSMiri Korenblit 41d1e879ecSMiri Korenblit return mld_link_sta->fw_id; 42d1e879ecSMiri Korenblit } 43d1e879ecSMiri Korenblit 44d1e879ecSMiri Korenblit static void 45d1e879ecSMiri Korenblit iwl_mld_fill_ampdu_size_and_dens(struct ieee80211_link_sta *link_sta, 46d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link, 47d1e879ecSMiri Korenblit __le32 *tx_ampdu_max_size, 48d1e879ecSMiri Korenblit __le32 *tx_ampdu_spacing) 49d1e879ecSMiri Korenblit { 50d1e879ecSMiri Korenblit u32 agg_size = 0, mpdu_dens = 0; 51d1e879ecSMiri Korenblit 52d1e879ecSMiri Korenblit if (WARN_ON(!link_sta || !link)) 53d1e879ecSMiri Korenblit return; 54d1e879ecSMiri Korenblit 55d1e879ecSMiri Korenblit /* Note that we always use only legacy & highest supported PPDUs, so 56d1e879ecSMiri Korenblit * of Draft P802.11be D.30 Table 10-12a--Fields used for calculating 57d1e879ecSMiri Korenblit * the maximum A-MPDU size of various PPDU types in different bands, 58d1e879ecSMiri Korenblit * we only need to worry about the highest supported PPDU type here. 59d1e879ecSMiri Korenblit */ 60d1e879ecSMiri Korenblit 61d1e879ecSMiri Korenblit if (link_sta->ht_cap.ht_supported) { 62d1e879ecSMiri Korenblit agg_size = link_sta->ht_cap.ampdu_factor; 63d1e879ecSMiri Korenblit mpdu_dens = link_sta->ht_cap.ampdu_density; 64d1e879ecSMiri Korenblit } 65d1e879ecSMiri Korenblit 66d1e879ecSMiri Korenblit if (link->chanreq.oper.chan->band == NL80211_BAND_6GHZ) { 67d1e879ecSMiri Korenblit /* overwrite HT values on 6 GHz */ 68d1e879ecSMiri Korenblit mpdu_dens = 69d1e879ecSMiri Korenblit le16_get_bits(link_sta->he_6ghz_capa.capa, 70d1e879ecSMiri Korenblit IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); 71d1e879ecSMiri Korenblit agg_size = 72d1e879ecSMiri Korenblit le16_get_bits(link_sta->he_6ghz_capa.capa, 73d1e879ecSMiri Korenblit IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); 74d1e879ecSMiri Korenblit } else if (link_sta->vht_cap.vht_supported) { 75d1e879ecSMiri Korenblit /* if VHT supported overwrite HT value */ 76d1e879ecSMiri Korenblit agg_size = 77d1e879ecSMiri Korenblit u32_get_bits(link_sta->vht_cap.cap, 78d1e879ecSMiri Korenblit IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); 79d1e879ecSMiri Korenblit } 80d1e879ecSMiri Korenblit 81d1e879ecSMiri Korenblit /* D6.0 10.12.2 A-MPDU length limit rules 82d1e879ecSMiri Korenblit * A STA indicates the maximum length of the A-MPDU preEOF padding 83d1e879ecSMiri Korenblit * that it can receive in an HE PPDU in the Maximum A-MPDU Length 84d1e879ecSMiri Korenblit * Exponent field in its HT Capabilities, VHT Capabilities, 85d1e879ecSMiri Korenblit * and HE 6 GHz Band Capabilities elements (if present) and the 86d1e879ecSMiri Korenblit * Maximum AMPDU Length Exponent Extension field in its HE 87d1e879ecSMiri Korenblit * Capabilities element 88d1e879ecSMiri Korenblit */ 89d1e879ecSMiri Korenblit if (link_sta->he_cap.has_he) 90d1e879ecSMiri Korenblit agg_size += 91d1e879ecSMiri Korenblit u8_get_bits(link_sta->he_cap.he_cap_elem.mac_cap_info[3], 92d1e879ecSMiri Korenblit IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); 93d1e879ecSMiri Korenblit 94d1e879ecSMiri Korenblit if (link_sta->eht_cap.has_eht) 95d1e879ecSMiri Korenblit agg_size += 96d1e879ecSMiri Korenblit u8_get_bits(link_sta->eht_cap.eht_cap_elem.mac_cap_info[1], 97d1e879ecSMiri Korenblit IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK); 98d1e879ecSMiri Korenblit 99d1e879ecSMiri Korenblit /* Limit to max A-MPDU supported by FW */ 100d1e879ecSMiri Korenblit agg_size = min_t(u32, agg_size, 101d1e879ecSMiri Korenblit STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT); 102d1e879ecSMiri Korenblit 103d1e879ecSMiri Korenblit *tx_ampdu_max_size = cpu_to_le32(agg_size); 104d1e879ecSMiri Korenblit *tx_ampdu_spacing = cpu_to_le32(mpdu_dens); 105d1e879ecSMiri Korenblit } 106d1e879ecSMiri Korenblit 107d1e879ecSMiri Korenblit static u8 iwl_mld_get_uapsd_acs(struct ieee80211_sta *sta) 108d1e879ecSMiri Korenblit { 109d1e879ecSMiri Korenblit u8 uapsd_acs = 0; 110d1e879ecSMiri Korenblit 111d1e879ecSMiri Korenblit if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) 112d1e879ecSMiri Korenblit uapsd_acs |= BIT(AC_BK); 113d1e879ecSMiri Korenblit if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) 114d1e879ecSMiri Korenblit uapsd_acs |= BIT(AC_BE); 115d1e879ecSMiri Korenblit if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) 116d1e879ecSMiri Korenblit uapsd_acs |= BIT(AC_VI); 117d1e879ecSMiri Korenblit if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) 118d1e879ecSMiri Korenblit uapsd_acs |= BIT(AC_VO); 119d1e879ecSMiri Korenblit 120d1e879ecSMiri Korenblit return uapsd_acs | uapsd_acs << 4; 121d1e879ecSMiri Korenblit } 122d1e879ecSMiri Korenblit 123d1e879ecSMiri Korenblit static u8 iwl_mld_he_get_ppe_val(u8 *ppe, u8 ppe_pos_bit) 124d1e879ecSMiri Korenblit { 125d1e879ecSMiri Korenblit u8 byte_num = ppe_pos_bit / 8; 126d1e879ecSMiri Korenblit u8 bit_num = ppe_pos_bit % 8; 127d1e879ecSMiri Korenblit u8 residue_bits; 128d1e879ecSMiri Korenblit u8 res; 129d1e879ecSMiri Korenblit 130d1e879ecSMiri Korenblit if (bit_num <= 5) 131d1e879ecSMiri Korenblit return (ppe[byte_num] >> bit_num) & 132d1e879ecSMiri Korenblit (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1); 133d1e879ecSMiri Korenblit 134d1e879ecSMiri Korenblit /* If bit_num > 5, we have to combine bits with next byte. 135d1e879ecSMiri Korenblit * Calculate how many bits we need to take from current byte (called 136d1e879ecSMiri Korenblit * here "residue_bits"), and add them to bits from next byte. 137d1e879ecSMiri Korenblit */ 138d1e879ecSMiri Korenblit 139d1e879ecSMiri Korenblit residue_bits = 8 - bit_num; 140d1e879ecSMiri Korenblit 141d1e879ecSMiri Korenblit res = (ppe[byte_num + 1] & 142d1e879ecSMiri Korenblit (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) << 143d1e879ecSMiri Korenblit residue_bits; 144d1e879ecSMiri Korenblit res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1); 145d1e879ecSMiri Korenblit 146d1e879ecSMiri Korenblit return res; 147d1e879ecSMiri Korenblit } 148d1e879ecSMiri Korenblit 149d1e879ecSMiri Korenblit static void iwl_mld_parse_ppe(struct iwl_mld *mld, 150d1e879ecSMiri Korenblit struct iwl_he_pkt_ext_v2 *pkt_ext, u8 nss, 151d1e879ecSMiri Korenblit u8 ru_index_bitmap, u8 *ppe, u8 ppe_pos_bit, 152d1e879ecSMiri Korenblit bool inheritance) 153d1e879ecSMiri Korenblit { 154d1e879ecSMiri Korenblit /* FW currently supports only nss == MAX_HE_SUPP_NSS 155d1e879ecSMiri Korenblit * 156d1e879ecSMiri Korenblit * If nss > MAX: we can ignore values we don't support 157d1e879ecSMiri Korenblit * If nss < MAX: we can set zeros in other streams 158d1e879ecSMiri Korenblit */ 159d1e879ecSMiri Korenblit if (nss > MAX_HE_SUPP_NSS) { 160d1e879ecSMiri Korenblit IWL_DEBUG_INFO(mld, "Got NSS = %d - trimming to %d\n", nss, 161d1e879ecSMiri Korenblit MAX_HE_SUPP_NSS); 162d1e879ecSMiri Korenblit nss = MAX_HE_SUPP_NSS; 163d1e879ecSMiri Korenblit } 164d1e879ecSMiri Korenblit 165d1e879ecSMiri Korenblit for (int i = 0; i < nss; i++) { 166d1e879ecSMiri Korenblit u8 ru_index_tmp = ru_index_bitmap << 1; 167d1e879ecSMiri Korenblit u8 low_th = IWL_HE_PKT_EXT_NONE, high_th = IWL_HE_PKT_EXT_NONE; 168d1e879ecSMiri Korenblit 169d1e879ecSMiri Korenblit for (u8 bw = 0; 170d1e879ecSMiri Korenblit bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]); 171d1e879ecSMiri Korenblit bw++) { 172d1e879ecSMiri Korenblit ru_index_tmp >>= 1; 173d1e879ecSMiri Korenblit 174d1e879ecSMiri Korenblit /* According to the 11be spec, if for a specific BW the PPE Thresholds 175d1e879ecSMiri Korenblit * isn't present - it should inherit the thresholds from the last 176d1e879ecSMiri Korenblit * BW for which we had PPE Thresholds. In 11ax though, we don't have 177d1e879ecSMiri Korenblit * this inheritance - continue in this case 178d1e879ecSMiri Korenblit */ 179d1e879ecSMiri Korenblit if (!(ru_index_tmp & 1)) { 180d1e879ecSMiri Korenblit if (inheritance) 181d1e879ecSMiri Korenblit goto set_thresholds; 182d1e879ecSMiri Korenblit else 183d1e879ecSMiri Korenblit continue; 184d1e879ecSMiri Korenblit } 185d1e879ecSMiri Korenblit 186d1e879ecSMiri Korenblit high_th = iwl_mld_he_get_ppe_val(ppe, ppe_pos_bit); 187d1e879ecSMiri Korenblit ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE; 188d1e879ecSMiri Korenblit low_th = iwl_mld_he_get_ppe_val(ppe, ppe_pos_bit); 189d1e879ecSMiri Korenblit ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE; 190d1e879ecSMiri Korenblit 191d1e879ecSMiri Korenblit set_thresholds: 192d1e879ecSMiri Korenblit pkt_ext->pkt_ext_qam_th[i][bw][0] = low_th; 193d1e879ecSMiri Korenblit pkt_ext->pkt_ext_qam_th[i][bw][1] = high_th; 194d1e879ecSMiri Korenblit } 195d1e879ecSMiri Korenblit } 196d1e879ecSMiri Korenblit } 197d1e879ecSMiri Korenblit 198d1e879ecSMiri Korenblit static void iwl_mld_set_pkt_ext_from_he_ppe(struct iwl_mld *mld, 199d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta, 200d1e879ecSMiri Korenblit struct iwl_he_pkt_ext_v2 *pkt_ext, 201d1e879ecSMiri Korenblit bool inheritance) 202d1e879ecSMiri Korenblit { 203d1e879ecSMiri Korenblit u8 nss = (link_sta->he_cap.ppe_thres[0] & 204d1e879ecSMiri Korenblit IEEE80211_PPE_THRES_NSS_MASK) + 1; 205d1e879ecSMiri Korenblit u8 *ppe = &link_sta->he_cap.ppe_thres[0]; 206d1e879ecSMiri Korenblit u8 ru_index_bitmap = 207d1e879ecSMiri Korenblit u8_get_bits(*ppe, 208d1e879ecSMiri Korenblit IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); 209d1e879ecSMiri Korenblit /* Starting after PPE header */ 210d1e879ecSMiri Korenblit u8 ppe_pos_bit = IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE; 211d1e879ecSMiri Korenblit 212d1e879ecSMiri Korenblit iwl_mld_parse_ppe(mld, pkt_ext, nss, ru_index_bitmap, ppe, ppe_pos_bit, 213d1e879ecSMiri Korenblit inheritance); 214d1e879ecSMiri Korenblit } 215d1e879ecSMiri Korenblit 216d1e879ecSMiri Korenblit static int 217d1e879ecSMiri Korenblit iwl_mld_set_pkt_ext_from_nominal_padding(struct iwl_he_pkt_ext_v2 *pkt_ext, 218d1e879ecSMiri Korenblit u8 nominal_padding) 219d1e879ecSMiri Korenblit { 220d1e879ecSMiri Korenblit int low_th = -1; 221d1e879ecSMiri Korenblit int high_th = -1; 222d1e879ecSMiri Korenblit 223d1e879ecSMiri Korenblit /* all the macros are the same for EHT and HE */ 224d1e879ecSMiri Korenblit switch (nominal_padding) { 225d1e879ecSMiri Korenblit case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US: 226d1e879ecSMiri Korenblit low_th = IWL_HE_PKT_EXT_NONE; 227d1e879ecSMiri Korenblit high_th = IWL_HE_PKT_EXT_NONE; 228d1e879ecSMiri Korenblit break; 229d1e879ecSMiri Korenblit case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US: 230d1e879ecSMiri Korenblit low_th = IWL_HE_PKT_EXT_BPSK; 231d1e879ecSMiri Korenblit high_th = IWL_HE_PKT_EXT_NONE; 232d1e879ecSMiri Korenblit break; 233d1e879ecSMiri Korenblit case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US: 234d1e879ecSMiri Korenblit case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US: 235d1e879ecSMiri Korenblit low_th = IWL_HE_PKT_EXT_NONE; 236d1e879ecSMiri Korenblit high_th = IWL_HE_PKT_EXT_BPSK; 237d1e879ecSMiri Korenblit break; 238d1e879ecSMiri Korenblit } 239d1e879ecSMiri Korenblit 240d1e879ecSMiri Korenblit if (low_th < 0 || high_th < 0) 241d1e879ecSMiri Korenblit return -EINVAL; 242d1e879ecSMiri Korenblit 243d1e879ecSMiri Korenblit /* Set the PPE thresholds accordingly */ 244d1e879ecSMiri Korenblit for (int i = 0; i < MAX_HE_SUPP_NSS; i++) { 245d1e879ecSMiri Korenblit for (u8 bw = 0; 246d1e879ecSMiri Korenblit bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]); 247d1e879ecSMiri Korenblit bw++) { 248d1e879ecSMiri Korenblit pkt_ext->pkt_ext_qam_th[i][bw][0] = low_th; 249d1e879ecSMiri Korenblit pkt_ext->pkt_ext_qam_th[i][bw][1] = high_th; 250d1e879ecSMiri Korenblit } 251d1e879ecSMiri Korenblit } 252d1e879ecSMiri Korenblit 253d1e879ecSMiri Korenblit return 0; 254d1e879ecSMiri Korenblit } 255d1e879ecSMiri Korenblit 256d1e879ecSMiri Korenblit static void iwl_mld_get_optimal_ppe_info(struct iwl_he_pkt_ext_v2 *pkt_ext, 257d1e879ecSMiri Korenblit u8 nominal_padding) 258d1e879ecSMiri Korenblit { 259d1e879ecSMiri Korenblit for (int i = 0; i < MAX_HE_SUPP_NSS; i++) { 260d1e879ecSMiri Korenblit for (u8 bw = 0; bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]); 261d1e879ecSMiri Korenblit bw++) { 262d1e879ecSMiri Korenblit u8 *qam_th = &pkt_ext->pkt_ext_qam_th[i][bw][0]; 263d1e879ecSMiri Korenblit 264d1e879ecSMiri Korenblit if (nominal_padding > 265d1e879ecSMiri Korenblit IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US && 266d1e879ecSMiri Korenblit qam_th[1] == IWL_HE_PKT_EXT_NONE) 267d1e879ecSMiri Korenblit qam_th[1] = IWL_HE_PKT_EXT_4096QAM; 268d1e879ecSMiri Korenblit else if (nominal_padding == 269d1e879ecSMiri Korenblit IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US && 270d1e879ecSMiri Korenblit qam_th[0] == IWL_HE_PKT_EXT_NONE && 271d1e879ecSMiri Korenblit qam_th[1] == IWL_HE_PKT_EXT_NONE) 272d1e879ecSMiri Korenblit qam_th[0] = IWL_HE_PKT_EXT_4096QAM; 273d1e879ecSMiri Korenblit } 274d1e879ecSMiri Korenblit } 275d1e879ecSMiri Korenblit } 276d1e879ecSMiri Korenblit 277d1e879ecSMiri Korenblit static void iwl_mld_fill_pkt_ext(struct iwl_mld *mld, 278d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta, 279d1e879ecSMiri Korenblit struct iwl_he_pkt_ext_v2 *pkt_ext) 280d1e879ecSMiri Korenblit { 281d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 282d1e879ecSMiri Korenblit return; 283d1e879ecSMiri Korenblit 284d1e879ecSMiri Korenblit /* Initialize the PPE thresholds to "None" (7), as described in Table 285d1e879ecSMiri Korenblit * 9-262ac of 80211.ax/D3.0. 286d1e879ecSMiri Korenblit */ 287d1e879ecSMiri Korenblit memset(pkt_ext, IWL_HE_PKT_EXT_NONE, sizeof(*pkt_ext)); 288d1e879ecSMiri Korenblit 289d1e879ecSMiri Korenblit if (link_sta->eht_cap.has_eht) { 290d1e879ecSMiri Korenblit u8 nominal_padding = 291d1e879ecSMiri Korenblit u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5], 292d1e879ecSMiri Korenblit IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); 293d1e879ecSMiri Korenblit 294d1e879ecSMiri Korenblit /* If PPE Thresholds exists, parse them into a FW-familiar 295d1e879ecSMiri Korenblit * format. 296d1e879ecSMiri Korenblit */ 297d1e879ecSMiri Korenblit if (link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] & 298d1e879ecSMiri Korenblit IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { 299d1e879ecSMiri Korenblit u8 nss = (link_sta->eht_cap.eht_ppe_thres[0] & 300d1e879ecSMiri Korenblit IEEE80211_EHT_PPE_THRES_NSS_MASK) + 1; 301d1e879ecSMiri Korenblit u8 *ppe = &link_sta->eht_cap.eht_ppe_thres[0]; 302d1e879ecSMiri Korenblit u8 ru_index_bitmap = 303d1e879ecSMiri Korenblit u16_get_bits(*ppe, 304d1e879ecSMiri Korenblit IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); 305d1e879ecSMiri Korenblit /* Starting after PPE header */ 306d1e879ecSMiri Korenblit u8 ppe_pos_bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; 307d1e879ecSMiri Korenblit 308d1e879ecSMiri Korenblit iwl_mld_parse_ppe(mld, pkt_ext, nss, ru_index_bitmap, 309d1e879ecSMiri Korenblit ppe, ppe_pos_bit, true); 310d1e879ecSMiri Korenblit /* EHT PPE Thresholds doesn't exist - set the API according to 311d1e879ecSMiri Korenblit * HE PPE Tresholds 312d1e879ecSMiri Korenblit */ 313d1e879ecSMiri Korenblit } else if (link_sta->he_cap.he_cap_elem.phy_cap_info[6] & 314d1e879ecSMiri Korenblit IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { 315d1e879ecSMiri Korenblit /* Even though HE Capabilities IE doesn't contain PPE 316d1e879ecSMiri Korenblit * Thresholds for BW 320Mhz, thresholds for this BW will 317d1e879ecSMiri Korenblit * be filled in with the same values as 160Mhz, due to 318d1e879ecSMiri Korenblit * the inheritance, as required. 319d1e879ecSMiri Korenblit */ 320d1e879ecSMiri Korenblit iwl_mld_set_pkt_ext_from_he_ppe(mld, link_sta, pkt_ext, 321d1e879ecSMiri Korenblit true); 322d1e879ecSMiri Korenblit 323d1e879ecSMiri Korenblit /* According to the requirements, for MCSs 12-13 the 324d1e879ecSMiri Korenblit * maximum value between HE PPE Threshold and Common 325d1e879ecSMiri Korenblit * Nominal Packet Padding needs to be taken 326d1e879ecSMiri Korenblit */ 327d1e879ecSMiri Korenblit iwl_mld_get_optimal_ppe_info(pkt_ext, nominal_padding); 328d1e879ecSMiri Korenblit 329d1e879ecSMiri Korenblit /* if PPE Thresholds doesn't present in both EHT IE and HE IE - 330d1e879ecSMiri Korenblit * take the Thresholds from Common Nominal Packet Padding field 331d1e879ecSMiri Korenblit */ 332d1e879ecSMiri Korenblit } else { 333d1e879ecSMiri Korenblit iwl_mld_set_pkt_ext_from_nominal_padding(pkt_ext, 334d1e879ecSMiri Korenblit nominal_padding); 335d1e879ecSMiri Korenblit } 336d1e879ecSMiri Korenblit } else if (link_sta->he_cap.has_he) { 337d1e879ecSMiri Korenblit /* If PPE Thresholds exist, parse them into a FW-familiar format. */ 338d1e879ecSMiri Korenblit if (link_sta->he_cap.he_cap_elem.phy_cap_info[6] & 339d1e879ecSMiri Korenblit IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { 340d1e879ecSMiri Korenblit iwl_mld_set_pkt_ext_from_he_ppe(mld, link_sta, pkt_ext, 341d1e879ecSMiri Korenblit false); 342d1e879ecSMiri Korenblit /* PPE Thresholds doesn't exist - set the API PPE values 343d1e879ecSMiri Korenblit * according to Common Nominal Packet Padding field. 344d1e879ecSMiri Korenblit */ 345d1e879ecSMiri Korenblit } else { 346d1e879ecSMiri Korenblit u8 nominal_padding = 347d1e879ecSMiri Korenblit u8_get_bits(link_sta->he_cap.he_cap_elem.phy_cap_info[9], 348d1e879ecSMiri Korenblit IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); 349d1e879ecSMiri Korenblit if (nominal_padding != IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED) 350d1e879ecSMiri Korenblit iwl_mld_set_pkt_ext_from_nominal_padding(pkt_ext, 351d1e879ecSMiri Korenblit nominal_padding); 352d1e879ecSMiri Korenblit } 353d1e879ecSMiri Korenblit } 354d1e879ecSMiri Korenblit 355d1e879ecSMiri Korenblit for (int i = 0; i < MAX_HE_SUPP_NSS; i++) { 356d1e879ecSMiri Korenblit for (int bw = 0; 357d1e879ecSMiri Korenblit bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]); 358d1e879ecSMiri Korenblit bw++) { 359d1e879ecSMiri Korenblit u8 *qam_th = 360d1e879ecSMiri Korenblit &pkt_ext->pkt_ext_qam_th[i][bw][0]; 361d1e879ecSMiri Korenblit 362d1e879ecSMiri Korenblit IWL_DEBUG_HT(mld, 363d1e879ecSMiri Korenblit "PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n", 364d1e879ecSMiri Korenblit i, bw, qam_th[0], qam_th[1]); 365d1e879ecSMiri Korenblit } 366d1e879ecSMiri Korenblit } 367d1e879ecSMiri Korenblit } 368d1e879ecSMiri Korenblit 369d1e879ecSMiri Korenblit static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta) 370d1e879ecSMiri Korenblit { 371d1e879ecSMiri Korenblit u8 *mac_cap_info = 372d1e879ecSMiri Korenblit &link_sta->he_cap.he_cap_elem.mac_cap_info[0]; 373d1e879ecSMiri Korenblit u32 htc_flags = 0; 374d1e879ecSMiri Korenblit 375d1e879ecSMiri Korenblit if (mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) 376d1e879ecSMiri Korenblit htc_flags |= IWL_HE_HTC_SUPPORT; 377d1e879ecSMiri Korenblit if ((mac_cap_info[1] & IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION) || 378d1e879ecSMiri Korenblit (mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION)) { 379d1e879ecSMiri Korenblit u8 link_adap = 380d1e879ecSMiri Korenblit ((mac_cap_info[2] & 381d1e879ecSMiri Korenblit IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION) << 1) + 382d1e879ecSMiri Korenblit (mac_cap_info[1] & 383d1e879ecSMiri Korenblit IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION); 384d1e879ecSMiri Korenblit 385d1e879ecSMiri Korenblit if (link_adap == 2) 386d1e879ecSMiri Korenblit htc_flags |= 387d1e879ecSMiri Korenblit IWL_HE_HTC_LINK_ADAP_UNSOLICITED; 388d1e879ecSMiri Korenblit else if (link_adap == 3) 389d1e879ecSMiri Korenblit htc_flags |= IWL_HE_HTC_LINK_ADAP_BOTH; 390d1e879ecSMiri Korenblit } 391d1e879ecSMiri Korenblit if (mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) 392d1e879ecSMiri Korenblit htc_flags |= IWL_HE_HTC_BSR_SUPP; 393d1e879ecSMiri Korenblit if (mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) 394d1e879ecSMiri Korenblit htc_flags |= IWL_HE_HTC_OMI_SUPP; 395d1e879ecSMiri Korenblit if (mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) 396d1e879ecSMiri Korenblit htc_flags |= IWL_HE_HTC_BQR_SUPP; 397d1e879ecSMiri Korenblit 398d1e879ecSMiri Korenblit return htc_flags; 399d1e879ecSMiri Korenblit } 400d1e879ecSMiri Korenblit 401d1e879ecSMiri Korenblit static int iwl_mld_send_sta_cmd(struct iwl_mld *mld, 402d1e879ecSMiri Korenblit const struct iwl_sta_cfg_cmd *cmd) 403d1e879ecSMiri Korenblit { 404d1e879ecSMiri Korenblit int ret = iwl_mld_send_cmd_pdu(mld, 405d1e879ecSMiri Korenblit WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), 406d1e879ecSMiri Korenblit cmd); 407d1e879ecSMiri Korenblit if (ret) 408d1e879ecSMiri Korenblit IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); 409d1e879ecSMiri Korenblit return ret; 410d1e879ecSMiri Korenblit } 411d1e879ecSMiri Korenblit 412d1e879ecSMiri Korenblit static int 413d1e879ecSMiri Korenblit iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, 414d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta) 415d1e879ecSMiri Korenblit { 416d1e879ecSMiri Korenblit struct ieee80211_sta *sta = link_sta->sta; 417d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 418d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link; 419d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link; 420d1e879ecSMiri Korenblit struct iwl_sta_cfg_cmd cmd = {}; 421d1e879ecSMiri Korenblit int fw_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); 422d1e879ecSMiri Korenblit 423d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 424d1e879ecSMiri Korenblit 425d1e879ecSMiri Korenblit link = link_conf_dereference_protected(mld_sta->vif, 426d1e879ecSMiri Korenblit link_sta->link_id); 427d1e879ecSMiri Korenblit 428d1e879ecSMiri Korenblit mld_link = iwl_mld_link_from_mac80211(link); 429d1e879ecSMiri Korenblit 430d1e879ecSMiri Korenblit if (WARN_ON(!link || !mld_link) || fw_id < 0) 431d1e879ecSMiri Korenblit return -EINVAL; 432d1e879ecSMiri Korenblit 433d1e879ecSMiri Korenblit cmd.sta_id = cpu_to_le32(fw_id); 434d1e879ecSMiri Korenblit cmd.station_type = cpu_to_le32(mld_sta->sta_type); 435d1e879ecSMiri Korenblit cmd.link_id = cpu_to_le32(mld_link->fw_id); 436d1e879ecSMiri Korenblit 437d1e879ecSMiri Korenblit memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN); 438d1e879ecSMiri Korenblit memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN); 439d1e879ecSMiri Korenblit 440d1e879ecSMiri Korenblit if (mld_sta->sta_state >= IEEE80211_STA_ASSOC) 441d1e879ecSMiri Korenblit cmd.assoc_id = cpu_to_le32(sta->aid); 442d1e879ecSMiri Korenblit 443d1e879ecSMiri Korenblit if (sta->mfp || mld_sta->sta_state < IEEE80211_STA_AUTHORIZED) 444d1e879ecSMiri Korenblit cmd.mfp = cpu_to_le32(1); 445d1e879ecSMiri Korenblit 446d1e879ecSMiri Korenblit switch (link_sta->rx_nss) { 447d1e879ecSMiri Korenblit case 1: 448d1e879ecSMiri Korenblit cmd.mimo = cpu_to_le32(0); 449d1e879ecSMiri Korenblit break; 450d1e879ecSMiri Korenblit case 2 ... 8: 451d1e879ecSMiri Korenblit cmd.mimo = cpu_to_le32(1); 452d1e879ecSMiri Korenblit break; 453d1e879ecSMiri Korenblit } 454d1e879ecSMiri Korenblit 455d1e879ecSMiri Korenblit switch (link_sta->smps_mode) { 456d1e879ecSMiri Korenblit case IEEE80211_SMPS_AUTOMATIC: 457d1e879ecSMiri Korenblit case IEEE80211_SMPS_NUM_MODES: 458d1e879ecSMiri Korenblit WARN_ON(1); 459d1e879ecSMiri Korenblit break; 460d1e879ecSMiri Korenblit case IEEE80211_SMPS_STATIC: 461d1e879ecSMiri Korenblit /* override NSS */ 462d1e879ecSMiri Korenblit cmd.mimo = cpu_to_le32(0); 463d1e879ecSMiri Korenblit break; 464d1e879ecSMiri Korenblit case IEEE80211_SMPS_DYNAMIC: 465d1e879ecSMiri Korenblit cmd.mimo_protection = cpu_to_le32(1); 466d1e879ecSMiri Korenblit break; 467d1e879ecSMiri Korenblit case IEEE80211_SMPS_OFF: 468d1e879ecSMiri Korenblit /* nothing */ 469d1e879ecSMiri Korenblit break; 470d1e879ecSMiri Korenblit } 471d1e879ecSMiri Korenblit 472d1e879ecSMiri Korenblit iwl_mld_fill_ampdu_size_and_dens(link_sta, link, 473d1e879ecSMiri Korenblit &cmd.tx_ampdu_max_size, 474d1e879ecSMiri Korenblit &cmd.tx_ampdu_spacing); 475d1e879ecSMiri Korenblit 476d1e879ecSMiri Korenblit if (sta->wme) { 477d1e879ecSMiri Korenblit cmd.sp_length = 478d1e879ecSMiri Korenblit cpu_to_le32(sta->max_sp ? sta->max_sp * 2 : 128); 479d1e879ecSMiri Korenblit cmd.uapsd_acs = cpu_to_le32(iwl_mld_get_uapsd_acs(sta)); 480d1e879ecSMiri Korenblit } 481d1e879ecSMiri Korenblit 482d1e879ecSMiri Korenblit if (link_sta->he_cap.has_he) { 483d1e879ecSMiri Korenblit cmd.trig_rnd_alloc = 484d1e879ecSMiri Korenblit cpu_to_le32(link->uora_exists ? 1 : 0); 485d1e879ecSMiri Korenblit 486d1e879ecSMiri Korenblit /* PPE Thresholds */ 487d1e879ecSMiri Korenblit iwl_mld_fill_pkt_ext(mld, link_sta, &cmd.pkt_ext); 488d1e879ecSMiri Korenblit 489d1e879ecSMiri Korenblit /* HTC flags */ 490d1e879ecSMiri Korenblit cmd.htc_flags = 491d1e879ecSMiri Korenblit cpu_to_le32(iwl_mld_get_htc_flags(link_sta)); 492d1e879ecSMiri Korenblit 493d1e879ecSMiri Korenblit if (link_sta->he_cap.he_cap_elem.mac_cap_info[2] & 494d1e879ecSMiri Korenblit IEEE80211_HE_MAC_CAP2_ACK_EN) 495d1e879ecSMiri Korenblit cmd.ack_enabled = cpu_to_le32(1); 496d1e879ecSMiri Korenblit } 497d1e879ecSMiri Korenblit 498d1e879ecSMiri Korenblit return iwl_mld_send_sta_cmd(mld, &cmd); 499d1e879ecSMiri Korenblit } 500d1e879ecSMiri Korenblit 501d1e879ecSMiri Korenblit IWL_MLD_ALLOC_FN(link_sta, link_sta) 502d1e879ecSMiri Korenblit 503d1e879ecSMiri Korenblit static int 504d1e879ecSMiri Korenblit iwl_mld_add_link_sta(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta) 505d1e879ecSMiri Korenblit { 506d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); 507d1e879ecSMiri Korenblit struct iwl_mld_link_sta *mld_link_sta; 508d1e879ecSMiri Korenblit int ret; 509d1e879ecSMiri Korenblit u8 fw_id; 510d1e879ecSMiri Korenblit 511d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 512d1e879ecSMiri Korenblit 513d1e879ecSMiri Korenblit /* We will fail to add it to the FW anyway */ 514d1e879ecSMiri Korenblit if (iwl_mld_error_before_recovery(mld)) 515d1e879ecSMiri Korenblit return -ENODEV; 516d1e879ecSMiri Korenblit 517d1e879ecSMiri Korenblit mld_link_sta = iwl_mld_link_sta_from_mac80211(link_sta); 518d1e879ecSMiri Korenblit 519d1e879ecSMiri Korenblit /* We need to preserve the fw sta ids during a restart, since the fw 520d1e879ecSMiri Korenblit * will recover SN/PN for them, this is why the mld_link_sta exists. 521d1e879ecSMiri Korenblit */ 522d1e879ecSMiri Korenblit if (mld_link_sta) { 523d1e879ecSMiri Korenblit /* But if we are not restarting, this is not OK */ 524d1e879ecSMiri Korenblit WARN_ON(!mld->fw_status.in_hw_restart); 525d1e879ecSMiri Korenblit 526d1e879ecSMiri Korenblit /* Avoid adding a STA that is already in FW to avoid an assert */ 527d1e879ecSMiri Korenblit if (WARN_ON(mld_link_sta->in_fw)) 528d1e879ecSMiri Korenblit return -EINVAL; 529d1e879ecSMiri Korenblit 530d1e879ecSMiri Korenblit fw_id = mld_link_sta->fw_id; 531d1e879ecSMiri Korenblit goto add_to_fw; 532d1e879ecSMiri Korenblit } 533d1e879ecSMiri Korenblit 534d1e879ecSMiri Korenblit /* Allocate a fw id and map it to the link_sta */ 535d1e879ecSMiri Korenblit ret = iwl_mld_allocate_link_sta_fw_id(mld, &fw_id, link_sta); 536d1e879ecSMiri Korenblit if (ret) 537d1e879ecSMiri Korenblit return ret; 538d1e879ecSMiri Korenblit 539d1e879ecSMiri Korenblit if (link_sta == &link_sta->sta->deflink) { 540d1e879ecSMiri Korenblit mld_link_sta = &mld_sta->deflink; 541d1e879ecSMiri Korenblit } else { 542d1e879ecSMiri Korenblit mld_link_sta = kzalloc(sizeof(*mld_link_sta), GFP_KERNEL); 543d1e879ecSMiri Korenblit if (!mld_link_sta) 544d1e879ecSMiri Korenblit return -ENOMEM; 545d1e879ecSMiri Korenblit } 546d1e879ecSMiri Korenblit 547d1e879ecSMiri Korenblit mld_link_sta->fw_id = fw_id; 548d1e879ecSMiri Korenblit rcu_assign_pointer(mld_sta->link[link_sta->link_id], mld_link_sta); 549d1e879ecSMiri Korenblit 550d1e879ecSMiri Korenblit add_to_fw: 551d1e879ecSMiri Korenblit ret = iwl_mld_add_modify_sta_cmd(mld, link_sta); 552d1e879ecSMiri Korenblit if (ret) { 553d1e879ecSMiri Korenblit RCU_INIT_POINTER(mld->fw_id_to_link_sta[fw_id], NULL); 554d1e879ecSMiri Korenblit RCU_INIT_POINTER(mld_sta->link[link_sta->link_id], NULL); 555d1e879ecSMiri Korenblit if (link_sta != &link_sta->sta->deflink) 556d1e879ecSMiri Korenblit kfree(mld_link_sta); 557d1e879ecSMiri Korenblit return ret; 558d1e879ecSMiri Korenblit } 559d1e879ecSMiri Korenblit mld_link_sta->in_fw = true; 560d1e879ecSMiri Korenblit 561d1e879ecSMiri Korenblit return 0; 562d1e879ecSMiri Korenblit } 563d1e879ecSMiri Korenblit 564d1e879ecSMiri Korenblit static int iwl_mld_rm_sta_from_fw(struct iwl_mld *mld, u8 fw_sta_id) 565d1e879ecSMiri Korenblit { 566d1e879ecSMiri Korenblit struct iwl_remove_sta_cmd cmd = { 567d1e879ecSMiri Korenblit .sta_id = cpu_to_le32(fw_sta_id), 568d1e879ecSMiri Korenblit }; 569d1e879ecSMiri Korenblit int ret; 570d1e879ecSMiri Korenblit 571d1e879ecSMiri Korenblit ret = iwl_mld_send_cmd_pdu(mld, 572d1e879ecSMiri Korenblit WIDE_ID(MAC_CONF_GROUP, STA_REMOVE_CMD), 573d1e879ecSMiri Korenblit &cmd); 574d1e879ecSMiri Korenblit if (ret) 575d1e879ecSMiri Korenblit IWL_ERR(mld, "Failed to remove station. Id=%d\n", fw_sta_id); 576d1e879ecSMiri Korenblit 577d1e879ecSMiri Korenblit return ret; 578d1e879ecSMiri Korenblit } 579d1e879ecSMiri Korenblit 580d1e879ecSMiri Korenblit static void 581d1e879ecSMiri Korenblit iwl_mld_remove_link_sta(struct iwl_mld *mld, 582d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta) 583d1e879ecSMiri Korenblit { 584d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); 585d1e879ecSMiri Korenblit struct iwl_mld_link_sta *mld_link_sta = 586d1e879ecSMiri Korenblit iwl_mld_link_sta_from_mac80211(link_sta); 587d1e879ecSMiri Korenblit 588d1e879ecSMiri Korenblit if (WARN_ON(!mld_link_sta)) 589d1e879ecSMiri Korenblit return; 590d1e879ecSMiri Korenblit 591d1e879ecSMiri Korenblit iwl_mld_rm_sta_from_fw(mld, mld_link_sta->fw_id); 592d1e879ecSMiri Korenblit mld_link_sta->in_fw = false; 593d1e879ecSMiri Korenblit 594d1e879ecSMiri Korenblit /* Now that the STA doesn't exist in FW, we don't expect any new 595d1e879ecSMiri Korenblit * notifications for it. Cancel the ones that are already pending 596d1e879ecSMiri Korenblit */ 597d1e879ecSMiri Korenblit iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_STA, 598d1e879ecSMiri Korenblit mld_link_sta->fw_id); 599d1e879ecSMiri Korenblit 600d1e879ecSMiri Korenblit /* This will not be done upon reconfig, so do it also when 601d1e879ecSMiri Korenblit * failed to remove from fw 602d1e879ecSMiri Korenblit */ 603d1e879ecSMiri Korenblit RCU_INIT_POINTER(mld->fw_id_to_link_sta[mld_link_sta->fw_id], NULL); 604d1e879ecSMiri Korenblit RCU_INIT_POINTER(mld_sta->link[link_sta->link_id], NULL); 605d1e879ecSMiri Korenblit if (mld_link_sta != &mld_sta->deflink) 606d1e879ecSMiri Korenblit kfree_rcu(mld_link_sta, rcu_head); 607d1e879ecSMiri Korenblit } 608d1e879ecSMiri Korenblit 609d1e879ecSMiri Korenblit int iwl_mld_update_all_link_stations(struct iwl_mld *mld, 610d1e879ecSMiri Korenblit struct ieee80211_sta *sta) 611d1e879ecSMiri Korenblit { 612d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 613d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta; 614d1e879ecSMiri Korenblit int link_id; 615d1e879ecSMiri Korenblit 616d1e879ecSMiri Korenblit for_each_sta_active_link(mld_sta->vif, sta, link_sta, link_id) { 617d1e879ecSMiri Korenblit int ret = iwl_mld_add_modify_sta_cmd(mld, link_sta); 618d1e879ecSMiri Korenblit 619d1e879ecSMiri Korenblit if (ret) 620d1e879ecSMiri Korenblit return ret; 621d1e879ecSMiri Korenblit } 622d1e879ecSMiri Korenblit return 0; 623d1e879ecSMiri Korenblit } 624d1e879ecSMiri Korenblit 625d1e879ecSMiri Korenblit static void iwl_mld_destroy_sta(struct ieee80211_sta *sta) 626d1e879ecSMiri Korenblit { 627d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 628d1e879ecSMiri Korenblit 629d1e879ecSMiri Korenblit kfree(mld_sta->dup_data); 630d1e879ecSMiri Korenblit kfree(mld_sta->mpdu_counters); 631d1e879ecSMiri Korenblit } 632d1e879ecSMiri Korenblit 633d1e879ecSMiri Korenblit static int 634d1e879ecSMiri Korenblit iwl_mld_alloc_dup_data(struct iwl_mld *mld, struct iwl_mld_sta *mld_sta) 635d1e879ecSMiri Korenblit { 636d1e879ecSMiri Korenblit struct iwl_mld_rxq_dup_data *dup_data; 637d1e879ecSMiri Korenblit 638d1e879ecSMiri Korenblit if (mld->fw_status.in_hw_restart) 639d1e879ecSMiri Korenblit return 0; 640d1e879ecSMiri Korenblit 641d1e879ecSMiri Korenblit dup_data = kcalloc(mld->trans->num_rx_queues, sizeof(*dup_data), 642d1e879ecSMiri Korenblit GFP_KERNEL); 643d1e879ecSMiri Korenblit if (!dup_data) 644d1e879ecSMiri Korenblit return -ENOMEM; 645d1e879ecSMiri Korenblit 646d1e879ecSMiri Korenblit /* Initialize all the last_seq values to 0xffff which can never 647d1e879ecSMiri Korenblit * compare equal to the frame's seq_ctrl in the check in 648d1e879ecSMiri Korenblit * iwl_mld_is_dup() since the lower 4 bits are the fragment 649d1e879ecSMiri Korenblit * number and fragmented packets don't reach that function. 650d1e879ecSMiri Korenblit * 651d1e879ecSMiri Korenblit * This thus allows receiving a packet with seqno 0 and the 652d1e879ecSMiri Korenblit * retry bit set as the very first packet on a new TID. 653d1e879ecSMiri Korenblit */ 654d1e879ecSMiri Korenblit for (int q = 0; q < mld->trans->num_rx_queues; q++) 655d1e879ecSMiri Korenblit memset(dup_data[q].last_seq, 0xff, 656d1e879ecSMiri Korenblit sizeof(dup_data[q].last_seq)); 657d1e879ecSMiri Korenblit mld_sta->dup_data = dup_data; 658d1e879ecSMiri Korenblit 659d1e879ecSMiri Korenblit return 0; 660d1e879ecSMiri Korenblit } 661d1e879ecSMiri Korenblit 662d1e879ecSMiri Korenblit static void iwl_mld_alloc_mpdu_counters(struct iwl_mld *mld, 663d1e879ecSMiri Korenblit struct ieee80211_sta *sta) 664d1e879ecSMiri Korenblit { 665d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 666d1e879ecSMiri Korenblit struct ieee80211_vif *vif = mld_sta->vif; 667d1e879ecSMiri Korenblit 668d1e879ecSMiri Korenblit if (mld->fw_status.in_hw_restart) 669d1e879ecSMiri Korenblit return; 670d1e879ecSMiri Korenblit 671d1e879ecSMiri Korenblit /* MPDUs are counted only when EMLSR is possible */ 672d1e879ecSMiri Korenblit if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION || 673d1e879ecSMiri Korenblit sta->tdls || !ieee80211_vif_is_mld(vif)) 674d1e879ecSMiri Korenblit return; 675d1e879ecSMiri Korenblit 676d1e879ecSMiri Korenblit mld_sta->mpdu_counters = kcalloc(mld->trans->num_rx_queues, 677d1e879ecSMiri Korenblit sizeof(*mld_sta->mpdu_counters), 678d1e879ecSMiri Korenblit GFP_KERNEL); 679d1e879ecSMiri Korenblit if (!mld_sta->mpdu_counters) 680d1e879ecSMiri Korenblit return; 681d1e879ecSMiri Korenblit 682d1e879ecSMiri Korenblit for (int q = 0; q < mld->trans->num_rx_queues; q++) 683d1e879ecSMiri Korenblit spin_lock_init(&mld_sta->mpdu_counters[q].lock); 684d1e879ecSMiri Korenblit } 685d1e879ecSMiri Korenblit 686d1e879ecSMiri Korenblit static int 687d1e879ecSMiri Korenblit iwl_mld_init_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, 688d1e879ecSMiri Korenblit struct ieee80211_vif *vif, enum iwl_fw_sta_type type) 689d1e879ecSMiri Korenblit { 690d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 691d1e879ecSMiri Korenblit 692d1e879ecSMiri Korenblit mld_sta->vif = vif; 693d1e879ecSMiri Korenblit mld_sta->sta_type = type; 694d1e879ecSMiri Korenblit mld_sta->mld = mld; 695d1e879ecSMiri Korenblit 696d1e879ecSMiri Korenblit if (!mld->fw_status.in_hw_restart) 697d1e879ecSMiri Korenblit for (int i = 0; i < ARRAY_SIZE(sta->txq); i++) 698d1e879ecSMiri Korenblit iwl_mld_init_txq(iwl_mld_txq_from_mac80211(sta->txq[i])); 699d1e879ecSMiri Korenblit 700d1e879ecSMiri Korenblit iwl_mld_alloc_mpdu_counters(mld, sta); 701d1e879ecSMiri Korenblit 702d1e879ecSMiri Korenblit iwl_mld_toggle_tx_ant(mld, &mld_sta->data_tx_ant); 703d1e879ecSMiri Korenblit 704d1e879ecSMiri Korenblit return iwl_mld_alloc_dup_data(mld, mld_sta); 705d1e879ecSMiri Korenblit } 706d1e879ecSMiri Korenblit 707d1e879ecSMiri Korenblit int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, 708d1e879ecSMiri Korenblit struct ieee80211_vif *vif, enum iwl_fw_sta_type type) 709d1e879ecSMiri Korenblit { 710d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 711d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta; 712d1e879ecSMiri Korenblit int link_id; 713d1e879ecSMiri Korenblit int ret; 714d1e879ecSMiri Korenblit 715d1e879ecSMiri Korenblit ret = iwl_mld_init_sta(mld, sta, vif, type); 716d1e879ecSMiri Korenblit if (ret) 717d1e879ecSMiri Korenblit return ret; 718d1e879ecSMiri Korenblit 719d1e879ecSMiri Korenblit /* We could have add only the deflink link_sta, but it will not work 720d1e879ecSMiri Korenblit * in the restart case if the single link that is active during 721d1e879ecSMiri Korenblit * reconfig is not the deflink one. 722d1e879ecSMiri Korenblit */ 723d1e879ecSMiri Korenblit for_each_sta_active_link(mld_sta->vif, sta, link_sta, link_id) { 724d1e879ecSMiri Korenblit ret = iwl_mld_add_link_sta(mld, link_sta); 725d1e879ecSMiri Korenblit if (ret) 726d1e879ecSMiri Korenblit goto destroy_sta; 727d1e879ecSMiri Korenblit } 728d1e879ecSMiri Korenblit 729d1e879ecSMiri Korenblit return 0; 730d1e879ecSMiri Korenblit 731d1e879ecSMiri Korenblit destroy_sta: 732d1e879ecSMiri Korenblit iwl_mld_destroy_sta(sta); 733d1e879ecSMiri Korenblit 734d1e879ecSMiri Korenblit return ret; 735d1e879ecSMiri Korenblit } 736d1e879ecSMiri Korenblit 737d1e879ecSMiri Korenblit void iwl_mld_flush_sta_txqs(struct iwl_mld *mld, struct ieee80211_sta *sta) 738d1e879ecSMiri Korenblit { 739d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 740d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta; 741d1e879ecSMiri Korenblit int link_id; 742d1e879ecSMiri Korenblit 743d1e879ecSMiri Korenblit for_each_sta_active_link(mld_sta->vif, sta, link_sta, link_id) { 744d1e879ecSMiri Korenblit int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); 745d1e879ecSMiri Korenblit 746d1e879ecSMiri Korenblit if (fw_sta_id < 0) 747d1e879ecSMiri Korenblit continue; 748d1e879ecSMiri Korenblit 749d1e879ecSMiri Korenblit iwl_mld_flush_link_sta_txqs(mld, fw_sta_id); 750d1e879ecSMiri Korenblit } 751d1e879ecSMiri Korenblit } 752d1e879ecSMiri Korenblit 753d1e879ecSMiri Korenblit void iwl_mld_wait_sta_txqs_empty(struct iwl_mld *mld, struct ieee80211_sta *sta) 754d1e879ecSMiri Korenblit { 755d1e879ecSMiri Korenblit /* Avoid a warning in iwl_trans_wait_txq_empty if are anyway on the way 756d1e879ecSMiri Korenblit * to a restart. 757d1e879ecSMiri Korenblit */ 758d1e879ecSMiri Korenblit if (iwl_mld_error_before_recovery(mld)) 759d1e879ecSMiri Korenblit return; 760d1e879ecSMiri Korenblit 761d1e879ecSMiri Korenblit for (int i = 0; i < ARRAY_SIZE(sta->txq); i++) { 762d1e879ecSMiri Korenblit struct iwl_mld_txq *mld_txq = 763d1e879ecSMiri Korenblit iwl_mld_txq_from_mac80211(sta->txq[i]); 764d1e879ecSMiri Korenblit 765d1e879ecSMiri Korenblit if (!mld_txq->status.allocated) 766d1e879ecSMiri Korenblit continue; 767d1e879ecSMiri Korenblit 768d1e879ecSMiri Korenblit iwl_trans_wait_txq_empty(mld->trans, mld_txq->fw_id); 769d1e879ecSMiri Korenblit } 770d1e879ecSMiri Korenblit } 771d1e879ecSMiri Korenblit 772d1e879ecSMiri Korenblit void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta) 773d1e879ecSMiri Korenblit { 774d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 775d1e879ecSMiri Korenblit struct ieee80211_vif *vif = mld_sta->vif; 776d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta; 777d1e879ecSMiri Korenblit u8 link_id; 778d1e879ecSMiri Korenblit 779d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 780d1e879ecSMiri Korenblit 781d1e879ecSMiri Korenblit /* Tell the HW to flush the queues */ 782d1e879ecSMiri Korenblit iwl_mld_flush_sta_txqs(mld, sta); 783d1e879ecSMiri Korenblit 784d1e879ecSMiri Korenblit /* Wait for trans to empty its queues */ 785d1e879ecSMiri Korenblit iwl_mld_wait_sta_txqs_empty(mld, sta); 786d1e879ecSMiri Korenblit 787d1e879ecSMiri Korenblit /* Now we can remove the queues */ 788d1e879ecSMiri Korenblit for (int i = 0; i < ARRAY_SIZE(sta->txq); i++) 789d1e879ecSMiri Korenblit iwl_mld_remove_txq(mld, sta->txq[i]); 790d1e879ecSMiri Korenblit 791d1e879ecSMiri Korenblit for_each_sta_active_link(vif, sta, link_sta, link_id) { 792d1e879ecSMiri Korenblit /* Mac8011 will remove the groupwise keys after the sta is 793d1e879ecSMiri Korenblit * removed, but FW expects all the keys to be removed before 794d1e879ecSMiri Korenblit * the STA is, so remove them all here. 795d1e879ecSMiri Korenblit */ 796*67128af0SJohannes Berg if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) 797d1e879ecSMiri Korenblit iwl_mld_remove_ap_keys(mld, vif, sta, link_id); 798d1e879ecSMiri Korenblit 799d1e879ecSMiri Korenblit /* Remove the link_sta */ 800d1e879ecSMiri Korenblit iwl_mld_remove_link_sta(mld, link_sta); 801d1e879ecSMiri Korenblit } 802d1e879ecSMiri Korenblit 803d1e879ecSMiri Korenblit iwl_mld_destroy_sta(sta); 804d1e879ecSMiri Korenblit } 805d1e879ecSMiri Korenblit 806d1e879ecSMiri Korenblit u32 iwl_mld_fw_sta_id_mask(struct iwl_mld *mld, struct ieee80211_sta *sta) 807d1e879ecSMiri Korenblit { 808d1e879ecSMiri Korenblit struct ieee80211_vif *vif = iwl_mld_sta_from_mac80211(sta)->vif; 809d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta; 810d1e879ecSMiri Korenblit unsigned int link_id; 811d1e879ecSMiri Korenblit u32 result = 0; 812d1e879ecSMiri Korenblit 813d1e879ecSMiri Korenblit KUNIT_STATIC_STUB_REDIRECT(iwl_mld_fw_sta_id_mask, mld, sta); 814d1e879ecSMiri Korenblit 815d1e879ecSMiri Korenblit /* This function should only be used with the wiphy lock held, 816d1e879ecSMiri Korenblit * In other cases, it is not guaranteed that the link_sta will exist 817d1e879ecSMiri Korenblit * in the driver too, and it is checked in 818d1e879ecSMiri Korenblit * iwl_mld_fw_sta_id_from_link_sta. 819d1e879ecSMiri Korenblit */ 820d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 821d1e879ecSMiri Korenblit 822d1e879ecSMiri Korenblit for_each_sta_active_link(vif, sta, link_sta, link_id) { 823d1e879ecSMiri Korenblit int fw_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); 824d1e879ecSMiri Korenblit 825d1e879ecSMiri Korenblit if (!(fw_id < 0)) 826d1e879ecSMiri Korenblit result |= BIT(fw_id); 827d1e879ecSMiri Korenblit } 828d1e879ecSMiri Korenblit 829d1e879ecSMiri Korenblit return result; 830d1e879ecSMiri Korenblit } 831d1e879ecSMiri Korenblit EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_fw_sta_id_mask); 832d1e879ecSMiri Korenblit 833d1e879ecSMiri Korenblit static void iwl_mld_count_mpdu(struct ieee80211_link_sta *link_sta, int queue, 834d1e879ecSMiri Korenblit u32 count, bool tx) 835d1e879ecSMiri Korenblit { 836d1e879ecSMiri Korenblit struct iwl_mld_per_q_mpdu_counter *queue_counter; 837d1e879ecSMiri Korenblit struct iwl_mld_per_link_mpdu_counter *link_counter; 838d1e879ecSMiri Korenblit struct iwl_mld_vif *mld_vif; 839d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta; 840d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link; 841d1e879ecSMiri Korenblit struct iwl_mld *mld; 842d1e879ecSMiri Korenblit int total_mpdus = 0; 843d1e879ecSMiri Korenblit 844d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 845d1e879ecSMiri Korenblit return; 846d1e879ecSMiri Korenblit 847d1e879ecSMiri Korenblit mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); 848d1e879ecSMiri Korenblit if (!mld_sta->mpdu_counters) 849d1e879ecSMiri Korenblit return; 850d1e879ecSMiri Korenblit 851d1e879ecSMiri Korenblit mld_vif = iwl_mld_vif_from_mac80211(mld_sta->vif); 852d1e879ecSMiri Korenblit mld_link = iwl_mld_link_dereference_check(mld_vif, link_sta->link_id); 853d1e879ecSMiri Korenblit 854d1e879ecSMiri Korenblit if (WARN_ON_ONCE(!mld_link)) 855d1e879ecSMiri Korenblit return; 856d1e879ecSMiri Korenblit 857d1e879ecSMiri Korenblit queue_counter = &mld_sta->mpdu_counters[queue]; 858d1e879ecSMiri Korenblit 859d1e879ecSMiri Korenblit mld = mld_vif->mld; 860d1e879ecSMiri Korenblit 861d1e879ecSMiri Korenblit /* If it the window is over, first clear the counters. 862d1e879ecSMiri Korenblit * When we are not blocked by TPT, the window is managed by check_tpt_wk 863d1e879ecSMiri Korenblit */ 864d1e879ecSMiri Korenblit if ((mld_vif->emlsr.blocked_reasons & IWL_MLD_EMLSR_BLOCKED_TPT) && 865d1e879ecSMiri Korenblit time_is_before_jiffies(queue_counter->window_start_time + 866d1e879ecSMiri Korenblit IWL_MLD_TPT_COUNT_WINDOW)) { 867d1e879ecSMiri Korenblit memset(queue_counter->per_link, 0, 868d1e879ecSMiri Korenblit sizeof(queue_counter->per_link)); 869d1e879ecSMiri Korenblit queue_counter->window_start_time = jiffies; 870d1e879ecSMiri Korenblit 871d1e879ecSMiri Korenblit IWL_DEBUG_INFO(mld, "MPDU counters are cleared\n"); 872d1e879ecSMiri Korenblit } 873d1e879ecSMiri Korenblit 874d1e879ecSMiri Korenblit link_counter = &queue_counter->per_link[mld_link->fw_id]; 875d1e879ecSMiri Korenblit 876d1e879ecSMiri Korenblit spin_lock_bh(&queue_counter->lock); 877d1e879ecSMiri Korenblit 878d1e879ecSMiri Korenblit /* Update the statistics for this TPT measurement window */ 879d1e879ecSMiri Korenblit if (tx) 880d1e879ecSMiri Korenblit link_counter->tx += count; 881d1e879ecSMiri Korenblit else 882d1e879ecSMiri Korenblit link_counter->rx += count; 883d1e879ecSMiri Korenblit 884d1e879ecSMiri Korenblit /* 885d1e879ecSMiri Korenblit * Next, evaluate whether we should queue an unblock, 886d1e879ecSMiri Korenblit * skip this if we are not blocked due to low throughput. 887d1e879ecSMiri Korenblit */ 888d1e879ecSMiri Korenblit if (!(mld_vif->emlsr.blocked_reasons & IWL_MLD_EMLSR_BLOCKED_TPT)) 889d1e879ecSMiri Korenblit goto unlock; 890d1e879ecSMiri Korenblit 891d1e879ecSMiri Korenblit for (int i = 0; i <= IWL_FW_MAX_LINK_ID; i++) 892d1e879ecSMiri Korenblit total_mpdus += tx ? queue_counter->per_link[i].tx : 893d1e879ecSMiri Korenblit queue_counter->per_link[i].rx; 894d1e879ecSMiri Korenblit 895d1e879ecSMiri Korenblit /* Unblock is already queued if the threshold was reached before */ 896d1e879ecSMiri Korenblit if (total_mpdus - count >= IWL_MLD_ENTER_EMLSR_TPT_THRESH) 897d1e879ecSMiri Korenblit goto unlock; 898d1e879ecSMiri Korenblit 899d1e879ecSMiri Korenblit if (total_mpdus >= IWL_MLD_ENTER_EMLSR_TPT_THRESH) 900d1e879ecSMiri Korenblit wiphy_work_queue(mld->wiphy, &mld_vif->emlsr.unblock_tpt_wk); 901d1e879ecSMiri Korenblit 902d1e879ecSMiri Korenblit unlock: 903d1e879ecSMiri Korenblit spin_unlock_bh(&queue_counter->lock); 904d1e879ecSMiri Korenblit } 905d1e879ecSMiri Korenblit 906d1e879ecSMiri Korenblit /* must be called under rcu_read_lock() */ 907d1e879ecSMiri Korenblit void iwl_mld_count_mpdu_rx(struct ieee80211_link_sta *link_sta, int queue, 908d1e879ecSMiri Korenblit u32 count) 909d1e879ecSMiri Korenblit { 910d1e879ecSMiri Korenblit iwl_mld_count_mpdu(link_sta, queue, count, false); 911d1e879ecSMiri Korenblit } 912d1e879ecSMiri Korenblit 913d1e879ecSMiri Korenblit /* must be called under rcu_read_lock() */ 914d1e879ecSMiri Korenblit void iwl_mld_count_mpdu_tx(struct ieee80211_link_sta *link_sta, u32 count) 915d1e879ecSMiri Korenblit { 916d1e879ecSMiri Korenblit /* use queue 0 for all TX */ 917d1e879ecSMiri Korenblit iwl_mld_count_mpdu(link_sta, 0, count, true); 918d1e879ecSMiri Korenblit } 919d1e879ecSMiri Korenblit 920d1e879ecSMiri Korenblit static int iwl_mld_allocate_internal_txq(struct iwl_mld *mld, 921d1e879ecSMiri Korenblit struct iwl_mld_int_sta *internal_sta, 922d1e879ecSMiri Korenblit u8 tid) 923d1e879ecSMiri Korenblit { 924d1e879ecSMiri Korenblit u32 sta_mask = BIT(internal_sta->sta_id); 925d1e879ecSMiri Korenblit int queue, size; 926d1e879ecSMiri Korenblit 927d1e879ecSMiri Korenblit size = max_t(u32, IWL_MGMT_QUEUE_SIZE, 928d1e879ecSMiri Korenblit mld->trans->cfg->min_txq_size); 929d1e879ecSMiri Korenblit 930d1e879ecSMiri Korenblit queue = iwl_trans_txq_alloc(mld->trans, 0, sta_mask, tid, size, 931d1e879ecSMiri Korenblit IWL_WATCHDOG_DISABLED); 932d1e879ecSMiri Korenblit 933d1e879ecSMiri Korenblit if (queue >= 0) 934d1e879ecSMiri Korenblit IWL_DEBUG_TX_QUEUES(mld, 935d1e879ecSMiri Korenblit "Enabling TXQ #%d for sta mask 0x%x tid %d\n", 936d1e879ecSMiri Korenblit queue, sta_mask, tid); 937d1e879ecSMiri Korenblit return queue; 938d1e879ecSMiri Korenblit } 939d1e879ecSMiri Korenblit 940d1e879ecSMiri Korenblit static int iwl_mld_send_aux_sta_cmd(struct iwl_mld *mld, 941d1e879ecSMiri Korenblit const struct iwl_mld_int_sta *internal_sta) 942d1e879ecSMiri Korenblit { 943d1e879ecSMiri Korenblit struct iwl_aux_sta_cmd cmd = { 944d1e879ecSMiri Korenblit .sta_id = cpu_to_le32(internal_sta->sta_id), 945d1e879ecSMiri Korenblit /* TODO: CDB - properly set the lmac_id */ 946d1e879ecSMiri Korenblit .lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX), 947d1e879ecSMiri Korenblit }; 948d1e879ecSMiri Korenblit 949d1e879ecSMiri Korenblit return iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, AUX_STA_CMD), 950d1e879ecSMiri Korenblit &cmd); 951d1e879ecSMiri Korenblit } 952d1e879ecSMiri Korenblit 953d1e879ecSMiri Korenblit static int 954d1e879ecSMiri Korenblit iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld, 955d1e879ecSMiri Korenblit const struct iwl_mld_int_sta *internal_sta, 956d1e879ecSMiri Korenblit u8 fw_link_id, 957d1e879ecSMiri Korenblit const u8 *addr) 958d1e879ecSMiri Korenblit { 959d1e879ecSMiri Korenblit struct iwl_sta_cfg_cmd cmd = {}; 960d1e879ecSMiri Korenblit 961d1e879ecSMiri Korenblit if (internal_sta->sta_type == STATION_TYPE_AUX) 962d1e879ecSMiri Korenblit return iwl_mld_send_aux_sta_cmd(mld, internal_sta); 963d1e879ecSMiri Korenblit 964d1e879ecSMiri Korenblit cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id); 965d1e879ecSMiri Korenblit cmd.link_id = cpu_to_le32(fw_link_id); 966d1e879ecSMiri Korenblit cmd.station_type = cpu_to_le32(internal_sta->sta_type); 967d1e879ecSMiri Korenblit 968d1e879ecSMiri Korenblit /* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP. 969d1e879ecSMiri Korenblit * On the other hand, FW will never check this flag during RX since 970d1e879ecSMiri Korenblit * an AP/GO doesn't receive protected broadcast management frames. 971d1e879ecSMiri Korenblit * So, we can set it unconditionally. 972d1e879ecSMiri Korenblit */ 973d1e879ecSMiri Korenblit if (internal_sta->sta_type == STATION_TYPE_BCAST_MGMT) 974d1e879ecSMiri Korenblit cmd.mfp = cpu_to_le32(1); 975d1e879ecSMiri Korenblit 976d1e879ecSMiri Korenblit if (addr) { 977d1e879ecSMiri Korenblit memcpy(cmd.peer_mld_address, addr, ETH_ALEN); 978d1e879ecSMiri Korenblit memcpy(cmd.peer_link_address, addr, ETH_ALEN); 979d1e879ecSMiri Korenblit } 980d1e879ecSMiri Korenblit 981d1e879ecSMiri Korenblit return iwl_mld_send_sta_cmd(mld, &cmd); 982d1e879ecSMiri Korenblit } 983d1e879ecSMiri Korenblit 984d1e879ecSMiri Korenblit static int iwl_mld_add_internal_sta(struct iwl_mld *mld, 985d1e879ecSMiri Korenblit struct iwl_mld_int_sta *internal_sta, 986d1e879ecSMiri Korenblit enum iwl_fw_sta_type sta_type, 987d1e879ecSMiri Korenblit u8 fw_link_id, const u8 *addr, u8 tid) 988d1e879ecSMiri Korenblit { 989d1e879ecSMiri Korenblit int ret, queue_id; 990d1e879ecSMiri Korenblit 991d1e879ecSMiri Korenblit ret = iwl_mld_allocate_link_sta_fw_id(mld, 992d1e879ecSMiri Korenblit &internal_sta->sta_id, 993d1e879ecSMiri Korenblit ERR_PTR(-EINVAL)); 994d1e879ecSMiri Korenblit if (ret) 995d1e879ecSMiri Korenblit return ret; 996d1e879ecSMiri Korenblit 997d1e879ecSMiri Korenblit internal_sta->sta_type = sta_type; 998d1e879ecSMiri Korenblit 999d1e879ecSMiri Korenblit ret = iwl_mld_add_internal_sta_to_fw(mld, internal_sta, fw_link_id, 1000d1e879ecSMiri Korenblit addr); 1001d1e879ecSMiri Korenblit if (ret) 1002d1e879ecSMiri Korenblit goto err; 1003d1e879ecSMiri Korenblit 1004d1e879ecSMiri Korenblit queue_id = iwl_mld_allocate_internal_txq(mld, internal_sta, tid); 1005d1e879ecSMiri Korenblit if (queue_id < 0) { 1006d1e879ecSMiri Korenblit iwl_mld_rm_sta_from_fw(mld, internal_sta->sta_id); 1007d1e879ecSMiri Korenblit ret = queue_id; 1008d1e879ecSMiri Korenblit goto err; 1009d1e879ecSMiri Korenblit } 1010d1e879ecSMiri Korenblit 1011d1e879ecSMiri Korenblit internal_sta->queue_id = queue_id; 1012d1e879ecSMiri Korenblit 1013d1e879ecSMiri Korenblit return 0; 1014d1e879ecSMiri Korenblit err: 1015d1e879ecSMiri Korenblit iwl_mld_free_internal_sta(mld, internal_sta); 1016d1e879ecSMiri Korenblit return ret; 1017d1e879ecSMiri Korenblit } 1018d1e879ecSMiri Korenblit 1019d1e879ecSMiri Korenblit int iwl_mld_add_bcast_sta(struct iwl_mld *mld, 1020d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1021d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link) 1022d1e879ecSMiri Korenblit { 1023d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 1024d1e879ecSMiri Korenblit const u8 bcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 1025d1e879ecSMiri Korenblit const u8 *addr; 1026d1e879ecSMiri Korenblit 1027d1e879ecSMiri Korenblit if (WARN_ON(!mld_link)) 1028d1e879ecSMiri Korenblit return -EINVAL; 1029d1e879ecSMiri Korenblit 1030d1e879ecSMiri Korenblit if (WARN_ON(vif->type != NL80211_IFTYPE_AP && 1031d1e879ecSMiri Korenblit vif->type != NL80211_IFTYPE_ADHOC)) 1032d1e879ecSMiri Korenblit return -EINVAL; 1033d1e879ecSMiri Korenblit 1034d1e879ecSMiri Korenblit addr = vif->type == NL80211_IFTYPE_ADHOC ? link->bssid : bcast_addr; 1035d1e879ecSMiri Korenblit 1036d1e879ecSMiri Korenblit return iwl_mld_add_internal_sta(mld, &mld_link->bcast_sta, 1037d1e879ecSMiri Korenblit STATION_TYPE_BCAST_MGMT, 1038d1e879ecSMiri Korenblit mld_link->fw_id, addr, 1039d1e879ecSMiri Korenblit IWL_MGMT_TID); 1040d1e879ecSMiri Korenblit } 1041d1e879ecSMiri Korenblit 1042d1e879ecSMiri Korenblit int iwl_mld_add_mcast_sta(struct iwl_mld *mld, 1043d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1044d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link) 1045d1e879ecSMiri Korenblit { 1046d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 1047d1e879ecSMiri Korenblit const u8 mcast_addr[] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; 1048d1e879ecSMiri Korenblit 1049d1e879ecSMiri Korenblit if (WARN_ON(!mld_link)) 1050d1e879ecSMiri Korenblit return -EINVAL; 1051d1e879ecSMiri Korenblit 1052d1e879ecSMiri Korenblit if (WARN_ON(vif->type != NL80211_IFTYPE_AP && 1053d1e879ecSMiri Korenblit vif->type != NL80211_IFTYPE_ADHOC)) 1054d1e879ecSMiri Korenblit return -EINVAL; 1055d1e879ecSMiri Korenblit 1056d1e879ecSMiri Korenblit return iwl_mld_add_internal_sta(mld, &mld_link->mcast_sta, 1057d1e879ecSMiri Korenblit STATION_TYPE_MCAST, 1058d1e879ecSMiri Korenblit mld_link->fw_id, mcast_addr, 0); 1059d1e879ecSMiri Korenblit } 1060d1e879ecSMiri Korenblit 1061d1e879ecSMiri Korenblit int iwl_mld_add_aux_sta(struct iwl_mld *mld, 1062d1e879ecSMiri Korenblit struct iwl_mld_int_sta *internal_sta) 1063d1e879ecSMiri Korenblit { 1064d1e879ecSMiri Korenblit return iwl_mld_add_internal_sta(mld, internal_sta, STATION_TYPE_AUX, 1065d1e879ecSMiri Korenblit 0, NULL, IWL_MAX_TID_COUNT); 1066d1e879ecSMiri Korenblit } 1067d1e879ecSMiri Korenblit 1068d1e879ecSMiri Korenblit static void iwl_mld_remove_internal_sta(struct iwl_mld *mld, 1069d1e879ecSMiri Korenblit struct iwl_mld_int_sta *internal_sta, 1070d1e879ecSMiri Korenblit bool flush, u8 tid) 1071d1e879ecSMiri Korenblit { 1072d1e879ecSMiri Korenblit if (WARN_ON_ONCE(internal_sta->sta_id == IWL_INVALID_STA || 1073d1e879ecSMiri Korenblit internal_sta->queue_id == IWL_MLD_INVALID_QUEUE)) 1074d1e879ecSMiri Korenblit return; 1075d1e879ecSMiri Korenblit 1076d1e879ecSMiri Korenblit if (flush) 1077d1e879ecSMiri Korenblit iwl_mld_flush_link_sta_txqs(mld, internal_sta->sta_id); 1078d1e879ecSMiri Korenblit 1079d1e879ecSMiri Korenblit iwl_mld_free_txq(mld, BIT(internal_sta->sta_id), 1080d1e879ecSMiri Korenblit tid, internal_sta->queue_id); 1081d1e879ecSMiri Korenblit 1082d1e879ecSMiri Korenblit iwl_mld_rm_sta_from_fw(mld, internal_sta->sta_id); 1083d1e879ecSMiri Korenblit 1084d1e879ecSMiri Korenblit iwl_mld_free_internal_sta(mld, internal_sta); 1085d1e879ecSMiri Korenblit } 1086d1e879ecSMiri Korenblit 1087d1e879ecSMiri Korenblit void iwl_mld_remove_bcast_sta(struct iwl_mld *mld, 1088d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1089d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link) 1090d1e879ecSMiri Korenblit { 1091d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 1092d1e879ecSMiri Korenblit 1093d1e879ecSMiri Korenblit if (WARN_ON(!mld_link)) 1094d1e879ecSMiri Korenblit return; 1095d1e879ecSMiri Korenblit 1096d1e879ecSMiri Korenblit if (WARN_ON(vif->type != NL80211_IFTYPE_AP && 1097d1e879ecSMiri Korenblit vif->type != NL80211_IFTYPE_ADHOC)) 1098d1e879ecSMiri Korenblit return; 1099d1e879ecSMiri Korenblit 1100d1e879ecSMiri Korenblit iwl_mld_remove_internal_sta(mld, &mld_link->bcast_sta, true, 1101d1e879ecSMiri Korenblit IWL_MGMT_TID); 1102d1e879ecSMiri Korenblit } 1103d1e879ecSMiri Korenblit 1104d1e879ecSMiri Korenblit void iwl_mld_remove_mcast_sta(struct iwl_mld *mld, 1105d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1106d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link) 1107d1e879ecSMiri Korenblit { 1108d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 1109d1e879ecSMiri Korenblit 1110d1e879ecSMiri Korenblit if (WARN_ON(!mld_link)) 1111d1e879ecSMiri Korenblit return; 1112d1e879ecSMiri Korenblit 1113d1e879ecSMiri Korenblit if (WARN_ON(vif->type != NL80211_IFTYPE_AP && 1114d1e879ecSMiri Korenblit vif->type != NL80211_IFTYPE_ADHOC)) 1115d1e879ecSMiri Korenblit return; 1116d1e879ecSMiri Korenblit 1117d1e879ecSMiri Korenblit iwl_mld_remove_internal_sta(mld, &mld_link->mcast_sta, true, 0); 1118d1e879ecSMiri Korenblit } 1119d1e879ecSMiri Korenblit 1120d1e879ecSMiri Korenblit void iwl_mld_remove_aux_sta(struct iwl_mld *mld, 1121d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1122d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link) 1123d1e879ecSMiri Korenblit { 1124d1e879ecSMiri Korenblit struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); 1125d1e879ecSMiri Korenblit 1126d1e879ecSMiri Korenblit if (WARN_ON(!mld_link)) 1127d1e879ecSMiri Korenblit return; 1128d1e879ecSMiri Korenblit 1129d1e879ecSMiri Korenblit /* TODO: Hotspot 2.0 */ 1130d1e879ecSMiri Korenblit if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE)) 1131d1e879ecSMiri Korenblit return; 1132d1e879ecSMiri Korenblit 1133d1e879ecSMiri Korenblit iwl_mld_remove_internal_sta(mld, &mld_link->aux_sta, false, 1134d1e879ecSMiri Korenblit IWL_MAX_TID_COUNT); 1135d1e879ecSMiri Korenblit } 1136d1e879ecSMiri Korenblit 1137d1e879ecSMiri Korenblit static int iwl_mld_update_sta_resources(struct iwl_mld *mld, 1138d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1139d1e879ecSMiri Korenblit struct ieee80211_sta *sta, 1140d1e879ecSMiri Korenblit u32 old_sta_mask, 1141d1e879ecSMiri Korenblit u32 new_sta_mask) 1142d1e879ecSMiri Korenblit { 1143d1e879ecSMiri Korenblit int ret; 1144d1e879ecSMiri Korenblit 1145d1e879ecSMiri Korenblit ret = iwl_mld_update_sta_txqs(mld, sta, old_sta_mask, new_sta_mask); 1146d1e879ecSMiri Korenblit if (ret) 1147d1e879ecSMiri Korenblit return ret; 1148d1e879ecSMiri Korenblit 1149d1e879ecSMiri Korenblit ret = iwl_mld_update_sta_keys(mld, vif, sta, old_sta_mask, new_sta_mask); 1150d1e879ecSMiri Korenblit if (ret) 1151d1e879ecSMiri Korenblit return ret; 1152d1e879ecSMiri Korenblit 1153d1e879ecSMiri Korenblit return iwl_mld_update_sta_baids(mld, old_sta_mask, new_sta_mask); 1154d1e879ecSMiri Korenblit } 1155d1e879ecSMiri Korenblit 1156d1e879ecSMiri Korenblit int iwl_mld_update_link_stas(struct iwl_mld *mld, 1157d1e879ecSMiri Korenblit struct ieee80211_vif *vif, 1158d1e879ecSMiri Korenblit struct ieee80211_sta *sta, 1159d1e879ecSMiri Korenblit u16 old_links, u16 new_links) 1160d1e879ecSMiri Korenblit { 1161d1e879ecSMiri Korenblit struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 1162d1e879ecSMiri Korenblit struct iwl_mld_link_sta *mld_link_sta; 1163d1e879ecSMiri Korenblit unsigned long links_to_add = ~old_links & new_links; 1164d1e879ecSMiri Korenblit unsigned long links_to_rem = old_links & ~new_links; 1165d1e879ecSMiri Korenblit unsigned long old_links_long = old_links; 1166d1e879ecSMiri Korenblit unsigned long sta_mask_added = 0; 1167d1e879ecSMiri Korenblit u32 current_sta_mask = 0, sta_mask_to_rem = 0; 1168d1e879ecSMiri Korenblit unsigned int link_id, sta_id; 1169d1e879ecSMiri Korenblit int ret; 1170d1e879ecSMiri Korenblit 1171d1e879ecSMiri Korenblit lockdep_assert_wiphy(mld->wiphy); 1172d1e879ecSMiri Korenblit 1173d1e879ecSMiri Korenblit for_each_set_bit(link_id, &old_links_long, 1174d1e879ecSMiri Korenblit IEEE80211_MLD_MAX_NUM_LINKS) { 1175d1e879ecSMiri Korenblit mld_link_sta = 1176d1e879ecSMiri Korenblit iwl_mld_link_sta_dereference_check(mld_sta, link_id); 1177d1e879ecSMiri Korenblit 1178d1e879ecSMiri Korenblit if (WARN_ON(!mld_link_sta)) 1179d1e879ecSMiri Korenblit return -EINVAL; 1180d1e879ecSMiri Korenblit 1181d1e879ecSMiri Korenblit current_sta_mask |= BIT(mld_link_sta->fw_id); 1182d1e879ecSMiri Korenblit if (links_to_rem & BIT(link_id)) 1183d1e879ecSMiri Korenblit sta_mask_to_rem |= BIT(mld_link_sta->fw_id); 1184d1e879ecSMiri Korenblit } 1185d1e879ecSMiri Korenblit 1186d1e879ecSMiri Korenblit if (sta_mask_to_rem) { 1187d1e879ecSMiri Korenblit ret = iwl_mld_update_sta_resources(mld, vif, sta, 1188d1e879ecSMiri Korenblit current_sta_mask, 1189d1e879ecSMiri Korenblit current_sta_mask & 1190d1e879ecSMiri Korenblit ~sta_mask_to_rem); 1191d1e879ecSMiri Korenblit if (ret) 1192d1e879ecSMiri Korenblit return ret; 1193d1e879ecSMiri Korenblit 1194d1e879ecSMiri Korenblit current_sta_mask &= ~sta_mask_to_rem; 1195d1e879ecSMiri Korenblit } 1196d1e879ecSMiri Korenblit 1197d1e879ecSMiri Korenblit for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 1198d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta = 1199d1e879ecSMiri Korenblit link_sta_dereference_protected(sta, link_id); 1200d1e879ecSMiri Korenblit 1201d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 1202d1e879ecSMiri Korenblit return -EINVAL; 1203d1e879ecSMiri Korenblit 1204d1e879ecSMiri Korenblit iwl_mld_remove_link_sta(mld, link_sta); 1205d1e879ecSMiri Korenblit } 1206d1e879ecSMiri Korenblit 1207d1e879ecSMiri Korenblit for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { 1208d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta = 1209d1e879ecSMiri Korenblit link_sta_dereference_protected(sta, link_id); 1210d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link; 1211d1e879ecSMiri Korenblit 1212d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 1213d1e879ecSMiri Korenblit return -EINVAL; 1214d1e879ecSMiri Korenblit 1215d1e879ecSMiri Korenblit ret = iwl_mld_add_link_sta(mld, link_sta); 1216d1e879ecSMiri Korenblit if (ret) 1217d1e879ecSMiri Korenblit goto remove_added_link_stas; 1218d1e879ecSMiri Korenblit 1219d1e879ecSMiri Korenblit mld_link_sta = 1220d1e879ecSMiri Korenblit iwl_mld_link_sta_dereference_check(mld_sta, 1221d1e879ecSMiri Korenblit link_id); 1222d1e879ecSMiri Korenblit 1223d1e879ecSMiri Korenblit link = link_conf_dereference_protected(mld_sta->vif, 1224d1e879ecSMiri Korenblit link_sta->link_id); 1225d1e879ecSMiri Korenblit iwl_mld_config_tlc_link(mld, vif, link, link_sta); 1226d1e879ecSMiri Korenblit 1227d1e879ecSMiri Korenblit sta_mask_added |= BIT(mld_link_sta->fw_id); 1228d1e879ecSMiri Korenblit } 1229d1e879ecSMiri Korenblit 1230d1e879ecSMiri Korenblit if (sta_mask_added) { 1231d1e879ecSMiri Korenblit ret = iwl_mld_update_sta_resources(mld, vif, sta, 1232d1e879ecSMiri Korenblit current_sta_mask, 1233d1e879ecSMiri Korenblit current_sta_mask | 1234d1e879ecSMiri Korenblit sta_mask_added); 1235d1e879ecSMiri Korenblit if (ret) 1236d1e879ecSMiri Korenblit goto remove_added_link_stas; 1237d1e879ecSMiri Korenblit } 1238d1e879ecSMiri Korenblit 1239d1e879ecSMiri Korenblit /* We couldn't activate the links before it has a STA. Now we can */ 1240d1e879ecSMiri Korenblit for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { 1241d1e879ecSMiri Korenblit struct ieee80211_bss_conf *link = 1242d1e879ecSMiri Korenblit link_conf_dereference_protected(mld_sta->vif, link_id); 1243d1e879ecSMiri Korenblit 1244d1e879ecSMiri Korenblit if (WARN_ON(!link)) 1245d1e879ecSMiri Korenblit continue; 1246d1e879ecSMiri Korenblit 1247d1e879ecSMiri Korenblit iwl_mld_activate_link(mld, link); 1248d1e879ecSMiri Korenblit } 1249d1e879ecSMiri Korenblit 1250d1e879ecSMiri Korenblit return 0; 1251d1e879ecSMiri Korenblit 1252d1e879ecSMiri Korenblit remove_added_link_stas: 1253d1e879ecSMiri Korenblit for_each_set_bit(sta_id, &sta_mask_added, mld->fw->ucode_capa.num_stations) { 1254d1e879ecSMiri Korenblit struct ieee80211_link_sta *link_sta = 1255d1e879ecSMiri Korenblit wiphy_dereference(mld->wiphy, 1256d1e879ecSMiri Korenblit mld->fw_id_to_link_sta[sta_id]); 1257d1e879ecSMiri Korenblit 1258d1e879ecSMiri Korenblit if (WARN_ON(!link_sta)) 1259d1e879ecSMiri Korenblit continue; 1260d1e879ecSMiri Korenblit 1261d1e879ecSMiri Korenblit iwl_mld_remove_link_sta(mld, link_sta); 1262d1e879ecSMiri Korenblit } 1263d1e879ecSMiri Korenblit 1264d1e879ecSMiri Korenblit return ret; 1265d1e879ecSMiri Korenblit } 1266