1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2 /*
3 * Copyright (C) 2024-2026 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 * @fw_id_to_ba: maps a fw (BA) id to a corresponding Block Ack session data.
176 * @num_rx_ba_sessions: tracks the number of active Rx Block Ack (BA) sessions.
177 * the driver ensures that new BA sessions are blocked once the maximum
178 * supported by the firmware is reached, preventing firmware asserts.
179 * @rxq_sync: manages RX queue sync state
180 * @txqs_to_add: a list of &ieee80211_txq's to allocate in &add_txqs_wk
181 * @add_txqs_wk: a worker to allocate txqs.
182 * @add_txqs_lock: to lock the &txqs_to_add list.
183 * @error_recovery_buf: pointer to the recovery buffer that will be read
184 * from firmware upon fw/hw error and sent back to the firmware in
185 * reconfig flow (after NIC reset).
186 * @mcast_filter_cmd: pointer to the multicast filter command.
187 * @mgmt_tx_ant: stores the last TX antenna index; used for setting
188 * TX rate_n_flags for non-STA mgmt frames (toggles on every TX failure).
189 * @set_tx_ant: stores the last TX antenna bitmask set by user space (if any)
190 * @set_rx_ant: stores the last RX antenna bitmask set by user space (if any)
191 * @low_latency: low-latency manager.
192 * @tzone: thermal zone device's data
193 * @cooling_dev: cooling device's related data
194 * @ibss_manager: in IBSS mode (only one vif can be active), indicates what
195 * firmware indicated about having transmitted the last beacon, i.e.
196 * being IBSS manager for that time and needing to respond to probe
197 * requests
198 * @ptp_data: data of the PTP clock
199 * @time_sync: time sync data.
200 * @ftm_initiator: FTM initiator data
201 * @nan_device_vif: points to the NAN device vif if exists
202 */
203 struct iwl_mld {
204 /* Add here fields that need clean up on restart */
205 struct_group(zeroed_on_hw_restart,
206 struct ieee80211_bss_conf __rcu *fw_id_to_bss_conf[IWL_FW_MAX_LINKS];
207 struct ieee80211_vif __rcu *fw_id_to_vif[NUM_MAC_INDEX_DRIVER];
208 struct ieee80211_txq __rcu *fw_id_to_txq[IWL_MAX_TVQM_QUEUES];
209 u8 used_phy_ids: NUM_PHY_CTX;
210 u8 num_igtks;
211 struct {
212 bool on;
213 u32 ampdu_ref;
214 bool ampdu_toggle;
215 u8 p80;
216 struct {
217 struct iwl_rx_phy_air_sniffer_ntfy data;
218 u8 valid:1, used:1;
219 } phy;
220 #ifdef CONFIG_IWLWIFI_DEBUGFS
221 __le16 cur_aid;
222 u8 cur_bssid[ETH_ALEN];
223 bool ptp_time;
224 #endif
225 } monitor;
226 #ifdef CONFIG_PM_SLEEP
227 bool netdetect;
228 #endif /* CONFIG_PM_SLEEP */
229 struct ieee80211_vif *p2p_device_vif;
230 bool bt_is_active;
231 struct ieee80211_vif *nan_device_vif;
232 );
233 struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];
234 /* And here fields that survive a fw restart */
235 struct device *dev;
236 struct iwl_trans *trans;
237 const struct iwl_rf_cfg *cfg;
238 const struct iwl_fw *fw;
239 struct ieee80211_hw *hw;
240 struct wiphy *wiphy;
241 struct wiphy_iftype_ext_capab ext_capab[IWL_MLD_EXT_CAPA_NUM_IFTYPES];
242 u8 sta_ext_capab[IWL_MLD_STA_EXT_CAPA_SIZE];
243 struct iwl_nvm_data *nvm_data;
244 struct iwl_fw_runtime fwrt;
245 struct dentry *debugfs_dir;
246 struct iwl_notif_wait_data notif_wait;
247 struct list_head async_handlers_list;
248 spinlock_t async_handlers_lock;
249 struct wiphy_work async_handlers_wk;
250 struct wiphy_delayed_work ct_kill_exit_wk;
251
252 struct {
253 u32 running:1,
254 do_not_dump_once:1,
255 #ifdef CONFIG_PM_SLEEP
256 in_d3:1,
257 resuming:1,
258 #endif
259 in_hw_restart:1;
260
261 } fw_status;
262
263 struct {
264 u32 hw:1,
265 ct:1;
266 } radio_kill;
267
268 u32 power_budget_mw;
269
270 struct mac_address addresses[IWL_MLD_MAX_ADDRESSES];
271 struct iwl_mld_scan scan;
272 struct iwl_mld_survey *channel_survey;
273 #ifdef CONFIG_PM_SLEEP
274 struct wiphy_wowlan_support wowlan;
275 u32 debug_max_sleep;
276 #endif /* CONFIG_PM_SLEEP */
277 #ifdef CONFIG_IWLWIFI_LEDS
278 struct led_classdev led;
279 #endif
280 enum iwl_mcc_source mcc_src;
281
282 struct iwl_mld_baid_data __rcu *fw_id_to_ba[IWL_MAX_BAID];
283 u8 num_rx_ba_sessions;
284
285 struct iwl_mld_rx_queues_sync rxq_sync;
286
287 struct list_head txqs_to_add;
288 struct wiphy_work add_txqs_wk;
289 spinlock_t add_txqs_lock;
290
291 u8 *error_recovery_buf;
292 struct iwl_mcast_filter_cmd *mcast_filter_cmd;
293
294 u8 mgmt_tx_ant;
295
296 u8 set_tx_ant;
297 u8 set_rx_ant;
298
299 struct iwl_mld_low_latency low_latency;
300
301 bool ibss_manager;
302 #ifdef CONFIG_THERMAL
303 struct thermal_zone_device *tzone;
304 struct iwl_mld_cooling_device cooling_dev;
305 #endif
306
307 struct ptp_data ptp_data;
308
309 struct iwl_mld_time_sync_data __rcu *time_sync;
310
311 struct ftm_initiator_data ftm_initiator;
312 };
313
314 /* memset the part of the struct that requires cleanup on restart */
315 #define CLEANUP_STRUCT(_ptr) \
316 memset((void *)&(_ptr)->zeroed_on_hw_restart, 0, \
317 sizeof((_ptr)->zeroed_on_hw_restart))
318
319 /* Cleanup function for struct iwl_mld, will be called in restart */
320 static inline void
iwl_cleanup_mld(struct iwl_mld * mld)321 iwl_cleanup_mld(struct iwl_mld *mld)
322 {
323 CLEANUP_STRUCT(mld);
324 CLEANUP_STRUCT(&mld->scan);
325
326 #ifdef CONFIG_PM_SLEEP
327 mld->fw_status.in_d3 = false;
328 #endif
329
330 iwl_mld_low_latency_restart_cleanup(mld);
331 }
332
333 enum iwl_power_scheme {
334 IWL_POWER_SCHEME_CAM = 1,
335 IWL_POWER_SCHEME_BPS,
336 };
337
338 /**
339 * struct iwl_mld_mod_params - module parameters for iwlmld
340 * @power_scheme: one of enum iwl_power_scheme
341 */
342 struct iwl_mld_mod_params {
343 int power_scheme;
344 };
345
346 extern struct iwl_mld_mod_params iwlmld_mod_params;
347
348 /* Extract MLD priv from op_mode */
349 #define IWL_OP_MODE_GET_MLD(_iwl_op_mode) \
350 ((struct iwl_mld *)(_iwl_op_mode)->op_mode_specific)
351
352 #define IWL_MAC80211_GET_MLD(_hw) \
353 IWL_OP_MODE_GET_MLD((struct iwl_op_mode *)((_hw)->priv))
354
355 #ifdef CONFIG_IWLWIFI_DEBUGFS
356 void
357 iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir);
358 #else
359 static inline void
iwl_mld_add_debugfs_files(struct iwl_mld * mld,struct dentry * debugfs_dir)360 iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir)
361 {}
362 #endif
363
364 int iwl_mld_load_fw(struct iwl_mld *mld);
365 void iwl_mld_stop_fw(struct iwl_mld *mld);
366 int iwl_mld_start_fw(struct iwl_mld *mld);
367 void iwl_mld_send_recovery_cmd(struct iwl_mld *mld, u32 flags);
368
iwl_mld_set_ctkill(struct iwl_mld * mld,bool state)369 static inline void iwl_mld_set_ctkill(struct iwl_mld *mld, bool state)
370 {
371 mld->radio_kill.ct = state;
372
373 wiphy_rfkill_set_hw_state(mld->wiphy,
374 mld->radio_kill.hw || mld->radio_kill.ct);
375 }
376
iwl_mld_set_hwkill(struct iwl_mld * mld,bool state)377 static inline void iwl_mld_set_hwkill(struct iwl_mld *mld, bool state)
378 {
379 mld->radio_kill.hw = state;
380
381 wiphy_rfkill_set_hw_state(mld->wiphy,
382 mld->radio_kill.hw || mld->radio_kill.ct);
383 }
384
iwl_mld_get_valid_tx_ant(const struct iwl_mld * mld)385 static inline u8 iwl_mld_get_valid_tx_ant(const struct iwl_mld *mld)
386 {
387 u8 tx_ant = mld->fw->valid_tx_ant;
388
389 if (mld->nvm_data && mld->nvm_data->valid_tx_ant)
390 tx_ant &= mld->nvm_data->valid_tx_ant;
391
392 if (mld->set_tx_ant)
393 tx_ant &= mld->set_tx_ant;
394
395 return tx_ant;
396 }
397
iwl_mld_get_valid_rx_ant(const struct iwl_mld * mld)398 static inline u8 iwl_mld_get_valid_rx_ant(const struct iwl_mld *mld)
399 {
400 u8 rx_ant = mld->fw->valid_rx_ant;
401
402 if (mld->nvm_data && mld->nvm_data->valid_rx_ant)
403 rx_ant &= mld->nvm_data->valid_rx_ant;
404
405 if (mld->set_rx_ant)
406 rx_ant &= mld->set_rx_ant;
407
408 return rx_ant;
409 }
410
iwl_mld_nl80211_band_to_fw(enum nl80211_band band)411 static inline u8 iwl_mld_nl80211_band_to_fw(enum nl80211_band band)
412 {
413 switch (band) {
414 case NL80211_BAND_2GHZ:
415 return PHY_BAND_24;
416 case NL80211_BAND_5GHZ:
417 return PHY_BAND_5;
418 case NL80211_BAND_6GHZ:
419 return PHY_BAND_6;
420 default:
421 WARN_ONCE(1, "Unsupported band (%u)\n", band);
422 return PHY_BAND_5;
423 }
424 }
425
iwl_mld_phy_band_to_nl80211(u8 phy_band)426 static inline u8 iwl_mld_phy_band_to_nl80211(u8 phy_band)
427 {
428 switch (phy_band) {
429 case PHY_BAND_24:
430 return NL80211_BAND_2GHZ;
431 case PHY_BAND_5:
432 return NL80211_BAND_5GHZ;
433 case PHY_BAND_6:
434 return NL80211_BAND_6GHZ;
435 default:
436 WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band);
437 return NL80211_BAND_5GHZ;
438 }
439 }
440
441 static inline int
iwl_mld_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,enum nl80211_band band)442 iwl_mld_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
443 enum nl80211_band band)
444 {
445 int format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
446 int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
447 bool is_lb = band == NL80211_BAND_2GHZ;
448
449 if (format == RATE_MCS_MOD_TYPE_LEGACY_OFDM)
450 return is_lb ? rate + IWL_FIRST_OFDM_RATE : rate;
451
452 /* CCK is not allowed in 5 GHz */
453 return is_lb ? rate : -1;
454 }
455
456 extern const struct ieee80211_ops iwl_mld_hw_ops;
457
458 /**
459 * enum iwl_rx_handler_context: context for Rx handler
460 * @RX_HANDLER_SYNC: this means that it will be called in the Rx path
461 * which can't acquire the wiphy->mutex.
462 * @RX_HANDLER_ASYNC: If the handler needs to hold wiphy->mutex
463 * (and only in this case!), it should be set as ASYNC. In that case,
464 * it will be called from a worker with wiphy->mutex held.
465 */
466 enum iwl_rx_handler_context {
467 RX_HANDLER_SYNC,
468 RX_HANDLER_ASYNC,
469 };
470
471 /**
472 * struct iwl_rx_handler: handler for FW notification
473 * @val_fn: input validation function.
474 * @sizes: an array that mapps a version to the expected size.
475 * @fn: the function is called when notification is handled
476 * @cmd_id: command id
477 * @n_sizes: number of elements in &sizes.
478 * @context: see &iwl_rx_handler_context
479 * @obj_type: the type of the object that this handler is related to.
480 * See &iwl_mld_object_type. Use IWL_MLD_OBJECT_TYPE_NONE if not related.
481 * @cancel: function to cancel the notification. valid only if obj_type is not
482 * IWL_MLD_OBJECT_TYPE_NONE.
483 */
484 struct iwl_rx_handler {
485 union {
486 bool (*val_fn)(struct iwl_mld *mld, struct iwl_rx_packet *pkt);
487 const struct iwl_notif_struct_size *sizes;
488 };
489 void (*fn)(struct iwl_mld *mld, struct iwl_rx_packet *pkt);
490 u16 cmd_id;
491 u8 n_sizes;
492 u8 context;
493 enum iwl_mld_object_type obj_type;
494 bool (*cancel)(struct iwl_mld *mld, struct iwl_rx_packet *pkt,
495 u32 obj_id);
496 };
497
498 /**
499 * struct iwl_notif_struct_size: map a notif ver to the expected size
500 *
501 * @size: the size to expect
502 * @ver: the version of the notification
503 */
504 struct iwl_notif_struct_size {
505 u32 size:24, ver:8;
506 };
507
508 #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
509 extern const struct iwl_hcmd_arr iwl_mld_groups[];
510 extern const unsigned int global_iwl_mld_goups_size;
511 extern const struct iwl_rx_handler iwl_mld_rx_handlers[];
512 extern const unsigned int iwl_mld_rx_handlers_num;
513
514 bool
515 iwl_mld_is_dup(struct iwl_mld *mld, struct ieee80211_sta *sta,
516 struct ieee80211_hdr *hdr,
517 const struct iwl_rx_mpdu_desc *mpdu_desc,
518 struct ieee80211_rx_status *rx_status, int queue);
519
520 void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans,
521 const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw,
522 struct ieee80211_hw *hw, struct dentry *dbgfs_dir);
523 #endif
524
525 #define IWL_MLD_INVALID_FW_ID 0xff
526
527 #define IWL_MLD_ALLOC_FN(_type, _mac80211_type) \
528 int \
529 iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld, \
530 u8 *fw_id, \
531 struct ieee80211_##_mac80211_type *mac80211_ptr) \
532 { \
533 u8 rand = IWL_MLD_DIS_RANDOM_FW_ID ? 0 : get_random_u8(); \
534 u8 arr_sz = ARRAY_SIZE(mld->fw_id_to_##_mac80211_type); \
535 if (__builtin_types_compatible_p(typeof(*mac80211_ptr), \
536 struct ieee80211_link_sta)) \
537 arr_sz = mld->fw->ucode_capa.num_stations; \
538 if (__builtin_types_compatible_p(typeof(*mac80211_ptr), \
539 struct ieee80211_bss_conf)) \
540 arr_sz = mld->fw->ucode_capa.num_links; \
541 for (int i = 0; i < arr_sz; i++) { \
542 u8 idx = (i + rand) % arr_sz; \
543 if (rcu_access_pointer(mld->fw_id_to_##_mac80211_type[idx])) \
544 continue; \
545 IWL_DEBUG_INFO(mld, "Allocated at index %d / %d\n", idx, arr_sz); \
546 *fw_id = idx; \
547 rcu_assign_pointer(mld->fw_id_to_##_mac80211_type[idx], mac80211_ptr); \
548 return 0; \
549 } \
550 return -ENOSPC; \
551 }
552
553 #define IWL_MLD_ALLOC_FN_STATIC(_type, _mac80211_type) \
554 static IWL_MLD_ALLOC_FN(_type, _mac80211_type)
555
556 static inline struct ieee80211_bss_conf *
iwl_mld_fw_id_to_link_conf(struct iwl_mld * mld,u8 fw_link_id)557 iwl_mld_fw_id_to_link_conf(struct iwl_mld *mld, u8 fw_link_id)
558 {
559 struct ieee80211_bss_conf *link;
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 link = wiphy_dereference(mld->wiphy,
566 mld->fw_id_to_bss_conf[fw_link_id]);
567 if (IS_ERR(link))
568 return NULL;
569
570 return link;
571 }
572
573 #define MSEC_TO_TU(_msec) ((_msec) * 1000 / 1024)
574
575 void iwl_mld_add_vif_debugfs(struct ieee80211_hw *hw,
576 struct ieee80211_vif *vif);
577 void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw,
578 struct ieee80211_vif *vif,
579 struct ieee80211_bss_conf *link_conf,
580 struct dentry *dir);
581 void iwl_mld_add_link_sta_debugfs(struct ieee80211_hw *hw,
582 struct ieee80211_vif *vif,
583 struct ieee80211_link_sta *link_sta,
584 struct dentry *dir);
585
586 /* Utilities */
587
iwl_mld_mac80211_ac_to_fw_tx_fifo(enum ieee80211_ac_numbers ac)588 static inline u8 iwl_mld_mac80211_ac_to_fw_tx_fifo(enum ieee80211_ac_numbers ac)
589 {
590 static const u8 mac80211_ac_to_fw_tx_fifo[] = {
591 IWL_BZ_EDCA_TX_FIFO_VO,
592 IWL_BZ_EDCA_TX_FIFO_VI,
593 IWL_BZ_EDCA_TX_FIFO_BE,
594 IWL_BZ_EDCA_TX_FIFO_BK,
595 IWL_BZ_TRIG_TX_FIFO_VO,
596 IWL_BZ_TRIG_TX_FIFO_VI,
597 IWL_BZ_TRIG_TX_FIFO_BE,
598 IWL_BZ_TRIG_TX_FIFO_BK,
599 };
600 return mac80211_ac_to_fw_tx_fifo[ac];
601 }
602
603 static inline u32
iwl_mld_get_lmac_id(struct iwl_mld * mld,enum nl80211_band band)604 iwl_mld_get_lmac_id(struct iwl_mld *mld, enum nl80211_band band)
605 {
606 if (!fw_has_capa(&mld->fw->ucode_capa,
607 IWL_UCODE_TLV_CAPA_CDB_SUPPORT) ||
608 band == NL80211_BAND_2GHZ)
609 return IWL_LMAC_24G_INDEX;
610 return IWL_LMAC_5G_INDEX;
611 }
612
613 /* Check if we had an error, but reconfig flow didn't start yet */
iwl_mld_error_before_recovery(struct iwl_mld * mld)614 static inline bool iwl_mld_error_before_recovery(struct iwl_mld *mld)
615 {
616 return mld->fw_status.in_hw_restart &&
617 !iwl_trans_fw_running(mld->trans);
618 }
619
620 int iwl_mld_tdls_sta_count(struct iwl_mld *mld);
621
622 #endif /* __iwl_mld_h__ */
623