1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: wlan_hdd_eht.c 20 * 21 * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) 22 * support. 23 * 24 */ 25 26 #include "wlan_hdd_main.h" 27 #include "wlan_hdd_eht.h" 28 #include "osif_sync.h" 29 #include "wlan_utility.h" 30 #include "wlan_mlme_ucfg_api.h" 31 #include "qc_sap_ioctl.h" 32 #include "wma_api.h" 33 #include "wlan_osif_features.h" 34 #include "wlan_psoc_mlme_ucfg_api.h" 35 36 #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) 37 #define CHAN_WIDTH_SET_40MHZ_IN_2G \ 38 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 39 #define CHAN_WIDTH_SET_40MHZ_80MHZ_IN_5G \ 40 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 41 #define CHAN_WIDTH_SET_160MHZ_IN_5G \ 42 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 43 #define CHAN_WIDTH_SET_80PLUS80_MHZ_IN_5G \ 44 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 45 hdd_update_tgt_eht_cap(struct hdd_context * hdd_ctx,struct wma_tgt_cfg * cfg)46 void hdd_update_tgt_eht_cap(struct hdd_context *hdd_ctx, 47 struct wma_tgt_cfg *cfg) 48 { 49 tDot11fIEeht_cap eht_cap_ini = {0}; 50 51 ucfg_mlme_update_tgt_eht_cap(hdd_ctx->psoc, cfg); 52 sme_update_tgt_eht_cap(hdd_ctx->mac_handle, cfg, &eht_cap_ini); 53 } 54 55 /* 56 * Typical 802.11 Multi-Link element 57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 58 * | Elem ID | Elem Len |Elem ID Extn | MLink Ctrl | Common Info | Link Info | 59 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 60 * 1 1 1 2 Variable Len Variable Len 61 */ wlan_hdd_get_mlo_link_id(struct hdd_beacon_data * beacon,uint8_t * link_id,uint8_t * num_link)62 void wlan_hdd_get_mlo_link_id(struct hdd_beacon_data *beacon, 63 uint8_t *link_id, uint8_t *num_link) 64 { 65 const uint8_t *mlie, *cmn_info_ie, *link_info_ie; 66 uint8_t total_len, cmn_info_len, link_info_len; 67 uint8_t link_len; 68 69 mlie = wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, MLO_IE_OUI_SIZE, 70 beacon->tail, beacon->tail_len); 71 if (mlie) { 72 hdd_debug("ML IE found in beacon data"); 73 *num_link = 1; 74 75 mlie++; /* WLAN_MAC_EID_EXT */ 76 total_len = *mlie++; /* length */ 77 78 cmn_info_ie = mlie + 3; 79 cmn_info_len = *cmn_info_ie; 80 81 /* 802.11 Common info sub-element in Multi-link element 82 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 * |Cmn info Len |MLD MAC| Link ID | ..... 84 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 85 * 1 6 0/1 86 */ 87 88 *link_id = *(cmn_info_ie + 1 + QDF_MAC_ADDR_SIZE); 89 90 /* Length of link info equal total length minus below: 91 * 1-Byte Extn Ele ID 92 * 2-Byte Multi link control 93 * Length of Common info sub-element 94 */ 95 96 link_info_ie = cmn_info_ie + cmn_info_len; 97 link_info_len = total_len - cmn_info_len - 3; 98 while (link_info_len > 0) { 99 link_info_ie++; 100 link_info_len--; 101 /* length of sub element ID */ 102 link_len = *link_info_ie++; 103 link_info_len--; 104 link_info_ie += link_len; 105 link_info_len -= link_len; 106 (*num_link)++; 107 } 108 } else { 109 *num_link = 0; 110 hdd_debug("ML IE not found in beacon data"); 111 } 112 } 113 wlan_hdd_check_11be_support(struct hdd_beacon_data * beacon,struct sap_config * config)114 void wlan_hdd_check_11be_support(struct hdd_beacon_data *beacon, 115 struct sap_config *config) 116 { 117 const uint8_t *ie; 118 119 ie = wlan_get_ext_ie_ptr_from_ext_id(EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE, 120 beacon->tail, beacon->tail_len); 121 if (ie) 122 config->SapHw_mode = eCSR_DOT11_MODE_11be; 123 } 124 125 static void hdd_update_wiphy_eht_caps_6ghz(struct hdd_context * hdd_ctx,tDot11fIEeht_cap eht_cap)126 hdd_update_wiphy_eht_caps_6ghz(struct hdd_context *hdd_ctx, 127 tDot11fIEeht_cap eht_cap) 128 { 129 struct ieee80211_supported_band *band_6g = 130 hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ]; 131 uint8_t *phy_info = 132 hdd_ctx->iftype_data_6g->eht_cap.eht_cap_elem.phy_cap_info; 133 struct ieee80211_sband_iftype_data *iftype_sta; 134 struct ieee80211_sband_iftype_data *iftype_ap; 135 136 if (!band_6g || !phy_info) { 137 hdd_debug("6ghz not supported in wiphy"); 138 return; 139 } 140 141 hdd_ctx->iftype_data_6g->types_mask = 142 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 143 band_6g->n_iftype_data = EHT_OPMODE_SUPPORTED; 144 band_6g->iftype_data = hdd_ctx->iftype_data_6g; 145 iftype_sta = hdd_ctx->iftype_data_6g; 146 iftype_ap = hdd_ctx->iftype_data_6g + 1; 147 148 149 hdd_ctx->iftype_data_6g->eht_cap.has_eht = eht_cap.present; 150 if (hdd_ctx->iftype_data_6g->eht_cap.has_eht && 151 !hdd_ctx->iftype_data_6g->he_cap.has_he) { 152 hdd_debug("6 GHz HE caps not present"); 153 hdd_ctx->iftype_data_6g->eht_cap.has_eht = false; 154 band_6g->n_iftype_data = 1; 155 return; 156 } 157 158 if (eht_cap.support_320mhz_6ghz) 159 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; 160 161 if (eht_cap.su_beamformer) 162 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 163 164 if (eht_cap.su_beamformee) 165 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 166 167 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_6g, 168 sizeof(struct ieee80211_supported_band)); 169 170 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 171 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 172 } 173 hdd_update_wiphy_eht_cap(struct hdd_context * hdd_ctx)174 void hdd_update_wiphy_eht_cap(struct hdd_context *hdd_ctx) 175 { 176 tDot11fIEeht_cap eht_cap_cfg; 177 struct ieee80211_supported_band *band_2g = 178 hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]; 179 struct ieee80211_supported_band *band_5g = 180 hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; 181 QDF_STATUS status; 182 uint8_t *phy_info_5g = 183 hdd_ctx->iftype_data_5g->eht_cap.eht_cap_elem.phy_cap_info; 184 uint8_t *phy_info_2g = 185 hdd_ctx->iftype_data_2g->eht_cap.eht_cap_elem.phy_cap_info; 186 bool eht_capab; 187 struct ieee80211_sband_iftype_data *iftype_sta; 188 struct ieee80211_sband_iftype_data *iftype_ap; 189 190 hdd_enter(); 191 192 ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); 193 if (!eht_capab) 194 return; 195 196 status = ucfg_mlme_cfg_get_eht_caps(hdd_ctx->psoc, &eht_cap_cfg); 197 if (QDF_IS_STATUS_ERROR(status)) 198 return; 199 200 if (band_2g) { 201 iftype_sta = hdd_ctx->iftype_data_2g; 202 iftype_ap = hdd_ctx->iftype_data_2g + 1; 203 hdd_ctx->iftype_data_2g->types_mask = 204 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 205 band_2g->n_iftype_data = EHT_OPMODE_SUPPORTED; 206 band_2g->iftype_data = hdd_ctx->iftype_data_2g; 207 208 hdd_ctx->iftype_data_2g->eht_cap.has_eht = eht_cap_cfg.present; 209 if (hdd_ctx->iftype_data_2g->eht_cap.has_eht && 210 !hdd_ctx->iftype_data_2g->he_cap.has_he) { 211 hdd_debug("2.4 GHz HE caps not present"); 212 hdd_ctx->iftype_data_2g->eht_cap.has_eht = false; 213 band_2g->n_iftype_data = 1; 214 goto band_5ghz; 215 } 216 217 if (eht_cap_cfg.su_beamformer) 218 phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 219 220 if (eht_cap_cfg.su_beamformee) 221 phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 222 223 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_2g, 224 sizeof(struct ieee80211_supported_band)); 225 226 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 227 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 228 } 229 230 band_5ghz: 231 if (band_5g) { 232 iftype_sta = hdd_ctx->iftype_data_5g; 233 iftype_ap = hdd_ctx->iftype_data_5g + 1; 234 hdd_ctx->iftype_data_5g->types_mask = 235 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 236 band_5g->n_iftype_data = EHT_OPMODE_SUPPORTED; 237 band_5g->iftype_data = hdd_ctx->iftype_data_5g; 238 239 hdd_ctx->iftype_data_5g->eht_cap.has_eht = eht_cap_cfg.present; 240 if (hdd_ctx->iftype_data_5g->eht_cap.has_eht && 241 !hdd_ctx->iftype_data_5g->he_cap.has_he) { 242 hdd_debug("5 GHz HE caps not present"); 243 hdd_ctx->iftype_data_5g->eht_cap.has_eht = false; 244 band_5g->n_iftype_data = 1; 245 goto band_6ghz; 246 } 247 248 if (eht_cap_cfg.su_beamformer) 249 phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 250 251 if (eht_cap_cfg.su_beamformee) 252 phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 253 254 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_5g, 255 sizeof(struct ieee80211_supported_band)); 256 257 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 258 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 259 } 260 261 band_6ghz: 262 hdd_update_wiphy_eht_caps_6ghz(hdd_ctx, eht_cap_cfg); 263 264 hdd_exit(); 265 } 266 hdd_set_11be_rate_code(struct hdd_adapter * adapter,uint16_t rate_code)267 int hdd_set_11be_rate_code(struct hdd_adapter *adapter, uint16_t rate_code) 268 { 269 uint8_t preamble = 0, nss = 0, rix = 0; 270 int ret; 271 struct sap_config *sap_config = NULL; 272 273 if (adapter->device_mode == QDF_SAP_MODE) 274 sap_config = &adapter->deflink->session.ap.sap_config; 275 276 if (!sap_config) { 277 if (!sme_is_feature_supported_by_fw(DOT11BE)) { 278 hdd_err_rl("Target does not support 11be"); 279 return -EIO; 280 } 281 } else if (sap_config->SapHw_mode != eCSR_DOT11_MODE_11be && 282 sap_config->SapHw_mode != eCSR_DOT11_MODE_11be_ONLY) { 283 hdd_err_rl("Invalid hw mode, SAP hw_mode= 0x%x, ch_freq = %d", 284 sap_config->SapHw_mode, sap_config->chan_freq); 285 return -EIO; 286 } 287 288 if ((rate_code >> 8) != WMI_RATE_PREAMBLE_EHT) { 289 hdd_err_rl("Invalid input: %x", rate_code); 290 return -EIO; 291 } 292 293 rix = RC_2_RATE_IDX_11BE(rate_code); 294 preamble = rate_code >> 8; 295 nss = HT_RC_2_STREAMS_11BE(rate_code) + 1; 296 297 hdd_debug("SET_11BE_RATE rate_code %d rix %d preamble %x nss %d", 298 rate_code, rix, preamble, nss); 299 300 ret = wma_cli_set_command(adapter->deflink->vdev_id, 301 wmi_vdev_param_fixed_rate, 302 rate_code, VDEV_CMD); 303 304 return ret; 305 } 306 307 /** 308 * hdd_map_eht_gi_to_os() - map txrate_gi to os guard interval 309 * @guard_interval: guard interval get from fw rate 310 * 311 * Return: os guard interval value 312 */ hdd_map_eht_gi_to_os(enum txrate_gi guard_interval)313 static inline uint8_t hdd_map_eht_gi_to_os(enum txrate_gi guard_interval) 314 { 315 switch (guard_interval) { 316 case TXRATE_GI_0_8_US: 317 return NL80211_RATE_INFO_EHT_GI_0_8; 318 case TXRATE_GI_1_6_US: 319 return NL80211_RATE_INFO_EHT_GI_1_6; 320 case TXRATE_GI_3_2_US: 321 return NL80211_RATE_INFO_EHT_GI_3_2; 322 default: 323 return NL80211_RATE_INFO_EHT_GI_0_8; 324 } 325 } 326 327 /** 328 * wlan_hdd_fill_os_eht_rateflags() - Fill EHT related rate_info 329 * @os_rate: rate info for os 330 * @rate_flags: rate flags 331 * @dcm: dcm from rate 332 * @guard_interval: guard interval from rate 333 * 334 * Return: none 335 */ wlan_hdd_fill_os_eht_rateflags(struct rate_info * os_rate,enum tx_rate_info rate_flags,uint8_t dcm,enum txrate_gi guard_interval)336 void wlan_hdd_fill_os_eht_rateflags(struct rate_info *os_rate, 337 enum tx_rate_info rate_flags, 338 uint8_t dcm, 339 enum txrate_gi guard_interval) 340 { 341 /* as fw not yet report ofdma to host, so don't 342 * fill RATE_INFO_BW_EHT_RU. 343 */ 344 if (rate_flags & (TX_RATE_EHT80 | TX_RATE_EHT40 | 345 TX_RATE_EHT20 | TX_RATE_EHT160 | TX_RATE_EHT320)) { 346 if (rate_flags & TX_RATE_EHT320) 347 hdd_set_rate_bw(os_rate, HDD_RATE_BW_320); 348 else if (rate_flags & TX_RATE_EHT160) 349 hdd_set_rate_bw(os_rate, HDD_RATE_BW_160); 350 else if (rate_flags & TX_RATE_EHT80) 351 hdd_set_rate_bw(os_rate, HDD_RATE_BW_80); 352 else if (rate_flags & TX_RATE_EHT40) 353 hdd_set_rate_bw(os_rate, HDD_RATE_BW_40); 354 355 os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; 356 } 357 } 358 359 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER 360 void wlan_hdd_refill_os_eht_rateflags(struct rate_info * os_rate,uint8_t preamble)361 wlan_hdd_refill_os_eht_rateflags(struct rate_info *os_rate, uint8_t preamble) 362 { 363 if (preamble == DOT11_BE) 364 os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; 365 } 366 367 void wlan_hdd_refill_os_eht_bw(struct rate_info * os_rate,enum rx_tlv_bw bw)368 wlan_hdd_refill_os_eht_bw(struct rate_info *os_rate, enum rx_tlv_bw bw) 369 { 370 if (bw == RX_TLV_BW_320MHZ) 371 os_rate->bw = RATE_INFO_BW_320; 372 else 373 os_rate->bw = RATE_INFO_BW_20; /* Invalid bw: set 20M */ 374 } 375 #endif 376 #endif 377