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