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