File Index
Files and directories
Sign in
FILE

tlc.c

File preview with syntax highlighting.

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