Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/iwlwifi/mvm/link.c
48287 views
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
/*
3
* Copyright (C) 2022 - 2024 Intel Corporation
4
*/
5
#include "mvm.h"
6
#include "time-event.h"
7
8
#define HANDLE_ESR_REASONS(HOW) \
9
HOW(BLOCKED_PREVENTION) \
10
HOW(BLOCKED_WOWLAN) \
11
HOW(BLOCKED_TPT) \
12
HOW(BLOCKED_FW) \
13
HOW(BLOCKED_NON_BSS) \
14
HOW(BLOCKED_ROC) \
15
HOW(BLOCKED_TMP_NON_BSS) \
16
HOW(EXIT_MISSED_BEACON) \
17
HOW(EXIT_LOW_RSSI) \
18
HOW(EXIT_COEX) \
19
HOW(EXIT_BANDWIDTH) \
20
HOW(EXIT_CSA) \
21
HOW(EXIT_LINK_USAGE)
22
23
static const char *const iwl_mvm_esr_states_names[] = {
24
#define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x,
25
HANDLE_ESR_REASONS(NAME_ENTRY)
26
};
27
28
const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state)
29
{
30
int offs = ilog2(state);
31
32
if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) ||
33
!iwl_mvm_esr_states_names[offs])
34
return "UNKNOWN";
35
36
return iwl_mvm_esr_states_names[offs];
37
}
38
39
static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask)
40
{
41
#define NAME_FMT(x) "%s"
42
#define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "",
43
IWL_DEBUG_INFO(mvm,
44
"EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT)
45
" (0x%x)\n",
46
HANDLE_ESR_REASONS(NAME_PR)
47
mask);
48
#undef NAME_FMT
49
#undef NAME_PR
50
}
51
52
static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,
53
struct iwl_link_config_cmd *cmd,
54
enum iwl_ctxt_action action)
55
{
56
int ret;
57
58
cmd->action = cpu_to_le32(action);
59
ret = iwl_mvm_send_cmd_pdu(mvm,
60
WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), 0,
61
sizeof(*cmd), cmd);
62
if (ret)
63
IWL_ERR(mvm, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n",
64
action, ret);
65
return ret;
66
}
67
68
void iwl_mvm_set_link_fw_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
69
struct ieee80211_bss_conf *link_conf)
70
{
71
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
72
struct iwl_mvm_vif_link_info *link_info =
73
mvmvif->link[link_conf->link_id];
74
75
if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
76
link_info->fw_link_id = mvmvif->id;
77
}
78
79
int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
80
struct ieee80211_bss_conf *link_conf)
81
{
82
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
83
unsigned int link_id = link_conf->link_id;
84
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
85
struct iwl_link_config_cmd cmd = {};
86
unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
87
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
88
89
if (WARN_ON_ONCE(!link_info))
90
return -EINVAL;
91
92
iwl_mvm_set_link_fw_id(mvm, vif, link_conf);
93
94
/* Update SF - Disable if needed. if this fails, SF might still be on
95
* while many macs are bound, which is forbidden - so fail the binding.
96
*/
97
if (iwl_mvm_sf_update(mvm, vif, false))
98
return -EINVAL;
99
100
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
101
cmd.mac_id = cpu_to_le32(mvmvif->id);
102
cmd.spec_link_id = link_conf->link_id;
103
WARN_ON_ONCE(link_info->phy_ctxt);
104
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
105
106
memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
107
108
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
109
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
110
111
if (cmd_ver < 2)
112
cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
113
114
return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
115
}
116
117
struct iwl_mvm_esr_iter_data {
118
struct ieee80211_vif *vif;
119
unsigned int link_id;
120
bool lift_block;
121
};
122
123
static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac,
124
struct ieee80211_vif *vif)
125
{
126
struct iwl_mvm_esr_iter_data *data = _data;
127
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
128
int link_id;
129
130
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
131
return;
132
133
for_each_mvm_vif_valid_link(mvmvif, link_id) {
134
struct iwl_mvm_vif_link_info *link_info =
135
mvmvif->link[link_id];
136
if (vif == data->vif && link_id == data->link_id)
137
continue;
138
if (link_info->active)
139
data->lift_block = false;
140
}
141
}
142
143
int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
144
unsigned int link_id, bool active)
145
{
146
/* An active link of a non-station vif blocks EMLSR. Upon activation
147
* block EMLSR on the bss vif. Upon deactivation, check if this link
148
* was the last non-station link active, and if so unblock the bss vif
149
*/
150
struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
151
struct iwl_mvm_esr_iter_data data = {
152
.vif = vif,
153
.link_id = link_id,
154
.lift_block = true,
155
};
156
157
if (IS_ERR_OR_NULL(bss_vif))
158
return 0;
159
160
if (active)
161
return iwl_mvm_block_esr_sync(mvm, bss_vif,
162
IWL_MVM_ESR_BLOCKED_NON_BSS);
163
164
ieee80211_iterate_active_interfaces(mvm->hw,
165
IEEE80211_IFACE_ITER_NORMAL,
166
iwl_mvm_esr_vif_iterator, &data);
167
if (data.lift_block) {
168
mutex_lock(&mvm->mutex);
169
iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS);
170
mutex_unlock(&mvm->mutex);
171
}
172
173
return 0;
174
}
175
176
int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
177
struct ieee80211_bss_conf *link_conf,
178
u32 changes, bool active)
179
{
180
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
181
unsigned int link_id = link_conf->link_id;
182
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
183
struct iwl_mvm_phy_ctxt *phyctxt;
184
struct iwl_link_config_cmd cmd = {};
185
u32 ht_flag, flags = 0, flags_mask = 0;
186
int ret;
187
unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
188
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
189
190
if (WARN_ON_ONCE(!link_info ||
191
link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
192
return -EINVAL;
193
194
if (changes & LINK_CONTEXT_MODIFY_ACTIVE) {
195
/* When activating a link, phy context should be valid;
196
* when deactivating a link, it also should be valid since
197
* the link was active before. So, do nothing in this case.
198
* Since a link is added first with FW_CTXT_INVALID, then we
199
* can get here in case it's removed before it was activated.
200
*/
201
if (!link_info->phy_ctxt)
202
return 0;
203
204
/* Catch early if driver tries to activate or deactivate a link
205
* twice.
206
*/
207
WARN_ON_ONCE(active == link_info->active);
208
209
/* When deactivating a link session protection should
210
* be stopped. Also let the firmware know if we can't Tx.
211
*/
212
if (!active && vif->type == NL80211_IFTYPE_STATION) {
213
iwl_mvm_stop_session_protection(mvm, vif);
214
if (link_info->csa_block_tx) {
215
cmd.block_tx = 1;
216
link_info->csa_block_tx = false;
217
}
218
}
219
}
220
221
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
222
223
/* The phy_id, link address and listen_lmac can be modified only until
224
* the link becomes active, otherwise they will be ignored.
225
*/
226
phyctxt = link_info->phy_ctxt;
227
if (phyctxt)
228
cmd.phy_id = cpu_to_le32(phyctxt->id);
229
else
230
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
231
cmd.mac_id = cpu_to_le32(mvmvif->id);
232
233
memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
234
235
cmd.active = cpu_to_le32(active);
236
237
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
238
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
239
240
iwl_mvm_set_fw_basic_rates(mvm, vif, link_info,
241
&cmd.cck_rates, &cmd.ofdm_rates);
242
243
cmd.cck_short_preamble = cpu_to_le32(link_conf->use_short_preamble);
244
cmd.short_slot = cpu_to_le32(link_conf->use_short_slot);
245
246
/* The fw does not distinguish between ht and fat */
247
ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT;
248
iwl_mvm_set_fw_protection_flags(mvm, vif, link_conf,
249
&cmd.protection_flags,
250
ht_flag, LINK_PROT_FLG_TGG_PROTECT);
251
252
iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac,
253
&cmd.qos_flags);
254
255
256
cmd.bi = cpu_to_le32(link_conf->beacon_int);
257
cmd.dtim_interval = cpu_to_le32(link_conf->beacon_int *
258
link_conf->dtim_period);
259
260
if (!link_conf->he_support || iwlwifi_mod_params.disable_11ax ||
261
(vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
262
changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
263
goto send_cmd;
264
}
265
266
cmd.htc_trig_based_pkt_ext = link_conf->htc_trig_based_pkt_ext;
267
268
if (link_conf->uora_exists) {
269
cmd.rand_alloc_ecwmin =
270
link_conf->uora_ocw_range & 0x7;
271
cmd.rand_alloc_ecwmax =
272
(link_conf->uora_ocw_range >> 3) & 0x7;
273
}
274
275
/* ap_sta may be NULL if we're disconnecting */
276
if (changes & LINK_CONTEXT_MODIFY_HE_PARAMS && mvmvif->ap_sta) {
277
struct ieee80211_link_sta *link_sta =
278
link_sta_dereference_check(mvmvif->ap_sta, link_id);
279
280
if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he &&
281
link_sta->he_cap.he_cap_elem.mac_cap_info[5] &
282
IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX)
283
cmd.ul_mu_data_disable = 1;
284
}
285
286
/* TODO how to set ndp_fdbk_buff_th_exp? */
287
288
if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id],
289
&cmd.trig_based_txf[0])) {
290
flags |= LINK_FLG_MU_EDCA_CW;
291
flags_mask |= LINK_FLG_MU_EDCA_CW;
292
}
293
294
if (changes & LINK_CONTEXT_MODIFY_EHT_PARAMS) {
295
struct ieee80211_chanctx_conf *ctx;
296
struct cfg80211_chan_def *def = NULL;
297
298
rcu_read_lock();
299
ctx = rcu_dereference(link_conf->chanctx_conf);
300
if (ctx)
301
def = iwl_mvm_chanctx_def(mvm, ctx);
302
303
if (iwlwifi_mod_params.disable_11be ||
304
!link_conf->eht_support || !def ||
305
iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6)
306
changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
307
else
308
cmd.puncture_mask = cpu_to_le16(def->punctured);
309
rcu_read_unlock();
310
}
311
312
cmd.bss_color = link_conf->he_bss_color.color;
313
314
if (!link_conf->he_bss_color.enabled) {
315
flags |= LINK_FLG_BSS_COLOR_DIS;
316
flags_mask |= LINK_FLG_BSS_COLOR_DIS;
317
}
318
319
cmd.frame_time_rts_th = cpu_to_le16(link_conf->frame_time_rts_th);
320
321
/* Block 26-tone RU OFDMA transmissions */
322
if (link_info->he_ru_2mhz_block) {
323
flags |= LINK_FLG_RU_2MHZ_BLOCK;
324
flags_mask |= LINK_FLG_RU_2MHZ_BLOCK;
325
}
326
327
if (link_conf->nontransmitted) {
328
ether_addr_copy(cmd.ref_bssid_addr,
329
link_conf->transmitter_bssid);
330
cmd.bssid_index = link_conf->bssid_index;
331
}
332
333
send_cmd:
334
cmd.modify_mask = cpu_to_le32(changes);
335
cmd.flags = cpu_to_le32(flags);
336
if (cmd_ver < 6)
337
cmd.flags_mask = cpu_to_le32(flags_mask);
338
cmd.spec_link_id = link_conf->link_id;
339
if (cmd_ver < 2)
340
cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
341
342
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
343
if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
344
link_info->active = active;
345
346
return ret;
347
}
348
349
int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
350
struct ieee80211_bss_conf *link_conf)
351
{
352
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
353
unsigned int link_id = link_conf->link_id;
354
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
355
struct iwl_link_config_cmd cmd = {};
356
int ret;
357
358
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
359
link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
360
cmd.spec_link_id = link_conf->link_id;
361
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
362
363
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
364
365
if (!ret && iwl_mvm_sf_update(mvm, vif, true))
366
IWL_ERR(mvm, "Failed to update SF state\n");
367
368
return ret;
369
}
370
371
/* link should be deactivated before removal, so in most cases we need to
372
* perform these two operations together
373
*/
374
int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
375
struct ieee80211_bss_conf *link_conf)
376
{
377
int ret;
378
379
ret = iwl_mvm_link_changed(mvm, vif, link_conf,
380
LINK_CONTEXT_MODIFY_ACTIVE, false);
381
if (ret)
382
return ret;
383
384
ret = iwl_mvm_remove_link(mvm, vif, link_conf);
385
if (ret)
386
return ret;
387
388
return ret;
389
}
390
391
struct iwl_mvm_rssi_to_grade {
392
s8 rssi[2];
393
u16 grade;
394
};
395
396
#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
397
{ \
398
.rssi = {_lb, _hb_uhb}, \
399
.grade = _grade \
400
}
401
402
/*
403
* This array must be sorted by increasing RSSI for proper functionality.
404
* The grades are actually estimated throughput, represented as fixed-point
405
* with a scale factor of 1/10.
406
*/
407
static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = {
408
RSSI_TO_GRADE_LINE(-85, -89, 177),
409
RSSI_TO_GRADE_LINE(-83, -86, 344),
410
RSSI_TO_GRADE_LINE(-82, -85, 516),
411
RSSI_TO_GRADE_LINE(-80, -83, 688),
412
RSSI_TO_GRADE_LINE(-77, -79, 1032),
413
RSSI_TO_GRADE_LINE(-73, -76, 1376),
414
RSSI_TO_GRADE_LINE(-70, -74, 1548),
415
RSSI_TO_GRADE_LINE(-69, -72, 1750),
416
RSSI_TO_GRADE_LINE(-65, -68, 2064),
417
RSSI_TO_GRADE_LINE(-61, -66, 2294),
418
RSSI_TO_GRADE_LINE(-58, -61, 2580),
419
RSSI_TO_GRADE_LINE(-55, -58, 2868),
420
RSSI_TO_GRADE_LINE(-46, -55, 3098),
421
RSSI_TO_GRADE_LINE(-43, -54, 3442)
422
};
423
424
#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
425
426
#define DEFAULT_CHAN_LOAD_LB 30
427
#define DEFAULT_CHAN_LOAD_HB 15
428
#define DEFAULT_CHAN_LOAD_UHB 0
429
430
/* Factors calculation is done with fixed-point with a scaling factor of 1/256 */
431
#define SCALE_FACTOR 256
432
433
/* Convert a percentage from [0,100] to [0,255] */
434
#define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100)
435
436
static unsigned int
437
iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf)
438
{
439
enum nl80211_chan_width chan_width =
440
link_conf->chanreq.oper.width;
441
int mhz = nl80211_chan_width_to_mhz(chan_width);
442
unsigned int n_subchannels, n_punctured, puncturing_penalty;
443
444
if (WARN_ONCE(mhz < 20 || mhz > 320,
445
"Invalid channel width : (%d)\n", mhz))
446
return SCALE_FACTOR;
447
448
/* No puncturing, no penalty */
449
if (mhz < 80)
450
return SCALE_FACTOR;
451
452
/* total number of subchannels */
453
n_subchannels = mhz / 20;
454
/* how many of these are punctured */
455
n_punctured = hweight16(link_conf->chanreq.oper.punctured);
456
457
puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels;
458
return SCALE_FACTOR - puncturing_penalty;
459
}
460
461
static unsigned int
462
iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
463
{
464
struct ieee80211_vif *vif = link_conf->vif;
465
struct iwl_mvm_vif_link_info *mvm_link =
466
iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id];
467
const struct element *bss_load_elem;
468
const struct ieee80211_bss_load_elem *bss_load;
469
enum nl80211_band band = link_conf->chanreq.oper.chan->band;
470
const struct cfg80211_bss_ies *ies;
471
unsigned int chan_load;
472
u32 chan_load_by_us;
473
474
rcu_read_lock();
475
if (ieee80211_vif_link_active(vif, link_conf->link_id))
476
ies = rcu_dereference(link_conf->bss->beacon_ies);
477
else
478
ies = rcu_dereference(link_conf->bss->ies);
479
480
if (ies)
481
bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
482
ies->data, ies->len);
483
else
484
bss_load_elem = NULL;
485
486
/* If there isn't BSS Load element, take the defaults */
487
if (!bss_load_elem ||
488
bss_load_elem->datalen != sizeof(*bss_load)) {
489
rcu_read_unlock();
490
switch (band) {
491
case NL80211_BAND_2GHZ:
492
chan_load = DEFAULT_CHAN_LOAD_LB;
493
break;
494
case NL80211_BAND_5GHZ:
495
chan_load = DEFAULT_CHAN_LOAD_HB;
496
break;
497
case NL80211_BAND_6GHZ:
498
chan_load = DEFAULT_CHAN_LOAD_UHB;
499
break;
500
default:
501
chan_load = 0;
502
break;
503
}
504
/* The defaults are given in percentage */
505
return NORMALIZE_PERCENT_TO_255(chan_load);
506
}
507
508
bss_load = (const void *)bss_load_elem->data;
509
/* Channel util is in range 0-255 */
510
chan_load = bss_load->channel_util;
511
rcu_read_unlock();
512
513
if (!mvm_link || !mvm_link->active)
514
return chan_load;
515
516
if (WARN_ONCE(!mvm_link->phy_ctxt,
517
"Active link (%u) without phy ctxt assigned!\n",
518
link_conf->link_id))
519
return chan_load;
520
521
/* channel load by us is given in percentage */
522
chan_load_by_us =
523
NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us);
524
525
/* Use only values that firmware sends that can possibly be valid */
526
if (chan_load_by_us <= chan_load)
527
chan_load -= chan_load_by_us;
528
529
return chan_load;
530
}
531
532
static unsigned int
533
iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf)
534
{
535
return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf);
536
}
537
538
/* This function calculates the grade of a link. Returns 0 in error case */
539
VISIBLE_IF_IWLWIFI_KUNIT
540
unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf)
541
{
542
enum nl80211_band band;
543
int i, rssi_idx;
544
s32 link_rssi;
545
unsigned int grade = MAX_GRADE;
546
547
if (WARN_ON_ONCE(!link_conf))
548
return 0;
549
550
band = link_conf->chanreq.oper.chan->band;
551
if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
552
band != NL80211_BAND_5GHZ &&
553
band != NL80211_BAND_6GHZ,
554
"Invalid band (%u)\n", band))
555
return 0;
556
557
link_rssi = MBM_TO_DBM(link_conf->bss->signal);
558
/*
559
* For 6 GHz the RSSI of the beacons is lower than
560
* the RSSI of the data.
561
*/
562
if (band == NL80211_BAND_6GHZ)
563
link_rssi += 4;
564
565
rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
566
567
/* No valid RSSI - take the lowest grade */
568
if (!link_rssi)
569
link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
570
571
/* Get grade based on RSSI */
572
for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
573
const struct iwl_mvm_rssi_to_grade *line =
574
&rssi_to_grade_map[i];
575
576
if (link_rssi > line->rssi[rssi_idx])
577
continue;
578
grade = line->grade;
579
break;
580
}
581
582
/* apply the channel load and puncturing factors */
583
grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR;
584
grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR;
585
return grade;
586
}
587
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade);
588
589
static
590
u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
591
struct iwl_mvm_link_sel_data *data,
592
unsigned long usable_links,
593
u8 *best_link_idx)
594
{
595
u8 n_data = 0;
596
u16 max_grade = 0;
597
unsigned long link_id;
598
599
/* TODO: don't select links that weren't discovered in the last scan */
600
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
601
struct ieee80211_bss_conf *link_conf =
602
link_conf_dereference_protected(vif, link_id);
603
604
if (WARN_ON_ONCE(!link_conf))
605
continue;
606
607
data[n_data].link_id = link_id;
608
data[n_data].chandef = &link_conf->chanreq.oper;
609
data[n_data].signal = link_conf->bss->signal / 100;
610
data[n_data].grade = iwl_mvm_get_link_grade(link_conf);
611
612
if (data[n_data].grade > max_grade) {
613
max_grade = data[n_data].grade;
614
*best_link_idx = n_data;
615
}
616
n_data++;
617
}
618
619
return n_data;
620
}
621
622
struct iwl_mvm_bw_to_rssi_threshs {
623
s8 low;
624
s8 high;
625
};
626
627
#define BW_TO_RSSI_THRESHOLDS(_bw) \
628
[IWL_PHY_CHANNEL_MODE ## _bw] = { \
629
.low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \
630
.high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \
631
}
632
633
s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm,
634
const struct cfg80211_chan_def *chandef,
635
bool low)
636
{
637
const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = {
638
BW_TO_RSSI_THRESHOLDS(20),
639
BW_TO_RSSI_THRESHOLDS(40),
640
BW_TO_RSSI_THRESHOLDS(80),
641
BW_TO_RSSI_THRESHOLDS(160)
642
/* 320 MHz has the same thresholds as 20 MHz */
643
};
644
const struct iwl_mvm_bw_to_rssi_threshs *threshs;
645
u8 chan_width = iwl_mvm_get_channel_width(chandef);
646
647
if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ &&
648
chandef->chan->band != NL80211_BAND_5GHZ &&
649
chandef->chan->band != NL80211_BAND_6GHZ))
650
return S8_MAX;
651
652
/* 6 GHz will always use 20 MHz thresholds, regardless of the BW */
653
if (chan_width == IWL_PHY_CHANNEL_MODE320)
654
chan_width = IWL_PHY_CHANNEL_MODE20;
655
656
threshs = &bw_to_rssi_threshs_map[chan_width];
657
658
return low ? threshs->low : threshs->high;
659
}
660
661
static u32
662
iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm,
663
struct ieee80211_vif *vif,
664
const struct iwl_mvm_link_sel_data *link,
665
bool primary)
666
{
667
struct wiphy *wiphy = mvm->hw->wiphy;
668
struct ieee80211_bss_conf *conf;
669
enum iwl_mvm_esr_state ret = 0;
670
s8 thresh;
671
672
conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]);
673
if (WARN_ON_ONCE(!conf))
674
return false;
675
676
/* BT Coex effects eSR mode only if one of the links is on LB */
677
if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
678
(!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal,
679
primary)))
680
ret |= IWL_MVM_ESR_EXIT_COEX;
681
682
thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef,
683
false);
684
685
if (link->signal < thresh)
686
ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
687
688
if (conf->csa_active)
689
ret |= IWL_MVM_ESR_EXIT_CSA;
690
691
if (ret) {
692
IWL_DEBUG_INFO(mvm,
693
"Link %d is not allowed for esr\n",
694
link->link_id);
695
iwl_mvm_print_esr_state(mvm, ret);
696
}
697
return ret;
698
}
699
700
VISIBLE_IF_IWLWIFI_KUNIT
701
bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
702
const struct iwl_mvm_link_sel_data *a,
703
const struct iwl_mvm_link_sel_data *b)
704
{
705
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
706
struct iwl_mvm *mvm = mvmvif->mvm;
707
enum iwl_mvm_esr_state ret = 0;
708
709
/* Per-link considerations */
710
if (iwl_mvm_esr_disallowed_with_link(mvm, vif, a, true) ||
711
iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false))
712
return false;
713
714
if (a->chandef->chan->band == b->chandef->chan->band ||
715
a->chandef->width != b->chandef->width)
716
ret |= IWL_MVM_ESR_EXIT_BANDWIDTH;
717
718
if (ret) {
719
IWL_DEBUG_INFO(mvm,
720
"Links %d and %d are not a valid pair for EMLSR\n",
721
a->link_id, b->link_id);
722
iwl_mvm_print_esr_state(mvm, ret);
723
return false;
724
}
725
726
return true;
727
728
}
729
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
730
731
/*
732
* Returns the combined eSR grade of two given links.
733
* Returns 0 if eSR is not allowed with these 2 links.
734
*/
735
static
736
unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
737
const struct iwl_mvm_link_sel_data *a,
738
const struct iwl_mvm_link_sel_data *b,
739
u8 *primary_id)
740
{
741
struct ieee80211_bss_conf *primary_conf;
742
struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy;
743
unsigned int primary_load;
744
745
lockdep_assert_wiphy(wiphy);
746
747
/* a is always primary, b is always secondary */
748
if (b->grade > a->grade)
749
swap(a, b);
750
751
*primary_id = a->link_id;
752
753
if (!iwl_mvm_mld_valid_link_pair(vif, a, b))
754
return 0;
755
756
primary_conf = wiphy_dereference(wiphy, vif->link_conf[*primary_id]);
757
758
if (WARN_ON_ONCE(!primary_conf))
759
return 0;
760
761
primary_load = iwl_mvm_get_chan_load(primary_conf);
762
763
return a->grade +
764
((b->grade * primary_load) / SCALE_FACTOR);
765
}
766
767
void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
768
{
769
struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS];
770
struct iwl_mvm_link_sel_data *best_link;
771
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
772
u32 max_active_links = iwl_mvm_max_active_links(mvm, vif);
773
u16 usable_links = ieee80211_vif_usable_links(vif);
774
u8 best, primary_link, best_in_pair, n_data;
775
u16 max_esr_grade = 0, new_active_links;
776
777
lockdep_assert_wiphy(mvm->hw->wiphy);
778
779
if (!mvmvif->authorized || !ieee80211_vif_is_mld(vif))
780
return;
781
782
if (!IWL_MVM_AUTO_EML_ENABLE)
783
return;
784
785
/* The logic below is a simple version that doesn't suit more than 2
786
* links
787
*/
788
WARN_ON_ONCE(max_active_links > 2);
789
790
n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links,
791
&best);
792
793
if (WARN(!n_data, "Couldn't find a valid grade for any link!\n"))
794
return;
795
796
best_link = &data[best];
797
primary_link = best_link->link_id;
798
new_active_links = BIT(best_link->link_id);
799
800
/* eSR is not supported/blocked, or only one usable link */
801
if (max_active_links == 1 || !iwl_mvm_vif_has_esr_cap(mvm, vif) ||
802
mvmvif->esr_disable_reason || n_data == 1)
803
goto set_active;
804
805
for (u8 a = 0; a < n_data; a++)
806
for (u8 b = a + 1; b < n_data; b++) {
807
u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a],
808
&data[b],
809
&best_in_pair);
810
811
if (esr_grade <= max_esr_grade)
812
continue;
813
814
max_esr_grade = esr_grade;
815
primary_link = best_in_pair;
816
new_active_links = BIT(data[a].link_id) |
817
BIT(data[b].link_id);
818
}
819
820
/* No valid pair was found, go with the best link */
821
if (hweight16(new_active_links) <= 1)
822
goto set_active;
823
824
/* For equal grade - prefer EMLSR */
825
if (best_link->grade > max_esr_grade) {
826
primary_link = best_link->link_id;
827
new_active_links = BIT(best_link->link_id);
828
}
829
set_active:
830
IWL_DEBUG_INFO(mvm, "Link selection result: 0x%x. Primary = %d\n",
831
new_active_links, primary_link);
832
ieee80211_set_active_links_async(vif, new_active_links);
833
mvmvif->link_selection_res = new_active_links;
834
mvmvif->link_selection_primary = primary_link;
835
}
836
837
u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif)
838
{
839
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
840
841
/* relevant data is written with both locks held, so read with either */
842
lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) ||
843
lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx));
844
845
if (!ieee80211_vif_is_mld(vif))
846
return 0;
847
848
/* In AP mode, there is no primary link */
849
if (vif->type == NL80211_IFTYPE_AP)
850
return __ffs(vif->active_links);
851
852
if (mvmvif->esr_active &&
853
!WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links)))
854
return mvmvif->primary_link;
855
856
return __ffs(vif->active_links);
857
}
858
859
/*
860
* For non-MLO/single link, this will return the deflink/single active link,
861
* respectively
862
*/
863
u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
864
{
865
switch (hweight16(vif->active_links)) {
866
case 0:
867
return 0;
868
default:
869
WARN_ON(1);
870
fallthrough;
871
case 1:
872
return __ffs(vif->active_links);
873
case 2:
874
return __ffs(vif->active_links & ~BIT(link_id));
875
}
876
}
877
878
/* Reasons that can cause esr prevention */
879
#define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON
880
#define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400)
881
#define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300)
882
#define IWL_MVM_ESR_PREVENT_LONG (HZ * 600)
883
884
static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm,
885
struct iwl_mvm_vif *mvmvif,
886
enum iwl_mvm_esr_state reason)
887
{
888
bool timeout_expired = time_after(jiffies,
889
mvmvif->last_esr_exit.ts +
890
IWL_MVM_PREVENT_ESR_TIMEOUT);
891
unsigned long delay;
892
893
lockdep_assert_held(&mvm->mutex);
894
895
/* Only handle reasons that can cause prevention */
896
if (!(reason & IWL_MVM_ESR_PREVENT_REASONS))
897
return false;
898
899
/*
900
* Reset the counter if more than 400 seconds have passed between one
901
* exit and the other, or if we exited due to a different reason.
902
* Will also reset the counter after the long prevention is done.
903
*/
904
if (timeout_expired || mvmvif->last_esr_exit.reason != reason) {
905
mvmvif->exit_same_reason_count = 1;
906
return false;
907
}
908
909
mvmvif->exit_same_reason_count++;
910
if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
911
mvmvif->exit_same_reason_count > 3))
912
return false;
913
914
mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
915
916
/*
917
* For the second exit, use a short prevention, and for the third one,
918
* use a long prevention.
919
*/
920
delay = mvmvif->exit_same_reason_count == 2 ?
921
IWL_MVM_ESR_PREVENT_SHORT :
922
IWL_MVM_ESR_PREVENT_LONG;
923
924
IWL_DEBUG_INFO(mvm,
925
"Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n",
926
delay / HZ, mvmvif->exit_same_reason_count,
927
iwl_get_esr_state_string(reason), reason);
928
929
wiphy_delayed_work_queue(mvm->hw->wiphy,
930
&mvmvif->prevent_esr_done_wk, delay);
931
return true;
932
}
933
934
#define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ)
935
936
/* API to exit eSR mode */
937
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
938
enum iwl_mvm_esr_state reason,
939
u8 link_to_keep)
940
{
941
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
942
u16 new_active_links;
943
bool prevented;
944
945
lockdep_assert_held(&mvm->mutex);
946
947
if (!IWL_MVM_AUTO_EML_ENABLE)
948
return;
949
950
/* Nothing to do */
951
if (!mvmvif->esr_active)
952
return;
953
954
if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized))
955
return;
956
957
if (WARN_ON(!(vif->active_links & BIT(link_to_keep))))
958
link_to_keep = __ffs(vif->active_links);
959
960
new_active_links = BIT(link_to_keep);
961
IWL_DEBUG_INFO(mvm,
962
"Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n",
963
iwl_get_esr_state_string(reason), reason,
964
vif->active_links, new_active_links);
965
966
ieee80211_set_active_links_async(vif, new_active_links);
967
968
/* Prevent EMLSR if needed */
969
prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason);
970
971
/* Remember why and when we exited EMLSR */
972
mvmvif->last_esr_exit.ts = jiffies;
973
mvmvif->last_esr_exit.reason = reason;
974
975
/*
976
* If EMLSR is prevented now - don't try to get back to EMLSR.
977
* If we exited due to a blocking event, we will try to get back to
978
* EMLSR when the corresponding unblocking event will happen.
979
*/
980
if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS)
981
return;
982
983
/* If EMLSR is not blocked - try enabling it again in 30 seconds */
984
wiphy_delayed_work_queue(mvm->hw->wiphy,
985
&mvmvif->mlo_int_scan_wk,
986
round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME));
987
}
988
989
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
990
enum iwl_mvm_esr_state reason,
991
u8 link_to_keep)
992
{
993
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
994
995
lockdep_assert_held(&mvm->mutex);
996
997
if (!IWL_MVM_AUTO_EML_ENABLE)
998
return;
999
1000
/* This should be called only with disable reasons */
1001
if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1002
return;
1003
1004
if (mvmvif->esr_disable_reason & reason)
1005
return;
1006
1007
IWL_DEBUG_INFO(mvm,
1008
"Blocking EMLSR mode. reason = %s (0x%x)\n",
1009
iwl_get_esr_state_string(reason), reason);
1010
1011
mvmvif->esr_disable_reason |= reason;
1012
1013
iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1014
1015
iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
1016
}
1017
1018
int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1019
enum iwl_mvm_esr_state reason)
1020
{
1021
int primary_link = iwl_mvm_get_primary_link(vif);
1022
int ret;
1023
1024
if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif))
1025
return 0;
1026
1027
/* This should be called only with blocking reasons */
1028
if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1029
return 0;
1030
1031
/* leave ESR immediately, not only async with iwl_mvm_block_esr() */
1032
ret = ieee80211_set_active_links(vif, BIT(primary_link));
1033
if (ret)
1034
return ret;
1035
1036
mutex_lock(&mvm->mutex);
1037
/* only additionally block for consistency and to avoid concurrency */
1038
iwl_mvm_block_esr(mvm, vif, reason, primary_link);
1039
mutex_unlock(&mvm->mutex);
1040
1041
return 0;
1042
}
1043
1044
static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
1045
struct ieee80211_vif *vif)
1046
{
1047
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1048
bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts +
1049
IWL_MVM_TRIGGER_LINK_SEL_TIME);
1050
1051
lockdep_assert_held(&mvm->mutex);
1052
1053
if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized ||
1054
mvmvif->esr_active)
1055
return;
1056
1057
IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n");
1058
1059
/* If we exited due to an EXIT reason, and the exit was in less than
1060
* 30 seconds, then a MLO scan was scheduled already.
1061
*/
1062
if (!need_new_sel &&
1063
!(mvmvif->last_esr_exit.reason & IWL_MVM_BLOCK_ESR_REASONS)) {
1064
IWL_DEBUG_INFO(mvm, "Wait for MLO scan\n");
1065
return;
1066
}
1067
1068
/*
1069
* If EMLSR was blocked for more than 30 seconds, or the last link
1070
* selection decided to not enter EMLSR, trigger a new scan.
1071
*/
1072
if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) {
1073
IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n");
1074
wiphy_delayed_work_queue(mvm->hw->wiphy,
1075
&mvmvif->mlo_int_scan_wk, 0);
1076
/*
1077
* If EMLSR was blocked for less than 30 seconds, and the last link
1078
* selection decided to use EMLSR, activate EMLSR using the previous
1079
* link selection result.
1080
*/
1081
} else {
1082
IWL_DEBUG_INFO(mvm,
1083
"Use the latest link selection result: 0x%x\n",
1084
mvmvif->link_selection_res);
1085
ieee80211_set_active_links_async(vif,
1086
mvmvif->link_selection_res);
1087
}
1088
}
1089
1090
void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1091
enum iwl_mvm_esr_state reason)
1092
{
1093
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1094
1095
lockdep_assert_held(&mvm->mutex);
1096
1097
if (!IWL_MVM_AUTO_EML_ENABLE)
1098
return;
1099
1100
/* This should be called only with disable reasons */
1101
if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1102
return;
1103
1104
/* No Change */
1105
if (!(mvmvif->esr_disable_reason & reason))
1106
return;
1107
1108
mvmvif->esr_disable_reason &= ~reason;
1109
1110
IWL_DEBUG_INFO(mvm,
1111
"Unblocking EMLSR mode. reason = %s (0x%x)\n",
1112
iwl_get_esr_state_string(reason), reason);
1113
iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1114
1115
if (!mvmvif->esr_disable_reason)
1116
iwl_mvm_esr_unblocked(mvm, vif);
1117
}
1118
1119
void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link)
1120
{
1121
link->bcast_sta.sta_id = IWL_INVALID_STA;
1122
link->mcast_sta.sta_id = IWL_INVALID_STA;
1123
link->ap_sta_id = IWL_INVALID_STA;
1124
1125
for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++)
1126
link->smps_requests[r] =
1127
IEEE80211_SMPS_AUTOMATIC;
1128
}
1129
1130