xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/link.c (revision af2d6148d2a159e1a0862bce5a2c88c1618a2b27)
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 static u8 iwl_mld_sta_rx_bw_to_fw(enum ieee80211_sta_rx_bandwidth bw)
246 {
247 	switch (bw) {
248 	default: /* potential future values not supported by this hw/driver */
249 	case IEEE80211_STA_RX_BW_20:
250 		return IWL_LINK_MODIFY_BW_20;
251 	case IEEE80211_STA_RX_BW_40:
252 		return IWL_LINK_MODIFY_BW_40;
253 	case IEEE80211_STA_RX_BW_80:
254 		return IWL_LINK_MODIFY_BW_80;
255 	case IEEE80211_STA_RX_BW_160:
256 		return IWL_LINK_MODIFY_BW_160;
257 	case IEEE80211_STA_RX_BW_320:
258 		return IWL_LINK_MODIFY_BW_320;
259 	}
260 }
261 
262 static int _iwl_mld_change_link_in_fw(struct iwl_mld *mld,
263 				      struct ieee80211_bss_conf *link,
264 				      enum ieee80211_sta_rx_bandwidth bw,
265 				      u32 changes)
266 {
267 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
268 	struct ieee80211_vif *vif = link->vif;
269 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
270 	struct ieee80211_chanctx_conf *chan_ctx;
271 	struct iwl_link_config_cmd cmd = {};
272 	u32 flags = 0;
273 
274 	lockdep_assert_wiphy(mld->wiphy);
275 
276 	if (WARN_ON(!mld_link))
277 		return -EINVAL;
278 
279 	cmd.link_id = cpu_to_le32(mld_link->fw_id);
280 	cmd.spec_link_id = link->link_id;
281 	cmd.mac_id = cpu_to_le32(mld_vif->fw_id);
282 
283 	chan_ctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx);
284 
285 	cmd.phy_id = cpu_to_le32(chan_ctx ?
286 		iwl_mld_phy_from_mac80211(chan_ctx)->fw_id :
287 		FW_CTXT_ID_INVALID);
288 
289 	ether_addr_copy(cmd.local_link_addr, link->addr);
290 
291 	cmd.active = cpu_to_le32(mld_link->active);
292 
293 	if ((changes & LINK_CONTEXT_MODIFY_ACTIVE) && !mld_link->active &&
294 	    mld_link->silent_deactivation) {
295 		/* We are de-activating a link that is having CSA with
296 		 * immediate quiet in EMLSR. Tell the firmware not to send any
297 		 * frame.
298 		 */
299 		cmd.block_tx = 1;
300 		mld_link->silent_deactivation = false;
301 	}
302 
303 	if (vif->type == NL80211_IFTYPE_ADHOC && link->bssid)
304 		ether_addr_copy(cmd.ibss_bssid_addr, link->bssid);
305 
306 	/* Channel context is needed to get the rates */
307 	if (chan_ctx)
308 		iwl_mld_fill_rates(mld, link, chan_ctx, &cmd.cck_rates,
309 				   &cmd.ofdm_rates);
310 
311 	cmd.cck_short_preamble = cpu_to_le32(link->use_short_preamble);
312 	cmd.short_slot = cpu_to_le32(link->use_short_slot);
313 
314 	iwl_mld_fill_protection_flags(mld, link, &cmd.protection_flags);
315 
316 	iwl_mld_fill_qos_params(link, cmd.ac, &cmd.qos_flags);
317 
318 	cmd.bi = cpu_to_le32(link->beacon_int);
319 	cmd.dtim_interval = cpu_to_le32(link->beacon_int * link->dtim_period);
320 
321 	if (changes & LINK_CONTEXT_MODIFY_BANDWIDTH)
322 		cmd.modify_bandwidth = iwl_mld_sta_rx_bw_to_fw(bw);
323 
324 	/* Configure HE parameters only if HE is supported, and only after
325 	 * the parameters are set in mac80211 (meaning after assoc)
326 	 */
327 	if (!link->he_support || iwlwifi_mod_params.disable_11ax ||
328 	    (vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
329 		changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
330 		goto send_cmd;
331 	}
332 
333 	/* ap_sta may be NULL if we're disconnecting */
334 	if (mld_vif->ap_sta) {
335 		struct ieee80211_link_sta *link_sta =
336 			link_sta_dereference_check(mld_vif->ap_sta,
337 						   link->link_id);
338 
339 		if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he &&
340 		    link_sta->he_cap.he_cap_elem.mac_cap_info[5] &
341 		    IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX)
342 			cmd.ul_mu_data_disable = 1;
343 	}
344 
345 	cmd.htc_trig_based_pkt_ext = link->htc_trig_based_pkt_ext;
346 
347 	if (link->uora_exists) {
348 		cmd.rand_alloc_ecwmin = link->uora_ocw_range & 0x7;
349 		cmd.rand_alloc_ecwmax = (link->uora_ocw_range >> 3) & 0x7;
350 	}
351 
352 	if (iwl_mld_fill_mu_edca(mld, mld_link, cmd.trig_based_txf))
353 		flags |= LINK_FLG_MU_EDCA_CW;
354 
355 	cmd.bss_color = link->he_bss_color.color;
356 
357 	if (!link->he_bss_color.enabled)
358 		flags |= LINK_FLG_BSS_COLOR_DIS;
359 
360 	cmd.frame_time_rts_th = cpu_to_le16(link->frame_time_rts_th);
361 
362 	/* Block 26-tone RU OFDMA transmissions */
363 	if (mld_link->he_ru_2mhz_block)
364 		flags |= LINK_FLG_RU_2MHZ_BLOCK;
365 
366 	if (link->nontransmitted) {
367 		ether_addr_copy(cmd.ref_bssid_addr, link->transmitter_bssid);
368 		cmd.bssid_index = link->bssid_index;
369 	}
370 
371 	/* The only EHT parameter is puncturing, and starting from PHY cmd
372 	 * version 6 - it is sent there. For older versions of the PHY cmd,
373 	 * puncturing is not needed at all.
374 	 */
375 	if (WARN_ON(changes & LINK_CONTEXT_MODIFY_EHT_PARAMS))
376 		changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
377 
378 send_cmd:
379 	cmd.modify_mask = cpu_to_le32(changes);
380 	cmd.flags = cpu_to_le32(flags);
381 
382 	return iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_MODIFY);
383 }
384 
385 int iwl_mld_change_link_in_fw(struct iwl_mld *mld,
386 			      struct ieee80211_bss_conf *link,
387 			      u32 changes)
388 {
389 	if (WARN_ON(changes & LINK_CONTEXT_MODIFY_BANDWIDTH))
390 		changes &= ~LINK_CONTEXT_MODIFY_BANDWIDTH;
391 
392 	return _iwl_mld_change_link_in_fw(mld, link, 0, changes);
393 }
394 
395 int iwl_mld_change_link_omi_bw(struct iwl_mld *mld,
396 			       struct ieee80211_bss_conf *link,
397 			       enum ieee80211_sta_rx_bandwidth bw)
398 {
399 	return _iwl_mld_change_link_in_fw(mld, link, bw,
400 					  LINK_CONTEXT_MODIFY_BANDWIDTH);
401 }
402 
403 int iwl_mld_activate_link(struct iwl_mld *mld,
404 			  struct ieee80211_bss_conf *link)
405 {
406 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
407 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(mld_link->vif);
408 	int ret;
409 
410 	lockdep_assert_wiphy(mld->wiphy);
411 
412 	if (WARN_ON(!mld_link || mld_link->active))
413 		return -EINVAL;
414 
415 	mld_link->rx_omi.exit_ts = jiffies;
416 	mld_link->active = true;
417 
418 	ret = iwl_mld_change_link_in_fw(mld, link,
419 					LINK_CONTEXT_MODIFY_ACTIVE);
420 	if (ret)
421 		mld_link->active = false;
422 	else
423 		mld_vif->last_link_activation_time =
424 			ktime_get_boottime_seconds();
425 
426 	return ret;
427 }
428 
429 void iwl_mld_deactivate_link(struct iwl_mld *mld,
430 			     struct ieee80211_bss_conf *link)
431 {
432 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
433 	struct iwl_probe_resp_data *probe_data;
434 
435 	lockdep_assert_wiphy(mld->wiphy);
436 
437 	if (WARN_ON(!mld_link || !mld_link->active))
438 		return;
439 
440 	iwl_mld_cancel_session_protection(mld, link->vif, link->link_id);
441 
442 	/* If we deactivate the link, we will probably remove it, or switch
443 	 * channel. In both cases, the CSA or Notice of Absence information is
444 	 * now irrelevant. Remove the data here.
445 	 */
446 	probe_data = wiphy_dereference(mld->wiphy, mld_link->probe_resp_data);
447 	RCU_INIT_POINTER(mld_link->probe_resp_data, NULL);
448 	if (probe_data)
449 		kfree_rcu(probe_data, rcu_head);
450 
451 	mld_link->active = false;
452 
453 	iwl_mld_change_link_in_fw(mld, link, LINK_CONTEXT_MODIFY_ACTIVE);
454 
455 	/* Now that the link is not active in FW, we don't expect any new
456 	 * notifications for it. Cancel the ones that are already pending
457 	 */
458 	iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_LINK,
459 					       mld_link->fw_id);
460 }
461 
462 static void
463 iwl_mld_rm_link_from_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link)
464 {
465 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
466 	struct iwl_link_config_cmd cmd = {};
467 
468 	lockdep_assert_wiphy(mld->wiphy);
469 
470 	if (WARN_ON(!mld_link))
471 		return;
472 
473 	cmd.link_id = cpu_to_le32(mld_link->fw_id);
474 	cmd.spec_link_id = link->link_id;
475 	cmd.phy_id = cpu_to_le32(FW_CTXT_ID_INVALID);
476 
477 	iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE);
478 }
479 
480 static void iwl_mld_omi_bw_update(struct iwl_mld *mld,
481 				  struct ieee80211_bss_conf *link_conf,
482 				  struct iwl_mld_link *mld_link,
483 				  struct ieee80211_link_sta *link_sta,
484 				  enum ieee80211_sta_rx_bandwidth bw,
485 				  bool ap_update)
486 {
487 	enum ieee80211_sta_rx_bandwidth apply_bw;
488 
489 	mld_link->rx_omi.desired_bw = bw;
490 
491 	/* Can't update OMI while already in progress, desired_bw was
492 	 * set so on FW notification the worker will see the change
493 	 * and apply new the new desired bw.
494 	 */
495 	if (mld_link->rx_omi.bw_in_progress)
496 		return;
497 
498 	if (bw == IEEE80211_STA_RX_BW_MAX)
499 		apply_bw = ieee80211_chan_width_to_rx_bw(link_conf->chanreq.oper.width);
500 	else
501 		apply_bw = bw;
502 
503 	if (!ap_update) {
504 		/* The update isn't due to AP tracking after leaving OMI,
505 		 * where the AP could increase BW and then we must tell
506 		 * it that we can do the increased BW as well, if we did
507 		 * update the chandef.
508 		 * In this case, if we want MAX, then we will need to send
509 		 * a new OMI to the AP if it increases its own bandwidth as
510 		 * we can (due to internal and FW limitations, and being
511 		 * worried the AP might break) only send to what we're doing
512 		 * at the moment. In this case, set last_max_bw; otherwise
513 		 * if we really want to decrease our bandwidth set it to 0
514 		 * to indicate no updates are needed if the AP changes.
515 		 */
516 		if (bw != IEEE80211_STA_RX_BW_MAX)
517 			mld_link->rx_omi.last_max_bw = apply_bw;
518 		else
519 			mld_link->rx_omi.last_max_bw = 0;
520 	} else {
521 		/* Otherwise, if we're already trying to do maximum and
522 		 * the AP is changing, set last_max_bw to the new max the
523 		 * AP is using, we'll only get to this code path if the
524 		 * new bandwidth of the AP is bigger than what we sent it
525 		 * previously. This avoids repeatedly sending updates if
526 		 * it changes bandwidth, only doing it once on an increase.
527 		 */
528 		mld_link->rx_omi.last_max_bw = apply_bw;
529 	}
530 
531 	if (ieee80211_prepare_rx_omi_bw(link_sta, bw)) {
532 		mld_link->rx_omi.bw_in_progress = apply_bw;
533 		iwl_mld_change_link_omi_bw(mld, link_conf, apply_bw);
534 	}
535 }
536 
537 static void iwl_mld_omi_bw_finished_work(struct wiphy *wiphy,
538 					 struct wiphy_work *work)
539 {
540 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
541 	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
542 	struct iwl_mld_link *mld_link =
543 		container_of(work, typeof(*mld_link), rx_omi.finished_work.work);
544 	enum ieee80211_sta_rx_bandwidth desired_bw, switched_to_bw;
545 	struct ieee80211_vif *vif = mld_link->vif;
546 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
547 	struct ieee80211_bss_conf *link_conf;
548 	struct ieee80211_link_sta *link_sta;
549 
550 	if (!mld_vif->ap_sta)
551 		return;
552 
553 	link_sta = wiphy_dereference(mld->wiphy,
554 				     mld_vif->ap_sta->link[mld_link->link_id]);
555 	if (WARN_ON_ONCE(!link_sta))
556 		return;
557 
558 	link_conf = link_conf_dereference_protected(vif, link_sta->link_id);
559 	if (WARN_ON_ONCE(!link_conf))
560 		return;
561 
562 	if (WARN_ON(!mld_link->rx_omi.bw_in_progress))
563 		return;
564 
565 	desired_bw = mld_link->rx_omi.desired_bw;
566 	switched_to_bw = mld_link->rx_omi.bw_in_progress;
567 
568 	ieee80211_finalize_rx_omi_bw(link_sta);
569 	mld_link->rx_omi.bw_in_progress = 0;
570 
571 	if (desired_bw != switched_to_bw)
572 		iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta,
573 				      desired_bw, false);
574 }
575 
576 static struct ieee80211_vif *
577 iwl_mld_get_omi_bw_reduction_pointers(struct iwl_mld *mld,
578 				      struct ieee80211_link_sta **link_sta,
579 				      struct iwl_mld_link **mld_link)
580 {
581 	struct iwl_mld_vif *mld_vif;
582 	struct ieee80211_vif *vif;
583 	int n_link_stas = 0;
584 
585 	*link_sta = NULL;
586 
587 	if (mld->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC)
588 		return NULL;
589 
590 	vif = iwl_mld_get_bss_vif(mld);
591 	if (!vif)
592 		return NULL;
593 
594 	for (int i = 0; i < ARRAY_SIZE(mld->fw_id_to_link_sta); i++) {
595 		struct ieee80211_link_sta *tmp;
596 
597 		tmp = wiphy_dereference(mld->wiphy, mld->fw_id_to_link_sta[i]);
598 		if (IS_ERR_OR_NULL(tmp))
599 			continue;
600 
601 		n_link_stas++;
602 		*link_sta = tmp;
603 	}
604 
605 	/* can't do anything if we have TDLS peers or EMLSR */
606 	if (n_link_stas != 1)
607 		return NULL;
608 
609 	mld_vif = iwl_mld_vif_from_mac80211(vif);
610 	*mld_link = iwl_mld_link_dereference_check(mld_vif,
611 						   (*link_sta)->link_id);
612 	if (WARN_ON(!*mld_link))
613 		return NULL;
614 
615 	return vif;
616 }
617 
618 void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld,
619 			       struct ieee80211_bss_conf *link_conf,
620 			       enum ieee80211_sta_rx_bandwidth bw)
621 {
622 	struct ieee80211_link_sta *link_sta;
623 	struct iwl_mld_link *mld_link;
624 	struct ieee80211_vif *vif;
625 
626 	vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link);
627 	if (!vif)
628 		return;
629 
630 	if (WARN_ON(link_conf->vif != vif))
631 		return;
632 
633 	/* This is 0 if we requested an OMI BW reduction and don't want to
634 	 * be sending an OMI when the AP's bandwidth changes.
635 	 */
636 	if (!mld_link->rx_omi.last_max_bw)
637 		return;
638 
639 	/* We only need to tell the AP if it increases BW over what we last
640 	 * told it we were using, if it reduces then our last OMI to it will
641 	 * not get used anyway (e.g. we said we want 160 but it's doing 80.)
642 	 */
643 	if (bw < mld_link->rx_omi.last_max_bw)
644 		return;
645 
646 	iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, true);
647 }
648 
649 void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld,
650 				     struct iwl_rx_packet *pkt)
651 {
652 	int ver = iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP,
653 					  OMI_SEND_STATUS_NOTIF, 1);
654 	struct ieee80211_link_sta *link_sta;
655 	struct iwl_mld_link *mld_link;
656 	struct ieee80211_vif *vif;
657 
658 	if (ver == 2) {
659 		const struct iwl_omi_send_status_notif *notif =
660 			(const void *)pkt->data;
661 		u32 sta_id = le32_to_cpu(notif->sta_id);
662 		struct iwl_mld_vif *mld_vif;
663 
664 		if (IWL_FW_CHECK(mld, sta_id >= mld->fw->ucode_capa.num_stations,
665 				 "Invalid station %d\n", sta_id))
666 			return;
667 
668 		link_sta = wiphy_dereference(mld->wiphy,
669 					     mld->fw_id_to_link_sta[sta_id]);
670 		if (IWL_FW_CHECK(mld, !link_sta, "Station does not exist\n"))
671 			return;
672 
673 		vif = iwl_mld_sta_from_mac80211(link_sta->sta)->vif;
674 		mld_vif = iwl_mld_vif_from_mac80211(vif);
675 
676 		mld_link = iwl_mld_link_dereference_check(mld_vif,
677 							  link_sta->link_id);
678 		if (WARN(!mld_link, "Link %d does not exist\n",
679 			 link_sta->link_id))
680 			return;
681 	} else {
682 		vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta,
683 							    &mld_link);
684 	}
685 	if (IWL_FW_CHECK(mld, !vif, "unexpected OMI notification\n"))
686 		return;
687 
688 	if (IWL_FW_CHECK(mld, !mld_link->rx_omi.bw_in_progress,
689 			 "OMI notification when not requested\n"))
690 		return;
691 
692 	wiphy_delayed_work_queue(mld->hw->wiphy,
693 				 &mld_link->rx_omi.finished_work,
694 				 msecs_to_jiffies(IWL_MLD_OMI_AP_SETTLE_DELAY));
695 }
696 
697 void iwl_mld_leave_omi_bw_reduction(struct iwl_mld *mld)
698 {
699 	struct ieee80211_bss_conf *link_conf;
700 	struct ieee80211_link_sta *link_sta;
701 	struct iwl_mld_link *mld_link;
702 	struct ieee80211_vif *vif;
703 
704 	vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link);
705 	if (!vif)
706 		return;
707 
708 	link_conf = link_conf_dereference_protected(vif, link_sta->link_id);
709 	if (WARN_ON_ONCE(!link_conf))
710 		return;
711 
712 	if (!link_conf->he_support)
713 		return;
714 
715 	mld_link->rx_omi.exit_ts = jiffies;
716 
717 	iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta,
718 			      IEEE80211_STA_RX_BW_MAX, false);
719 }
720 
721 void iwl_mld_check_omi_bw_reduction(struct iwl_mld *mld)
722 {
723 	enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_MAX;
724 	struct ieee80211_chanctx_conf *chanctx;
725 	struct ieee80211_bss_conf *link_conf;
726 	struct ieee80211_link_sta *link_sta;
727 	struct cfg80211_chan_def chandef;
728 	struct iwl_mld_link *mld_link;
729 	struct iwl_mld_vif *mld_vif;
730 	struct ieee80211_vif *vif;
731 	struct iwl_mld_phy *phy;
732 	u16 punctured;
733 	int exit_thr;
734 
735 	/* not allowed in CAM mode */
736 	if (iwlmld_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
737 		return;
738 
739 	/* must have one BSS connection (no P2P), no TDLS, nor EMLSR */
740 	vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link);
741 	if (!vif)
742 		return;
743 
744 	link_conf = link_conf_dereference_protected(vif, link_sta->link_id);
745 	if (WARN_ON_ONCE(!link_conf))
746 		return;
747 
748 	if (!link_conf->he_support)
749 		return;
750 
751 	chanctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx);
752 	if (WARN_ON(!chanctx))
753 		return;
754 
755 	mld_vif = iwl_mld_vif_from_mac80211(vif);
756 	if (!mld_vif->authorized)
757 		goto apply;
758 
759 	/* must not be in low-latency mode */
760 	if (iwl_mld_vif_low_latency(mld_vif))
761 		goto apply;
762 
763 	chandef = link_conf->chanreq.oper;
764 
765 	switch (chandef.width) {
766 	case NL80211_CHAN_WIDTH_320:
767 		exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_320;
768 		break;
769 	case NL80211_CHAN_WIDTH_160:
770 		exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_160;
771 		break;
772 	default:
773 		/* since we reduce to 80 MHz, must have more to start with */
774 		goto apply;
775 	}
776 
777 	/* not to be done if primary 80 MHz is punctured */
778 	if (cfg80211_chandef_primary(&chandef, NL80211_CHAN_WIDTH_80,
779 				     &punctured) < 0 ||
780 	    punctured != 0)
781 		goto apply;
782 
783 	phy = iwl_mld_phy_from_mac80211(chanctx);
784 
785 	if (phy->channel_load_by_us > exit_thr) {
786 		/* send OMI for max bandwidth */
787 		goto apply;
788 	}
789 
790 	if (phy->channel_load_by_us > IWL_MLD_OMI_ENTER_CHAN_LOAD) {
791 		/* no changes between enter/exit thresholds */
792 		return;
793 	}
794 
795 	if (time_is_after_jiffies(mld_link->rx_omi.exit_ts +
796 				  msecs_to_jiffies(IWL_MLD_OMI_EXIT_PROTECTION)))
797 		return;
798 
799 	/* reduce bandwidth to 80 MHz to save power */
800 	bw = IEEE80211_STA_RX_BW_80;
801 apply:
802 	iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, false);
803 }
804 
805 IWL_MLD_ALLOC_FN(link, bss_conf)
806 
807 /* Constructor function for struct iwl_mld_link */
808 static int
809 iwl_mld_init_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
810 		  struct iwl_mld_link *mld_link)
811 {
812 	mld_link->vif = link->vif;
813 	mld_link->link_id = link->link_id;
814 	mld_link->average_beacon_energy = 0;
815 
816 	iwl_mld_init_internal_sta(&mld_link->bcast_sta);
817 	iwl_mld_init_internal_sta(&mld_link->mcast_sta);
818 	iwl_mld_init_internal_sta(&mld_link->mon_sta);
819 
820 	if (!mld->fw_status.in_hw_restart)
821 		wiphy_delayed_work_init(&mld_link->rx_omi.finished_work,
822 					iwl_mld_omi_bw_finished_work);
823 
824 	return iwl_mld_allocate_link_fw_id(mld, &mld_link->fw_id, link);
825 }
826 
827 /* Initializes the link structure, maps fw id to the ieee80211_bss_conf, and
828  * adds a link to the fw
829  */
830 int iwl_mld_add_link(struct iwl_mld *mld,
831 		     struct ieee80211_bss_conf *bss_conf)
832 {
833 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
834 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
835 	bool is_deflink = bss_conf == &bss_conf->vif->bss_conf;
836 	int ret;
837 
838 	if (!link) {
839 		if (is_deflink)
840 			link = &mld_vif->deflink;
841 		else
842 			link = kzalloc(sizeof(*link), GFP_KERNEL);
843 	} else {
844 		WARN_ON(!mld->fw_status.in_hw_restart);
845 	}
846 
847 	ret = iwl_mld_init_link(mld, bss_conf, link);
848 	if (ret)
849 		goto free;
850 
851 	rcu_assign_pointer(mld_vif->link[bss_conf->link_id], link);
852 
853 	ret = iwl_mld_add_link_to_fw(mld, bss_conf);
854 	if (ret) {
855 		RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
856 		RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
857 		goto free;
858 	}
859 
860 	return ret;
861 
862 free:
863 	if (!is_deflink)
864 		kfree(link);
865 	return ret;
866 }
867 
868 /* Remove link from fw, unmap the bss_conf, and destroy the link structure */
869 void iwl_mld_remove_link(struct iwl_mld *mld,
870 			 struct ieee80211_bss_conf *bss_conf)
871 {
872 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
873 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
874 	bool is_deflink = link == &mld_vif->deflink;
875 
876 	if (WARN_ON(!link || link->active))
877 		return;
878 
879 	iwl_mld_rm_link_from_fw(mld, bss_conf);
880 	/* Continue cleanup on failure */
881 
882 	if (!is_deflink)
883 		kfree_rcu(link, rcu_head);
884 
885 	RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
886 
887 	wiphy_delayed_work_cancel(mld->wiphy, &link->rx_omi.finished_work);
888 
889 	if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links))
890 		return;
891 
892 	RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
893 }
894 
895 void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld,
896 					struct iwl_rx_packet *pkt)
897 {
898 	const struct iwl_missed_beacons_notif *notif = (const void *)pkt->data;
899 	union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };
900 	u32 link_id = le32_to_cpu(notif->link_id);
901 	u32 missed_bcon = le32_to_cpu(notif->consec_missed_beacons);
902 	u32 missed_bcon_since_rx =
903 		le32_to_cpu(notif->consec_missed_beacons_since_last_rx);
904 	u32 scnd_lnk_bcn_lost =
905 		le32_to_cpu(notif->consec_missed_beacons_other_link);
906 	struct ieee80211_bss_conf *link_conf =
907 		iwl_mld_fw_id_to_link_conf(mld, link_id);
908 	u32 bss_param_ch_cnt_link_id;
909 	struct ieee80211_vif *vif;
910 
911 	if (WARN_ON(!link_conf))
912 		return;
913 
914 	vif = link_conf->vif;
915 	bss_param_ch_cnt_link_id = link_conf->bss_param_ch_cnt_link_id;
916 
917 	IWL_DEBUG_INFO(mld,
918 		       "missed bcn link_id=%u, %u consecutive=%u\n",
919 		       link_id, missed_bcon, missed_bcon_since_rx);
920 
921 	if (WARN_ON(!vif))
922 		return;
923 
924 	mld->trans->dbg.dump_file_name_ext_valid = true;
925 	snprintf(mld->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
926 		 "LinkId_%d_MacType_%d", link_id,
927 		 iwl_mld_mac80211_iftype_to_fw(vif));
928 
929 	iwl_dbg_tlv_time_point(&mld->fwrt,
930 			       IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data);
931 
932 	if (missed_bcon >= IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG) {
933 		if (missed_bcon_since_rx >=
934 		    IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD) {
935 			ieee80211_connection_loss(vif);
936 			return;
937 		}
938 		IWL_WARN(mld,
939 			 "missed beacons exceeds threshold, but receiving data. Stay connected, Expect bugs.\n");
940 		return;
941 	}
942 
943 	if (missed_bcon_since_rx > IWL_MLD_MISSED_BEACONS_THRESHOLD) {
944 		ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC);
945 
946 		/* try to switch links, no-op if we don't have MLO */
947 		iwl_mld_int_mlo_scan(mld, vif);
948 	}
949 
950 	/* no more logic if we're not in EMLSR */
951 	if (hweight16(vif->active_links) <= 1)
952 		return;
953 
954 	/* We are processing a notification before link activation */
955 	if (le32_to_cpu(notif->other_link_id) == FW_CTXT_ID_INVALID)
956 		return;
957 
958 	/* Exit EMLSR if we lost more than
959 	 * IWL_MLD_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links
960 	 * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH on current link.
961 	 * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED
962 	 * on current link and the link's bss_param_ch_count has changed on
963 	 * the other link's beacon.
964 	 */
965 	if ((missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS &&
966 	     scnd_lnk_bcn_lost >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) ||
967 	    missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH ||
968 	    (bss_param_ch_cnt_link_id != link_id &&
969 	     missed_bcon >=
970 	     IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) {
971 		iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_MISSED_BEACON,
972 				   iwl_mld_get_primary_link(vif));
973 	}
974 }
975 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_handle_missed_beacon_notif);
976 
977 bool iwl_mld_cancel_missed_beacon_notif(struct iwl_mld *mld,
978 					struct iwl_rx_packet *pkt,
979 					u32 removed_link_id)
980 {
981 	struct iwl_missed_beacons_notif *notif = (void *)pkt->data;
982 
983 	if (le32_to_cpu(notif->other_link_id) == removed_link_id) {
984 		/* Second link is being removed. Don't cancel the notification,
985 		 * but mark second link as invalid.
986 		 */
987 		notif->other_link_id = cpu_to_le32(FW_CTXT_ID_INVALID);
988 	}
989 
990 	/* If the primary link is removed, cancel the notification */
991 	return le32_to_cpu(notif->link_id) == removed_link_id;
992 }
993 
994 int iwl_mld_link_set_associated(struct iwl_mld *mld, struct ieee80211_vif *vif,
995 				struct ieee80211_bss_conf *link)
996 {
997 	return iwl_mld_change_link_in_fw(mld, link, LINK_CONTEXT_MODIFY_ALL &
998 					 ~(LINK_CONTEXT_MODIFY_ACTIVE |
999 					   LINK_CONTEXT_MODIFY_EHT_PARAMS));
1000 }
1001 
1002 struct iwl_mld_rssi_to_grade {
1003 	s8 rssi[2];
1004 	u16 grade;
1005 };
1006 
1007 #define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
1008 	{ \
1009 		.rssi = {_lb, _hb_uhb}, \
1010 		.grade = _grade \
1011 	}
1012 
1013 /*
1014  * This array must be sorted by increasing RSSI for proper functionality.
1015  * The grades are actually estimated throughput, represented as fixed-point
1016  * with a scale factor of 1/10.
1017  */
1018 static const struct iwl_mld_rssi_to_grade rssi_to_grade_map[] = {
1019 	RSSI_TO_GRADE_LINE(-85, -89, 172),
1020 	RSSI_TO_GRADE_LINE(-83, -86, 344),
1021 	RSSI_TO_GRADE_LINE(-82, -85, 516),
1022 	RSSI_TO_GRADE_LINE(-80, -83, 688),
1023 	RSSI_TO_GRADE_LINE(-77, -79, 1032),
1024 	RSSI_TO_GRADE_LINE(-73, -76, 1376),
1025 	RSSI_TO_GRADE_LINE(-70, -74, 1548),
1026 	RSSI_TO_GRADE_LINE(-69, -72, 1720),
1027 	RSSI_TO_GRADE_LINE(-65, -68, 2064),
1028 	RSSI_TO_GRADE_LINE(-61, -66, 2294),
1029 	RSSI_TO_GRADE_LINE(-58, -61, 2580),
1030 	RSSI_TO_GRADE_LINE(-55, -58, 2868),
1031 	RSSI_TO_GRADE_LINE(-46, -55, 3098),
1032 	RSSI_TO_GRADE_LINE(-43, -54, 3442)
1033 };
1034 
1035 #define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
1036 
1037 #define DEFAULT_CHAN_LOAD_2GHZ	30
1038 #define DEFAULT_CHAN_LOAD_5GHZ	15
1039 #define DEFAULT_CHAN_LOAD_6GHZ	0
1040 
1041 /* Factors calculation is done with fixed-point with a scaling factor of 1/256 */
1042 #define SCALE_FACTOR 256
1043 #define MAX_CHAN_LOAD 256
1044 
1045 static unsigned int
1046 iwl_mld_get_n_subchannels(const struct ieee80211_bss_conf *link_conf)
1047 {
1048 	enum nl80211_chan_width chan_width =
1049 		link_conf->chanreq.oper.width;
1050 	int mhz = nl80211_chan_width_to_mhz(chan_width);
1051 	unsigned int n_subchannels;
1052 
1053 	if (WARN_ONCE(mhz < 20 || mhz > 320,
1054 		      "Invalid channel width : (%d)\n", mhz))
1055 		return 1;
1056 
1057 	/* total number of subchannels */
1058 	n_subchannels = mhz / 20;
1059 
1060 	/* No puncturing if less than 80 MHz */
1061 	if (mhz >= 80)
1062 		n_subchannels -= hweight16(link_conf->chanreq.oper.punctured);
1063 
1064 	return n_subchannels;
1065 }
1066 
1067 static int
1068 iwl_mld_get_chan_load_from_element(struct iwl_mld *mld,
1069 				   struct ieee80211_bss_conf *link_conf)
1070 {
1071 	struct ieee80211_vif *vif = link_conf->vif;
1072 	const struct cfg80211_bss_ies *ies;
1073 	const struct element *bss_load_elem = NULL;
1074 	const struct ieee80211_bss_load_elem *bss_load;
1075 
1076 	guard(rcu)();
1077 
1078 	if (ieee80211_vif_link_active(vif, link_conf->link_id))
1079 		ies = rcu_dereference(link_conf->bss->beacon_ies);
1080 	else
1081 		ies = rcu_dereference(link_conf->bss->ies);
1082 
1083 	if (ies)
1084 		bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
1085 						   ies->data, ies->len);
1086 
1087 	if (!bss_load_elem ||
1088 	    bss_load_elem->datalen != sizeof(*bss_load))
1089 		return -EINVAL;
1090 
1091 	bss_load = (const void *)bss_load_elem->data;
1092 
1093 	return bss_load->channel_util;
1094 }
1095 
1096 static unsigned int
1097 iwl_mld_get_chan_load_by_us(struct iwl_mld *mld,
1098 			    struct ieee80211_bss_conf *link_conf,
1099 			    bool expect_active_link)
1100 {
1101 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
1102 	struct ieee80211_chanctx_conf *chan_ctx;
1103 	struct iwl_mld_phy *phy;
1104 
1105 	if (!mld_link || !mld_link->active) {
1106 		WARN_ON(expect_active_link);
1107 		return 0;
1108 	}
1109 
1110 	if (WARN_ONCE(!rcu_access_pointer(mld_link->chan_ctx),
1111 		      "Active link (%u) without channel ctxt assigned!\n",
1112 		      link_conf->link_id))
1113 		return 0;
1114 
1115 	chan_ctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx);
1116 	phy = iwl_mld_phy_from_mac80211(chan_ctx);
1117 
1118 	return phy->channel_load_by_us;
1119 }
1120 
1121 /* Returns error if the channel utilization element is invalid/unavailable */
1122 int iwl_mld_get_chan_load_by_others(struct iwl_mld *mld,
1123 				    struct ieee80211_bss_conf *link_conf,
1124 				    bool expect_active_link)
1125 {
1126 	int chan_load;
1127 	unsigned int chan_load_by_us;
1128 
1129 	/* get overall load */
1130 	chan_load = iwl_mld_get_chan_load_from_element(mld, link_conf);
1131 	if (chan_load < 0)
1132 		return chan_load;
1133 
1134 	chan_load_by_us = iwl_mld_get_chan_load_by_us(mld, link_conf,
1135 						      expect_active_link);
1136 
1137 	/* channel load by us is given in percentage */
1138 	chan_load_by_us =
1139 		NORMALIZE_PERCENT_TO_255(chan_load_by_us);
1140 
1141 	/* Use only values that firmware sends that can possibly be valid */
1142 	if (chan_load_by_us <= chan_load)
1143 		chan_load -= chan_load_by_us;
1144 
1145 	return chan_load;
1146 }
1147 
1148 static unsigned int
1149 iwl_mld_get_default_chan_load(struct ieee80211_bss_conf *link_conf)
1150 {
1151 	enum nl80211_band band = link_conf->chanreq.oper.chan->band;
1152 
1153 	switch (band) {
1154 	case NL80211_BAND_2GHZ:
1155 		return DEFAULT_CHAN_LOAD_2GHZ;
1156 	case NL80211_BAND_5GHZ:
1157 		return DEFAULT_CHAN_LOAD_5GHZ;
1158 	case NL80211_BAND_6GHZ:
1159 		return DEFAULT_CHAN_LOAD_6GHZ;
1160 	default:
1161 		WARN_ON(1);
1162 		return 0;
1163 	}
1164 }
1165 
1166 unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld,
1167 				   struct ieee80211_bss_conf *link_conf)
1168 {
1169 	int chan_load;
1170 
1171 	chan_load = iwl_mld_get_chan_load_by_others(mld, link_conf, false);
1172 	if (chan_load >= 0)
1173 		return chan_load;
1174 
1175 	/* No information from the element, take the defaults */
1176 	chan_load = iwl_mld_get_default_chan_load(link_conf);
1177 
1178 	/* The defaults are given in percentage */
1179 	return NORMALIZE_PERCENT_TO_255(chan_load);
1180 }
1181 
1182 static unsigned int
1183 iwl_mld_get_avail_chan_load(struct iwl_mld *mld,
1184 			    struct ieee80211_bss_conf *link_conf)
1185 {
1186 	return MAX_CHAN_LOAD - iwl_mld_get_chan_load(mld, link_conf);
1187 }
1188 
1189 /* This function calculates the grade of a link. Returns 0 in error case */
1190 unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
1191 				    struct ieee80211_bss_conf *link_conf)
1192 {
1193 	enum nl80211_band band;
1194 	int rssi_idx;
1195 	s32 link_rssi;
1196 	unsigned int grade = MAX_GRADE;
1197 
1198 	if (WARN_ON_ONCE(!link_conf))
1199 		return 0;
1200 
1201 	band = link_conf->chanreq.oper.chan->band;
1202 	if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
1203 		      band != NL80211_BAND_5GHZ &&
1204 		      band != NL80211_BAND_6GHZ,
1205 		      "Invalid band (%u)\n", band))
1206 		return 0;
1207 
1208 	link_rssi = MBM_TO_DBM(link_conf->bss->signal);
1209 	/*
1210 	 * For 6 GHz the RSSI of the beacons is lower than
1211 	 * the RSSI of the data.
1212 	 */
1213 	if (band == NL80211_BAND_6GHZ && link_rssi)
1214 		link_rssi += 4;
1215 
1216 	rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
1217 
1218 	/* No valid RSSI - take the lowest grade */
1219 	if (!link_rssi)
1220 		link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
1221 
1222 	IWL_DEBUG_EHT(mld,
1223 		      "Calculating grade of link %d: band = %d, bandwidth = %d, punctured subchannels =0x%x RSSI = %d\n",
1224 		      link_conf->link_id, band,
1225 		      link_conf->chanreq.oper.width,
1226 		      link_conf->chanreq.oper.punctured, link_rssi);
1227 
1228 	/* Get grade based on RSSI */
1229 	for (int i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
1230 		const struct iwl_mld_rssi_to_grade *line =
1231 			&rssi_to_grade_map[i];
1232 
1233 		if (link_rssi > line->rssi[rssi_idx])
1234 			continue;
1235 		grade = line->grade;
1236 		break;
1237 	}
1238 
1239 	/* Apply the channel load and puncturing factors */
1240 	grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) / SCALE_FACTOR;
1241 	grade = grade * iwl_mld_get_n_subchannels(link_conf);
1242 
1243 	IWL_DEBUG_EHT(mld, "Link %d's grade: %d\n", link_conf->link_id, grade);
1244 
1245 	return grade;
1246 }
1247 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_link_grade);
1248 
1249 void iwl_mld_handle_beacon_filter_notif(struct iwl_mld *mld,
1250 					struct iwl_rx_packet *pkt)
1251 {
1252 	const struct iwl_beacon_filter_notif *notif = (const void *)pkt->data;
1253 	u32 link_id = le32_to_cpu(notif->link_id);
1254 	struct ieee80211_bss_conf *link_conf =
1255 		iwl_mld_fw_id_to_link_conf(mld, link_id);
1256 	struct iwl_mld_link *mld_link;
1257 
1258 	if (IWL_FW_CHECK(mld, !link_conf, "invalid link ID %d\n", link_id))
1259 		return;
1260 
1261 	mld_link = iwl_mld_link_from_mac80211(link_conf);
1262 	if (WARN_ON_ONCE(!mld_link))
1263 		return;
1264 
1265 	mld_link->average_beacon_energy = le32_to_cpu(notif->average_energy);
1266 }
1267