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