Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/iwlwifi/mvm/rs-fw.c
48286 views
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
/*
3
* Copyright (C) 2017 Intel Deutschland GmbH
4
* Copyright (C) 2018-2025 Intel Corporation
5
*/
6
#include "rs.h"
7
#include "fw-api.h"
8
#include "sta.h"
9
#include "iwl-op-mode.h"
10
#include "mvm.h"
11
12
static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_link_sta *link_sta)
13
{
14
switch (link_sta->bandwidth) {
15
case IEEE80211_STA_RX_BW_320:
16
return IWL_TLC_MNG_CH_WIDTH_320MHZ;
17
case IEEE80211_STA_RX_BW_160:
18
return IWL_TLC_MNG_CH_WIDTH_160MHZ;
19
case IEEE80211_STA_RX_BW_80:
20
return IWL_TLC_MNG_CH_WIDTH_80MHZ;
21
case IEEE80211_STA_RX_BW_40:
22
return IWL_TLC_MNG_CH_WIDTH_40MHZ;
23
case IEEE80211_STA_RX_BW_20:
24
default:
25
return IWL_TLC_MNG_CH_WIDTH_20MHZ;
26
}
27
}
28
29
static u8 rs_fw_set_active_chains(u8 chains)
30
{
31
u8 fw_chains = 0;
32
33
if (chains & ANT_A)
34
fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
35
if (chains & ANT_B)
36
fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
37
38
return fw_chains;
39
}
40
41
static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta)
42
{
43
struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
44
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
45
struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
46
u8 supp = 0;
47
48
if (he_cap->has_he)
49
return 0;
50
51
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
52
supp |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ);
53
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
54
supp |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ);
55
if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
56
supp |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ);
57
if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
58
supp |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ);
59
60
return supp;
61
}
62
63
static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
64
struct ieee80211_vif *vif,
65
struct ieee80211_link_sta *link_sta,
66
const struct ieee80211_sta_he_cap *sband_he_cap)
67
{
68
struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
69
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
70
struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
71
bool vht_ena = vht_cap->vht_supported;
72
u16 flags = 0;
73
74
/* get STBC flags */
75
if (mvm->cfg->ht_params.stbc &&
76
(num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
77
if (he_cap->has_he && he_cap->he_cap_elem.phy_cap_info[2] &
78
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
79
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
80
else if (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
81
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
82
else if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)
83
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
84
}
85
86
if (mvm->cfg->ht_params.ldpc &&
87
((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
88
(vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
89
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
90
91
/* consider LDPC support in case of HE */
92
if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
93
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
94
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
95
96
if (sband_he_cap &&
97
!(sband_he_cap->he_cap_elem.phy_cap_info[1] &
98
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
99
flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
100
101
if (he_cap->has_he &&
102
(he_cap->he_cap_elem.phy_cap_info[3] &
103
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK &&
104
sband_he_cap &&
105
sband_he_cap->he_cap_elem.phy_cap_info[3] &
106
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK))
107
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
108
109
return flags;
110
}
111
112
static
113
int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap,
114
int nss)
115
{
116
u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
117
(0x3 << (2 * (nss - 1)));
118
rx_mcs >>= (2 * (nss - 1));
119
120
switch (rx_mcs) {
121
case IEEE80211_VHT_MCS_SUPPORT_0_7:
122
return IWL_TLC_MNG_HT_RATE_MCS7;
123
case IEEE80211_VHT_MCS_SUPPORT_0_8:
124
return IWL_TLC_MNG_HT_RATE_MCS8;
125
case IEEE80211_VHT_MCS_SUPPORT_0_9:
126
return IWL_TLC_MNG_HT_RATE_MCS9;
127
default:
128
WARN_ON_ONCE(1);
129
break;
130
}
131
132
return 0;
133
}
134
135
static void
136
rs_fw_vht_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
137
const struct ieee80211_sta_vht_cap *vht_cap,
138
struct iwl_tlc_config_cmd_v4 *cmd)
139
{
140
u16 supp;
141
int i, highest_mcs;
142
u8 max_nss = link_sta->rx_nss;
143
struct ieee80211_vht_cap ieee_vht_cap = {
144
.vht_cap_info = cpu_to_le32(vht_cap->cap),
145
.supp_mcs = vht_cap->vht_mcs,
146
};
147
148
/* the station support only a single receive chain */
149
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
150
max_nss = 1;
151
152
for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
153
int nss = i + 1;
154
155
highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, nss);
156
if (!highest_mcs)
157
continue;
158
159
supp = BIT(highest_mcs + 1) - 1;
160
if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
161
supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
162
163
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp);
164
/*
165
* Check if VHT extended NSS indicates that the bandwidth/NSS
166
* configuration is supported - only for MCS 0 since we already
167
* decoded the MCS bits anyway ourselves.
168
*/
169
if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160 &&
170
ieee80211_get_vht_max_nss(&ieee_vht_cap,
171
IEEE80211_VHT_CHANWIDTH_160MHZ,
172
0, true, nss) >= nss)
173
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
174
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80];
175
}
176
}
177
178
static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
179
{
180
switch (mcs) {
181
case IEEE80211_HE_MCS_SUPPORT_0_7:
182
return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1;
183
case IEEE80211_HE_MCS_SUPPORT_0_9:
184
return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1;
185
case IEEE80211_HE_MCS_SUPPORT_0_11:
186
return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1;
187
case IEEE80211_HE_MCS_NOT_SUPPORTED:
188
return 0;
189
}
190
191
WARN(1, "invalid HE MCS %d\n", mcs);
192
return 0;
193
}
194
195
static void
196
rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
197
const struct ieee80211_sta_he_cap *sband_he_cap,
198
struct iwl_tlc_config_cmd_v4 *cmd)
199
{
200
const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
201
u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
202
u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
203
u16 tx_mcs_80 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_80);
204
u16 tx_mcs_160 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_160);
205
int i;
206
u8 nss = link_sta->rx_nss;
207
208
/* the station support only a single receive chain */
209
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
210
nss = 1;
211
212
for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
213
u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3;
214
u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3;
215
u16 _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3;
216
u16 _tx_mcs_80 = (tx_mcs_80 >> (2 * i)) & 0x3;
217
218
/* If one side doesn't support - mark both as not supporting */
219
if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
220
_tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
221
_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
222
_tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
223
}
224
if (_mcs_80 > _tx_mcs_80)
225
_mcs_80 = _tx_mcs_80;
226
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] =
227
cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_80));
228
229
/* If one side doesn't support - mark both as not supporting */
230
if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
231
_tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
232
_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
233
_tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
234
}
235
if (_mcs_160 > _tx_mcs_160)
236
_mcs_160 = _tx_mcs_160;
237
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
238
cpu_to_le16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_160));
239
}
240
}
241
242
static u8 rs_fw_eht_max_nss(u8 rx_nss, u8 tx_nss)
243
{
244
u8 tx = u8_get_bits(tx_nss, IEEE80211_EHT_MCS_NSS_TX);
245
u8 rx = u8_get_bits(rx_nss, IEEE80211_EHT_MCS_NSS_RX);
246
/* the max nss that can be used,
247
* is the min with our tx capa and the peer rx capa.
248
*/
249
return min(tx, rx);
250
}
251
252
#define MAX_NSS_MCS(mcs_num, rx, tx) \
253
rs_fw_eht_max_nss((rx)->rx_tx_mcs ##mcs_num## _max_nss, \
254
(tx)->rx_tx_mcs ##mcs_num## _max_nss)
255
256
static void rs_fw_set_eht_mcs_nss(__le16 ht_rates[][3],
257
enum IWL_TLC_MCS_PER_BW bw,
258
u8 max_nss, u16 mcs_msk)
259
{
260
if (max_nss >= 2)
261
ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le16(mcs_msk);
262
263
if (max_nss >= 1)
264
ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le16(mcs_msk);
265
}
266
267
static const
268
struct ieee80211_eht_mcs_nss_supp_bw *
269
rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw,
270
const struct ieee80211_eht_mcs_nss_supp *eht_mcs)
271
{
272
switch (bw) {
273
case IWL_TLC_MCS_PER_BW_80:
274
return &eht_mcs->bw._80;
275
case IWL_TLC_MCS_PER_BW_160:
276
return &eht_mcs->bw._160;
277
case IWL_TLC_MCS_PER_BW_320:
278
return &eht_mcs->bw._320;
279
default:
280
return NULL;
281
}
282
}
283
284
static void
285
rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif,
286
const struct ieee80211_link_sta *link_sta,
287
const struct ieee80211_sta_he_cap *sband_he_cap,
288
const struct ieee80211_sta_eht_cap *sband_eht_cap,
289
struct iwl_tlc_config_cmd_v4 *cmd)
290
{
291
/* peer RX mcs capa */
292
const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs =
293
&link_sta->eht_cap.eht_mcs_nss_supp;
294
/* our TX mcs capa */
295
const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs =
296
&sband_eht_cap->eht_mcs_nss_supp;
297
298
enum IWL_TLC_MCS_PER_BW bw;
299
struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20;
300
struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_tx_20;
301
302
/* peer is 20Mhz only */
303
if (vif->type == NL80211_IFTYPE_AP &&
304
!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
305
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
306
mcs_rx_20 = eht_rx_mcs->only_20mhz;
307
} else {
308
mcs_rx_20.rx_tx_mcs7_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss;
309
mcs_rx_20.rx_tx_mcs9_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss;
310
mcs_rx_20.rx_tx_mcs11_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs11_max_nss;
311
mcs_rx_20.rx_tx_mcs13_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs13_max_nss;
312
}
313
314
/* nic is 20Mhz only */
315
if (!(sband_he_cap->he_cap_elem.phy_cap_info[0] &
316
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
317
mcs_tx_20 = eht_tx_mcs->only_20mhz;
318
} else {
319
mcs_tx_20.rx_tx_mcs7_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss;
320
mcs_tx_20.rx_tx_mcs9_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss;
321
mcs_tx_20.rx_tx_mcs11_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs11_max_nss;
322
mcs_tx_20.rx_tx_mcs13_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs13_max_nss;
323
}
324
325
/* rates for 20/40/80 bw */
326
bw = IWL_TLC_MCS_PER_BW_80;
327
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
328
MAX_NSS_MCS(7, &mcs_rx_20, &mcs_tx_20), GENMASK(7, 0));
329
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
330
MAX_NSS_MCS(9, &mcs_rx_20, &mcs_tx_20), GENMASK(9, 8));
331
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
332
MAX_NSS_MCS(11, &mcs_rx_20, &mcs_tx_20), GENMASK(11, 10));
333
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
334
MAX_NSS_MCS(13, &mcs_rx_20, &mcs_tx_20), GENMASK(13, 12));
335
336
/* rate for 160/320 bw */
337
for (bw = IWL_TLC_MCS_PER_BW_160; bw <= IWL_TLC_MCS_PER_BW_320; bw++) {
338
const struct ieee80211_eht_mcs_nss_supp_bw *mcs_rx =
339
rs_fw_rs_mcs2eht_mcs(bw, eht_rx_mcs);
340
const struct ieee80211_eht_mcs_nss_supp_bw *mcs_tx =
341
rs_fw_rs_mcs2eht_mcs(bw, eht_tx_mcs);
342
343
/* got unsupported index for bw */
344
if (!mcs_rx || !mcs_tx)
345
continue;
346
347
/* break out if we don't support the bandwidth */
348
if (cmd->max_ch_width < (bw + IWL_TLC_MNG_CH_WIDTH_80MHZ))
349
break;
350
351
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
352
MAX_NSS_MCS(9, mcs_rx, mcs_tx), GENMASK(9, 0));
353
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
354
MAX_NSS_MCS(11, mcs_rx, mcs_tx), GENMASK(11, 10));
355
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
356
MAX_NSS_MCS(13, mcs_rx, mcs_tx), GENMASK(13, 12));
357
}
358
359
/* the station support only a single receive chain */
360
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC ||
361
link_sta->rx_nss < 2)
362
memset(cmd->ht_rates[IWL_TLC_NSS_2], 0,
363
sizeof(cmd->ht_rates[IWL_TLC_NSS_2]));
364
}
365
366
static void rs_fw_set_supp_rates(struct ieee80211_vif *vif,
367
struct ieee80211_link_sta *link_sta,
368
struct ieee80211_supported_band *sband,
369
const struct ieee80211_sta_he_cap *sband_he_cap,
370
const struct ieee80211_sta_eht_cap *sband_eht_cap,
371
struct iwl_tlc_config_cmd_v4 *cmd)
372
{
373
int i;
374
u16 supp = 0;
375
unsigned long tmp; /* must be unsigned long for for_each_set_bit */
376
const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
377
const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
378
const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
379
380
/* non HT rates */
381
tmp = link_sta->supp_rates[sband->band];
382
for_each_set_bit(i, &tmp, BITS_PER_LONG)
383
supp |= BIT(sband->bitrates[i].hw_value);
384
385
cmd->non_ht_rates = cpu_to_le16(supp);
386
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
387
388
/* HT/VHT rates */
389
if (link_sta->eht_cap.has_eht && sband_he_cap && sband_eht_cap) {
390
cmd->mode = IWL_TLC_MNG_MODE_EHT;
391
rs_fw_eht_set_enabled_rates(vif, link_sta, sband_he_cap,
392
sband_eht_cap, cmd);
393
} else if (he_cap->has_he && sband_he_cap) {
394
cmd->mode = IWL_TLC_MNG_MODE_HE;
395
rs_fw_he_set_enabled_rates(link_sta, sband_he_cap, cmd);
396
} else if (vht_cap->vht_supported) {
397
cmd->mode = IWL_TLC_MNG_MODE_VHT;
398
rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd);
399
} else if (ht_cap->ht_supported) {
400
cmd->mode = IWL_TLC_MNG_MODE_HT;
401
cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
402
cpu_to_le16(ht_cap->mcs.rx_mask[0]);
403
404
/* the station support only a single receive chain */
405
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
406
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
407
0;
408
else
409
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
410
cpu_to_le16(ht_cap->mcs.rx_mask[1]);
411
}
412
}
413
414
void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
415
struct iwl_rx_cmd_buffer *rxb)
416
{
417
struct iwl_rx_packet *pkt = rxb_addr(rxb);
418
struct iwl_tlc_update_notif *notif;
419
struct ieee80211_sta *sta;
420
struct ieee80211_link_sta *link_sta;
421
struct iwl_mvm_sta *mvmsta;
422
struct iwl_mvm_link_sta *mvm_link_sta;
423
struct iwl_lq_sta_rs_fw *lq_sta;
424
u32 flags;
425
426
rcu_read_lock();
427
428
notif = (void *)pkt->data;
429
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[notif->sta_id]);
430
sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
431
if (IS_ERR_OR_NULL(sta) || !link_sta) {
432
/* can happen in remove station flow where mvm removed internally
433
* the station before removing from FW
434
*/
435
IWL_DEBUG_RATE(mvm,
436
"Invalid mvm RCU pointer for sta id (%d) in TLC notification\n",
437
notif->sta_id);
438
goto out;
439
}
440
441
mvmsta = iwl_mvm_sta_from_mac80211(sta);
442
443
flags = le32_to_cpu(notif->flags);
444
445
mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]);
446
if (!mvm_link_sta) {
447
IWL_DEBUG_RATE(mvm,
448
"Invalid mvmsta RCU pointer for link (%d) of sta id (%d) in TLC notification\n",
449
link_sta->link_id, notif->sta_id);
450
goto out;
451
}
452
lq_sta = &mvm_link_sta->lq_sta.rs_fw;
453
454
if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
455
char pretty_rate[100];
456
457
lq_sta->last_rate_n_flags =
458
iwl_mvm_v3_rate_from_fw(notif->rate, mvm->fw_rates_ver);
459
rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
460
lq_sta->last_rate_n_flags);
461
IWL_DEBUG_RATE(mvm, "rate: %s\n", pretty_rate);
462
}
463
464
if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) {
465
u32 enabled = le32_to_cpu(notif->amsdu_enabled);
466
u16 size = le32_to_cpu(notif->amsdu_size);
467
int i;
468
469
if (size < 2000) {
470
size = 0;
471
enabled = 0;
472
}
473
474
if (link_sta->agg.max_amsdu_len < size) {
475
/*
476
* In debug link_sta->agg.max_amsdu_len < size
477
* so also check with orig_amsdu_len which holds the
478
* original data before debugfs changed the value
479
*/
480
WARN_ON(mvm_link_sta->orig_amsdu_len < size);
481
goto out;
482
}
483
484
mvmsta->amsdu_enabled = enabled;
485
mvmsta->max_amsdu_len = size;
486
link_sta->agg.max_rc_amsdu_len = mvmsta->max_amsdu_len;
487
488
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
489
if (mvmsta->amsdu_enabled & BIT(i))
490
link_sta->agg.max_tid_amsdu_len[i] =
491
iwl_mvm_max_amsdu_size(mvm, sta, i);
492
else
493
/*
494
* Not so elegant, but this will effectively
495
* prevent AMSDU on this TID
496
*/
497
link_sta->agg.max_tid_amsdu_len[i] = 1;
498
}
499
500
ieee80211_sta_recalc_aggregates(sta);
501
502
IWL_DEBUG_RATE(mvm,
503
"AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
504
le32_to_cpu(notif->amsdu_size), size,
505
mvmsta->amsdu_enabled);
506
}
507
out:
508
rcu_read_unlock();
509
}
510
511
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
512
struct ieee80211_bss_conf *link_conf,
513
struct ieee80211_link_sta *link_sta)
514
{
515
#if defined(__linux__)
516
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
517
#endif
518
const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
519
const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
520
const struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
521
522
if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan))
523
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
524
525
if (link_conf->chanreq.oper.chan->band == NL80211_BAND_6GHZ) {
526
switch (le16_get_bits(link_sta->he_6ghz_capa.capa,
527
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
528
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
529
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
530
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
531
return IEEE80211_MAX_MPDU_LEN_VHT_7991;
532
default:
533
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
534
}
535
} else if (link_conf->chanreq.oper.chan->band == NL80211_BAND_2GHZ &&
536
eht_cap->has_eht) {
537
switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0],
538
IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) {
539
case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454:
540
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
541
case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991:
542
return IEEE80211_MAX_MPDU_LEN_VHT_7991;
543
default:
544
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
545
}
546
} else if (vht_cap->vht_supported) {
547
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
548
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
549
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
550
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
551
return IEEE80211_MAX_MPDU_LEN_VHT_7991;
552
default:
553
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
554
}
555
} else if (ht_cap->ht_supported) {
556
if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU)
557
/*
558
* agg is offloaded so we need to assume that agg
559
* are enabled and max mpdu in ampdu is 4095
560
* (spec 802.11-2016 9.3.2.1)
561
*/
562
return IEEE80211_MAX_MPDU_LEN_HT_BA;
563
else
564
return IEEE80211_MAX_MPDU_LEN_HT_3839;
565
}
566
567
/* in legacy mode no amsdu is enabled so return zero */
568
return 0;
569
}
570
571
void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,
572
struct ieee80211_vif *vif,
573
struct ieee80211_sta *sta,
574
struct ieee80211_bss_conf *link_conf,
575
struct ieee80211_link_sta *link_sta,
576
enum nl80211_band band)
577
{
578
struct ieee80211_hw *hw = mvm->hw;
579
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
580
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
581
struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
582
u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta);
583
const struct ieee80211_sta_he_cap *sband_he_cap =
584
ieee80211_get_he_iftype_cap_vif(sband, vif);
585
const struct ieee80211_sta_eht_cap *sband_eht_cap =
586
ieee80211_get_eht_iftype_cap_vif(sband, vif);
587
struct iwl_mvm_link_sta *mvm_link_sta;
588
struct iwl_lq_sta_rs_fw *lq_sta;
589
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
590
.max_ch_width = mvmsta->authorized ?
591
rs_fw_bw_from_sta_bw(link_sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
592
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, vif, link_sta,
593
sband_he_cap)),
594
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
595
.sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta),
596
.max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
597
cpu_to_le16(max_amsdu_len) : 0,
598
};
599
unsigned int link_id = link_conf->link_id;
600
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
601
int cmd_ver;
602
int ret;
603
604
/* Enable extra EHT LTF if there's mutual support by AP and client */
605
if (sband_eht_cap &&
606
sband_eht_cap->eht_cap_elem.phy_cap_info[5] &
607
IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF &&
608
link_sta->eht_cap.has_eht &&
609
link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] &
610
IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) {
611
IWL_DEBUG_RATE(mvm, "Set support for Extra EHT LTF\n");
612
cfg_cmd.flags |=
613
cpu_to_le16(IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK);
614
}
615
616
rcu_read_lock();
617
mvm_link_sta = rcu_dereference(mvmsta->link[link_id]);
618
if (WARN_ON_ONCE(!mvm_link_sta)) {
619
rcu_read_unlock();
620
return;
621
}
622
623
cfg_cmd.sta_id = mvm_link_sta->sta_id;
624
625
lq_sta = &mvm_link_sta->lq_sta.rs_fw;
626
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
627
628
rcu_read_unlock();
629
630
#ifdef CONFIG_IWLWIFI_DEBUGFS
631
iwl_mvm_reset_frame_stats(mvm);
632
#endif
633
rs_fw_set_supp_rates(vif, link_sta, sband,
634
sband_he_cap, sband_eht_cap,
635
&cfg_cmd);
636
637
/*
638
* since TLC offload works with one mode we can assume
639
* that only vht/ht is used and also set it as station max amsdu
640
*/
641
link_sta->agg.max_amsdu_len = max_amsdu_len;
642
ieee80211_sta_recalc_aggregates(sta);
643
644
cfg_cmd.max_tx_op = cpu_to_le16(mvmvif->max_tx_op);
645
646
cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0);
647
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n",
648
cfg_cmd.sta_id, cfg_cmd.max_ch_width, cfg_cmd.mode);
649
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, chains=0x%X, ch_wid_supp=%d, flags=0x%X\n",
650
cfg_cmd.chains, cfg_cmd.sgi_ch_width_supp, cfg_cmd.flags);
651
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, mpdu_len=%d, no_ht_rate=0x%X, tx_op=%d\n",
652
cfg_cmd.max_mpdu_len, cfg_cmd.non_ht_rates, cfg_cmd.max_tx_op);
653
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][0]=0x%X, ht_rate[1][0]=0x%X\n",
654
cfg_cmd.ht_rates[0][0], cfg_cmd.ht_rates[1][0]);
655
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][1]=0x%X, ht_rate[1][1]=0x%X\n",
656
cfg_cmd.ht_rates[0][1], cfg_cmd.ht_rates[1][1]);
657
IWL_DEBUG_RATE(mvm, "TLC CONFIG CMD, ht_rate[0][2]=0x%X, ht_rate[1][2]=0x%X\n",
658
cfg_cmd.ht_rates[0][2], cfg_cmd.ht_rates[1][2]);
659
if (cmd_ver == 4) {
660
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC,
661
sizeof(cfg_cmd), &cfg_cmd);
662
} else if (cmd_ver < 4) {
663
struct iwl_tlc_config_cmd_v3 cfg_cmd_v3 = {
664
.sta_id = cfg_cmd.sta_id,
665
.max_ch_width = cfg_cmd.max_ch_width,
666
.mode = cfg_cmd.mode,
667
.chains = cfg_cmd.chains,
668
.amsdu = !!cfg_cmd.max_mpdu_len,
669
.flags = cfg_cmd.flags,
670
.non_ht_rates = cfg_cmd.non_ht_rates,
671
.ht_rates[0][0] = cfg_cmd.ht_rates[0][0],
672
.ht_rates[0][1] = cfg_cmd.ht_rates[0][1],
673
.ht_rates[1][0] = cfg_cmd.ht_rates[1][0],
674
.ht_rates[1][1] = cfg_cmd.ht_rates[1][1],
675
.sgi_ch_width_supp = cfg_cmd.sgi_ch_width_supp,
676
.max_mpdu_len = cfg_cmd.max_mpdu_len,
677
};
678
679
u16 cmd_size = sizeof(cfg_cmd_v3);
680
681
/* In old versions of the API the struct is 4 bytes smaller */
682
if (iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) < 3)
683
cmd_size -= 4;
684
685
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, cmd_size,
686
&cfg_cmd_v3);
687
} else {
688
ret = -EINVAL;
689
}
690
691
if (ret)
692
IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
693
}
694
695
int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
696
bool enable)
697
{
698
/* TODO: need to introduce a new FW cmd since LQ cmd is not relevant */
699
IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n");
700
return 0;
701
}
702
703
void iwl_mvm_rs_add_sta_link(struct iwl_mvm *mvm,
704
struct iwl_mvm_link_sta *link_sta)
705
{
706
struct iwl_lq_sta_rs_fw *lq_sta;
707
708
lq_sta = &link_sta->lq_sta.rs_fw;
709
710
lq_sta->pers.drv = mvm;
711
lq_sta->pers.sta_id = link_sta->sta_id;
712
lq_sta->pers.chains = 0;
713
memset(lq_sta->pers.chain_signal, 0,
714
sizeof(lq_sta->pers.chain_signal));
715
lq_sta->pers.last_rssi = S8_MIN;
716
lq_sta->last_rate_n_flags = 0;
717
718
#ifdef CONFIG_MAC80211_DEBUGFS
719
lq_sta->pers.dbg_fixed_rate = 0;
720
#endif
721
}
722
723
void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
724
{
725
unsigned int link_id;
726
727
IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
728
729
for (link_id = 0; link_id < ARRAY_SIZE(mvmsta->link); link_id++) {
730
struct iwl_mvm_link_sta *link =
731
rcu_dereference_protected(mvmsta->link[link_id],
732
lockdep_is_held(&mvm->mutex));
733
if (!link)
734
continue;
735
736
iwl_mvm_rs_add_sta_link(mvm, link);
737
}
738
}
739
740