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