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