xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/mld.h (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2 /*
3  * Copyright (C) 2024-2025 Intel Corporation
4  */
5 #ifndef __iwl_mld_h__
6 #define __iwl_mld_h__
7 
8 #include <linux/leds.h>
9 #include <net/mac80211.h>
10 
11 #include "iwl-trans.h"
12 #include "iwl-op-mode.h"
13 #include "fw/runtime.h"
14 #include "fw/notif-wait.h"
15 #include "fw/api/commands.h"
16 #include "fw/api/scan.h"
17 #include "fw/api/mac-cfg.h"
18 #include "fw/api/mac.h"
19 #include "fw/api/phy-ctxt.h"
20 #include "fw/api/datapath.h"
21 #include "fw/api/rx.h"
22 #include "fw/api/rs.h"
23 #include "fw/api/context.h"
24 #include "fw/api/coex.h"
25 #include "fw/api/location.h"
26 
27 #include "fw/dbg.h"
28 
29 #include "notif.h"
30 #include "scan.h"
31 #include "rx.h"
32 #include "thermal.h"
33 #include "low_latency.h"
34 #include "constants.h"
35 #include "ptp.h"
36 #include "time_sync.h"
37 #include "ftm-initiator.h"
38 #include "nan.h"
39 
40 /**
41  * DOC: Introduction
42  *
43  * iwlmld is an operation mode (a.k.a. op_mode) for Intel wireless devices.
44  * It is used for devices that ship after 2024 which typically support
45  * the WiFi-7 features. MLD stands for multi-link device. Note that there are
46  * devices that do not support WiFi-7 or even WiFi 6E and yet use iwlmld, but
47  * the firmware APIs used in this driver are WiFi-7 compatible.
48  *
49  * In the architecture of iwlwifi, an op_mode is a layer that translates
50  * mac80211's APIs into commands for the firmware and, of course, notifications
51  * from the firmware to mac80211's APIs. An op_mode must implement the
52  * interface defined in iwl-op-mode.h to interact with the transport layer
53  * which allows to send and receive data to the device, start the hardware,
54  * etc...
55  */
56 
57 /**
58  * DOC: Locking policy
59  *
60  * iwlmld has a very simple locking policy: it doesn't have any mutexes. It
61  * relies on cfg80211's wiphy->mtx and takes the lock when needed. All the
62  * control flows originating from mac80211 already acquired the lock, so that
63  * part is trivial, but also notifications that are received from the firmware
64  * and handled asynchronously are handled only after having taken the lock.
65  * This is described in notif.c.
66  * There are spin_locks needed to synchronize with the data path, around the
67  * allocation of the queues, for example.
68  */
69 
70 /**
71  * DOC: Debugfs
72  *
73  * iwlmld adds its share of debugfs hooks and its handlers are synchronized
74  * with the wiphy_lock using wiphy_locked_debugfs. This avoids races against
75  * resources deletion while the debugfs hook is being used.
76  */
77 
78 /**
79  * DOC: Main resources
80  *
81  * iwlmld is designed with the life cycle of the resource in mind. The
82  * resources are:
83  *
84  *  - struct iwl_mld (matches mac80211's struct ieee80211_hw)
85  *
86  *  - struct iwl_mld_vif (matches macu80211's struct ieee80211_vif)
87  *    iwl_mld_vif contains an array of pointers to struct iwl_mld_link
88  *    which describe the links for this vif.
89  *
90  *  - struct iwl_mld_sta (matches mac80211's struct ieee80211_sta)
91  *    iwl_mld_sta contains an array of points to struct iwl_mld_link_sta
92  *    which describes the link stations for this station
93  *
94  * Each object has properties that can survive a firmware reset or not.
95  * Asynchronous firmware notifications can declare themselves as dependent on a
96  * certain instance of those resources and that means that the notifications
97  * will be cancelled once the instance is destroyed.
98  */
99 
100 #define IWL_MLD_MAX_ADDRESSES		5
101 
102 /**
103  * struct iwl_mld - MLD op mode
104  *
105  * @fw_id_to_bss_conf: maps a fw id of a link to the corresponding
106  *	ieee80211_bss_conf.
107  * @fw_id_to_vif: maps a fw id of a MAC context to the corresponding
108  *	ieee80211_vif. Mapping is valid only when the MAC exists in the fw.
109  * @fw_id_to_txq: maps a fw id of a txq to the corresponding
110  *	ieee80211_txq.
111  * @used_phy_ids: a bitmap of the phy IDs used. If a bit is set, it means
112  *	that the index of this bit is already used as a PHY id.
113  * @num_igtks: the number if iGTKs that were sent to the FW.
114  * @monitor: monitor related data
115  * @monitor.on: does a monitor vif exist (singleton hence bool)
116  * @monitor.ampdu_ref: the id of the A-MPDU for sniffer
117  * @monitor.ampdu_toggle: the state of the previous packet to track A-MPDU
118  * @monitor.cur_aid: current association id tracked by the sniffer
119  * @monitor.cur_bssid: current bssid tracked by the sniffer
120  * @monitor.ptp_time: set the Rx mactime using the device's PTP clock time
121  * @monitor.p80: primary channel position relative to he whole bandwidth, in
122  *	steps of 80 MHz
123  * @monitor.phy: PHY data information
124  * @monitor.phy.data: PHY data (&struct iwl_rx_phy_air_sniffer_ntfy) received
125  * @monitor.phy.valid: PHY data is valid (was received)
126  * @monitor.phy.used: PHY data was used by an RX
127  * @fw_id_to_link_sta: maps a fw id of a sta to the corresponding
128  *	ieee80211_link_sta. This is not cleaned up on restart since we want to
129  *	preserve the fw sta ids during a restart (for SN/PN restoring).
130  *	FW ids of internal stations will be mapped to ERR_PTR, and will be
131  *	re-allocated during a restart, so make sure to free it in restart
132  *	cleanup using iwl_mld_free_internal_sta
133  * @netdetect: indicates the FW is in suspend mode with netdetect configured
134  * @p2p_device_vif: points to the p2p device vif if exists
135  * @bt_is_active: indicates that BT is active
136  * @dev: pointer to device struct. For printing purposes
137  * @trans: pointer to the transport layer
138  * @cfg: pointer to the device configuration
139  * @fw: a pointer to the fw object
140  * @hw: pointer to the hw object.
141  * @wiphy: a pointer to the wiphy struct, for easier access to it.
142  * @ext_capab: extended capabilities that will be set to wiphy on registration.
143  * @sta_ext_capab: extended capabilities for the station interface.
144  * @nvm_data: pointer to the nvm_data that includes all our capabilities
145  * @fwrt: fw runtime data
146  * @debugfs_dir: debugfs directory
147  * @notif_wait: notification wait related data.
148  * @async_handlers_list: a list of all async RX handlers. When a notifciation
149  *	with an async handler is received, it is added to this list.
150  *	When &async_handlers_wk runs - it runs these handlers one by one.
151  * @async_handlers_lock: a lock for &async_handlers_list. Sync
152  *	&async_handlers_wk and RX notifcation path.
153  * @async_handlers_wk: A work to run all async RX handlers from
154  *	&async_handlers_list.
155  * @ct_kill_exit_wk: worker to exit thermal kill
156  * @fw_status: bitmap of fw status bits
157  * @running: true if the firmware is running
158  * @do_not_dump_once: true if firmware dump must be prevented once
159  * @in_d3: indicates FW is in suspend mode and should be resumed
160  * @resuming: indicates the driver is resuming from wowlan
161  * @in_hw_restart: indicates that we are currently in restart flow.
162  *	rather than restarted. Should be unset upon restart.
163  * @radio_kill: bitmap of radio kill status
164  * @radio_kill.hw: radio is killed by hw switch
165  * @radio_kill.ct: radio is killed because the device it too hot
166  * @power_budget_mw: maximum cTDP power budget as defined for this system and
167  *	device
168  * @addresses: device MAC addresses.
169  * @scan: instance of the scan object
170  * @channel_survey: channel survey information collected during scan
171  * @wowlan: WoWLAN support data.
172  * @debug_max_sleep: maximum sleep time in D3 (for debug purposes)
173  * @led: the led device
174  * @mcc_src: the source id of the MCC, comes from the firmware
175  * @bios_enable_puncturing: is puncturing enabled by bios
176  * @fw_id_to_ba: maps a fw (BA) id to a corresponding Block Ack session data.
177  * @num_rx_ba_sessions: tracks the number of active Rx Block Ack (BA) sessions.
178  *	the driver ensures that new BA sessions are blocked once the maximum
179  *	supported by the firmware is reached, preventing firmware asserts.
180  * @rxq_sync: manages RX queue sync state
181  * @txqs_to_add: a list of &ieee80211_txq's to allocate in &add_txqs_wk
182  * @add_txqs_wk: a worker to allocate txqs.
183  * @add_txqs_lock: to lock the &txqs_to_add list.
184  * @error_recovery_buf: pointer to the recovery buffer that will be read
185  *	from firmware upon fw/hw error and sent back to the firmware in
186  *	reconfig flow (after NIC reset).
187  * @mcast_filter_cmd: pointer to the multicast filter command.
188  * @mgmt_tx_ant: stores the last TX antenna index; used for setting
189  *	TX rate_n_flags for non-STA mgmt frames (toggles on every TX failure).
190  * @set_tx_ant: stores the last TX antenna bitmask set by user space (if any)
191  * @set_rx_ant: stores the last RX antenna bitmask set by user space (if any)
192  * @fw_rates_ver_3: FW rates are in version 3
193  * @low_latency: low-latency manager.
194  * @tzone: thermal zone device's data
195  * @cooling_dev: cooling device's related data
196  * @ibss_manager: in IBSS mode (only one vif can be active), indicates what
197  *	firmware indicated about having transmitted the last beacon, i.e.
198  *	being IBSS manager for that time and needing to respond to probe
199  *	requests
200  * @ptp_data: data of the PTP clock
201  * @time_sync: time sync data.
202  * @ftm_initiator: FTM initiator data
203  * @nan_device_vif: points to the NAN device vif if exists
204  */
205 struct iwl_mld {
206 	/* Add here fields that need clean up on restart */
207 	struct_group(zeroed_on_hw_restart,
208 		struct ieee80211_bss_conf __rcu *fw_id_to_bss_conf[IWL_FW_MAX_LINK_ID + 1];
209 		struct ieee80211_vif __rcu *fw_id_to_vif[NUM_MAC_INDEX_DRIVER];
210 		struct ieee80211_txq __rcu *fw_id_to_txq[IWL_MAX_TVQM_QUEUES];
211 		u8 used_phy_ids: NUM_PHY_CTX;
212 		u8 num_igtks;
213 		struct {
214 			bool on;
215 			u32 ampdu_ref;
216 			bool ampdu_toggle;
217 			u8 p80;
218 			struct {
219 				struct iwl_rx_phy_air_sniffer_ntfy data;
220 				u8 valid:1, used:1;
221 			} phy;
222 #ifdef CONFIG_IWLWIFI_DEBUGFS
223 			__le16 cur_aid;
224 			u8 cur_bssid[ETH_ALEN];
225 			bool ptp_time;
226 #endif
227 		} monitor;
228 #ifdef CONFIG_PM_SLEEP
229 		bool netdetect;
230 #endif /* CONFIG_PM_SLEEP */
231 		struct ieee80211_vif *p2p_device_vif;
232 		bool bt_is_active;
233 		struct ieee80211_vif *nan_device_vif;
234 	);
235 	struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];
236 	/* And here fields that survive a fw restart */
237 	struct device *dev;
238 	struct iwl_trans *trans;
239 	const struct iwl_rf_cfg *cfg;
240 	const struct iwl_fw *fw;
241 	struct ieee80211_hw *hw;
242 	struct wiphy *wiphy;
243 	struct wiphy_iftype_ext_capab ext_capab[IWL_MLD_EXT_CAPA_NUM_IFTYPES];
244 	u8 sta_ext_capab[IWL_MLD_STA_EXT_CAPA_SIZE];
245 	struct iwl_nvm_data *nvm_data;
246 	struct iwl_fw_runtime fwrt;
247 	struct dentry *debugfs_dir;
248 	struct iwl_notif_wait_data notif_wait;
249 	struct list_head async_handlers_list;
250 	spinlock_t async_handlers_lock;
251 	struct wiphy_work async_handlers_wk;
252 	struct wiphy_delayed_work ct_kill_exit_wk;
253 
254 	struct {
255 		u32 running:1,
256 		    do_not_dump_once:1,
257 #ifdef CONFIG_PM_SLEEP
258 		    in_d3:1,
259 		    resuming:1,
260 #endif
261 		    in_hw_restart:1;
262 
263 	} fw_status;
264 
265 	struct {
266 		u32 hw:1,
267 		    ct:1;
268 	} radio_kill;
269 
270 	u32 power_budget_mw;
271 
272 	struct mac_address addresses[IWL_MLD_MAX_ADDRESSES];
273 	struct iwl_mld_scan scan;
274 	struct iwl_mld_survey *channel_survey;
275 #ifdef CONFIG_PM_SLEEP
276 	struct wiphy_wowlan_support wowlan;
277 	u32 debug_max_sleep;
278 #endif /* CONFIG_PM_SLEEP */
279 #ifdef CONFIG_IWLWIFI_LEDS
280 	struct led_classdev led;
281 #endif
282 	enum iwl_mcc_source mcc_src;
283 	bool bios_enable_puncturing;
284 
285 	struct iwl_mld_baid_data __rcu *fw_id_to_ba[IWL_MAX_BAID];
286 	u8 num_rx_ba_sessions;
287 
288 	struct iwl_mld_rx_queues_sync rxq_sync;
289 
290 	struct list_head txqs_to_add;
291 	struct wiphy_work add_txqs_wk;
292 	spinlock_t add_txqs_lock;
293 
294 	u8 *error_recovery_buf;
295 	struct iwl_mcast_filter_cmd *mcast_filter_cmd;
296 
297 	u8 mgmt_tx_ant;
298 
299 	u8 set_tx_ant;
300 	u8 set_rx_ant;
301 
302 	bool fw_rates_ver_3;
303 
304 	struct iwl_mld_low_latency low_latency;
305 
306 	bool ibss_manager;
307 #ifdef CONFIG_THERMAL
308 	struct thermal_zone_device *tzone;
309 	struct iwl_mld_cooling_device cooling_dev;
310 #endif
311 
312 	struct ptp_data ptp_data;
313 
314 	struct iwl_mld_time_sync_data __rcu *time_sync;
315 
316 	struct ftm_initiator_data ftm_initiator;
317 };
318 
319 /* memset the part of the struct that requires cleanup on restart */
320 #define CLEANUP_STRUCT(_ptr)                             \
321 	memset((void *)&(_ptr)->zeroed_on_hw_restart, 0, \
322 	       sizeof((_ptr)->zeroed_on_hw_restart))
323 
324 /* Cleanup function for struct iwl_mld, will be called in restart */
325 static inline void
iwl_cleanup_mld(struct iwl_mld * mld)326 iwl_cleanup_mld(struct iwl_mld *mld)
327 {
328 	CLEANUP_STRUCT(mld);
329 	CLEANUP_STRUCT(&mld->scan);
330 
331 #ifdef CONFIG_PM_SLEEP
332 	mld->fw_status.in_d3 = false;
333 #endif
334 
335 	iwl_mld_low_latency_restart_cleanup(mld);
336 }
337 
338 enum iwl_power_scheme {
339 	IWL_POWER_SCHEME_CAM = 1,
340 	IWL_POWER_SCHEME_BPS,
341 };
342 
343 /**
344  * struct iwl_mld_mod_params - module parameters for iwlmld
345  * @power_scheme: one of enum iwl_power_scheme
346  */
347 struct iwl_mld_mod_params {
348 	int power_scheme;
349 };
350 
351 extern struct iwl_mld_mod_params iwlmld_mod_params;
352 
353 /* Extract MLD priv from op_mode */
354 #define IWL_OP_MODE_GET_MLD(_iwl_op_mode)		\
355 	((struct iwl_mld *)(_iwl_op_mode)->op_mode_specific)
356 
357 #define IWL_MAC80211_GET_MLD(_hw)			\
358 	IWL_OP_MODE_GET_MLD((struct iwl_op_mode *)((_hw)->priv))
359 
360 #ifdef CONFIG_IWLWIFI_DEBUGFS
361 void
362 iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir);
363 #else
364 static inline void
iwl_mld_add_debugfs_files(struct iwl_mld * mld,struct dentry * debugfs_dir)365 iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir)
366 {}
367 #endif
368 
369 int iwl_mld_load_fw(struct iwl_mld *mld);
370 void iwl_mld_stop_fw(struct iwl_mld *mld);
371 int iwl_mld_start_fw(struct iwl_mld *mld);
372 void iwl_mld_send_recovery_cmd(struct iwl_mld *mld, u32 flags);
373 
iwl_mld_set_ctkill(struct iwl_mld * mld,bool state)374 static inline void iwl_mld_set_ctkill(struct iwl_mld *mld, bool state)
375 {
376 	mld->radio_kill.ct = state;
377 
378 	wiphy_rfkill_set_hw_state(mld->wiphy,
379 				  mld->radio_kill.hw || mld->radio_kill.ct);
380 }
381 
iwl_mld_set_hwkill(struct iwl_mld * mld,bool state)382 static inline void iwl_mld_set_hwkill(struct iwl_mld *mld, bool state)
383 {
384 	mld->radio_kill.hw = state;
385 
386 	wiphy_rfkill_set_hw_state(mld->wiphy,
387 				  mld->radio_kill.hw || mld->radio_kill.ct);
388 }
389 
iwl_mld_get_valid_tx_ant(const struct iwl_mld * mld)390 static inline u8 iwl_mld_get_valid_tx_ant(const struct iwl_mld *mld)
391 {
392 	u8 tx_ant = mld->fw->valid_tx_ant;
393 
394 	if (mld->nvm_data && mld->nvm_data->valid_tx_ant)
395 		tx_ant &= mld->nvm_data->valid_tx_ant;
396 
397 	if (mld->set_tx_ant)
398 		tx_ant &= mld->set_tx_ant;
399 
400 	return tx_ant;
401 }
402 
iwl_mld_get_valid_rx_ant(const struct iwl_mld * mld)403 static inline u8 iwl_mld_get_valid_rx_ant(const struct iwl_mld *mld)
404 {
405 	u8 rx_ant = mld->fw->valid_rx_ant;
406 
407 	if (mld->nvm_data && mld->nvm_data->valid_rx_ant)
408 		rx_ant &= mld->nvm_data->valid_rx_ant;
409 
410 	if (mld->set_rx_ant)
411 		rx_ant &= mld->set_rx_ant;
412 
413 	return rx_ant;
414 }
415 
iwl_mld_nl80211_band_to_fw(enum nl80211_band band)416 static inline u8 iwl_mld_nl80211_band_to_fw(enum nl80211_band band)
417 {
418 	switch (band) {
419 	case NL80211_BAND_2GHZ:
420 		return PHY_BAND_24;
421 	case NL80211_BAND_5GHZ:
422 		return PHY_BAND_5;
423 	case NL80211_BAND_6GHZ:
424 		return PHY_BAND_6;
425 	default:
426 		WARN_ONCE(1, "Unsupported band (%u)\n", band);
427 		return PHY_BAND_5;
428 	}
429 }
430 
iwl_mld_phy_band_to_nl80211(u8 phy_band)431 static inline u8 iwl_mld_phy_band_to_nl80211(u8 phy_band)
432 {
433 	switch (phy_band) {
434 	case PHY_BAND_24:
435 		return NL80211_BAND_2GHZ;
436 	case PHY_BAND_5:
437 		return NL80211_BAND_5GHZ;
438 	case PHY_BAND_6:
439 		return NL80211_BAND_6GHZ;
440 	default:
441 		WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band);
442 		return NL80211_BAND_5GHZ;
443 	}
444 }
445 
446 static inline int
iwl_mld_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,enum nl80211_band band)447 iwl_mld_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
448 				      enum nl80211_band band)
449 {
450 	int format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
451 	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
452 	bool is_lb = band == NL80211_BAND_2GHZ;
453 
454 	if (format == RATE_MCS_MOD_TYPE_LEGACY_OFDM)
455 		return is_lb ? rate + IWL_FIRST_OFDM_RATE : rate;
456 
457 	/* CCK is not allowed in 5 GHz */
458 	return is_lb ? rate : -1;
459 }
460 
461 extern const struct ieee80211_ops iwl_mld_hw_ops;
462 
463 /**
464  * enum iwl_rx_handler_context: context for Rx handler
465  * @RX_HANDLER_SYNC: this means that it will be called in the Rx path
466  *	which can't acquire the wiphy->mutex.
467  * @RX_HANDLER_ASYNC: If the handler needs to hold wiphy->mutex
468  *	(and only in this case!), it should be set as ASYNC. In that case,
469  *	it will be called from a worker with wiphy->mutex held.
470  */
471 enum iwl_rx_handler_context {
472 	RX_HANDLER_SYNC,
473 	RX_HANDLER_ASYNC,
474 };
475 
476 /**
477  * struct iwl_rx_handler: handler for FW notification
478  * @val_fn: input validation function.
479  * @sizes: an array that mapps a version to the expected size.
480  * @fn: the function is called when notification is handled
481  * @cmd_id: command id
482  * @n_sizes: number of elements in &sizes.
483  * @context: see &iwl_rx_handler_context
484  * @obj_type: the type of the object that this handler is related to.
485  *	See &iwl_mld_object_type. Use IWL_MLD_OBJECT_TYPE_NONE if not related.
486  * @cancel: function to cancel the notification. valid only if obj_type is not
487  *	IWL_MLD_OBJECT_TYPE_NONE.
488  */
489 struct iwl_rx_handler {
490 	union {
491 		bool (*val_fn)(struct iwl_mld *mld, struct iwl_rx_packet *pkt);
492 		const struct iwl_notif_struct_size *sizes;
493 	};
494 	void (*fn)(struct iwl_mld *mld, struct iwl_rx_packet *pkt);
495 	u16 cmd_id;
496 	u8 n_sizes;
497 	u8 context;
498 	enum iwl_mld_object_type obj_type;
499 	bool (*cancel)(struct iwl_mld *mld, struct iwl_rx_packet *pkt,
500 		       u32 obj_id);
501 };
502 
503 /**
504  * struct iwl_notif_struct_size: map a notif ver to the expected size
505  *
506  * @size: the size to expect
507  * @ver: the version of the notification
508  */
509 struct iwl_notif_struct_size {
510 	u32 size:24, ver:8;
511 };
512 
513 #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
514 extern const struct iwl_hcmd_arr iwl_mld_groups[];
515 extern const unsigned int global_iwl_mld_goups_size;
516 extern const struct iwl_rx_handler iwl_mld_rx_handlers[];
517 extern const unsigned int iwl_mld_rx_handlers_num;
518 
519 bool
520 iwl_mld_is_dup(struct iwl_mld *mld, struct ieee80211_sta *sta,
521 	       struct ieee80211_hdr *hdr,
522 	       const struct iwl_rx_mpdu_desc *mpdu_desc,
523 	       struct ieee80211_rx_status *rx_status, int queue);
524 
525 void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans,
526 		       const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw,
527 		       struct ieee80211_hw *hw, struct dentry *dbgfs_dir);
528 #endif
529 
530 #define IWL_MLD_INVALID_FW_ID 0xff
531 
532 #define IWL_MLD_ALLOC_FN(_type, _mac80211_type)						\
533 static int										\
534 iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld,					\
535 				 u8 *fw_id,				\
536 				 struct ieee80211_##_mac80211_type *mac80211_ptr)	\
537 {											\
538 	u8 rand = IWL_MLD_DIS_RANDOM_FW_ID ? 0 : get_random_u8();			\
539 	u8 arr_sz = ARRAY_SIZE(mld->fw_id_to_##_mac80211_type);				\
540 	if (__builtin_types_compatible_p(typeof(*mac80211_ptr),				\
541 					 struct ieee80211_link_sta))			\
542 		arr_sz = mld->fw->ucode_capa.num_stations;				\
543 	if (__builtin_types_compatible_p(typeof(*mac80211_ptr),				\
544 					 struct ieee80211_bss_conf))			\
545 		arr_sz = mld->fw->ucode_capa.num_links;					\
546 	for (int i = 0; i < arr_sz; i++) {						\
547 		u8 idx = (i + rand) % arr_sz;						\
548 		if (rcu_access_pointer(mld->fw_id_to_##_mac80211_type[idx]))		\
549 			continue;							\
550 		IWL_DEBUG_INFO(mld, "Allocated at index %d / %d\n", idx, arr_sz);	\
551 		*fw_id = idx;								\
552 		rcu_assign_pointer(mld->fw_id_to_##_mac80211_type[idx], mac80211_ptr);	\
553 		return 0;								\
554 	}										\
555 	return -ENOSPC;									\
556 }
557 
558 static inline struct ieee80211_bss_conf *
iwl_mld_fw_id_to_link_conf(struct iwl_mld * mld,u8 fw_link_id)559 iwl_mld_fw_id_to_link_conf(struct iwl_mld *mld, u8 fw_link_id)
560 {
561 	if (IWL_FW_CHECK(mld, fw_link_id >= mld->fw->ucode_capa.num_links,
562 			 "Invalid fw_link_id: %d\n", fw_link_id))
563 		return NULL;
564 
565 	return wiphy_dereference(mld->wiphy,
566 				 mld->fw_id_to_bss_conf[fw_link_id]);
567 }
568 
569 #define MSEC_TO_TU(_msec)	((_msec) * 1000 / 1024)
570 
571 void iwl_mld_add_vif_debugfs(struct ieee80211_hw *hw,
572 			     struct ieee80211_vif *vif);
573 void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw,
574 			      struct ieee80211_vif *vif,
575 			      struct ieee80211_bss_conf *link_conf,
576 			      struct dentry *dir);
577 void iwl_mld_add_link_sta_debugfs(struct ieee80211_hw *hw,
578 				  struct ieee80211_vif *vif,
579 				  struct ieee80211_link_sta *link_sta,
580 				  struct dentry *dir);
581 
582 /* Utilities */
583 
iwl_mld_mac80211_ac_to_fw_tx_fifo(enum ieee80211_ac_numbers ac)584 static inline u8 iwl_mld_mac80211_ac_to_fw_tx_fifo(enum ieee80211_ac_numbers ac)
585 {
586 	static const u8 mac80211_ac_to_fw_tx_fifo[] = {
587 		IWL_BZ_EDCA_TX_FIFO_VO,
588 		IWL_BZ_EDCA_TX_FIFO_VI,
589 		IWL_BZ_EDCA_TX_FIFO_BE,
590 		IWL_BZ_EDCA_TX_FIFO_BK,
591 		IWL_BZ_TRIG_TX_FIFO_VO,
592 		IWL_BZ_TRIG_TX_FIFO_VI,
593 		IWL_BZ_TRIG_TX_FIFO_BE,
594 		IWL_BZ_TRIG_TX_FIFO_BK,
595 	};
596 	return mac80211_ac_to_fw_tx_fifo[ac];
597 }
598 
599 static inline u32
iwl_mld_get_lmac_id(struct iwl_mld * mld,enum nl80211_band band)600 iwl_mld_get_lmac_id(struct iwl_mld *mld, enum nl80211_band band)
601 {
602 	if (!fw_has_capa(&mld->fw->ucode_capa,
603 			 IWL_UCODE_TLV_CAPA_CDB_SUPPORT) ||
604 	    band == NL80211_BAND_2GHZ)
605 		return IWL_LMAC_24G_INDEX;
606 	return IWL_LMAC_5G_INDEX;
607 }
608 
609 /* Check if we had an error, but reconfig flow didn't start yet */
iwl_mld_error_before_recovery(struct iwl_mld * mld)610 static inline bool iwl_mld_error_before_recovery(struct iwl_mld *mld)
611 {
612 	return mld->fw_status.in_hw_restart &&
613 		!iwl_trans_fw_running(mld->trans);
614 }
615 
616 int iwl_mld_tdls_sta_count(struct iwl_mld *mld);
617 
618 #endif /* __iwl_mld_h__ */
619