xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/link.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2024-2025 Intel Corporation
4  */
5 
6 #include "constants.h"
7 #include "link.h"
8 #include "iface.h"
9 #include "mlo.h"
10 #include "hcmd.h"
11 #include "phy.h"
12 #include "fw/api/rs.h"
13 #include "fw/api/txq.h"
14 #include "fw/api/mac.h"
15 
16 #include "fw/api/context.h"
17 #include "fw/dbg.h"
18 
19 static int iwl_mld_send_link_cmd(struct iwl_mld *mld,
20 				 struct iwl_link_config_cmd *cmd,
21 				 enum iwl_ctxt_action action)
22 {
23 	int ret;
24 
25 	lockdep_assert_wiphy(mld->wiphy);
26 
27 	cmd->action = cpu_to_le32(action);
28 	ret = iwl_mld_send_cmd_pdu(mld,
29 				   WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD),
30 				   cmd);
31 	if (ret)
32 		IWL_ERR(mld, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n",
33 			action, ret);
34 	return ret;
35 }
36 
37 static int iwl_mld_add_link_to_fw(struct iwl_mld *mld,
38 				  struct ieee80211_bss_conf *link_conf)
39 {
40 	struct ieee80211_vif *vif = link_conf->vif;
41 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
42 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(link_conf);
43 	struct iwl_link_config_cmd cmd = {};
44 
45 	lockdep_assert_wiphy(mld->wiphy);
46 
47 	if (WARN_ON(!link))
48 		return -EINVAL;
49 
50 	cmd.link_id = cpu_to_le32(link->fw_id);
51 	cmd.mac_id = cpu_to_le32(mld_vif->fw_id);
52 	cmd.spec_link_id = link_conf->link_id;
53 	cmd.phy_id = cpu_to_le32(FW_CTXT_ID_INVALID);
54 
55 	ether_addr_copy(cmd.local_link_addr, link_conf->addr);
56 
57 	if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
58 		ether_addr_copy(cmd.ibss_bssid_addr, link_conf->bssid);
59 
60 	return iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_ADD);
61 }
62 
63 /* Get the basic rates of the used band and add the mandatory ones */
64 static void iwl_mld_fill_rates(struct iwl_mld *mld,
65 			       struct ieee80211_bss_conf *link,
66 			       struct ieee80211_chanctx_conf *chan_ctx,
67 			       __le32 *cck_rates, __le32 *ofdm_rates)
68 {
69 	struct cfg80211_chan_def *chandef =
70 		iwl_mld_get_chandef_from_chanctx(mld, chan_ctx);
71 	struct ieee80211_supported_band *sband =
72 		mld->hw->wiphy->bands[chandef->chan->band];
73 	unsigned long basic = link->basic_rates;
74 	int lowest_present_ofdm = 100;
75 	int lowest_present_cck = 100;
76 	u32 cck = 0;
77 	u32 ofdm = 0;
78 	int i;
79 
80 	for_each_set_bit(i, &basic, BITS_PER_LONG) {
81 		int hw = sband->bitrates[i].hw_value;
82 
83 		if (hw >= IWL_FIRST_OFDM_RATE) {
84 			ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
85 			if (lowest_present_ofdm > hw)
86 				lowest_present_ofdm = hw;
87 		} else {
88 			BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
89 
90 			cck |= BIT(hw);
91 			if (lowest_present_cck > hw)
92 				lowest_present_cck = hw;
93 		}
94 	}
95 
96 	/* Now we've got the basic rates as bitmaps in the ofdm and cck
97 	 * variables. This isn't sufficient though, as there might not
98 	 * be all the right rates in the bitmap. E.g. if the only basic
99 	 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
100 	 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
101 	 *
102 	 *    [...] a STA responding to a received frame shall transmit
103 	 *    its Control Response frame [...] at the highest rate in the
104 	 *    BSSBasicRateSet parameter that is less than or equal to the
105 	 *    rate of the immediately previous frame in the frame exchange
106 	 *    sequence ([...]) and that is of the same modulation class
107 	 *    ([...]) as the received frame. If no rate contained in the
108 	 *    BSSBasicRateSet parameter meets these conditions, then the
109 	 *    control frame sent in response to a received frame shall be
110 	 *    transmitted at the highest mandatory rate of the PHY that is
111 	 *    less than or equal to the rate of the received frame, and
112 	 *    that is of the same modulation class as the received frame.
113 	 *
114 	 * As a consequence, we need to add all mandatory rates that are
115 	 * lower than all of the basic rates to these bitmaps.
116 	 */
117 
118 	if (lowest_present_ofdm > IWL_RATE_24M_INDEX)
119 		ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE;
120 	if (lowest_present_ofdm > IWL_RATE_12M_INDEX)
121 		ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE;
122 	/* 6M already there or needed so always add */
123 	ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE;
124 
125 	/* CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
126 	 * Note, however:
127 	 *  - if no CCK rates are basic, it must be ERP since there must
128 	 *    be some basic rates at all, so they're OFDM => ERP PHY
129 	 *    (or we're in 5 GHz, and the cck bitmap will never be used)
130 	 *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
131 	 *  - if 5.5M is basic, 1M and 2M are mandatory
132 	 *  - if 2M is basic, 1M is mandatory
133 	 *  - if 1M is basic, that's the only valid ACK rate.
134 	 * As a consequence, it's not as complicated as it sounds, just add
135 	 * any lower rates to the ACK rate bitmap.
136 	 */
137 	if (lowest_present_cck > IWL_RATE_11M_INDEX)
138 		cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE;
139 	if (lowest_present_cck > IWL_RATE_5M_INDEX)
140 		cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE;
141 	if (lowest_present_cck > IWL_RATE_2M_INDEX)
142 		cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE;
143 	/* 1M already there or needed so always add */
144 	cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE;
145 
146 	*cck_rates = cpu_to_le32((u32)cck);
147 	*ofdm_rates = cpu_to_le32((u32)ofdm);
148 }
149 
150 static void iwl_mld_fill_protection_flags(struct iwl_mld *mld,
151 					  struct ieee80211_bss_conf *link,
152 					  __le32 *protection_flags)
153 {
154 	u8 protection_mode = link->ht_operation_mode &
155 				IEEE80211_HT_OP_MODE_PROTECTION;
156 	u8 ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT;
157 
158 	IWL_DEBUG_RATE(mld, "HT protection mode: %d\n", protection_mode);
159 
160 	if (link->use_cts_prot)
161 		*protection_flags |= cpu_to_le32(LINK_PROT_FLG_TGG_PROTECT);
162 
163 	/* See section 9.23.3.1 of IEEE 80211-2012.
164 	 * Nongreenfield HT STAs Present is not supported.
165 	 */
166 	switch (protection_mode) {
167 	case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
168 		break;
169 	case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
170 	case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
171 		*protection_flags |= cpu_to_le32(ht_flag);
172 		break;
173 	case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
174 		/* Protect when channel wider than 20MHz */
175 		if (link->chanreq.oper.width > NL80211_CHAN_WIDTH_20)
176 			*protection_flags |= cpu_to_le32(ht_flag);
177 		break;
178 	}
179 }
180 
181 static u8 iwl_mld_mac80211_ac_to_fw_ac(enum ieee80211_ac_numbers ac)
182 {
183 	static const u8 mac80211_ac_to_fw[] = {
184 		AC_VO,
185 		AC_VI,
186 		AC_BE,
187 		AC_BK
188 	};
189 
190 	return mac80211_ac_to_fw[ac];
191 }
192 
193 static void iwl_mld_fill_qos_params(struct ieee80211_bss_conf *link,
194 				    struct iwl_ac_qos *ac, __le32 *qos_flags)
195 {
196 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
197 
198 	/* no need to check mld_link since it is done in the caller */
199 
200 	for (int mac_ac = 0; mac_ac < IEEE80211_NUM_ACS; mac_ac++) {
201 		u8 txf = iwl_mld_mac80211_ac_to_fw_tx_fifo(mac_ac);
202 		u8 fw_ac = iwl_mld_mac80211_ac_to_fw_ac(mac_ac);
203 
204 		ac[fw_ac].cw_min =
205 			cpu_to_le16(mld_link->queue_params[mac_ac].cw_min);
206 		ac[fw_ac].cw_max =
207 			cpu_to_le16(mld_link->queue_params[mac_ac].cw_max);
208 		ac[fw_ac].edca_txop =
209 			cpu_to_le16(mld_link->queue_params[mac_ac].txop * 32);
210 		ac[fw_ac].aifsn = mld_link->queue_params[mac_ac].aifs;
211 		ac[fw_ac].fifos_mask = BIT(txf);
212 	}
213 
214 	if (link->qos)
215 		*qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
216 
217 	if (link->chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT)
218 		*qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
219 }
220 
221 static bool iwl_mld_fill_mu_edca(struct iwl_mld *mld,
222 				 const struct iwl_mld_link *mld_link,
223 				 struct iwl_he_backoff_conf *trig_based_txf)
224 {
225 	for (int mac_ac = 0; mac_ac < IEEE80211_NUM_ACS; mac_ac++) {
226 		const struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
227 			&mld_link->queue_params[mac_ac].mu_edca_param_rec;
228 		u8 fw_ac = iwl_mld_mac80211_ac_to_fw_ac(mac_ac);
229 
230 		if (!mld_link->queue_params[mac_ac].mu_edca)
231 			return false;
232 
233 		trig_based_txf[fw_ac].cwmin =
234 			cpu_to_le16(mu_edca->ecw_min_max & 0xf);
235 		trig_based_txf[fw_ac].cwmax =
236 			cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);
237 		trig_based_txf[fw_ac].aifsn =
238 			cpu_to_le16(mu_edca->aifsn & 0xf);
239 		trig_based_txf[fw_ac].mu_time =
240 			cpu_to_le16(mu_edca->mu_edca_timer);
241 	}
242 	return true;
243 }
244 
245 int
246 iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
247 			  u32 changes)
248 {
249 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
250 	struct ieee80211_vif *vif = link->vif;
251 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
252 	struct ieee80211_chanctx_conf *chan_ctx;
253 	struct iwl_link_config_cmd cmd = {};
254 	u32 flags = 0;
255 
256 	lockdep_assert_wiphy(mld->wiphy);
257 
258 	if (WARN_ON(!mld_link))
259 		return -EINVAL;
260 
261 	cmd.link_id = cpu_to_le32(mld_link->fw_id);
262 	cmd.spec_link_id = link->link_id;
263 	cmd.mac_id = cpu_to_le32(mld_vif->fw_id);
264 
265 	chan_ctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx);
266 
267 	cmd.phy_id = cpu_to_le32(chan_ctx ?
268 		iwl_mld_phy_from_mac80211(chan_ctx)->fw_id :
269 		FW_CTXT_ID_INVALID);
270 
271 	ether_addr_copy(cmd.local_link_addr, link->addr);
272 
273 	cmd.active = cpu_to_le32(mld_link->active);
274 
275 	if ((changes & LINK_CONTEXT_MODIFY_ACTIVE) && !mld_link->active &&
276 	    mld_link->silent_deactivation) {
277 		/* We are de-activating a link that is having CSA with
278 		 * immediate quiet in EMLSR. Tell the firmware not to send any
279 		 * frame.
280 		 */
281 		cmd.block_tx = 1;
282 		mld_link->silent_deactivation = false;
283 	}
284 
285 	if (vif->type == NL80211_IFTYPE_ADHOC && link->bssid)
286 		ether_addr_copy(cmd.ibss_bssid_addr, link->bssid);
287 
288 	/* Channel context is needed to get the rates */
289 	if (chan_ctx)
290 		iwl_mld_fill_rates(mld, link, chan_ctx, &cmd.cck_rates,
291 				   &cmd.ofdm_rates);
292 
293 	cmd.cck_short_preamble = cpu_to_le32(link->use_short_preamble);
294 	cmd.short_slot = cpu_to_le32(link->use_short_slot);
295 
296 	iwl_mld_fill_protection_flags(mld, link, &cmd.protection_flags);
297 
298 	iwl_mld_fill_qos_params(link, cmd.ac, &cmd.qos_flags);
299 
300 	cmd.bi = cpu_to_le32(link->beacon_int);
301 	cmd.dtim_interval = cpu_to_le32(link->beacon_int * link->dtim_period);
302 
303 	/* Configure HE parameters only if HE is supported, and only after
304 	 * the parameters are set in mac80211 (meaning after assoc)
305 	 */
306 	if (!link->he_support || iwlwifi_mod_params.disable_11ax ||
307 	    (vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
308 		changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
309 		goto send_cmd;
310 	}
311 
312 	/* ap_sta may be NULL if we're disconnecting */
313 	if (mld_vif->ap_sta) {
314 		struct ieee80211_link_sta *link_sta =
315 			link_sta_dereference_check(mld_vif->ap_sta,
316 						   link->link_id);
317 
318 		if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he &&
319 		    link_sta->he_cap.he_cap_elem.mac_cap_info[5] &
320 		    IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX)
321 			cmd.ul_mu_data_disable = 1;
322 	}
323 
324 	cmd.htc_trig_based_pkt_ext = link->htc_trig_based_pkt_ext;
325 
326 	if (link->uora_exists) {
327 		cmd.rand_alloc_ecwmin = link->uora_ocw_range & 0x7;
328 		cmd.rand_alloc_ecwmax = (link->uora_ocw_range >> 3) & 0x7;
329 	}
330 
331 	if (iwl_mld_fill_mu_edca(mld, mld_link, cmd.trig_based_txf))
332 		flags |= LINK_FLG_MU_EDCA_CW;
333 
334 	cmd.bss_color = link->he_bss_color.color;
335 
336 	if (!link->he_bss_color.enabled)
337 		flags |= LINK_FLG_BSS_COLOR_DIS;
338 
339 	cmd.frame_time_rts_th = cpu_to_le16(link->frame_time_rts_th);
340 
341 	/* Block 26-tone RU OFDMA transmissions */
342 	if (mld_link->he_ru_2mhz_block)
343 		flags |= LINK_FLG_RU_2MHZ_BLOCK;
344 
345 	if (link->nontransmitted) {
346 		ether_addr_copy(cmd.ref_bssid_addr, link->transmitter_bssid);
347 		cmd.bssid_index = link->bssid_index;
348 	}
349 
350 	/* The only EHT parameter is puncturing, and starting from PHY cmd
351 	 * version 6 - it is sent there. For older versions of the PHY cmd,
352 	 * puncturing is not needed at all.
353 	 */
354 	if (WARN_ON(changes & LINK_CONTEXT_MODIFY_EHT_PARAMS))
355 		changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
356 
357 send_cmd:
358 	cmd.modify_mask = cpu_to_le32(changes);
359 	cmd.flags = cpu_to_le32(flags);
360 
361 	return iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_MODIFY);
362 }
363 
364 int iwl_mld_activate_link(struct iwl_mld *mld,
365 			  struct ieee80211_bss_conf *link)
366 {
367 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
368 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(link->vif);
369 	int ret;
370 
371 	lockdep_assert_wiphy(mld->wiphy);
372 
373 	if (WARN_ON(!mld_link || mld_link->active))
374 		return -EINVAL;
375 
376 	mld_link->active = true;
377 
378 	ret = iwl_mld_change_link_in_fw(mld, link,
379 					LINK_CONTEXT_MODIFY_ACTIVE);
380 	if (ret)
381 		mld_link->active = false;
382 	else
383 		mld_vif->last_link_activation_time =
384 			ktime_get_boottime_seconds();
385 
386 	return ret;
387 }
388 
389 void iwl_mld_deactivate_link(struct iwl_mld *mld,
390 			     struct ieee80211_bss_conf *link)
391 {
392 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
393 	struct iwl_probe_resp_data *probe_data;
394 
395 	lockdep_assert_wiphy(mld->wiphy);
396 
397 	if (WARN_ON(!mld_link || !mld_link->active))
398 		return;
399 
400 	iwl_mld_cancel_session_protection(mld, link->vif, link->link_id);
401 
402 	/* If we deactivate the link, we will probably remove it, or switch
403 	 * channel. In both cases, the CSA or Notice of Absence information is
404 	 * now irrelevant. Remove the data here.
405 	 */
406 	probe_data = wiphy_dereference(mld->wiphy, mld_link->probe_resp_data);
407 	RCU_INIT_POINTER(mld_link->probe_resp_data, NULL);
408 	if (probe_data)
409 		kfree_rcu(probe_data, rcu_head);
410 
411 	mld_link->active = false;
412 
413 	iwl_mld_change_link_in_fw(mld, link, LINK_CONTEXT_MODIFY_ACTIVE);
414 
415 	/* Now that the link is not active in FW, we don't expect any new
416 	 * notifications for it. Cancel the ones that are already pending
417 	 */
418 	iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_LINK,
419 					       mld_link->fw_id);
420 }
421 
422 static void
423 iwl_mld_rm_link_from_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link)
424 {
425 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
426 	struct iwl_link_config_cmd cmd = {};
427 
428 	lockdep_assert_wiphy(mld->wiphy);
429 
430 	if (WARN_ON(!mld_link))
431 		return;
432 
433 	cmd.link_id = cpu_to_le32(mld_link->fw_id);
434 	cmd.spec_link_id = link->link_id;
435 	cmd.phy_id = cpu_to_le32(FW_CTXT_ID_INVALID);
436 
437 	iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE);
438 }
439 
440 IWL_MLD_ALLOC_FN(link, bss_conf)
441 
442 /* Constructor function for struct iwl_mld_link */
443 static int
444 iwl_mld_init_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
445 		  struct iwl_mld_link *mld_link)
446 {
447 	mld_link->average_beacon_energy = 0;
448 
449 	iwl_mld_init_internal_sta(&mld_link->bcast_sta);
450 	iwl_mld_init_internal_sta(&mld_link->mcast_sta);
451 	iwl_mld_init_internal_sta(&mld_link->mon_sta);
452 
453 	return iwl_mld_allocate_link_fw_id(mld, &mld_link->fw_id, link);
454 }
455 
456 /* Initializes the link structure, maps fw id to the ieee80211_bss_conf, and
457  * adds a link to the fw
458  */
459 int iwl_mld_add_link(struct iwl_mld *mld,
460 		     struct ieee80211_bss_conf *bss_conf)
461 {
462 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
463 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
464 	bool is_deflink = bss_conf == &bss_conf->vif->bss_conf;
465 	int ret;
466 
467 	if (!link) {
468 		if (is_deflink)
469 			link = &mld_vif->deflink;
470 		else
471 			link = kzalloc(sizeof(*link), GFP_KERNEL);
472 	} else {
473 		WARN_ON(!mld->fw_status.in_hw_restart);
474 	}
475 
476 	ret = iwl_mld_init_link(mld, bss_conf, link);
477 	if (ret)
478 		goto free;
479 
480 	rcu_assign_pointer(mld_vif->link[bss_conf->link_id], link);
481 
482 	ret = iwl_mld_add_link_to_fw(mld, bss_conf);
483 	if (ret) {
484 		RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
485 		RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
486 		goto free;
487 	}
488 
489 	return ret;
490 
491 free:
492 	if (!is_deflink)
493 		kfree(link);
494 	return ret;
495 }
496 
497 /* Remove link from fw, unmap the bss_conf, and destroy the link structure */
498 void iwl_mld_remove_link(struct iwl_mld *mld,
499 			 struct ieee80211_bss_conf *bss_conf)
500 {
501 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
502 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
503 	bool is_deflink = link == &mld_vif->deflink;
504 
505 	if (WARN_ON(!link || link->active))
506 		return;
507 
508 	iwl_mld_rm_link_from_fw(mld, bss_conf);
509 	/* Continue cleanup on failure */
510 
511 	if (!is_deflink)
512 		kfree_rcu(link, rcu_head);
513 
514 	RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
515 
516 	if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links))
517 		return;
518 
519 	RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
520 }
521 
522 void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld,
523 					struct iwl_rx_packet *pkt)
524 {
525 	const struct iwl_missed_beacons_notif *notif = (const void *)pkt->data;
526 	union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };
527 	u32 fw_link_id = le32_to_cpu(notif->link_id);
528 	u32 missed_bcon = le32_to_cpu(notif->consec_missed_beacons);
529 	u32 missed_bcon_since_rx =
530 		le32_to_cpu(notif->consec_missed_beacons_since_last_rx);
531 	u32 scnd_lnk_bcn_lost =
532 		le32_to_cpu(notif->consec_missed_beacons_other_link);
533 	struct ieee80211_bss_conf *link_conf =
534 		iwl_mld_fw_id_to_link_conf(mld, fw_link_id);
535 	struct ieee80211_bss_conf *other_link;
536 	u32 bss_param_ch_cnt_link_id, other_link_fw_id;
537 	struct ieee80211_vif *vif;
538 	u8 link_id;
539 
540 	if (WARN_ON(!link_conf))
541 		return;
542 
543 	vif = link_conf->vif;
544 	link_id = link_conf->link_id;
545 	bss_param_ch_cnt_link_id = link_conf->bss_param_ch_cnt_link_id;
546 
547 	IWL_DEBUG_INFO(mld,
548 		       "missed bcn link_id=%u, %u consecutive=%u\n",
549 		       link_id, missed_bcon, missed_bcon_since_rx);
550 
551 	if (WARN_ON(!vif))
552 		return;
553 
554 	iwl_dbg_tlv_time_point(&mld->fwrt,
555 			       IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data);
556 
557 	if (missed_bcon >= IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG) {
558 		if (missed_bcon_since_rx >=
559 		    IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD) {
560 			ieee80211_connection_loss(vif);
561 			return;
562 		}
563 		IWL_WARN(mld,
564 			 "missed beacons exceeds threshold, but receiving data. Stay connected, Expect bugs.\n");
565 		return;
566 	}
567 
568 	if (missed_bcon_since_rx > IWL_MLD_MISSED_BEACONS_THRESHOLD) {
569 		ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC);
570 
571 		/* Not in EMLSR and we can't hear the link.
572 		 * Try to switch to a better link. EMLSR case is handled below.
573 		 */
574 		if (!iwl_mld_emlsr_active(vif))
575 			iwl_mld_int_mlo_scan(mld, vif);
576 	}
577 
578 	/* no more logic if we're not in EMLSR */
579 	if (hweight16(vif->active_links) <= 1)
580 		return;
581 
582 	/* We are processing a notification before link activation */
583 	if (le32_to_cpu(notif->other_link_id) == FW_CTXT_ID_INVALID)
584 		return;
585 
586 	other_link_fw_id = le32_to_cpu(notif->other_link_id);
587 	other_link = iwl_mld_fw_id_to_link_conf(mld, other_link_fw_id);
588 
589 	if (IWL_FW_CHECK(mld, !other_link, "link doesn't exist for: %d\n",
590 			 other_link_fw_id))
591 		return;
592 
593 	IWL_DEBUG_EHT(mld,
594 		      "missed bcn on the other link (link_id=%u): %u\n",
595 		      other_link->link_id, scnd_lnk_bcn_lost);
596 
597 	/* Exit EMLSR if we lost more than
598 	 * IWL_MLD_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links
599 	 * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH on current link.
600 	 * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED
601 	 * on current link and the link's bss_param_ch_count has changed on
602 	 * the other link's beacon.
603 	 */
604 	if ((missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS &&
605 	     scnd_lnk_bcn_lost >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) ||
606 	    missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH ||
607 	    (bss_param_ch_cnt_link_id != link_id &&
608 	     missed_bcon >=
609 	     IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) {
610 		iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_MISSED_BEACON,
611 				   iwl_mld_get_primary_link(vif));
612 	}
613 }
614 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_handle_missed_beacon_notif);
615 
616 bool iwl_mld_cancel_missed_beacon_notif(struct iwl_mld *mld,
617 					struct iwl_rx_packet *pkt,
618 					u32 removed_link_id)
619 {
620 	struct iwl_missed_beacons_notif *notif = (void *)pkt->data;
621 
622 	if (le32_to_cpu(notif->other_link_id) == removed_link_id) {
623 		/* Second link is being removed. Don't cancel the notification,
624 		 * but mark second link as invalid.
625 		 */
626 		notif->other_link_id = cpu_to_le32(FW_CTXT_ID_INVALID);
627 	}
628 
629 	/* If the primary link is removed, cancel the notification */
630 	return le32_to_cpu(notif->link_id) == removed_link_id;
631 }
632 
633 int iwl_mld_link_set_associated(struct iwl_mld *mld, struct ieee80211_vif *vif,
634 				struct ieee80211_bss_conf *link)
635 {
636 	return iwl_mld_change_link_in_fw(mld, link, LINK_CONTEXT_MODIFY_ALL &
637 					 ~(LINK_CONTEXT_MODIFY_ACTIVE |
638 					   LINK_CONTEXT_MODIFY_EHT_PARAMS));
639 }
640 
641 struct iwl_mld_rssi_to_grade {
642 	s8 rssi[2];
643 	u16 grade;
644 };
645 
646 #define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
647 	{ \
648 		.rssi = {_lb, _hb_uhb}, \
649 		.grade = _grade \
650 	}
651 
652 /*
653  * This array must be sorted by increasing RSSI for proper functionality.
654  * The grades are actually estimated throughput, represented as fixed-point
655  * with a scale factor of 1/10.
656  */
657 static const struct iwl_mld_rssi_to_grade rssi_to_grade_map[] = {
658 	RSSI_TO_GRADE_LINE(-85, -89, 172),
659 	RSSI_TO_GRADE_LINE(-83, -86, 344),
660 	RSSI_TO_GRADE_LINE(-82, -85, 516),
661 	RSSI_TO_GRADE_LINE(-80, -83, 688),
662 	RSSI_TO_GRADE_LINE(-77, -79, 1032),
663 	RSSI_TO_GRADE_LINE(-73, -76, 1376),
664 	RSSI_TO_GRADE_LINE(-70, -74, 1548),
665 	RSSI_TO_GRADE_LINE(-69, -72, 1720),
666 	RSSI_TO_GRADE_LINE(-65, -68, 2064),
667 	RSSI_TO_GRADE_LINE(-61, -66, 2294),
668 	RSSI_TO_GRADE_LINE(-58, -61, 2580),
669 	RSSI_TO_GRADE_LINE(-55, -58, 2868),
670 	RSSI_TO_GRADE_LINE(-46, -55, 3098),
671 	RSSI_TO_GRADE_LINE(-43, -54, 3442)
672 };
673 
674 #define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
675 
676 #define DEFAULT_CHAN_LOAD_2GHZ	30
677 #define DEFAULT_CHAN_LOAD_5GHZ	15
678 #define DEFAULT_CHAN_LOAD_6GHZ	0
679 
680 /* Factors calculation is done with fixed-point with a scaling factor of 1/256 */
681 #define SCALE_FACTOR 256
682 #define MAX_CHAN_LOAD 256
683 
684 static unsigned int
685 iwl_mld_get_n_subchannels(const struct ieee80211_bss_conf *link_conf)
686 {
687 	enum nl80211_chan_width chan_width =
688 		link_conf->chanreq.oper.width;
689 	int mhz = nl80211_chan_width_to_mhz(chan_width);
690 	unsigned int n_subchannels;
691 
692 	if (WARN_ONCE(mhz < 20 || mhz > 320,
693 		      "Invalid channel width : (%d)\n", mhz))
694 		return 1;
695 
696 	/* total number of subchannels */
697 	n_subchannels = mhz / 20;
698 
699 	/* No puncturing if less than 80 MHz */
700 	if (mhz >= 80)
701 		n_subchannels -= hweight16(link_conf->chanreq.oper.punctured);
702 
703 	return n_subchannels;
704 }
705 
706 static int
707 iwl_mld_get_chan_load_from_element(struct iwl_mld *mld,
708 				   struct ieee80211_bss_conf *link_conf)
709 {
710 	struct ieee80211_vif *vif = link_conf->vif;
711 	const struct cfg80211_bss_ies *ies;
712 	const struct element *bss_load_elem = NULL;
713 	const struct ieee80211_bss_load_elem *bss_load;
714 
715 	guard(rcu)();
716 
717 	if (ieee80211_vif_link_active(vif, link_conf->link_id))
718 		ies = rcu_dereference(link_conf->bss->beacon_ies);
719 	else
720 		ies = rcu_dereference(link_conf->bss->ies);
721 
722 	if (ies)
723 		bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
724 						   ies->data, ies->len);
725 
726 	if (!bss_load_elem ||
727 	    bss_load_elem->datalen != sizeof(*bss_load))
728 		return -EINVAL;
729 
730 	bss_load = (const void *)bss_load_elem->data;
731 
732 	return bss_load->channel_util;
733 }
734 
735 static unsigned int
736 iwl_mld_get_chan_load_by_us(struct iwl_mld *mld,
737 			    struct ieee80211_bss_conf *link_conf,
738 			    bool expect_active_link)
739 {
740 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
741 	struct ieee80211_chanctx_conf *chan_ctx;
742 	struct iwl_mld_phy *phy;
743 
744 	if (!mld_link || !mld_link->active) {
745 		WARN_ON(expect_active_link);
746 		return 0;
747 	}
748 
749 	if (WARN_ONCE(!rcu_access_pointer(mld_link->chan_ctx),
750 		      "Active link (%u) without channel ctxt assigned!\n",
751 		      link_conf->link_id))
752 		return 0;
753 
754 	chan_ctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx);
755 	phy = iwl_mld_phy_from_mac80211(chan_ctx);
756 
757 	return phy->channel_load_by_us;
758 }
759 
760 /* Returns error if the channel utilization element is invalid/unavailable */
761 int iwl_mld_get_chan_load_by_others(struct iwl_mld *mld,
762 				    struct ieee80211_bss_conf *link_conf,
763 				    bool expect_active_link)
764 {
765 	int chan_load;
766 	unsigned int chan_load_by_us;
767 
768 	/* get overall load */
769 	chan_load = iwl_mld_get_chan_load_from_element(mld, link_conf);
770 	if (chan_load < 0)
771 		return chan_load;
772 
773 	chan_load_by_us = iwl_mld_get_chan_load_by_us(mld, link_conf,
774 						      expect_active_link);
775 
776 	/* channel load by us is given in percentage */
777 	chan_load_by_us =
778 		NORMALIZE_PERCENT_TO_255(chan_load_by_us);
779 
780 	/* Use only values that firmware sends that can possibly be valid */
781 	if (chan_load_by_us <= chan_load)
782 		chan_load -= chan_load_by_us;
783 
784 	return chan_load;
785 }
786 
787 static unsigned int
788 iwl_mld_get_default_chan_load(struct ieee80211_bss_conf *link_conf)
789 {
790 	enum nl80211_band band = link_conf->chanreq.oper.chan->band;
791 
792 	switch (band) {
793 	case NL80211_BAND_2GHZ:
794 		return DEFAULT_CHAN_LOAD_2GHZ;
795 	case NL80211_BAND_5GHZ:
796 		return DEFAULT_CHAN_LOAD_5GHZ;
797 	case NL80211_BAND_6GHZ:
798 		return DEFAULT_CHAN_LOAD_6GHZ;
799 	default:
800 		WARN_ON(1);
801 		return 0;
802 	}
803 }
804 
805 unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld,
806 				   struct ieee80211_bss_conf *link_conf)
807 {
808 	int chan_load;
809 
810 	chan_load = iwl_mld_get_chan_load_by_others(mld, link_conf, false);
811 	if (chan_load >= 0)
812 		return chan_load;
813 
814 	/* No information from the element, take the defaults */
815 	chan_load = iwl_mld_get_default_chan_load(link_conf);
816 
817 	/* The defaults are given in percentage */
818 	return NORMALIZE_PERCENT_TO_255(chan_load);
819 }
820 
821 static unsigned int
822 iwl_mld_get_avail_chan_load(struct iwl_mld *mld,
823 			    struct ieee80211_bss_conf *link_conf)
824 {
825 	return MAX_CHAN_LOAD - iwl_mld_get_chan_load(mld, link_conf);
826 }
827 
828 /* This function calculates the grade of a link. Returns 0 in error case */
829 unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
830 				    struct ieee80211_bss_conf *link_conf)
831 {
832 	enum nl80211_band band;
833 	int rssi_idx;
834 	s32 link_rssi;
835 	unsigned int grade = MAX_GRADE;
836 
837 	if (WARN_ON_ONCE(!link_conf))
838 		return 0;
839 
840 	band = link_conf->chanreq.oper.chan->band;
841 	if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
842 		      band != NL80211_BAND_5GHZ &&
843 		      band != NL80211_BAND_6GHZ,
844 		      "Invalid band (%u)\n", band))
845 		return 0;
846 
847 	link_rssi = MBM_TO_DBM(link_conf->bss->signal);
848 	/*
849 	 * For 6 GHz the RSSI of the beacons is lower than
850 	 * the RSSI of the data.
851 	 */
852 	if (band == NL80211_BAND_6GHZ && link_rssi)
853 		link_rssi += 4;
854 
855 	rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
856 
857 	/* No valid RSSI - take the lowest grade */
858 	if (!link_rssi)
859 		link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
860 
861 	IWL_DEBUG_EHT(mld,
862 		      "Calculating grade of link %d: band = %d, bandwidth = %d, punctured subchannels =0x%x RSSI = %d\n",
863 		      link_conf->link_id, band,
864 		      link_conf->chanreq.oper.width,
865 		      link_conf->chanreq.oper.punctured, link_rssi);
866 
867 	/* Get grade based on RSSI */
868 	for (int i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
869 		const struct iwl_mld_rssi_to_grade *line =
870 			&rssi_to_grade_map[i];
871 
872 		if (link_rssi > line->rssi[rssi_idx])
873 			continue;
874 		grade = line->grade;
875 		break;
876 	}
877 
878 	/* Apply the channel load and puncturing factors */
879 	grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) / SCALE_FACTOR;
880 	grade = grade * iwl_mld_get_n_subchannels(link_conf);
881 
882 	IWL_DEBUG_EHT(mld, "Link %d's grade: %d\n", link_conf->link_id, grade);
883 
884 	return grade;
885 }
886 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_link_grade);
887 
888 void iwl_mld_handle_beacon_filter_notif(struct iwl_mld *mld,
889 					struct iwl_rx_packet *pkt)
890 {
891 	const struct iwl_beacon_filter_notif *notif = (const void *)pkt->data;
892 	u32 link_id = le32_to_cpu(notif->link_id);
893 	struct ieee80211_bss_conf *link_conf =
894 		iwl_mld_fw_id_to_link_conf(mld, link_id);
895 	struct iwl_mld_link *mld_link;
896 
897 	if (IWL_FW_CHECK(mld, !link_conf, "invalid link ID %d\n", link_id))
898 		return;
899 
900 	mld_link = iwl_mld_link_from_mac80211(link_conf);
901 	if (WARN_ON_ONCE(!mld_link))
902 		return;
903 
904 	mld_link->average_beacon_energy = le32_to_cpu(notif->average_energy);
905 }
906