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