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 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 void wlan_hdd_get_mlo_link_id(struct hdd_beacon_data *beacon, 56 uint8_t *link_id, uint8_t *num_link) 57 { 58 const uint8_t *ie; 59 uint8_t len; 60 uint8_t link_len; 61 *num_link = 0; 62 63 ie = wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, MLO_IE_OUI_SIZE, 64 beacon->tail, beacon->tail_len); 65 if (ie) { 66 hdd_debug("find a mlo ie in beacon data"); 67 *num_link = 1; 68 ie++; /* WLAN_MAC_EID_EXT */ 69 len = *ie++; /* length */ 70 ie++; /* MLO_IE_OUI_TYPE */ 71 len--; 72 ie++; /* Multi-Link Control field 2octets */ 73 ie++; 74 len--; 75 len--; 76 ie++; /* Common Info Length */ 77 len--; 78 ie += QDF_MAC_ADDR_SIZE; /* mld mac addr */ 79 len -= QDF_MAC_ADDR_SIZE; 80 *link_id = *ie++; /* link id */ 81 len--; 82 while (len > 0) { 83 ie++; /* sub element ID */ 84 len--; 85 link_len = *ie++; /* length of sub element ID */ 86 len--; 87 ie += link_len; 88 len -= link_len; 89 (*num_link)++; 90 } 91 } else { 92 hdd_debug("there is no mlo ie in beacon data"); 93 } 94 } 95 96 void wlan_hdd_check_11be_support(struct hdd_beacon_data *beacon, 97 struct sap_config *config) 98 { 99 const uint8_t *ie; 100 101 ie = wlan_get_ext_ie_ptr_from_ext_id(EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE, 102 beacon->tail, beacon->tail_len); 103 if (ie) 104 config->SapHw_mode = eCSR_DOT11_MODE_11be; 105 } 106 107 static void 108 hdd_update_wiphy_eht_caps_6ghz(struct hdd_context *hdd_ctx, 109 tDot11fIEeht_cap eht_cap) 110 { 111 struct ieee80211_supported_band *band_6g = 112 hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ]; 113 uint8_t *phy_info = 114 hdd_ctx->iftype_data_6g->eht_cap.eht_cap_elem.phy_cap_info; 115 struct ieee80211_sband_iftype_data *iftype_sta; 116 struct ieee80211_sband_iftype_data *iftype_ap; 117 118 if (!band_6g || !phy_info) { 119 hdd_debug("6ghz not supported in wiphy"); 120 return; 121 } 122 123 hdd_ctx->iftype_data_6g->types_mask = 124 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 125 band_6g->n_iftype_data = EHT_OPMODE_SUPPORTED; 126 band_6g->iftype_data = hdd_ctx->iftype_data_6g; 127 iftype_sta = hdd_ctx->iftype_data_6g; 128 iftype_ap = hdd_ctx->iftype_data_6g + 1; 129 130 131 hdd_ctx->iftype_data_6g->eht_cap.has_eht = eht_cap.present; 132 if (hdd_ctx->iftype_data_6g->eht_cap.has_eht && 133 !hdd_ctx->iftype_data_6g->he_cap.has_he) { 134 hdd_debug("6 GHz HE caps not present"); 135 hdd_ctx->iftype_data_6g->eht_cap.has_eht = false; 136 band_6g->n_iftype_data = 1; 137 return; 138 } 139 140 if (eht_cap.support_320mhz_6ghz) 141 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; 142 143 if (eht_cap.su_beamformer) 144 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 145 146 if (eht_cap.su_beamformee) 147 phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 148 149 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_6g, 150 sizeof(struct ieee80211_supported_band)); 151 152 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 153 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 154 } 155 156 #ifdef CFG80211_RU_PUNCT_SUPPORT 157 static void hdd_update_wiphy_punct_support(struct hdd_context *hdd_ctx) 158 { 159 /* 160 * ru_punct_supp_bw is the minimum BW of puncture. 161 * If it is set to 80, then 160 and 320 puncture bandwidth will also be 162 * supported in this case. 163 * If it is set to 320, then only 320 puncture bandwidth is supported. 164 */ 165 hdd_ctx->wiphy->ru_punct_supp_bw = NL80211_RU_PUNCT_SUPP_BW_80; 166 hdd_debug("ru_punct_supp_bw: %d", hdd_ctx->wiphy->ru_punct_supp_bw); 167 } 168 #else 169 static void hdd_update_wiphy_punct_support(struct hdd_context *hdd_ctx) 170 { 171 } 172 #endif 173 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 (eht_cap_cfg.present) 201 hdd_update_wiphy_punct_support(hdd_ctx); 202 203 if (band_2g) { 204 iftype_sta = hdd_ctx->iftype_data_2g; 205 iftype_ap = hdd_ctx->iftype_data_2g + 1; 206 hdd_ctx->iftype_data_2g->types_mask = 207 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 208 band_2g->n_iftype_data = EHT_OPMODE_SUPPORTED; 209 band_2g->iftype_data = hdd_ctx->iftype_data_2g; 210 211 hdd_ctx->iftype_data_2g->eht_cap.has_eht = eht_cap_cfg.present; 212 if (hdd_ctx->iftype_data_2g->eht_cap.has_eht && 213 !hdd_ctx->iftype_data_2g->he_cap.has_he) { 214 hdd_debug("2.4 GHz HE caps not present"); 215 hdd_ctx->iftype_data_2g->eht_cap.has_eht = false; 216 band_2g->n_iftype_data = 1; 217 goto band_5ghz; 218 } 219 220 if (eht_cap_cfg.su_beamformer) 221 phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 222 223 if (eht_cap_cfg.su_beamformee) 224 phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 225 226 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_2g, 227 sizeof(struct ieee80211_supported_band)); 228 229 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 230 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 231 } 232 233 band_5ghz: 234 if (band_5g) { 235 iftype_sta = hdd_ctx->iftype_data_5g; 236 iftype_ap = hdd_ctx->iftype_data_5g + 1; 237 hdd_ctx->iftype_data_5g->types_mask = 238 (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); 239 band_5g->n_iftype_data = EHT_OPMODE_SUPPORTED; 240 band_5g->iftype_data = hdd_ctx->iftype_data_5g; 241 242 hdd_ctx->iftype_data_5g->eht_cap.has_eht = eht_cap_cfg.present; 243 if (hdd_ctx->iftype_data_5g->eht_cap.has_eht && 244 !hdd_ctx->iftype_data_5g->he_cap.has_he) { 245 hdd_debug("5 GHz HE caps not present"); 246 hdd_ctx->iftype_data_5g->eht_cap.has_eht = false; 247 band_5g->n_iftype_data = 1; 248 goto band_6ghz; 249 } 250 251 if (eht_cap_cfg.su_beamformer) 252 phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; 253 254 if (eht_cap_cfg.su_beamformee) 255 phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; 256 257 qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_5g, 258 sizeof(struct ieee80211_supported_band)); 259 260 iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); 261 iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); 262 } 263 264 band_6ghz: 265 hdd_update_wiphy_eht_caps_6ghz(hdd_ctx, eht_cap_cfg); 266 267 hdd_exit(); 268 } 269 270 int hdd_set_11be_rate_code(struct hdd_adapter *adapter, uint16_t rate_code) 271 { 272 uint8_t preamble = 0, nss = 0, rix = 0; 273 int ret; 274 struct sap_config *sap_config = NULL; 275 276 if (adapter->device_mode == QDF_SAP_MODE) 277 sap_config = &adapter->session.ap.sap_config; 278 279 if (!sap_config) { 280 if (!sme_is_feature_supported_by_fw(DOT11BE)) { 281 hdd_err_rl("Target does not support 11be"); 282 return -EIO; 283 } 284 } else if (sap_config->SapHw_mode != eCSR_DOT11_MODE_11be && 285 sap_config->SapHw_mode != eCSR_DOT11_MODE_11be_ONLY) { 286 hdd_err_rl("Invalid hw mode, SAP hw_mode= 0x%x, ch_freq = %d", 287 sap_config->SapHw_mode, sap_config->chan_freq); 288 return -EIO; 289 } 290 291 if ((rate_code >> 8) != WMI_RATE_PREAMBLE_EHT) { 292 hdd_err_rl("Invalid input: %x", rate_code); 293 return -EIO; 294 } 295 296 rix = RC_2_RATE_IDX_11BE(rate_code); 297 preamble = rate_code >> 8; 298 nss = HT_RC_2_STREAMS_11BE(rate_code) + 1; 299 300 hdd_debug("SET_11BE_RATE rate_code %d rix %d preamble %x nss %d", 301 rate_code, rix, preamble, nss); 302 303 ret = wma_cli_set_command(adapter->vdev_id, 304 wmi_vdev_param_fixed_rate, 305 rate_code, VDEV_CMD); 306 307 return ret; 308 } 309 310 /** 311 * hdd_map_eht_gi_to_os() - map txrate_gi to os guard interval 312 * @guard_interval: guard interval get from fw rate 313 * 314 * Return: os guard interval value 315 */ 316 static inline uint8_t hdd_map_eht_gi_to_os(enum txrate_gi guard_interval) 317 { 318 switch (guard_interval) { 319 case TXRATE_GI_0_8_US: 320 return NL80211_RATE_INFO_EHT_GI_0_8; 321 case TXRATE_GI_1_6_US: 322 return NL80211_RATE_INFO_EHT_GI_1_6; 323 case TXRATE_GI_3_2_US: 324 return NL80211_RATE_INFO_EHT_GI_3_2; 325 default: 326 return NL80211_RATE_INFO_EHT_GI_0_8; 327 } 328 } 329 330 /** 331 * wlan_hdd_fill_os_eht_rateflags() - Fill EHT related rate_info 332 * @os_rate: rate info for os 333 * @rate_flags: rate flags 334 * @dcm: dcm from rate 335 * @guard_interval: guard interval from rate 336 * 337 * Return: none 338 */ 339 void wlan_hdd_fill_os_eht_rateflags(struct rate_info *os_rate, 340 enum tx_rate_info rate_flags, 341 uint8_t dcm, 342 enum txrate_gi guard_interval) 343 { 344 /* as fw not yet report ofdma to host, so don't 345 * fill RATE_INFO_BW_EHT_RU. 346 */ 347 if (rate_flags & (TX_RATE_EHT80 | TX_RATE_EHT40 | 348 TX_RATE_EHT20 | TX_RATE_EHT160 | TX_RATE_EHT320)) { 349 if (rate_flags & TX_RATE_EHT320) 350 hdd_set_rate_bw(os_rate, HDD_RATE_BW_320); 351 else if (rate_flags & TX_RATE_EHT160) 352 hdd_set_rate_bw(os_rate, HDD_RATE_BW_160); 353 else if (rate_flags & TX_RATE_EHT80) 354 hdd_set_rate_bw(os_rate, HDD_RATE_BW_80); 355 else if (rate_flags & TX_RATE_EHT40) 356 hdd_set_rate_bw(os_rate, HDD_RATE_BW_40); 357 358 os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; 359 } 360 } 361 362 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER 363 void 364 wlan_hdd_refill_os_eht_rateflags(struct rate_info *os_rate, uint8_t preamble) 365 { 366 if (preamble == DOT11_BE) 367 os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; 368 } 369 370 void 371 wlan_hdd_refill_os_eht_bw(struct rate_info *os_rate, enum rx_tlv_bw bw) 372 { 373 if (bw == RX_TLV_BW_320MHZ) 374 os_rate->bw = RATE_INFO_BW_320; 375 else 376 os_rate->bw = RATE_INFO_BW_20; /* Invalid bw: set 20M */ 377 } 378 #endif 379 #endif 380