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
iwl_mld_fw_bw_from_sta_bw(const struct ieee80211_link_sta * link_sta)16 static 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
33 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)34 iwl_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
iwl_mld_get_fw_chains(struct iwl_mld * mld)95 static 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
iwl_mld_get_fw_sgi(struct ieee80211_link_sta * link_sta)108 static 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
134 static int
iwl_mld_get_highest_fw_mcs(const struct ieee80211_sta_vht_cap * vht_cap,int nss)135 iwl_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
157 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_v4 * cmd)158 iwl_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_v4 *cmd)
161 {
162 u16 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_le16(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
iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs)199 static u16 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
216 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_v4 * cmd)217 iwl_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_v4 *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_le16(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_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160));
260 }
261 }
262
iwl_mld_set_eht_mcs(__le16 ht_rates[][3],enum IWL_TLC_MCS_PER_BW bw,u8 max_nss,u16 mcs_msk)263 static void iwl_mld_set_eht_mcs(__le16 ht_rates[][3],
264 enum IWL_TLC_MCS_PER_BW bw,
265 u8 max_nss, u16 mcs_msk)
266 {
267 if (max_nss >= 2)
268 ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le16(mcs_msk);
269
270 if (max_nss >= 1)
271 ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le16(mcs_msk);
272 }
273
274 static const
275 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)276 iwl_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
iwl_mld_get_eht_max_nss(u8 rx_nss,u8 tx_nss)291 static 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
305 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_v4 * cmd)306 iwl_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_v4 *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
402 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_v4 * cmd)403 iwl_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_v4 *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_le16(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_le16(ht_cap->mcs.rx_mask[1]);
447 }
448 }
449
iwl_mld_send_tlc_cmd(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,enum nl80211_band band)450 static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
451 struct ieee80211_vif *vif,
452 struct ieee80211_link_sta *link_sta,
453 enum nl80211_band band)
454 {
455 struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
456 struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band];
457 const struct ieee80211_sta_he_cap *own_he_cap =
458 ieee80211_get_he_iftype_cap_vif(sband, vif);
459 const struct ieee80211_sta_eht_cap *own_eht_cap =
460 ieee80211_get_eht_iftype_cap_vif(sband, vif);
461 struct iwl_tlc_config_cmd_v4 cmd = {
462 /* For AP mode, use 20 MHz until the STA is authorized */
463 .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ?
464 iwl_mld_fw_bw_from_sta_bw(link_sta) :
465 IWL_TLC_MNG_CH_WIDTH_20MHZ,
466 .flags = iwl_mld_get_tlc_cmd_flags(mld, vif, link_sta,
467 own_he_cap, own_eht_cap),
468 .chains = iwl_mld_get_fw_chains(mld),
469 .sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta),
470 .max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len),
471 };
472 int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
473 int ret;
474
475 if (fw_sta_id < 0)
476 return;
477
478 cmd.sta_id = fw_sta_id;
479
480 iwl_mld_fill_supp_rates(mld, vif, link_sta, sband,
481 own_he_cap, own_eht_cap,
482 &cmd);
483
484 IWL_DEBUG_RATE(mld,
485 "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n",
486 cmd.sta_id, cmd.max_ch_width, cmd.mode);
487
488 /* Send async since this can be called within a RCU-read section */
489 ret = iwl_mld_send_cmd_with_flags_pdu(mld, WIDE_ID(DATA_PATH_GROUP,
490 TLC_MNG_CONFIG_CMD),
491 CMD_ASYNC, &cmd);
492 if (ret)
493 IWL_ERR(mld, "Failed to send TLC cmd (%d)\n", ret);
494 }
495
iwl_mld_send_tlc_dhc(struct iwl_mld * mld,u8 sta_id,u32 type,u32 data)496 int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data)
497 {
498 struct {
499 struct iwl_dhc_cmd dhc;
500 struct iwl_dhc_tlc_cmd tlc;
501 } __packed cmd = {
502 .tlc.sta_id = sta_id,
503 .tlc.type = cpu_to_le32(type),
504 .tlc.data[0] = cpu_to_le32(data),
505 .dhc.length = cpu_to_le32(sizeof(cmd.tlc) >> 2),
506 .dhc.index_and_mask =
507 cpu_to_le32(DHC_TABLE_INTEGRATION | DHC_TARGET_UMAC |
508 DHC_INTEGRATION_TLC_DEBUG_CONFIG),
509 };
510 int ret;
511
512 ret = iwl_mld_send_cmd_with_flags_pdu(mld,
513 WIDE_ID(IWL_ALWAYS_LONG_GROUP,
514 DEBUG_HOST_COMMAND),
515 CMD_ASYNC, &cmd);
516 IWL_DEBUG_RATE(mld, "sta_id %d, type: 0x%X, value: 0x%X, ret%d\n",
517 sta_id, type, data, ret);
518 return ret;
519 }
520
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)521 void iwl_mld_config_tlc_link(struct iwl_mld *mld,
522 struct ieee80211_vif *vif,
523 struct ieee80211_bss_conf *link_conf,
524 struct ieee80211_link_sta *link_sta)
525 {
526 struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
527 enum nl80211_band band;
528
529 if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan))
530 return;
531
532 /* Before we have information about a station, configure the A-MSDU RC
533 * limit such that iwlmd and mac80211 would not be allowed to build
534 * A-MSDUs.
535 */
536 if (mld_sta->sta_state < IEEE80211_STA_ASSOC) {
537 link_sta->agg.max_rc_amsdu_len = 1;
538 ieee80211_sta_recalc_aggregates(link_sta->sta);
539 }
540
541 band = link_conf->chanreq.oper.chan->band;
542 iwl_mld_send_tlc_cmd(mld, vif, link_sta, band);
543 }
544
iwl_mld_config_tlc(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta)545 void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
546 struct ieee80211_sta *sta)
547 {
548 struct ieee80211_bss_conf *link;
549 int link_id;
550
551 lockdep_assert_wiphy(mld->wiphy);
552
553 for_each_vif_active_link(vif, link, link_id) {
554 struct ieee80211_link_sta *link_sta =
555 link_sta_dereference_check(sta, link_id);
556
557 if (!link || !link_sta)
558 continue;
559
560 iwl_mld_config_tlc_link(mld, vif, link, link_sta);
561 }
562 }
563
564 static u16
iwl_mld_get_amsdu_size_of_tid(struct iwl_mld * mld,struct ieee80211_link_sta * link_sta,unsigned int tid)565 iwl_mld_get_amsdu_size_of_tid(struct iwl_mld *mld,
566 struct ieee80211_link_sta *link_sta,
567 unsigned int tid)
568 {
569 struct ieee80211_sta *sta = link_sta->sta;
570 struct ieee80211_vif *vif = iwl_mld_sta_from_mac80211(sta)->vif;
571 const u8 tid_to_mac80211_ac[] = {
572 IEEE80211_AC_BE,
573 IEEE80211_AC_BK,
574 IEEE80211_AC_BK,
575 IEEE80211_AC_BE,
576 IEEE80211_AC_VI,
577 IEEE80211_AC_VI,
578 IEEE80211_AC_VO,
579 IEEE80211_AC_VO,
580 };
581 unsigned int result = link_sta->agg.max_rc_amsdu_len;
582 u8 ac, txf, lmac;
583
584 lockdep_assert_wiphy(mld->wiphy);
585
586 /* Don't send an AMSDU that will be longer than the TXF.
587 * Add a security margin of 256 for the TX command + headers.
588 * We also want to have the start of the next packet inside the
589 * fifo to be able to send bursts.
590 */
591
592 if (WARN_ON(tid >= ARRAY_SIZE(tid_to_mac80211_ac)))
593 return 0;
594
595 ac = tid_to_mac80211_ac[tid];
596
597 /* For HE redirect to trigger based fifos */
598 if (link_sta->he_cap.has_he)
599 ac += 4;
600
601 txf = iwl_mld_mac80211_ac_to_fw_tx_fifo(ac);
602
603 /* Only one link: take the lmac according to the band */
604 if (hweight16(sta->valid_links) <= 1) {
605 enum nl80211_band band;
606 struct ieee80211_bss_conf *link =
607 wiphy_dereference(mld->wiphy,
608 vif->link_conf[link_sta->link_id]);
609
610 if (WARN_ON(!link || !link->chanreq.oper.chan))
611 band = NL80211_BAND_2GHZ;
612 else
613 band = link->chanreq.oper.chan->band;
614 lmac = iwl_mld_get_lmac_id(mld, band);
615
616 /* More than one link but with 2 lmacs: take the minimum */
617 } else if (fw_has_capa(&mld->fw->ucode_capa,
618 IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
619 lmac = IWL_LMAC_5G_INDEX;
620 result = min_t(unsigned int, result,
621 mld->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
622 lmac = IWL_LMAC_24G_INDEX;
623 /* More than one link but only one lmac */
624 } else {
625 lmac = IWL_LMAC_24G_INDEX;
626 }
627
628 return min_t(unsigned int, result,
629 mld->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
630 }
631
iwl_mld_handle_tlc_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)632 void iwl_mld_handle_tlc_notif(struct iwl_mld *mld,
633 struct iwl_rx_packet *pkt)
634 {
635 struct iwl_tlc_update_notif *notif = (void *)pkt->data;
636 struct ieee80211_link_sta *link_sta;
637 u32 flags = le32_to_cpu(notif->flags);
638 u32 enabled;
639 u16 size;
640
641 if (IWL_FW_CHECK(mld, notif->sta_id >= mld->fw->ucode_capa.num_stations,
642 "Invalid sta id (%d) in TLC notification\n",
643 notif->sta_id))
644 return;
645
646 link_sta = wiphy_dereference(mld->wiphy,
647 mld->fw_id_to_link_sta[notif->sta_id]);
648
649 if (WARN(IS_ERR_OR_NULL(link_sta),
650 "link_sta of sta id (%d) doesn't exist\n", notif->sta_id))
651 return;
652
653 if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
654 struct iwl_mld_link_sta *mld_link_sta =
655 iwl_mld_link_sta_from_mac80211(link_sta);
656 char pretty_rate[100];
657
658 if (WARN_ON(!mld_link_sta))
659 return;
660
661 mld_link_sta->last_rate_n_flags = le32_to_cpu(notif->rate);
662
663 rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
664 mld_link_sta->last_rate_n_flags);
665 IWL_DEBUG_RATE(mld, "TLC notif: new rate = %s\n", pretty_rate);
666 }
667
668 /* We are done processing the notif */
669 if (!(flags & IWL_TLC_NOTIF_FLAG_AMSDU))
670 return;
671
672 enabled = le32_to_cpu(notif->amsdu_enabled);
673 size = le32_to_cpu(notif->amsdu_size);
674
675 if (size < 2000) {
676 size = 0;
677 enabled = 0;
678 }
679
680 if (IWL_FW_CHECK(mld, size > link_sta->agg.max_amsdu_len,
681 "Invalid AMSDU len in TLC notif: %d (Max AMSDU len: %d)\n",
682 size, link_sta->agg.max_amsdu_len))
683 return;
684
685 link_sta->agg.max_rc_amsdu_len = size;
686
687 for (int i = 0; i < IWL_MAX_TID_COUNT; i++) {
688 if (enabled & BIT(i))
689 link_sta->agg.max_tid_amsdu_len[i] =
690 iwl_mld_get_amsdu_size_of_tid(mld, link_sta, i);
691 else
692 link_sta->agg.max_tid_amsdu_len[i] = 1;
693 }
694
695 ieee80211_sta_recalc_aggregates(link_sta->sta);
696
697 IWL_DEBUG_RATE(mld,
698 "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
699 le32_to_cpu(notif->amsdu_size), size, enabled);
700 }
701