xref: /linux/drivers/net/wireless/intel/iwlwifi/mvm/link.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
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 
iwl_get_esr_state_string(enum iwl_mvm_esr_state state)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 
iwl_mvm_print_esr_state(struct iwl_mvm * mvm,u32 mask)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 
iwl_mvm_link_cmd_send(struct iwl_mvm * mvm,struct iwl_link_config_cmd * cmd,enum iwl_ctxt_action action)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 
iwl_mvm_set_link_fw_id(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)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 
iwl_mvm_add_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)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 
iwl_mvm_esr_vif_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)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 
iwl_mvm_esr_non_bss_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,unsigned int link_id,bool active)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 
iwl_mvm_link_changed(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,u32 changes,bool active)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 
iwl_mvm_remove_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)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  */
iwl_mvm_disable_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)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
iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf * link_conf)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
iwl_mvm_get_chan_load(struct ieee80211_bss_conf * link_conf)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
iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf * link_conf)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
iwl_mvm_get_link_grade(struct ieee80211_bss_conf * link_conf)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
iwl_mvm_set_link_selection_data(struct ieee80211_vif * vif,struct iwl_mvm_link_sel_data * data,unsigned long usable_links,u8 * best_link_idx)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 
iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm * mvm,const struct cfg80211_chan_def * chandef,bool low)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
iwl_mvm_esr_disallowed_with_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * link,bool primary)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
iwl_mvm_mld_valid_link_pair(struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * a,const struct iwl_mvm_link_sel_data * b)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
iwl_mvm_get_esr_grade(struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * a,const struct iwl_mvm_link_sel_data * b,u8 * primary_id)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 
iwl_mvm_select_links(struct iwl_mvm * mvm,struct ieee80211_vif * vif)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 
iwl_mvm_get_primary_link(struct ieee80211_vif * vif)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  */
iwl_mvm_get_other_link(struct ieee80211_vif * vif,u8 link_id)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 
iwl_mvm_check_esr_prevention(struct iwl_mvm * mvm,struct iwl_mvm_vif * mvmvif,enum iwl_mvm_esr_state reason)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 */
iwl_mvm_exit_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason,u8 link_to_keep)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 
iwl_mvm_block_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason,u8 link_to_keep)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 
iwl_mvm_block_esr_sync(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason)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 
iwl_mvm_esr_unblocked(struct iwl_mvm * mvm,struct ieee80211_vif * vif)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 
iwl_mvm_unblock_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason)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 
iwl_mvm_init_link(struct iwl_mvm_vif_link_info * link)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