xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/tlc.c (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2024-2025 Intel Corporation
4  */
5 
6 #include <net/mac80211.h>
7 
8 #include "tlc.h"
9 #include "hcmd.h"
10 #include "sta.h"
11 #include "phy.h"
12 
13 #include "fw/api/rs.h"
14 #include "fw/api/context.h"
15 #include "fw/api/dhc.h"
16 
iwl_mld_fw_bw_from_sta_bw(const struct ieee80211_link_sta * link_sta)17 static u8 iwl_mld_fw_bw_from_sta_bw(const struct ieee80211_link_sta *link_sta)
18 {
19 	switch (link_sta->bandwidth) {
20 	case IEEE80211_STA_RX_BW_320:
21 		return IWL_TLC_MNG_CH_WIDTH_320MHZ;
22 	case IEEE80211_STA_RX_BW_160:
23 		return IWL_TLC_MNG_CH_WIDTH_160MHZ;
24 	case IEEE80211_STA_RX_BW_80:
25 		return IWL_TLC_MNG_CH_WIDTH_80MHZ;
26 	case IEEE80211_STA_RX_BW_40:
27 		return IWL_TLC_MNG_CH_WIDTH_40MHZ;
28 	case IEEE80211_STA_RX_BW_20:
29 	default:
30 		return IWL_TLC_MNG_CH_WIDTH_20MHZ;
31 	}
32 }
33 
34 static __le16
iwl_mld_get_tlc_cmd_flags(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,const struct ieee80211_sta_he_cap * own_he_cap,const struct ieee80211_sta_eht_cap * own_eht_cap)35 iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld,
36 			  struct ieee80211_vif *vif,
37 			  struct ieee80211_link_sta *link_sta,
38 			  const struct ieee80211_sta_he_cap *own_he_cap,
39 			  const struct ieee80211_sta_eht_cap *own_eht_cap)
40 {
41 	struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
42 	struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
43 	struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
44 	bool has_vht = vht_cap->vht_supported;
45 	u16 flags = 0;
46 
47 	/* STBC flags */
48 	if (mld->cfg->ht_params.stbc &&
49 	    (hweight8(iwl_mld_get_valid_tx_ant(mld)) > 1)) {
50 		if (he_cap->has_he && he_cap->he_cap_elem.phy_cap_info[2] &
51 				      IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
52 			flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
53 		else if (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
54 			flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
55 		else if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)
56 			flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
57 	}
58 
59 	/* LDPC */
60 	if (mld->cfg->ht_params.ldpc &&
61 	    ((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
62 	     (has_vht && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
63 		flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
64 
65 	if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
66 	    IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
67 		flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
68 
69 	if (own_he_cap &&
70 	    !(own_he_cap->he_cap_elem.phy_cap_info[1] &
71 			IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
72 		flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
73 
74 	/* DCM */
75 	if (he_cap->has_he &&
76 	    (he_cap->he_cap_elem.phy_cap_info[3] &
77 	     IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK &&
78 	     own_he_cap &&
79 	     own_he_cap->he_cap_elem.phy_cap_info[3] &
80 			IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK))
81 		flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
82 
83 	/* Extra EHT LTF */
84 	if (own_eht_cap &&
85 	    own_eht_cap->eht_cap_elem.phy_cap_info[5] &
86 		IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF &&
87 	    link_sta->eht_cap.has_eht &&
88 	    link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] &
89 	    IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) {
90 		flags |= IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK;
91 	}
92 
93 	return cpu_to_le16(flags);
94 }
95 
iwl_mld_get_fw_chains(struct iwl_mld * mld)96 static u8 iwl_mld_get_fw_chains(struct iwl_mld *mld)
97 {
98 	u8 chains = iwl_mld_get_valid_tx_ant(mld);
99 	u8 fw_chains = 0;
100 
101 	if (chains & ANT_A)
102 		fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
103 	if (chains & ANT_B)
104 		fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
105 
106 	return fw_chains;
107 }
108 
iwl_mld_get_fw_sgi(struct ieee80211_link_sta * link_sta)109 static u8 iwl_mld_get_fw_sgi(struct ieee80211_link_sta *link_sta)
110 {
111 	struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
112 	struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
113 	struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
114 	u8 sgi_chwidths = 0;
115 
116 	/* If the association supports HE, HT/VHT rates will never be used for
117 	 * Tx and therefor there's no need to set the
118 	 * sgi-per-channel-width-support bits
119 	 */
120 	if (he_cap->has_he)
121 		return 0;
122 
123 	if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
124 		sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ);
125 	if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
126 		sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ);
127 	if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
128 		sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ);
129 	if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
130 		sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ);
131 
132 	return sgi_chwidths;
133 }
134 
135 static int
iwl_mld_get_highest_fw_mcs(const struct ieee80211_sta_vht_cap * vht_cap,int nss)136 iwl_mld_get_highest_fw_mcs(const struct ieee80211_sta_vht_cap *vht_cap,
137 			   int nss)
138 {
139 	u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
140 		(0x3 << (2 * (nss - 1)));
141 	rx_mcs >>= (2 * (nss - 1));
142 
143 	switch (rx_mcs) {
144 	case IEEE80211_VHT_MCS_SUPPORT_0_7:
145 		return IWL_TLC_MNG_HT_RATE_MCS7;
146 	case IEEE80211_VHT_MCS_SUPPORT_0_8:
147 		return IWL_TLC_MNG_HT_RATE_MCS8;
148 	case IEEE80211_VHT_MCS_SUPPORT_0_9:
149 		return IWL_TLC_MNG_HT_RATE_MCS9;
150 	default:
151 		WARN_ON_ONCE(1);
152 		break;
153 	}
154 
155 	return 0;
156 }
157 
158 static void
iwl_mld_fill_vht_rates(const struct ieee80211_link_sta * link_sta,const struct ieee80211_sta_vht_cap * vht_cap,struct iwl_tlc_config_cmd * cmd)159 iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta,
160 		       const struct ieee80211_sta_vht_cap *vht_cap,
161 		       struct iwl_tlc_config_cmd *cmd)
162 {
163 	u32 supp;
164 	int i, highest_mcs;
165 	u8 max_nss = link_sta->rx_nss;
166 	struct ieee80211_vht_cap ieee_vht_cap = {
167 		.vht_cap_info = cpu_to_le32(vht_cap->cap),
168 		.supp_mcs = vht_cap->vht_mcs,
169 	};
170 
171 	/* the station support only a single receive chain */
172 	if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
173 		max_nss = 1;
174 
175 	for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
176 		int nss = i + 1;
177 
178 		highest_mcs = iwl_mld_get_highest_fw_mcs(vht_cap, nss);
179 		if (!highest_mcs)
180 			continue;
181 
182 		supp = BIT(highest_mcs + 1) - 1;
183 		if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
184 			supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
185 
186 		cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le32(supp);
187 		/* Check if VHT extended NSS indicates that the bandwidth/NSS
188 		 * configuration is supported - only for MCS 0 since we already
189 		 * decoded the MCS bits anyway ourselves.
190 		 */
191 		if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160 &&
192 		    ieee80211_get_vht_max_nss(&ieee_vht_cap,
193 					      IEEE80211_VHT_CHANWIDTH_160MHZ,
194 					      0, true, nss) >= nss)
195 			cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
196 				cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80];
197 	}
198 }
199 
iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs)200 static u32 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs)
201 {
202 	switch (mcs) {
203 	case IEEE80211_HE_MCS_SUPPORT_0_7:
204 		return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1;
205 	case IEEE80211_HE_MCS_SUPPORT_0_9:
206 		return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1;
207 	case IEEE80211_HE_MCS_SUPPORT_0_11:
208 		return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1;
209 	case IEEE80211_HE_MCS_NOT_SUPPORTED:
210 		return 0;
211 	}
212 
213 	WARN(1, "invalid HE MCS %d\n", mcs);
214 	return 0;
215 }
216 
217 static void
iwl_mld_fill_he_rates(const struct ieee80211_link_sta * link_sta,const struct ieee80211_sta_he_cap * own_he_cap,struct iwl_tlc_config_cmd * cmd)218 iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta,
219 		      const struct ieee80211_sta_he_cap *own_he_cap,
220 		      struct iwl_tlc_config_cmd *cmd)
221 {
222 	const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
223 	u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
224 	u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
225 	u16 tx_mcs_80 = le16_to_cpu(own_he_cap->he_mcs_nss_supp.tx_mcs_80);
226 	u16 tx_mcs_160 = le16_to_cpu(own_he_cap->he_mcs_nss_supp.tx_mcs_160);
227 	int i;
228 	u8 nss = link_sta->rx_nss;
229 
230 	/* the station support only a single receive chain */
231 	if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
232 		nss = 1;
233 
234 	for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
235 		u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3;
236 		u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3;
237 		u16 _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3;
238 		u16 _tx_mcs_80 = (tx_mcs_80 >> (2 * i)) & 0x3;
239 
240 		/* If one side doesn't support - mark both as not supporting */
241 		if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
242 		    _tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
243 			_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
244 			_tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
245 		}
246 		if (_mcs_80 > _tx_mcs_80)
247 			_mcs_80 = _tx_mcs_80;
248 		cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] =
249 			cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80));
250 
251 		/* If one side doesn't support - mark both as not supporting */
252 		if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
253 		    _tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
254 			_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
255 			_tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
256 		}
257 		if (_mcs_160 > _tx_mcs_160)
258 			_mcs_160 = _tx_mcs_160;
259 		cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
260 			cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160));
261 	}
262 }
263 
iwl_mld_set_eht_mcs(__le32 ht_rates[][3],enum IWL_TLC_MCS_PER_BW bw,u8 max_nss,u32 mcs_msk)264 static void iwl_mld_set_eht_mcs(__le32 ht_rates[][3],
265 				enum IWL_TLC_MCS_PER_BW bw,
266 				u8 max_nss, u32 mcs_msk)
267 {
268 	if (max_nss >= 2)
269 		ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le32(mcs_msk);
270 
271 	if (max_nss >= 1)
272 		ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le32(mcs_msk);
273 }
274 
275 static const
276 struct ieee80211_eht_mcs_nss_supp_bw *
iwl_mld_get_eht_mcs_of_bw(enum IWL_TLC_MCS_PER_BW bw,const struct ieee80211_eht_mcs_nss_supp * eht_mcs)277 iwl_mld_get_eht_mcs_of_bw(enum IWL_TLC_MCS_PER_BW bw,
278 			  const struct ieee80211_eht_mcs_nss_supp *eht_mcs)
279 {
280 	switch (bw) {
281 	case IWL_TLC_MCS_PER_BW_80:
282 		return &eht_mcs->bw._80;
283 	case IWL_TLC_MCS_PER_BW_160:
284 		return &eht_mcs->bw._160;
285 	case IWL_TLC_MCS_PER_BW_320:
286 		return &eht_mcs->bw._320;
287 	default:
288 		return NULL;
289 	}
290 }
291 
iwl_mld_get_eht_max_nss(u8 rx_nss,u8 tx_nss)292 static u8 iwl_mld_get_eht_max_nss(u8 rx_nss, u8 tx_nss)
293 {
294 	u8 tx = u8_get_bits(tx_nss, IEEE80211_EHT_MCS_NSS_TX);
295 	u8 rx = u8_get_bits(rx_nss, IEEE80211_EHT_MCS_NSS_RX);
296 	/* the max nss that can be used,
297 	 * is the min with our tx capa and the peer rx capa.
298 	 */
299 	return min(tx, rx);
300 }
301 
302 #define MAX_NSS_MCS(mcs_num, rx, tx) \
303 	iwl_mld_get_eht_max_nss((rx)->rx_tx_mcs ##mcs_num## _max_nss, \
304 				(tx)->rx_tx_mcs ##mcs_num## _max_nss)
305 
306 static void
iwl_mld_fill_eht_rates(struct ieee80211_vif * vif,const struct ieee80211_link_sta * link_sta,const struct ieee80211_sta_he_cap * own_he_cap,const struct ieee80211_sta_eht_cap * own_eht_cap,struct iwl_tlc_config_cmd * cmd)307 iwl_mld_fill_eht_rates(struct ieee80211_vif *vif,
308 		       const struct ieee80211_link_sta *link_sta,
309 		       const struct ieee80211_sta_he_cap *own_he_cap,
310 		       const struct ieee80211_sta_eht_cap *own_eht_cap,
311 		       struct iwl_tlc_config_cmd *cmd)
312 {
313 	/* peer RX mcs capa */
314 	const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs =
315 		&link_sta->eht_cap.eht_mcs_nss_supp;
316 	/* our TX mcs capa */
317 	const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs =
318 		&own_eht_cap->eht_mcs_nss_supp;
319 
320 	enum IWL_TLC_MCS_PER_BW bw;
321 	struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20;
322 	struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_tx_20;
323 
324 	/* peer is 20 MHz only */
325 	if (vif->type == NL80211_IFTYPE_AP &&
326 	    !(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
327 	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
328 		mcs_rx_20 = eht_rx_mcs->only_20mhz;
329 	} else {
330 		mcs_rx_20.rx_tx_mcs7_max_nss =
331 			eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss;
332 		mcs_rx_20.rx_tx_mcs9_max_nss =
333 			eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss;
334 		mcs_rx_20.rx_tx_mcs11_max_nss =
335 			eht_rx_mcs->bw._80.rx_tx_mcs11_max_nss;
336 		mcs_rx_20.rx_tx_mcs13_max_nss =
337 			eht_rx_mcs->bw._80.rx_tx_mcs13_max_nss;
338 	}
339 
340 	/* NIC is capable of 20 MHz only */
341 	if (!(own_he_cap->he_cap_elem.phy_cap_info[0] &
342 	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
343 		mcs_tx_20 = eht_tx_mcs->only_20mhz;
344 	} else {
345 		mcs_tx_20.rx_tx_mcs7_max_nss =
346 			eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss;
347 		mcs_tx_20.rx_tx_mcs9_max_nss =
348 			eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss;
349 		mcs_tx_20.rx_tx_mcs11_max_nss =
350 			eht_tx_mcs->bw._80.rx_tx_mcs11_max_nss;
351 		mcs_tx_20.rx_tx_mcs13_max_nss =
352 			eht_tx_mcs->bw._80.rx_tx_mcs13_max_nss;
353 	}
354 
355 	/* rates for 20/40/80 MHz */
356 	bw = IWL_TLC_MCS_PER_BW_80;
357 	iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
358 			    MAX_NSS_MCS(7, &mcs_rx_20, &mcs_tx_20),
359 			    GENMASK(7, 0));
360 	iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
361 			    MAX_NSS_MCS(9, &mcs_rx_20, &mcs_tx_20),
362 			    GENMASK(9, 8));
363 	iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
364 			    MAX_NSS_MCS(11, &mcs_rx_20, &mcs_tx_20),
365 			    GENMASK(11, 10));
366 	iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
367 			    MAX_NSS_MCS(13, &mcs_rx_20, &mcs_tx_20),
368 			    GENMASK(13, 12));
369 
370 	/* rates for 160/320 MHz */
371 	for (bw = IWL_TLC_MCS_PER_BW_160; bw <= IWL_TLC_MCS_PER_BW_320; bw++) {
372 		const struct ieee80211_eht_mcs_nss_supp_bw *mcs_rx =
373 			iwl_mld_get_eht_mcs_of_bw(bw, eht_rx_mcs);
374 		const struct ieee80211_eht_mcs_nss_supp_bw *mcs_tx =
375 			iwl_mld_get_eht_mcs_of_bw(bw, eht_tx_mcs);
376 
377 		/* got unsupported index for bw */
378 		if (!mcs_rx || !mcs_tx)
379 			continue;
380 
381 		/* break out if we don't support the bandwidth */
382 		if (cmd->max_ch_width < (bw + IWL_TLC_MNG_CH_WIDTH_80MHZ))
383 			break;
384 
385 		iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
386 				    MAX_NSS_MCS(9, mcs_rx, mcs_tx),
387 				    GENMASK(9, 0));
388 		iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
389 				    MAX_NSS_MCS(11, mcs_rx, mcs_tx),
390 				    GENMASK(11, 10));
391 		iwl_mld_set_eht_mcs(cmd->ht_rates, bw,
392 				    MAX_NSS_MCS(13, mcs_rx, mcs_tx),
393 				    GENMASK(13, 12));
394 	}
395 
396 	/* the station support only a single receive chain */
397 	if (link_sta->smps_mode == IEEE80211_SMPS_STATIC ||
398 	    link_sta->rx_nss < 2)
399 		memset(cmd->ht_rates[IWL_TLC_NSS_2], 0,
400 		       sizeof(cmd->ht_rates[IWL_TLC_NSS_2]));
401 }
402 
403 static void
iwl_mld_fill_supp_rates(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,struct ieee80211_supported_band * sband,const struct ieee80211_sta_he_cap * own_he_cap,const struct ieee80211_sta_eht_cap * own_eht_cap,struct iwl_tlc_config_cmd * cmd)404 iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif,
405 			struct ieee80211_link_sta *link_sta,
406 			struct ieee80211_supported_band *sband,
407 			const struct ieee80211_sta_he_cap *own_he_cap,
408 			const struct ieee80211_sta_eht_cap *own_eht_cap,
409 			struct iwl_tlc_config_cmd *cmd)
410 {
411 	int i;
412 	u16 non_ht_rates = 0;
413 	unsigned long rates_bitmap;
414 	const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
415 	const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
416 	const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
417 
418 	/* non HT rates */
419 	rates_bitmap = link_sta->supp_rates[sband->band];
420 	for_each_set_bit(i, &rates_bitmap, BITS_PER_LONG)
421 		non_ht_rates |= BIT(sband->bitrates[i].hw_value);
422 
423 	cmd->non_ht_rates = cpu_to_le16(non_ht_rates);
424 	cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
425 
426 	if (link_sta->eht_cap.has_eht && own_he_cap && own_eht_cap) {
427 		cmd->mode = IWL_TLC_MNG_MODE_EHT;
428 		iwl_mld_fill_eht_rates(vif, link_sta, own_he_cap,
429 				       own_eht_cap, cmd);
430 	} else if (he_cap->has_he && own_he_cap) {
431 		cmd->mode = IWL_TLC_MNG_MODE_HE;
432 		iwl_mld_fill_he_rates(link_sta, own_he_cap, cmd);
433 	} else if (vht_cap->vht_supported) {
434 		cmd->mode = IWL_TLC_MNG_MODE_VHT;
435 		iwl_mld_fill_vht_rates(link_sta, vht_cap, cmd);
436 	} else if (ht_cap->ht_supported) {
437 		cmd->mode = IWL_TLC_MNG_MODE_HT;
438 		cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
439 			cpu_to_le32(ht_cap->mcs.rx_mask[0]);
440 
441 		/* the station support only a single receive chain */
442 		if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
443 			cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
444 				0;
445 		else
446 			cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
447 				cpu_to_le32(ht_cap->mcs.rx_mask[1]);
448 	}
449 }
450 
iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd * cmd,struct iwl_tlc_config_cmd_v5 * cmd_v5)451 static int iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd *cmd,
452 					 struct iwl_tlc_config_cmd_v5 *cmd_v5)
453 {
454 	if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
455 		return -EINVAL;
456 
457 	/* Convert sta_mask to sta_id */
458 	cmd_v5->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
459 
460 	/* Copy all the rest */
461 	cmd_v5->max_ch_width = cmd->max_ch_width;
462 	cmd_v5->mode = cmd->mode;
463 	cmd_v5->chains = cmd->chains;
464 	cmd_v5->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
465 	cmd_v5->flags = cmd->flags;
466 	cmd_v5->non_ht_rates = cmd->non_ht_rates;
467 
468 	BUILD_BUG_ON(sizeof(cmd_v5->ht_rates) != sizeof(cmd->ht_rates));
469 	memcpy(cmd_v5->ht_rates, cmd->ht_rates, sizeof(cmd->ht_rates));
470 
471 	cmd_v5->max_mpdu_len = cmd->max_mpdu_len;
472 	cmd_v5->max_tx_op = cmd->max_tx_op;
473 
474 	return 0;
475 }
476 
iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd * cmd,struct iwl_tlc_config_cmd_v4 * cmd_v4)477 static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
478 					 struct iwl_tlc_config_cmd_v4 *cmd_v4)
479 {
480 	if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
481 		return -EINVAL;
482 
483 	/* Convert sta_mask to sta_id */
484 	cmd_v4->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
485 
486 	/* Copy everything until ht_rates */
487 	cmd_v4->max_ch_width = cmd->max_ch_width;
488 	cmd_v4->mode = cmd->mode;
489 	cmd_v4->chains = cmd->chains;
490 	cmd_v4->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
491 	cmd_v4->flags = cmd->flags;
492 	cmd_v4->non_ht_rates = cmd->non_ht_rates;
493 
494 	/* Convert ht_rates from __le32 to __le16 */
495 	BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates));
496 	BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates[0]) != ARRAY_SIZE(cmd->ht_rates[0]));
497 
498 	for (int nss = 0; nss < ARRAY_SIZE(cmd->ht_rates); nss++)
499 		for (int bw = 0; bw < ARRAY_SIZE(cmd->ht_rates[nss]); bw++)
500 			cmd_v4->ht_rates[nss][bw] =
501 				cpu_to_le16(le32_to_cpu(cmd->ht_rates[nss][bw]));
502 
503 	/* Copy the rest */
504 	cmd_v4->max_mpdu_len = cmd->max_mpdu_len;
505 	cmd_v4->max_tx_op = cmd->max_tx_op;
506 
507 	return 0;
508 }
509 
iwl_mld_send_tlc_cmd(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,struct ieee80211_bss_conf * link)510 static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
511 				 struct ieee80211_vif *vif,
512 				 struct ieee80211_link_sta *link_sta,
513 				 struct ieee80211_bss_conf *link)
514 {
515 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
516 	enum nl80211_band band = link->chanreq.oper.chan->band;
517 	struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band];
518 	const struct ieee80211_sta_he_cap *own_he_cap =
519 		ieee80211_get_he_iftype_cap_vif(sband, vif);
520 	const struct ieee80211_sta_eht_cap *own_eht_cap =
521 		ieee80211_get_eht_iftype_cap_vif(sband, vif);
522 	struct iwl_tlc_config_cmd cmd = {
523 		/* For AP mode, use 20 MHz until the STA is authorized */
524 		.max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ?
525 			iwl_mld_fw_bw_from_sta_bw(link_sta) :
526 			IWL_TLC_MNG_CH_WIDTH_20MHZ,
527 		.flags = iwl_mld_get_tlc_cmd_flags(mld, vif, link_sta,
528 						   own_he_cap, own_eht_cap),
529 		.chains = iwl_mld_get_fw_chains(mld),
530 		.sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta),
531 		.max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len),
532 	};
533 	int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
534 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
535 	u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
536 	struct ieee80211_chanctx_conf *chan_ctx;
537 	struct iwl_tlc_config_cmd_v5 cmd_v5 = {};
538 	struct iwl_tlc_config_cmd_v4 cmd_v4 = {};
539 	void *cmd_ptr;
540 	u8 cmd_size;
541 	u32 phy_id;
542 	int ret;
543 
544 	if (fw_sta_id < 0)
545 		return;
546 
547 	cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id));
548 
549 	chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf);
550 	if (WARN_ON(!chan_ctx))
551 		return;
552 
553 	phy_id = iwl_mld_phy_from_mac80211(chan_ctx)->fw_id;
554 	cmd.phy_id = cpu_to_le32(phy_id);
555 
556 	iwl_mld_fill_supp_rates(mld, vif, link_sta, sband,
557 				own_he_cap, own_eht_cap,
558 				&cmd);
559 
560 	if (cmd_ver == 6) {
561 		cmd_ptr = &cmd;
562 		cmd_size = sizeof(cmd);
563 	} else if (cmd_ver == 5) {
564 		/* TODO: remove support once FW moves to version 6 */
565 		ret = iwl_mld_convert_tlc_cmd_to_v5(&cmd, &cmd_v5);
566 		if (ret)
567 			return;
568 		cmd_ptr = &cmd_v5;
569 		cmd_size = sizeof(cmd_v5);
570 	} else if (cmd_ver == 4) {
571 		ret = iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4);
572 		if (ret)
573 			return;
574 		cmd_ptr = &cmd_v4;
575 		cmd_size = sizeof(cmd_v4);
576 	} else {
577 		IWL_ERR(mld, "Unsupported TLC config cmd version %d\n",
578 			cmd_ver);
579 		return;
580 	}
581 
582 	IWL_DEBUG_RATE(mld,
583 		       "TLC CONFIG CMD, sta_mask=0x%x, max_ch_width=%d, mode=%d, phy_id=%d\n",
584 		       le32_to_cpu(cmd.sta_mask), cmd.max_ch_width, cmd.mode,
585 		       le32_to_cpu(cmd.phy_id));
586 
587 	/* Send async since this can be called within a RCU-read section */
588 	ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr,
589 					      cmd_size);
590 	if (ret)
591 		IWL_ERR(mld, "Failed to send TLC cmd (%d)\n", ret);
592 }
593 
iwl_mld_send_tlc_dhc(struct iwl_mld * mld,u8 sta_id,u32 type,u32 data)594 int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data)
595 {
596 	struct {
597 		struct iwl_dhc_cmd dhc;
598 		struct iwl_dhc_tlc_cmd tlc;
599 	} __packed cmd = {
600 		.tlc.sta_id = sta_id,
601 		.tlc.type = cpu_to_le32(type),
602 		.tlc.data[0] = cpu_to_le32(data),
603 		.dhc.length = cpu_to_le32(sizeof(cmd.tlc) >> 2),
604 		.dhc.index_and_mask =
605 			cpu_to_le32(DHC_TABLE_INTEGRATION | DHC_TARGET_UMAC |
606 				    DHC_INTEGRATION_TLC_DEBUG_CONFIG),
607 	};
608 	int ret;
609 
610 	ret = iwl_mld_send_cmd_with_flags_pdu(mld,
611 					      WIDE_ID(IWL_ALWAYS_LONG_GROUP,
612 						      DEBUG_HOST_COMMAND),
613 					      CMD_ASYNC, &cmd);
614 	IWL_DEBUG_RATE(mld, "sta_id %d, type: 0x%X, value: 0x%X, ret%d\n",
615 		       sta_id, type, data, ret);
616 	return ret;
617 }
618 
iwl_mld_config_tlc_link(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct ieee80211_link_sta * link_sta)619 void iwl_mld_config_tlc_link(struct iwl_mld *mld,
620 			     struct ieee80211_vif *vif,
621 			     struct ieee80211_bss_conf *link_conf,
622 			     struct ieee80211_link_sta *link_sta)
623 {
624 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
625 
626 	if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan))
627 		return;
628 
629 	/* Before we have information about a station, configure the A-MSDU RC
630 	 * limit such that iwlmd and mac80211 would not be allowed to build
631 	 * A-MSDUs.
632 	 */
633 	if (mld_sta->sta_state < IEEE80211_STA_ASSOC) {
634 		link_sta->agg.max_rc_amsdu_len = 1;
635 		ieee80211_sta_recalc_aggregates(link_sta->sta);
636 	}
637 
638 	iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf);
639 }
640 
iwl_mld_config_tlc(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta)641 void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
642 			struct ieee80211_sta *sta)
643 {
644 	struct ieee80211_bss_conf *link;
645 	int link_id;
646 
647 	lockdep_assert_wiphy(mld->wiphy);
648 
649 	for_each_vif_active_link(vif, link, link_id) {
650 		struct ieee80211_link_sta *link_sta =
651 			link_sta_dereference_check(sta, link_id);
652 
653 		if (!link || !link_sta)
654 			continue;
655 
656 		iwl_mld_config_tlc_link(mld, vif, link, link_sta);
657 	}
658 }
659 
660 static u16
iwl_mld_get_amsdu_size_of_tid(struct iwl_mld * mld,struct ieee80211_link_sta * link_sta,unsigned int tid)661 iwl_mld_get_amsdu_size_of_tid(struct iwl_mld *mld,
662 			      struct ieee80211_link_sta *link_sta,
663 			      unsigned int tid)
664 {
665 	struct ieee80211_sta *sta = link_sta->sta;
666 	struct ieee80211_vif *vif = iwl_mld_sta_from_mac80211(sta)->vif;
667 	const u8 tid_to_mac80211_ac[] = {
668 		IEEE80211_AC_BE,
669 		IEEE80211_AC_BK,
670 		IEEE80211_AC_BK,
671 		IEEE80211_AC_BE,
672 		IEEE80211_AC_VI,
673 		IEEE80211_AC_VI,
674 		IEEE80211_AC_VO,
675 		IEEE80211_AC_VO,
676 	};
677 	unsigned int result = link_sta->agg.max_rc_amsdu_len;
678 	u8 ac, txf, lmac;
679 
680 	lockdep_assert_wiphy(mld->wiphy);
681 
682 	/* Don't send an AMSDU that will be longer than the TXF.
683 	 * Add a security margin of 256 for the TX command + headers.
684 	 * We also want to have the start of the next packet inside the
685 	 * fifo to be able to send bursts.
686 	 */
687 
688 	if (WARN_ON(tid >= ARRAY_SIZE(tid_to_mac80211_ac)))
689 		return 0;
690 
691 	ac = tid_to_mac80211_ac[tid];
692 
693 	/* For HE redirect to trigger based fifos */
694 	if (link_sta->he_cap.has_he)
695 		ac += 4;
696 
697 	txf = iwl_mld_mac80211_ac_to_fw_tx_fifo(ac);
698 
699 	/* Only one link: take the lmac according to the band */
700 	if (hweight16(sta->valid_links) <= 1) {
701 		enum nl80211_band band;
702 		struct ieee80211_bss_conf *link =
703 			wiphy_dereference(mld->wiphy,
704 					  vif->link_conf[link_sta->link_id]);
705 
706 		if (WARN_ON(!link || !link->chanreq.oper.chan))
707 			band = NL80211_BAND_2GHZ;
708 		else
709 			band = link->chanreq.oper.chan->band;
710 		lmac = iwl_mld_get_lmac_id(mld, band);
711 
712 	/* More than one link but with 2 lmacs: take the minimum */
713 	} else if (fw_has_capa(&mld->fw->ucode_capa,
714 			       IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
715 		lmac = IWL_LMAC_5G_INDEX;
716 		result = min_t(unsigned int, result,
717 			       mld->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
718 		lmac = IWL_LMAC_24G_INDEX;
719 	/* More than one link but only one lmac */
720 	} else {
721 		lmac = IWL_LMAC_24G_INDEX;
722 	}
723 
724 	return min_t(unsigned int, result,
725 		     mld->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
726 }
727 
iwl_mld_handle_tlc_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)728 void iwl_mld_handle_tlc_notif(struct iwl_mld *mld,
729 			      struct iwl_rx_packet *pkt)
730 {
731 	struct iwl_tlc_update_notif *notif = (void *)pkt->data;
732 	struct ieee80211_link_sta *link_sta;
733 	u32 flags = le32_to_cpu(notif->flags);
734 	u32 enabled;
735 	u16 size;
736 
737 	if (IWL_FW_CHECK(mld, notif->sta_id >= mld->fw->ucode_capa.num_stations,
738 			 "Invalid sta id (%d) in TLC notification\n",
739 			 notif->sta_id))
740 		return;
741 
742 	link_sta = wiphy_dereference(mld->wiphy,
743 				     mld->fw_id_to_link_sta[notif->sta_id]);
744 
745 	if (WARN(IS_ERR_OR_NULL(link_sta),
746 		 "link_sta of sta id (%d) doesn't exist\n", notif->sta_id))
747 		return;
748 
749 	if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
750 		struct iwl_mld_link_sta *mld_link_sta =
751 			iwl_mld_link_sta_from_mac80211(link_sta);
752 		char pretty_rate[100];
753 
754 		if (WARN_ON(!mld_link_sta))
755 			return;
756 
757 		mld_link_sta->last_rate_n_flags =
758 			iwl_v3_rate_from_v2_v3(notif->rate,
759 					       mld->fw_rates_ver_3);
760 
761 		rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
762 				     mld_link_sta->last_rate_n_flags);
763 		IWL_DEBUG_RATE(mld, "TLC notif: new rate = %s\n", pretty_rate);
764 	}
765 
766 	/* We are done processing the notif */
767 	if (!(flags & IWL_TLC_NOTIF_FLAG_AMSDU))
768 		return;
769 
770 	enabled = le32_to_cpu(notif->amsdu_enabled);
771 	size = le32_to_cpu(notif->amsdu_size);
772 
773 	if (size < 2000) {
774 		size = 0;
775 		enabled = 0;
776 	}
777 
778 	if (IWL_FW_CHECK(mld, size > link_sta->agg.max_amsdu_len,
779 			 "Invalid AMSDU len in TLC notif: %d (Max AMSDU len: %d)\n",
780 			 size, link_sta->agg.max_amsdu_len))
781 		return;
782 
783 	link_sta->agg.max_rc_amsdu_len = size;
784 
785 	for (int i = 0; i < IWL_MAX_TID_COUNT; i++) {
786 		if (enabled & BIT(i))
787 			link_sta->agg.max_tid_amsdu_len[i] =
788 				iwl_mld_get_amsdu_size_of_tid(mld, link_sta, i);
789 		else
790 			link_sta->agg.max_tid_amsdu_len[i] = 1;
791 	}
792 
793 	ieee80211_sta_recalc_aggregates(link_sta->sta);
794 
795 	IWL_DEBUG_RATE(mld,
796 		       "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
797 		       le32_to_cpu(notif->amsdu_size), size, enabled);
798 }
799