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