wifi: iwlwifi-next : updates - 2026-06-03

This pull request contains iwlwifi features and cleanups. Notably:
 
 - Bump max core version for BZ/SC/DR to 106.
 - Add KUnit tests for link grading, RSSI adjustment, and beacon
   handling;
 - Drop core101 support and remove TLC config v4/v5 compatibility code.
 - Fixes:
         Fix PCIe write pointer detection
         Fix STEP_URM register address
         Remove unneeded WoWLAN warning
         reduce NIC wakeups during dump.
         Revert MODULE_FIRMWARE relocation change
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQM3A3Pv7vbm9vtjWbacY7uyt+OfQUCaiA4nQAKCRDacY7uyt+O
 fcECAQC8YSlz1duQiMiuLTQ1WJ55yG8hncvPlgvUwEUHD8E/wgEAgjHPS566XWfU
 /H4pc3CEZT+w8LRHhvvJiYWXpmmnvgs=
 =+5Cu
 -----END PGP SIGNATURE-----

Merge tag 'iwlwifi-next-2026-06-03' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

Miri Korenblit says:
====================
wifi: iwlwifi-next : updates - 2026-06-03

This pull request contains iwlwifi features and cleanups. Notably:

- Bump max core version for BZ/SC/DR to 106.
- Add KUnit tests for link grading, RSSI adjustment, and beacon
  handling;
- Drop core101 support and remove TLC config v4/v5 compatibility code.
- Fixes:
        Fix PCIe write pointer detection
        Fix STEP_URM register address
        Remove unneeded WoWLAN warning
        reduce NIC wakeups during dump.
        Revert MODULE_FIRMWARE relocation change
====================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-06-04 13:05:52 +02:00
commit a26c2a22e7
43 changed files with 1032 additions and 307 deletions

View File

@ -10,10 +10,16 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
#define IWL_BZ_UCODE_CORE_MAX 105
#define IWL_BZ_UCODE_CORE_MAX 106
/* Lowest firmware core release supported */
#define IWL_BZ_UCODE_CORE_MIN 101
#define IWL_BZ_UCODE_CORE_MIN 102
#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0"
#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0"
#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0"
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0"
#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0"
static const struct iwl_family_base_params iwl_bz_base = {
.num_of_queues = 512,
@ -85,3 +91,9 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = {
.xtal_latency = 12000,
.low_latency_xtal = true,
};
IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);

View File

@ -9,10 +9,10 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
#define IWL_DR_UCODE_CORE_MAX 105
#define IWL_DR_UCODE_CORE_MAX 106
/* Lowest firmware core release supported */
#define IWL_DR_UCODE_CORE_MIN 101
#define IWL_DR_UCODE_CORE_MIN 102
#define IWL_DR_A_PE_A_FW_PRE "iwlwifi-dr-a0-pe-a0"

View File

@ -5,12 +5,6 @@
*/
#include "iwl-config.h"
#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0"
#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0"
#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0"
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0"
#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0"
#define IWL_DEVICE_FM \
.ht_params = { \
.stbc = true, \
@ -54,9 +48,3 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz";
const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz";
const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz";
const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz";
IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2025 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
#include "iwl-config.h"
@ -60,6 +60,7 @@ const char iwl_ax411_killer_1690i_name[] =
const char iwl_ax210_name[] = "Intel(R) Wi-Fi 6E AX210 160MHz";
const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz";
const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6 AX231";
const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz";
MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX));

View File

@ -10,10 +10,10 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
#define IWL_SC_UCODE_CORE_MAX 105
#define IWL_SC_UCODE_CORE_MAX 106
/* Lowest firmware core release supported */
#define IWL_SC_UCODE_CORE_MIN 101
#define IWL_SC_UCODE_CORE_MIN 102
#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0"
#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0"

View File

@ -466,8 +466,8 @@ enum iwl_legacy_cmds {
MCC_CHUB_UPDATE_CMD = 0xc9,
/**
* @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker
* with &struct iwl_mvm_marker_rsp
* @MARKER_CMD: trace marker command, uses &struct iwl_marker
* with &struct iwl_marker_rsp
*/
MARKER_CMD = 0xcb,

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2019, 2023-2024 Intel Corporation
* Copyright (C) 2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -99,14 +100,4 @@ struct iwl_phy_cfg_cmd_v3 {
struct iwl_phy_specific_cfg phy_specific_cfg;
} __packed; /* PHY_CONFIGURATION_CMD_API_S_VER_3 */
/*
* enum iwl_dc2dc_config_id - flag ids
*
* Ids of dc2dc configuration flags
*/
enum iwl_dc2dc_config_id {
DCDC_LOW_POWER_MODE_MSK_SET = 0x1, /* not used */
DCDC_FREQ_TUNE_SET = 0x2,
}; /* MARKER_ID_API_E_VER_1 */
#endif /* __iwl_fw_api_config_h__ */

View File

@ -57,7 +57,7 @@ enum iwl_data_path_subcmd_ids {
/**
* @TLC_MNG_CONFIG_CMD: &struct iwl_tlc_config_cmd_v4 or
* &struct iwl_tlc_config_cmd_v5 or &struct iwl_tlc_config_cmd.
* &struct iwl_tlc_config_cmd.
*/
TLC_MNG_CONFIG_CMD = 0xF,

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2005-2014, 2018-2025 Intel Corporation
* Copyright (C) 2005-2014, 2018-2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -262,20 +262,20 @@ struct iwl_mfu_assert_dump_notif {
} __packed; /* MFU_DUMP_ASSERT_API_S_VER_1 */
/**
* enum iwl_mvm_marker_id - marker ids
* enum iwl_marker_id - marker ids
*
* The ids for different type of markers to insert into the usniffer logs
*
* @MARKER_ID_TX_FRAME_LATENCY: TX latency marker
* @MARKER_ID_SYNC_CLOCK: sync FW time and systime
*/
enum iwl_mvm_marker_id {
enum iwl_marker_id {
MARKER_ID_TX_FRAME_LATENCY = 1,
MARKER_ID_SYNC_CLOCK = 2,
}; /* MARKER_ID_API_E_VER_2 */
/**
* struct iwl_mvm_marker - mark info into the usniffer logs
* struct iwl_marker - mark info into the usniffer logs
*
* (MARKER_CMD = 0xcb)
*
@ -284,12 +284,12 @@ enum iwl_mvm_marker_id {
* In the command response the ucode will return the GP2 time.
*
* @dw_len: The amount of dwords following this byte including this byte.
* @marker_id: A unique marker id (iwl_mvm_marker_id).
* @marker_id: A unique marker id (iwl_marker_id).
* @reserved: reserved.
* @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC
* @metadata: additional meta data that will be written to the unsiffer log
*/
struct iwl_mvm_marker {
struct iwl_marker {
u8 dw_len;
u8 marker_id;
__le16 reserved;
@ -298,11 +298,11 @@ struct iwl_mvm_marker {
} __packed; /* MARKER_API_S_VER_1 */
/**
* struct iwl_mvm_marker_rsp - Response to marker cmd
* struct iwl_marker_rsp - Response to marker cmd
*
* @gp2: The gp2 clock value in the FW
*/
struct iwl_mvm_marker_rsp {
struct iwl_marker_rsp {
__le32 gp2;
} __packed;

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2022, 2024-2025 Intel Corporation
* Copyright (C) 2012-2014, 2018-2022, 2024-2026 Intel Corporation
* Copyright (C) 2017 Intel Deutschland GmbH
*/
#ifndef __iwl_fw_api_rs_h__
@ -206,37 +206,6 @@ struct iwl_tlc_config_cmd_v4 {
__le16 max_tx_op;
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */
/**
* struct iwl_tlc_config_cmd_v5 - TLC configuration
* @sta_id: station id
* @reserved1: reserved
* @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw
* @mode: &enum iwl_tlc_mng_cfg_mode
* @chains: bitmask of &enum iwl_tlc_mng_cfg_chains
* @sgi_ch_width_supp: bitmap of SGI support per channel width
* use BIT(&enum iwl_tlc_mng_cfg_cw)
* @flags: bitmask of &enum iwl_tlc_mng_cfg_flags
* @non_ht_rates: bitmap of supported legacy rates
* @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per <nss, channel-width>
* pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz).
* @max_mpdu_len: max MPDU length, in bytes
* @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
* set zero for no limit.
*/
struct iwl_tlc_config_cmd_v5 {
u8 sta_id;
u8 reserved1[3];
u8 max_ch_width;
u8 mode;
u8 chains;
u8 sgi_ch_width_supp;
__le16 flags;
__le16 non_ht_rates;
__le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4];
__le16 max_mpdu_len;
__le16 max_tx_op;
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */
/**
* struct iwl_tlc_config_cmd - TLC configuration
* @sta_mask: station mask (in NAN we can have multiple logical stations of
@ -889,7 +858,6 @@ struct iwl_lq_cmd {
__le32 ss_params;
}; /* LINK_QUALITY_CMD_API_S_VER_1 */
u8 iwl_fw_rate_idx_to_plcp(int idx);
const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx);
const char *iwl_rs_pretty_ant(u8 ant);
const char *iwl_rs_pretty_bw(int bw);

View File

@ -103,7 +103,7 @@ static int iwl_dump_ini_prph_mac_iter_common(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = size;
for (i = 0; i < le32_to_cpu(size); i += 4)
*val++ = cpu_to_le32(iwl_read_prph(fwrt->trans, addr + i));
*val++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr + i));
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -158,9 +158,6 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt,
indirect_wr_addr += le32_to_cpu(offset);
indirect_rd_addr += le32_to_cpu(offset);
if (!iwl_trans_grab_nic_access(fwrt->trans))
return -EBUSY;
dphy_addr = (offset) ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW;
dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr);
@ -194,7 +191,6 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt,
*val++ = cpu_to_le32(prph_val);
}
iwl_trans_release_nic_access(fwrt->trans);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -283,8 +279,8 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->dev_addr.size;
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
le32_to_cpu(reg->dev_addr.size));
iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data,
le32_to_cpu(reg->dev_addr.size));
if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM &&
fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
@ -368,8 +364,8 @@ static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->internal_buffer.size;
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
le32_to_cpu(reg->internal_buffer.size));
iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data,
le32_to_cpu(reg->internal_buffer.size));
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -443,9 +439,6 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
if (!iwl_ini_txf_iter(fwrt, reg_data, idx))
return -EIO;
if (!iwl_trans_grab_nic_access(fwrt->trans))
return -EBUSY;
range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo);
range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);
@ -489,8 +482,6 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
reg_dump, iter->fifo_size);
out:
iwl_trans_release_nic_access(fwrt->trans);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -511,9 +502,6 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->dev_addr.size;
if (!iwl_trans_grab_nic_access(fwrt->trans))
return -EBUSY;
indirect_rd_wr_addr += le32_to_cpu(offset);
dphy_addr = offset ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW;
@ -537,7 +525,6 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt,
DPHYIP_INDIRECT_RD_SHIFT);
}
iwl_trans_release_nic_access(fwrt->trans);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -626,9 +613,6 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
if (!rxf_data.size)
return -EIO;
if (!iwl_trans_grab_nic_access(fwrt->trans))
return -EBUSY;
range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num);
range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
range->range_data_size = cpu_to_le32(rxf_data.size + registers_size);
@ -668,8 +652,6 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
*data++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr));
out:
iwl_trans_release_nic_access(fwrt->trans);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -686,8 +668,8 @@ iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = err_table->size;
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
le32_to_cpu(err_table->size));
iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data,
le32_to_cpu(err_table->size));
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -707,8 +689,8 @@ iwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt,
range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = special_mem->size;
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
le32_to_cpu(special_mem->size));
iwl_trans_read_mem_bytes_no_grab(fwrt->trans, addr, range->data,
le32_to_cpu(special_mem->size));
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -724,9 +706,6 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt,
u32 prph_data;
int i;
if (!iwl_trans_grab_nic_access(fwrt->trans))
return -EBUSY;
range->range_data_size = reg->dev_addr.size;
for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) {
prph_data =
@ -734,13 +713,11 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt,
(i % 2) ?
DBGI_SRAM_TARGET_ACCESS_RDATA_MSB :
DBGI_SRAM_TARGET_ACCESS_RDATA_LSB);
if (iwl_trans_is_hw_error_value(prph_data)) {
iwl_trans_release_nic_access(fwrt->trans);
if (iwl_trans_is_hw_error_value(prph_data))
return -EBUSY;
}
*val++ = cpu_to_le32(prph_data);
}
iwl_trans_release_nic_access(fwrt->trans);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -787,8 +764,8 @@ static int iwl_dump_ini_imr_iter(struct iwl_fw_runtime *fwrt,
fwrt->trans->dbg.imr_data.imr_curr_addr = imr_curr_addr + size_to_dump;
fwrt->trans->dbg.imr_data.imr2sram_remainbyte -= size_to_dump;
iwl_trans_read_mem_bytes(fwrt->trans, sram_addr, range->data,
size_to_dump);
iwl_trans_read_mem_bytes_no_grab(fwrt->trans, sram_addr, range->data,
size_to_dump);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@ -842,11 +819,6 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id,
struct iwl_fw_ini_monitor_dump *data,
const struct iwl_fw_mon_regs *addrs)
{
if (!iwl_trans_grab_nic_access(fwrt->trans)) {
IWL_ERR(fwrt, "Failed to get monitor header\n");
return NULL;
}
data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id,
&addrs->write_ptr);
if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
@ -859,8 +831,6 @@ iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id,
data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id,
&addrs->cur_frag);
iwl_trans_release_nic_access(fwrt->trans);
data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
return data->data;
@ -1266,6 +1236,7 @@ iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt,
* the first range or NULL if failed to fill headers.
* @fill_range: copies a given memory range into the dump.
* Returns the size of the range or negative error value otherwise.
* @requires_nic_access: indicates to dump only if NIC access was acquired
*/
struct iwl_dump_ini_mem_ops {
u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt,
@ -1278,6 +1249,7 @@ struct iwl_dump_ini_mem_ops {
int (*fill_range)(struct iwl_fw_runtime *fwrt,
struct iwl_dump_ini_region_data *reg_data,
void *range, int idx);
bool requires_nic_access;
};
struct iwl_fw_ini_dump_entry {
@ -1374,7 +1346,8 @@ static void iwl_dump_ini_mem_prep(struct iwl_fw_runtime *fwrt,
}
static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_dump_entry *entry)
struct iwl_fw_ini_dump_entry *entry,
bool have_nic_access)
{
struct iwl_dump_ini_region_data *reg_data = &entry->reg_data;
struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
@ -1388,6 +1361,9 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
u32 free_size;
u64 header_size;
if (!have_nic_access && ops->requires_nic_access)
goto out_err;
tlv = (void *)entry->data;
header = (void *)tlv->data;
@ -1541,36 +1517,42 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
.get_size = iwl_dump_ini_mon_smem_get_size,
.fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header,
.fill_range = iwl_dump_ini_mon_smem_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_DRAM_BUFFER] = {
.get_num_of_ranges = iwl_dump_ini_mon_dram_ranges,
.get_size = iwl_dump_ini_mon_dram_get_size,
.fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header,
.fill_range = iwl_dump_ini_mon_dram_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_TXF] = {
.get_num_of_ranges = iwl_dump_ini_txf_ranges,
.get_size = iwl_dump_ini_txf_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_txf_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_RXF] = {
.get_num_of_ranges = iwl_dump_ini_single_range,
.get_size = iwl_dump_ini_rxf_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_rxf_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = {
.get_num_of_ranges = iwl_dump_ini_single_range,
.get_size = iwl_dump_ini_err_table_get_size,
.fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
.fill_range = iwl_dump_ini_err_table_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = {
.get_num_of_ranges = iwl_dump_ini_single_range,
.get_size = iwl_dump_ini_err_table_get_size,
.fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
.fill_range = iwl_dump_ini_err_table_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_RSP_OR_NOTIF] = {
.get_num_of_ranges = iwl_dump_ini_single_range,
@ -1583,30 +1565,35 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
.get_size = iwl_dump_ini_mem_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_dev_mem_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_MAC] = {
.get_num_of_ranges = iwl_dump_ini_mem_ranges,
.get_size = iwl_dump_ini_mem_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_prph_mac_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_PHY] = {
.get_num_of_ranges = iwl_dump_ini_mem_ranges,
.get_size = iwl_dump_ini_mem_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_prph_phy_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE] = {
.get_num_of_ranges = iwl_dump_ini_mem_block_ranges,
.get_size = iwl_dump_ini_mem_block_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_prph_mac_block_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE] = {
.get_num_of_ranges = iwl_dump_ini_mem_block_ranges,
.get_size = iwl_dump_ini_mem_block_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_prph_phy_block_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_AUX] = {},
[IWL_FW_INI_REGION_PAGING] = {
@ -1626,6 +1613,7 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
.get_size = iwl_dump_ini_imr_get_size,
.fill_mem_hdr = iwl_dump_ini_imr_fill_header,
.fill_range = iwl_dump_ini_imr_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = {
.get_num_of_ranges = iwl_dump_ini_mem_ranges,
@ -1638,18 +1626,21 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
.get_size = iwl_dump_ini_special_mem_get_size,
.fill_mem_hdr = iwl_dump_ini_special_mem_fill_header,
.fill_range = iwl_dump_ini_special_mem_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_DBGI_SRAM] = {
.get_num_of_ranges = iwl_dump_ini_mem_ranges,
.get_size = iwl_dump_ini_mon_dbgi_get_size,
.fill_mem_hdr = iwl_dump_ini_mon_dbgi_fill_header,
.fill_range = iwl_dump_ini_dbgi_sram_iter,
.requires_nic_access = true,
},
[IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP] = {
.get_num_of_ranges = iwl_dump_ini_mem_ranges,
.get_size = iwl_dump_ini_mem_get_size,
.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
.fill_range = iwl_dump_ini_prph_snps_dphyip_iter,
.requires_nic_access = true,
},
};
@ -1733,8 +1724,11 @@ iwl_dump_ini_dump_entries(struct iwl_fw_runtime *fwrt,
enum iwl_dump_ini_region_selector which)
{
struct iwl_fw_ini_dump_entry *entry, *tmp;
bool have_nic_access;
u32 size = 0;
have_nic_access = iwl_trans_grab_nic_access(fwrt->trans);
list_for_each_entry_safe(entry, tmp, list, list) {
u32 dp = entry->region_dump_policy;
@ -1751,9 +1745,15 @@ iwl_dump_ini_dump_entries(struct iwl_fw_runtime *fwrt,
break;
}
size += iwl_dump_ini_mem(fwrt, entry);
size += iwl_dump_ini_mem(fwrt, entry, have_nic_access);
if (have_nic_access)
iwl_trans_resched_with_nic_access(fwrt->trans);
}
if (have_nic_access)
iwl_trans_release_nic_access(fwrt->trans);
return size;
}
@ -2383,8 +2383,8 @@ static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
{
struct iwl_mvm_marker marker = {
.dw_len = sizeof(struct iwl_mvm_marker) / 4,
struct iwl_marker marker = {
.dw_len = sizeof(struct iwl_marker) / 4,
.marker_id = MARKER_ID_SYNC_CLOCK,
};
struct iwl_host_cmd hcmd = {
@ -2392,7 +2392,7 @@ int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
.id = WIDE_ID(LONG_GROUP, MARKER_CMD),
.dataflags = {},
};
struct iwl_mvm_marker_rsp *resp;
struct iwl_marker_rsp *resp;
int cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
WIDE_ID(LONG_GROUP, MARKER_CMD),
IWL_FW_CMD_VER_UNKNOWN);

View File

@ -112,6 +112,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_FW_NUM_LINKS = IWL_UCODE_TLV_CONST_BASE + 1,
IWL_UCODE_TLV_FW_NUM_BEACONS = IWL_UCODE_TLV_CONST_BASE + 2,
IWL_UCODE_TLV_FW_NUM_MCAST_KEY_ENTRIES = IWL_UCODE_TLV_CONST_BASE + 3,
IWL_UCODE_TLV_FW_NAN_MAX_CHAN_SWITCH_TIME = IWL_UCODE_TLV_CONST_BASE + 4,
IWL_UCODE_TLV_TYPE_DEBUG_INFO = IWL_UCODE_TLV_DEBUG_BASE + 0,
IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_TLV_DEBUG_BASE + 1,

View File

@ -54,6 +54,7 @@ struct iwl_ucode_capabilities {
u32 num_links;
u32 num_beacons;
u32 num_mcast_key_entries;
u16 nan_max_chan_switch_time;
DECLARE_BITMAP(_api, NUM_IWL_UCODE_TLV_API);
DECLARE_BITMAP(_capa, NUM_IWL_UCODE_TLV_CAPA);

View File

@ -8,27 +8,6 @@
#include "iwl-drv.h"
#include "iwl-config.h"
#define IWL_DECLARE_RATE_INFO(r) \
[IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
/*
* Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
* */
static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO(1),
IWL_DECLARE_RATE_INFO(2),
IWL_DECLARE_RATE_INFO(5),
IWL_DECLARE_RATE_INFO(11),
IWL_DECLARE_RATE_INFO(6),
IWL_DECLARE_RATE_INFO(9),
IWL_DECLARE_RATE_INFO(12),
IWL_DECLARE_RATE_INFO(18),
IWL_DECLARE_RATE_INFO(24),
IWL_DECLARE_RATE_INFO(36),
IWL_DECLARE_RATE_INFO(48),
IWL_DECLARE_RATE_INFO(54),
};
/* mbps, mcs */
static const struct iwl_rate_mcs_info rate_mcs[IWL_RATE_COUNT] = {
{ "1", "BPSK DSSS"},
@ -61,12 +40,6 @@ static const char * const pretty_bw[] = {
"320Mhz",
};
u8 iwl_fw_rate_idx_to_plcp(int idx)
{
return fw_rate_idx_to_plcp[idx];
}
IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp);
const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx)
{
return &rate_mcs[idx];

View File

@ -2,7 +2,7 @@
/*
* Copyright (C) 2005-2014, 2018-2021 Intel Corporation
* Copyright (C) 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2025 Intel Corporation
* Copyright (C) 2018-2026 Intel Corporation
*/
#ifndef __IWL_CONFIG_H__
#define __IWL_CONFIG_H__
@ -372,7 +372,7 @@ struct iwl_mac_cfg {
};
/*
* These sizes were picked according to 8 MSDUs inside 64/256/612 A-MSDUs
* These sizes were picked according to 8 MSDUs inside 64/256/512 A-MSDUs
* in an A-MPDU, with additional overhead to account for processing time.
* They will be doubled for MACs starting from So/Ty that don't support
* putting multiple frames into a single buffer.
@ -669,6 +669,7 @@ extern const char iwl_ax411_killer_1690s_name[];
extern const char iwl_ax411_killer_1690i_name[];
extern const char iwl_ax210_name[];
extern const char iwl_ax211_name[];
extern const char iwl_ax231_name[];
extern const char iwl_ax411_name[];
extern const char iwl_killer_be1750s_name[];
extern const char iwl_killer_be1750i_name[];
@ -740,6 +741,7 @@ extern const struct iwl_rf_cfg iwl_rf_hr;
extern const struct iwl_rf_cfg iwl_rf_hr_80mhz;
extern const struct iwl_rf_cfg iwl_rf_gf;
#define iwl_rf_ot iwl_rf_hr_80mhz
#endif /* CONFIG_IWLMVM */
#if IS_ENABLED(CONFIG_IWLMLD)

View File

@ -1337,6 +1337,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
capa->num_mcast_key_entries =
le32_to_cpup((const __le32 *)tlv_data);
break;
case IWL_UCODE_TLV_FW_NAN_MAX_CHAN_SWITCH_TIME:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
capa->nan_max_chan_switch_time =
le32_to_cpup((const __le32 *)tlv_data);
break;
case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: {
const struct iwl_umac_debug_addrs *dbg_ptrs =
(const void *)tlv_data;

View File

@ -385,7 +385,8 @@ enum {
#define CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN BIT(4)
#define CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT BIT(5)
#define CNVI_PMU_STEP_FLOW 0xA2D588
#define CNVI_PMU_STEP_FLOW_BZ 0xA2D588
#define CNVI_PMU_STEP_FLOW_SC 0xA2D688
#define CNVI_PMU_STEP_FLOW_FORCE_URM BIT(2)
#define PREG_AUX_BUS_WPROT_0 0xA04CC0

View File

@ -558,6 +558,11 @@ bool iwl_trans_grab_nic_access(struct iwl_trans *trans)
}
IWL_EXPORT_SYMBOL(iwl_trans_grab_nic_access);
void iwl_trans_resched_with_nic_access(struct iwl_trans *trans)
{
iwl_trans_pcie_resched_with_nic_access(trans);
}
void __releases(nic_access)
iwl_trans_release_nic_access(struct iwl_trans *trans)
{

View File

@ -161,6 +161,10 @@ struct iwl_device_tx_cmd {
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
/* Maximum payload size for a non-NOCOPY host command (excluding the header) */
#define IWL_MAX_CMD_PAYLOAD_SIZE \
(TFD_MAX_PAYLOAD_SIZE - sizeof(struct iwl_cmd_header_wide))
/*
* number of transfer buffers (fragments) per transmit frame descriptor;
* this is just the driver's idea, the hardware supports 20
@ -981,6 +985,17 @@ void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg,
bool iwl_trans_grab_nic_access(struct iwl_trans *trans);
/**
* iwl_trans_resched_with_nic_access - reschedule while holding NIC access
* @trans: the transport pointer
*
* This can be called while holding NIC access, during periods where
* the lock itself isn't interesting, the NIC should remain active,
* but a lot of processing is happening and the CPU may need to be
* released. In practice, this is only during FW dump.
*/
void iwl_trans_resched_with_nic_access(struct iwl_trans *trans);
void __releases(nic_access)
iwl_trans_release_nic_access(struct iwl_trans *trans);

View File

@ -2066,8 +2066,11 @@ int iwl_mld_wowlan_suspend(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan)
if (!bss_vif->cfg.assoc) {
int ret;
/* If we're not associated, this must be netdetect */
if (WARN_ON(!wowlan->nd_config))
/*
* If not associated we can only do netdetect, if
* that's not enabled then just suspend normally.
*/
if (!wowlan->nd_config)
return 1;
ret = iwl_mld_netdetect_config(mld, bss_vif, wowlan);

View File

@ -3,6 +3,8 @@
* Copyright (C) 2024-2026 Intel Corporation
*/
#include <kunit/static_stub.h>
#include "constants.h"
#include "link.h"
#include "iface.h"
@ -1024,7 +1026,7 @@ iwl_mld_get_avail_chan_load(struct iwl_mld *mld,
return MAX_CHAN_LOAD - iwl_mld_get_chan_load(mld, link_conf);
}
static s8
VISIBLE_IF_IWLWIFI_KUNIT s8
iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf)
{
@ -1032,6 +1034,9 @@ iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
const struct cfg80211_bss_ies *beacon_ies;
const struct element *elem;
KUNIT_STATIC_STUB_REDIRECT(iwl_mld_get_dup_beacon_rssi_adjust,
mld, link_conf);
/* Duplicated beacon feature is only specific to 6 GHz */
if (WARN_ONCE(link_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ,
"Unexpected band %d\n",
@ -1077,6 +1082,7 @@ iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
return 0;
}
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_dup_beacon_rssi_adjust);
static s8 iwl_mld_get_primary_psd(const struct ieee80211_parsed_tpe_psd *psd,
const struct cfg80211_chan_def *chandef,
@ -1097,7 +1103,8 @@ static s8 iwl_mld_get_primary_psd(const struct ieee80211_parsed_tpe_psd *psd,
return psd->power[primary_idx] / 2;
}
static s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
VISIBLE_IF_IWLWIFI_KUNIT s8
iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
{
const struct ieee80211_parsed_tpe *tpe = &link_conf->tpe;
s8 psd_20mhz, psd_oper, psd_local, psd_reg, psd_boost;
@ -1107,6 +1114,9 @@ static s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
int bw_mhz, num_subchans;
u8 bw_index;
KUNIT_STATIC_STUB_REDIRECT(iwl_mld_get_psd_eirp_rssi_adjust,
link_conf);
/* PSD/EIRP adjustment is only specific to 6 GHz */
if (WARN_ONCE(link_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ,
"PSD/EIRP adjustment called for non-6 GHz band %d\n",
@ -1216,6 +1226,7 @@ static s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
return adjustment;
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_psd_eirp_rssi_adjust);
/* This function calculates the grade of a link. Returns 0 in error case */
unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,

View File

@ -142,6 +142,12 @@ int iwl_mld_link_set_associated(struct iwl_mld *mld, struct ieee80211_vif *vif,
unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf);
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
s8 iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf);
s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf);
#endif
unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf);

View File

@ -291,8 +291,13 @@ static void iwl_mld_hw_set_nan(struct iwl_mld *mld)
NAN_DEV_CAPA_NUM_RX_ANT_POS) &
NAN_DEV_CAPA_NUM_RX_ANT_MASK);
/* Maximal channel switch time is 4 msec */
hw->wiphy->nan_capa.max_channel_switch_time = 4 * USEC_PER_MSEC;
/* Maximal channel switch time - use FW TLV value if available */
if (mld->fw->ucode_capa.nan_max_chan_switch_time)
hw->wiphy->nan_capa.max_channel_switch_time =
mld->fw->ucode_capa.nan_max_chan_switch_time;
else
hw->wiphy->nan_capa.max_channel_switch_time =
4 * USEC_PER_MSEC;
hw->wiphy->nan_capa.phy.ht = mld->nvm_data->nan_phy_capa.ht;
hw->wiphy->nan_capa.phy.vht = mld->nvm_data->nan_phy_capa.vht;

View File

@ -25,7 +25,8 @@ bool iwl_mld_nan_supported(struct iwl_mld *mld)
iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, NAN_PEER_CMD), 0) >= 1 &&
iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), 0) >= 3 &&
iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), 0) >= 4 &&
iwl_fw_lookup_cmd_ver(fw, WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD), 0) >= 6)
iwl_fw_lookup_cmd_ver(fw, WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD), 0) >= 6 &&
mld->nvm_data->nan_phy_capa.ht.ht_supported)
return true;
return false;
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2024-2025 Intel Corporation
* Copyright (C) 2024-2026 Intel Corporation
*/
#include <linux/crc32.h>
@ -237,6 +237,12 @@ iwl_mld_scan_type iwl_mld_get_scan_type(struct iwl_mld *mld,
vif->type != NL80211_IFTYPE_P2P_DEVICE)
return IWL_SCAN_TYPE_FRAGMENTED;
/* While associated to MLD AP with active EMLSR, set all scan
* operations as fast-balance scans.
*/
if (iwl_mld_emlsr_active(vif))
return IWL_SCAN_TYPE_FAST_BALANCE;
/* In case of DCM with P2P GO set all scan requests as
* fast-balance scan
*/

View File

@ -538,6 +538,12 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
break;
}
/* In NAN, there is no association request so no initial SMPS info */
if (mld_sta->vif->type == NL80211_IFTYPE_NAN_DATA) {
cmd.mimo = cpu_to_le32(1);
cmd.mimo_protection = cpu_to_le32(0);
}
iwl_mld_fill_ampdu_size_and_dens(link_sta, is_6ghz,
&cmd.tx_ampdu_max_size,
&cmd.tx_ampdu_spacing);

View File

@ -13,24 +13,39 @@
#include "phy.h"
#include "mlo.h"
struct link_grading_input {
u8 link_id;
const struct cfg80211_chan_def *chandef;
bool active;
s32 signal;
bool has_chan_util_elem;
u8 chan_util;
u8 chan_load_by_us;
s8 dup_beacon_adj;
s8 psd_eirp_adj;
u16 punctured;
};
static const struct link_grading_test_case {
const char *desc;
struct {
struct {
u8 link_id;
const struct cfg80211_chan_def *chandef;
bool active;
s32 signal;
bool has_chan_util_elem;
u8 chan_util; /* 0-255 , used only if has_chan_util_elem is true */
u8 chan_load_by_us; /* 0-100, used only if active is true */;
} link;
} input;
struct link_grading_input link;
unsigned int expected_grade;
} link_grading_cases[] = {
/* Per-bandwidth grading table tests */
{
.desc = "channel util of 128 (50%)",
.input.link = {
.desc = "20 MHz grading table: -75 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
.signal = -75,
},
/* 137 * 0.7 (default 2.4GHz channel load 30%) */
.expected_grade = 96,
},
{
.desc = "20 MHz with channel util 128 (50%): -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
@ -41,8 +56,8 @@ static const struct link_grading_test_case {
.expected_grade = 86,
},
{
.desc = "channel util of 180 (70%)",
.input.link = {
.desc = "20 MHz with channel util 180 (70%): -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
@ -53,32 +68,222 @@ static const struct link_grading_test_case {
.expected_grade = 51,
},
{
.desc = "channel util of 180 (70%), channel load by us of 10%",
.input.link = {
.desc = "20 MHz active link with chan load by us 10%: -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = true,
.signal = -70,
.has_chan_util_elem = true,
.chan_util = 180,
.active = true,
.chan_load_by_us = 10,
},
.expected_grade = 67,
},
{
.desc = "no channel util element",
.input.link = {
{
.desc = "40 MHz grading table: -80 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.signal = -70,
.active = true,
.chandef = &chandef_5ghz_40mhz,
.active = false,
.signal = -80,
},
.expected_grade = 120,
/* 206 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 175,
},
{
.desc = "80 MHz grading table: -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_80mhz,
.active = false,
.signal = -70,
},
/* 548 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 466,
},
{
.desc = "160 MHz grading table: -65 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_160mhz,
.active = false,
.signal = -65,
},
/* 1240 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 1055,
},
{
.desc = "320 MHz grading table: -60 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_320mhz,
.active = false,
.signal = -60,
},
/* 3680 at -56 dBm (-60 + 4 dBm 6 GHz) */
.expected_grade = 3680,
},
/* 6 GHz RSSI adjustment integration tests */
{
.desc = "6 GHz 160 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -69,
},
/* -69 + 4 dBm = -65, grade 1240 */
.expected_grade = 1240,
},
{
.desc = "6 GHz 80 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -74,
},
/* -74 + 4 dBm = -70, grade 548 */
.expected_grade = 548,
},
{
.desc = "6 GHz 40 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_40mhz,
.active = false,
.signal = -84,
},
/* -84 + 4 dBm = -80, grade 206 */
.expected_grade = 206,
},
{
.desc = "6 GHz 20 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_20mhz,
.active = false,
.signal = -79,
},
.expected_grade = 137,
},
/* Duplicated beacon RSSI adjustment tests */
{
.desc = "6 GHz 40 MHz dup beacon: -81 dBm + 3 dBm = -78 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_40mhz,
.active = false,
.signal = -81,
.dup_beacon_adj = 3,
},
.expected_grade = 206,
},
{
.desc = "6 GHz 80 MHz dup beacon: -73 dBm + 6 dBm = -67 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -73,
.dup_beacon_adj = 6,
},
.expected_grade = 620,
},
{
.desc = "6 GHz 160 MHz dup beacon: -74 dBm + 9 dBm = -65 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -74,
.dup_beacon_adj = 9,
},
.expected_grade = 1240,
},
{
.desc = "6 GHz 320 MHz dup beacon: -72 dBm + 12 dBm = -60 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_320mhz,
.active = false,
.signal = -72,
.dup_beacon_adj = 12,
},
.expected_grade = 3296,
},
/* PSD/EIRP RSSI adjustment tests */
{
.desc = "6 GHz 80 MHz PSD/EIRP: -77 dBm + 3 dBm = -74 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -77,
.psd_eirp_adj = 3,
},
/* -77 + 3 dBm = -74, grade 412; fallback +4: -73 -> 548 */
.expected_grade = 412,
},
{
.desc = "6 GHz 160 MHz PSD/EIRP: -70 dBm + 3 dBm = -67 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -70,
.psd_eirp_adj = 3,
},
/* -70 + 3 dBm = -67, grade 1096; fallback +4: -66 -> 1240 */
.expected_grade = 1096,
},
/* Puncturing penalty tests */
{
.desc = "80 MHz with 20 MHz punctured: 3 active subchannels",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_80mhz,
.active = false,
.signal = -70,
.punctured = 0x2,
},
/* 548 * 0.85 (5GHz load) * 3/4 (puncturing) */
.expected_grade = 349,
},
{
.desc = "160 MHz with 40 MHz punctured: 6 active subchannels",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_160mhz,
.active = false,
.signal = -65,
.punctured = 0xC,
},
/* 1240 * 0.85 (5GHz load) * 6/8 (puncturing) */
.expected_grade = 791,
},
};
KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc);
static s8 fake_dup_beacon_rssi_adjust(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf)
{
const struct link_grading_test_case *params =
kunit_get_current_test()->param_value;
return params->link.dup_beacon_adj;
}
static s8 fake_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
{
const struct link_grading_test_case *params =
kunit_get_current_test()->param_value;
return params->link.psd_eirp_adj;
}
static void setup_link(struct ieee80211_bss_conf *link)
{
struct kunit *test = kunit_get_current_test();
@ -88,14 +293,14 @@ static void setup_link(struct ieee80211_bss_conf *link)
KUNIT_ALLOC_AND_ASSERT(test, link->bss);
link->bss->signal = DBM_TO_MBM(test_param->input.link.signal);
link->bss->signal = DBM_TO_MBM(test_param->link.signal);
link->chanreq.oper = *test_param->input.link.chandef;
link->chanreq.oper = *test_param->link.chandef;
if (test_param->input.link.has_chan_util_elem) {
if (test_param->link.has_chan_util_elem) {
struct cfg80211_bss_ies *ies;
struct ieee80211_bss_load_elem bss_load = {
.channel_util = test_param->input.link.chan_util,
.channel_util = test_param->link.chan_util,
};
struct element *elem =
iwlmld_kunit_gen_element(WLAN_EID_QBSS_LOAD,
@ -110,7 +315,10 @@ static void setup_link(struct ieee80211_bss_conf *link)
rcu_assign_pointer(link->bss->ies, ies);
}
if (test_param->input.link.active) {
if (test_param->link.punctured)
link->chanreq.oper.punctured = test_param->link.punctured;
if (test_param->link.active) {
struct ieee80211_chanctx_conf *chan_ctx =
wiphy_dereference(mld->wiphy, link->chanctx_conf);
struct iwl_mld_phy *phy;
@ -119,7 +327,7 @@ static void setup_link(struct ieee80211_bss_conf *link)
phy = iwl_mld_phy_from_mac80211(chan_ctx);
phy->channel_load_by_us = test_param->input.link.chan_load_by_us;
phy->channel_load_by_us = test_param->link.chan_load_by_us;
}
}
@ -131,12 +339,11 @@ static void test_link_grading(struct kunit *test)
struct ieee80211_vif *vif;
struct ieee80211_bss_conf *link;
unsigned int actual_grade;
/* Extract test case parameters */
u8 link_id = test_param->input.link.link_id;
bool active = test_param->input.link.active;
u8 link_id = test_param->link.link_id;
bool active = test_param->link.active;
u16 valid_links;
struct iwl_mld_kunit_link assoc_link = {
.chandef = test_param->input.link.chandef,
.chandef = test_param->link.chandef,
};
/* If the link is not active, use a different link as the assoc link */
@ -150,6 +357,11 @@ static void test_link_grading(struct kunit *test)
vif = iwlmld_kunit_setup_mlo_assoc(valid_links, &assoc_link);
kunit_activate_static_stub(test, iwl_mld_get_dup_beacon_rssi_adjust,
fake_dup_beacon_rssi_adjust);
kunit_activate_static_stub(test, iwl_mld_get_psd_eirp_rssi_adjust,
fake_psd_eirp_rssi_adjust);
wiphy_lock(mld->wiphy);
link = wiphy_dereference(mld->wiphy, vif->link_conf[link_id]);
KUNIT_ASSERT_NOT_NULL(test, link);

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* KUnit tests for channel helper functions
* KUnit tests for link helper functions
*
* Copyright (C) 2024-2025 Intel Corporation
* Copyright (C) 2024-2026 Intel Corporation
*/
#include <kunit/static_stub.h>
@ -96,8 +96,478 @@ static void test_missed_beacon(struct kunit *test)
/* TODO: add test cases for esr and check */
}
struct dup_beacon_test_case {
const char *desc;
enum nl80211_chan_width bandwidth;
bool has_he_oper;
bool dup_beacon_bit;
s8 expected_adj;
};
static const struct dup_beacon_test_case dup_beacon_cases[] = {
{
.desc = "20 MHz - no duplication",
.bandwidth = NL80211_CHAN_WIDTH_20,
.has_he_oper = true,
.dup_beacon_bit = true,
.expected_adj = 0,
},
{
.desc = "40 MHz with duplication - 3 dB",
.bandwidth = NL80211_CHAN_WIDTH_40,
.has_he_oper = true,
.dup_beacon_bit = true,
.expected_adj = 3,
},
{
.desc = "80 MHz with duplication - 6 dB",
.bandwidth = NL80211_CHAN_WIDTH_80,
.has_he_oper = true,
.dup_beacon_bit = true,
.expected_adj = 6,
},
{
.desc = "160 MHz with duplication - 9 dB",
.bandwidth = NL80211_CHAN_WIDTH_160,
.has_he_oper = true,
.dup_beacon_bit = true,
.expected_adj = 9,
},
{
.desc = "320 MHz with duplication - 12 dB",
.bandwidth = NL80211_CHAN_WIDTH_320,
.has_he_oper = true,
.dup_beacon_bit = true,
.expected_adj = 12,
},
{
.desc = "80 MHz without dup bit - no adjustment",
.bandwidth = NL80211_CHAN_WIDTH_80,
.has_he_oper = true,
.dup_beacon_bit = false,
.expected_adj = 0,
},
{
.desc = "80 MHz without HE oper - no adjustment",
.bandwidth = NL80211_CHAN_WIDTH_80,
.has_he_oper = false,
.dup_beacon_bit = true,
.expected_adj = 0,
},
};
KUNIT_ARRAY_PARAM_DESC(test_dup_beacon_rssi_adjust, dup_beacon_cases, desc);
struct psd_eirp_test_case {
const char *desc;
const struct cfg80211_chan_def *chandef;
enum ieee80211_ap_reg_power power_type;
struct {
s8 psd_20;
s8 psd_oper;
s8 eirp_20;
s8 eirp_oper;
} local, reg;
s8 expected_adj;
struct {
bool no_psd_data;
bool no_eirp_data;
bool no_reg_psd_data;
bool has_partial_psd;
u8 psd_partial_count;
bool non_uniform_psd;
bool has_unusable_channels;
} flags;
};
static const struct psd_eirp_test_case psd_eirp_cases[] = {
{
.desc = "20 MHz VLP baseline - no boost expected",
.chandef = &chandef_6ghz_20mhz,
.power_type = IEEE80211_REG_VLP_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 40,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 40,
},
.expected_adj = 0,
},
{
.desc = "40 MHz VLP - power limit prevents boost",
.chandef = &chandef_6ghz_40mhz,
.power_type = IEEE80211_REG_VLP_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 46,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 46,
},
.expected_adj = 0,
},
{
.desc = "80 MHz LPI - power limit caps the boost",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.expected_adj = 3,
},
{
.desc = "160 MHz LPI - power limit caps the boost",
.chandef = &chandef_6ghz_160mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 58,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 58,
},
.expected_adj = 3,
},
{
.desc = "320 MHz SP - power limit caps the boost",
.chandef = &chandef_6ghz_320mhz_pri0,
.power_type = IEEE80211_REG_SP_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 63,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 63,
},
.expected_adj = 3,
},
{
.desc = "80 MHz - EIRP prevents boost",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 20,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 20,
},
.expected_adj = 0,
},
{
.desc = "40 MHz - regulatory TPE sets lower limits",
.chandef = &chandef_6ghz_40mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 30, .psd_oper = 30,
.eirp_20 = 50, .eirp_oper = 56,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 46,
},
.expected_adj = 3,
},
{
.desc = "80 MHz - PSD missing, use EIRP only",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = S8_MAX, .psd_oper = S8_MAX,
.eirp_20 = 40, .eirp_oper = 52,
},
.reg = {
.psd_20 = S8_MAX, .psd_oper = S8_MAX,
.eirp_20 = 40, .eirp_oper = 52,
},
.expected_adj = 0,
.flags.no_psd_data = true,
},
{
.desc = "80 MHz - single PSD source available",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.expected_adj = 3,
.flags.no_reg_psd_data = true,
},
{
.desc = "80 MHz - partial PSD data present",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 24, .psd_oper = 24,
.eirp_20 = 40, .eirp_oper = 56,
},
.reg = {
.psd_20 = 24, .psd_oper = 24,
.eirp_20 = 40, .eirp_oper = 56,
},
.expected_adj = 0,
.flags.has_partial_psd = true,
.flags.psd_partial_count = 2,
},
{
.desc = "160 MHz - different PSD per sub-channel",
.chandef = &chandef_6ghz_160mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 8, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 58,
},
.reg = {
.psd_20 = 8, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 58,
},
.expected_adj = 11,
.flags.non_uniform_psd = true,
},
{
.desc = "80 MHz - EIRP missing, use PSD only",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = S8_MAX, .eirp_oper = S8_MAX,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = S8_MAX, .eirp_oper = S8_MAX,
},
.expected_adj = 3,
.flags.no_eirp_data = true,
},
{
.desc = "80 MHz - skip unusable channels in average",
.chandef = &chandef_6ghz_80mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 52,
},
.expected_adj = 3,
.flags.has_unusable_channels = true,
},
{
.desc = "40 MHz - no negative adjustment",
.chandef = &chandef_6ghz_40mhz,
.power_type = IEEE80211_REG_LPI_AP,
.local = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 18,
},
.reg = {
.psd_20 = 20, .psd_oper = 20,
.eirp_20 = 40, .eirp_oper = 18,
},
.expected_adj = 0,
},
};
KUNIT_ARRAY_PARAM_DESC(test_psd_eirp_rssi_adjust, psd_eirp_cases, desc);
static void setup_psd(struct ieee80211_bss_conf *link_conf,
const struct psd_eirp_test_case *params,
int num_subchannels)
{
int i;
if (params->flags.no_psd_data) {
link_conf->tpe.psd_local[0].valid = false;
link_conf->tpe.psd_reg_client[0].valid = false;
link_conf->tpe.psd_local[0].count = 0;
link_conf->tpe.psd_reg_client[0].count = 0;
} else if (params->flags.no_reg_psd_data) {
link_conf->tpe.psd_local[0].valid = true;
link_conf->tpe.psd_local[0].count = num_subchannels;
link_conf->tpe.psd_reg_client[0].valid = false;
link_conf->tpe.psd_reg_client[0].count = 0;
} else if (params->flags.has_partial_psd) {
link_conf->tpe.psd_local[0].valid = true;
link_conf->tpe.psd_local[0].count =
params->flags.psd_partial_count;
link_conf->tpe.psd_reg_client[0].valid = true;
link_conf->tpe.psd_reg_client[0].count =
params->flags.psd_partial_count;
} else {
link_conf->tpe.psd_local[0].valid = true;
link_conf->tpe.psd_local[0].count = num_subchannels;
link_conf->tpe.psd_reg_client[0].valid = true;
link_conf->tpe.psd_reg_client[0].count = num_subchannels;
}
/* TPE element stores PSD limit as value * 2 */
if (params->flags.non_uniform_psd) {
/* PSD varies per sub-channel: 10/12/10/8 dBm pattern */
static const s8 psd_values[] = {20, 24, 20, 16, 20, 24, 20, 16,
20, 24, 20, 16, 20, 24, 20};
/* Set primary channel (index 0) explicitly */
link_conf->tpe.psd_local[0].power[0] =
params->local.psd_20 * 2;
link_conf->tpe.psd_reg_client[0].power[0] =
params->reg.psd_20 * 2;
/* Set remaining subchannels with pattern */
for (i = 1; i < num_subchannels; i++) {
link_conf->tpe.psd_local[0].power[i] =
psd_values[i - 1];
link_conf->tpe.psd_reg_client[0].power[i] =
psd_values[i - 1];
}
} else if (params->flags.no_psd_data) {
for (i = 0; i < num_subchannels; i++) {
link_conf->tpe.psd_local[0].power[i] = S8_MAX;
link_conf->tpe.psd_reg_client[0].power[i] = S8_MAX;
}
} else if (params->flags.has_unusable_channels) {
/* Alternate usable/unusable channels for S8_MIN test */
/* Set primary channel (index 0) explicitly */
link_conf->tpe.psd_local[0].power[0] =
params->local.psd_20 * 2;
link_conf->tpe.psd_reg_client[0].power[0] =
params->reg.psd_20 * 2;
/* Alternate usable/unusable for remaining subchannels */
for (i = 1; i < num_subchannels; i++) {
if (i % 2 == 0) {
link_conf->tpe.psd_local[0].power[i] =
params->local.psd_oper * 2;
link_conf->tpe.psd_reg_client[0].power[i] =
params->reg.psd_oper * 2;
} else {
link_conf->tpe.psd_local[0].power[i] = S8_MIN;
link_conf->tpe.psd_reg_client[0].power[i] =
S8_MIN;
}
}
} else {
/* Set primary channel (index 0) separately */
link_conf->tpe.psd_local[0].power[0] =
params->local.psd_20 * 2;
link_conf->tpe.psd_reg_client[0].power[0] =
params->reg.psd_20 * 2;
/* Set remaining subchannels */
for (i = 1; i < num_subchannels; i++) {
link_conf->tpe.psd_local[0].power[i] =
params->local.psd_oper * 2;
link_conf->tpe.psd_reg_client[0].power[i] =
params->reg.psd_oper * 2;
}
}
}
static void setup_eirp(struct ieee80211_bss_conf *link_conf,
const struct psd_eirp_test_case *params,
int num_subchannels)
{
int i;
int count = ilog2(num_subchannels) + 1;
link_conf->tpe.max_local[0].valid = !params->flags.no_eirp_data;
link_conf->tpe.max_reg_client[0].valid = !params->flags.no_eirp_data;
if (params->flags.no_eirp_data) {
link_conf->tpe.max_local[0].count = 0;
link_conf->tpe.max_reg_client[0].count = 0;
return;
}
link_conf->tpe.max_local[0].count = count;
link_conf->tpe.max_reg_client[0].count = count;
/* TPE element stores EIRP limit as value * 2 */
link_conf->tpe.max_local[0].power[0] = params->local.eirp_20 * 2;
link_conf->tpe.max_reg_client[0].power[0] = params->reg.eirp_20 * 2;
for (i = 1; i < count; i++) {
link_conf->tpe.max_local[0].power[i] =
params->local.eirp_oper * 2;
link_conf->tpe.max_reg_client[0].power[i] =
params->reg.eirp_oper * 2;
}
}
static void test_dup_beacon_rssi_adjust(struct kunit *test)
{
const struct dup_beacon_test_case *params = test->param_value;
struct iwl_mld *mld = test->priv;
struct ieee80211_bss_conf *link_conf;
struct cfg80211_bss *bss;
struct element *he_elem = NULL;
s8 result;
KUNIT_ALLOC_AND_ASSERT(test, link_conf);
KUNIT_ALLOC_AND_ASSERT(test, bss);
link_conf->bss = bss;
link_conf->chanreq.oper.chan = &chan_6ghz;
link_conf->chanreq.oper.width = params->bandwidth;
if (params->has_he_oper) {
struct ieee80211_he_6ghz_oper he_6ghz = {};
if (params->dup_beacon_bit)
he_6ghz.control =
IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON;
he_elem = iwlmld_kunit_create_he_6ghz_oper(he_6ghz);
}
rcu_assign_pointer(bss->beacon_ies,
iwlmld_kunit_create_bss_ies(he_elem));
guard(wiphy)(mld->wiphy);
result = iwl_mld_get_dup_beacon_rssi_adjust(mld, link_conf);
KUNIT_EXPECT_EQ(test, result, params->expected_adj);
}
static void test_psd_eirp_rssi_adjust(struct kunit *test)
{
const struct psd_eirp_test_case *params = test->param_value;
struct ieee80211_bss_conf *link_conf;
int num_subchannels;
s8 result;
KUNIT_ALLOC_AND_ASSERT(test, link_conf);
link_conf->power_type = params->power_type;
link_conf->chanreq.oper = *params->chandef;
num_subchannels =
nl80211_chan_width_to_mhz(params->chandef->width) / 20;
setup_psd(link_conf, params, num_subchannels);
setup_eirp(link_conf, params, num_subchannels);
result = iwl_mld_get_psd_eirp_rssi_adjust(link_conf);
KUNIT_EXPECT_EQ(test, result, params->expected_adj);
}
static struct kunit_case link_cases[] = {
KUNIT_CASE_PARAM(test_missed_beacon, test_missed_beacon_gen_params),
KUNIT_CASE_PARAM(test_dup_beacon_rssi_adjust,
test_dup_beacon_rssi_adjust_gen_params),
KUNIT_CASE_PARAM(test_psd_eirp_rssi_adjust,
test_psd_eirp_rssi_adjust_gen_params),
{},
};

View File

@ -439,6 +439,66 @@ struct ieee80211_vif *iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1,
return vif;
}
struct element *
iwlmld_kunit_create_he_6ghz_oper(struct ieee80211_he_6ghz_oper he_6ghz)
{
struct kunit *test = kunit_get_current_test();
u8 *data;
size_t data_len;
size_t offset = 0;
__le32 he_oper_params;
__le16 he_mcs_nss_set = 0;
/* Build HE Operation IE with 6 GHz info using raw buffer.
* Cannot use struct embedding because ieee80211_he_operation
* has a flexible array member (optional[]).
*
* Layout:
* 1 byte: ext_id (WLAN_EID_EXT_HE_OPERATION)
* he_oper_params: he_oper_params (from ieee80211_he_operation)
* he_mcs_nss_set: he_mcs_nss_set (from ieee80211_he_operation)
* he_6ghz: ieee80211_he_6ghz_oper (goes into optional[])
*/
data_len = 1 + sizeof(he_oper_params) + sizeof(he_mcs_nss_set) +
sizeof(struct ieee80211_he_6ghz_oper);
data = kunit_kzalloc(test, data_len, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, data);
data[offset++] = WLAN_EID_EXT_HE_OPERATION;
he_oper_params = cpu_to_le32(IEEE80211_HE_OPERATION_6GHZ_OP_INFO);
memcpy(&data[offset], &he_oper_params, sizeof(he_oper_params));
offset += sizeof(he_oper_params);
memcpy(&data[offset], &he_mcs_nss_set, sizeof(he_mcs_nss_set));
offset += sizeof(he_mcs_nss_set);
memcpy(&data[offset], &he_6ghz, sizeof(he_6ghz));
return iwlmld_kunit_gen_element(WLAN_EID_EXTENSION, data, data_len);
}
struct cfg80211_bss_ies *iwlmld_kunit_create_bss_ies(struct element *elem)
{
struct kunit *test = kunit_get_current_test();
struct cfg80211_bss_ies *ies;
size_t ies_len = 0;
if (elem)
ies_len = sizeof(*elem) + elem->datalen;
ies = kunit_kzalloc(test, sizeof(*ies) + ies_len, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ies);
ies->len = ies_len;
if (elem)
memcpy(ies->data, elem, ies_len);
return ies;
}
struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len)
{
struct kunit *test = kunit_get_current_test();

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2024-2025 Intel Corporation
* Copyright (C) 2024-2026 Intel Corporation
*/
#ifndef __iwl_mld_kunit_utils_h__
@ -77,6 +77,8 @@ CHANNEL(chan_6ghz_221, NL80211_BAND_6GHZ, 7055);
NL80211_CHAN_WIDTH_160) \
CHANDEF(chandef_6ghz_320mhz, chan_6ghz, 6105, \
NL80211_CHAN_WIDTH_320) \
CHANDEF(chandef_6ghz_320mhz_pri0, chan_6ghz, 6265, \
NL80211_CHAN_WIDTH_320) \
CHANDEF(chandef_6ghz_221_160mhz, chan_6ghz_221, 6985, \
NL80211_CHAN_WIDTH_160) \
/* Feel free to add more */
@ -121,6 +123,11 @@ iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1,
struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len);
struct element *
iwlmld_kunit_create_he_6ghz_oper(struct ieee80211_he_6ghz_oper he_6ghz);
struct cfg80211_bss_ies *iwlmld_kunit_create_bss_ies(struct element *elem);
/**
* iwlmld_kunit_get_phy_of_link - Get the phy of a link
*

View File

@ -467,65 +467,6 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld,
}
}
static int iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd *cmd,
struct iwl_tlc_config_cmd_v5 *cmd_v5)
{
if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
return -EINVAL;
/* Convert sta_mask to sta_id */
cmd_v5->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
/* Copy all the rest */
cmd_v5->max_ch_width = cmd->max_ch_width;
cmd_v5->mode = cmd->mode;
cmd_v5->chains = cmd->chains;
cmd_v5->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
cmd_v5->flags = cmd->flags;
cmd_v5->non_ht_rates = cmd->non_ht_rates;
BUILD_BUG_ON(sizeof(cmd_v5->ht_rates) != sizeof(cmd->ht_rates));
memcpy(cmd_v5->ht_rates, cmd->ht_rates, sizeof(cmd->ht_rates));
cmd_v5->max_mpdu_len = cmd->max_mpdu_len;
cmd_v5->max_tx_op = cmd->max_tx_op;
return 0;
}
static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
struct iwl_tlc_config_cmd_v4 *cmd_v4)
{
if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
return -EINVAL;
/* Convert sta_mask to sta_id */
cmd_v4->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
/* Copy everything until ht_rates */
cmd_v4->max_ch_width = cmd->max_ch_width;
cmd_v4->mode = cmd->mode;
cmd_v4->chains = cmd->chains;
cmd_v4->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
cmd_v4->flags = cmd->flags;
cmd_v4->non_ht_rates = cmd->non_ht_rates;
/* Convert ht_rates from __le32 to __le16 */
BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates));
BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates[0]) != ARRAY_SIZE(cmd->ht_rates[0]));
for (int nss = 0; nss < ARRAY_SIZE(cmd->ht_rates); nss++)
for (int bw = 0; bw < ARRAY_SIZE(cmd->ht_rates[nss]); bw++)
cmd_v4->ht_rates[nss][bw] =
cpu_to_le16(le32_to_cpu(cmd->ht_rates[nss][bw]));
/* Copy the rest */
cmd_v4->max_mpdu_len = cmd->max_mpdu_len;
cmd_v4->max_tx_op = cmd->max_tx_op;
return 0;
}
static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
struct ieee80211_vif *vif,
struct iwl_mld_sta *mld_sta,
@ -544,8 +485,6 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
};
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
struct iwl_tlc_config_cmd_v5 cmd_v5 = {};
struct iwl_tlc_config_cmd_v4 cmd_v4 = {};
void *cmd_ptr;
u8 cmd_size;
int ret;
@ -558,19 +497,6 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
if (cmd_ver == 6) {
cmd_ptr = &cmd;
cmd_size = sizeof(cmd);
} else if (cmd_ver == 5) {
/* TODO: remove support once FW moves to version 6 */
ret = iwl_mld_convert_tlc_cmd_to_v5(&cmd, &cmd_v5);
if (ret)
return;
cmd_ptr = &cmd_v5;
cmd_size = sizeof(cmd_v5);
} else if (cmd_ver == 4) {
ret = iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4);
if (ret)
return;
cmd_ptr = &cmd_v4;
cmd_size = sizeof(cmd_v4);
} else {
IWL_ERR(mld, "Unsupported TLC config cmd version %d\n",
cmd_ver);

View File

@ -563,7 +563,8 @@ iwl_mld_fill_tx_cmd(struct iwl_mld *mld, struct sk_buff *skb,
* - when no sta is given.
* - frames that are sent to an NMI sta, which is only used for management.
*/
if (unlikely(!sta || mld_sta->vif->type == NL80211_IFTYPE_NAN ||
if (unlikely(!sta ||
(mld_sta && mld_sta->vif->type == NL80211_IFTYPE_NAN) ||
info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) {
flags |= IWL_TX_FLAGS_CMD_RATE;
rate_n_flags = iwl_mld_get_tx_rate_n_flags(mld, info, sta,

View File

@ -2,7 +2,7 @@
/*
* Copyright (C) 2012-2014, 2020 Intel Corporation
* Copyright (C) 2016 Intel Deutschland GmbH
* Copyright (C) 2022, 2024 Intel Corporation
* Copyright (C) 2022, 2024, 2026 Intel Corporation
*/
#include <net/mac80211.h>
#include "fw-api.h"
@ -76,6 +76,9 @@ static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
if (vif == data->ignore_vif)
return;
if (vif->type == NL80211_IFTYPE_P2P_DEVICE && !mvmvif->p2p_in_binding)
return;
if (mvmvif->deflink.phy_ctxt != data->phyctxt)
return;

View File

@ -935,9 +935,9 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
: IWL_MAC_BEACON_CCK_V1;
if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
flags |= iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
flags |= iwl_mvm_rate_idx_to_fw_idx(fw, rate_idx);
else
flags |= iwl_fw_rate_idx_to_plcp(rate_idx);
flags |= iwl_mvm_rate_idx_to_plcp(rate_idx);
return flags;
}
@ -998,7 +998,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
else
rate_n_flags |= RATE_MCS_MOD_TYPE_LEGACY_OFDM;
rate_n_flags |= iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate);
rate_n_flags |= iwl_mvm_rate_idx_to_fw_idx(mvm->fw, rate);
tx_params->rate_n_flags = iwl_mvm_v3_rate_to_fw(rate_n_flags,
mvm->fw_rates_ver);

View File

@ -1104,6 +1104,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
spin_unlock_bh(&mvm->time_event_lock);
mvmvif->roc_activity = ROC_NUM_ACTIVITIES;
mvmvif->p2p_in_binding = false;
mvmvif->bf_enabled = false;
mvmvif->ba_enabled = false;
@ -4634,6 +4635,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)
static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
lockdep_assert_held(&mvm->mutex);
@ -4642,10 +4644,18 @@ static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN(ret, "Failed binding P2P_DEVICE\n"))
return ret;
mvmvif->p2p_in_binding = true;
/* The station and queue allocation must be done only after the binding
* is done, as otherwise the FW might incorrectly configure its state.
*/
return iwl_mvm_add_p2p_bcast_sta(mvm, vif);
ret = iwl_mvm_add_p2p_bcast_sta(mvm, vif);
if (ret) {
iwl_mvm_binding_remove_vif(mvm, vif);
mvmvif->p2p_in_binding = false;
}
return ret;
}
static int iwl_mvm_roc(struct ieee80211_hw *hw,

View File

@ -383,6 +383,8 @@ struct iwl_mvm_vif_link_info {
* @pm_enabled: indicates powersave is enabled
* @roc_activity: currently running ROC activity for this vif (or
* ROC_NUM_ACTIVITIES if no activity is running).
* @p2p_in_binding: indicates that this P2P-Device interface should be
* added to the binding, i.e. is running ROC right now
* @session_prot_connection_loss: the connection was lost due to session
* protection ending without receiving a beacon, so we need to now
* protect the deauth separately
@ -492,6 +494,7 @@ struct iwl_mvm_vif {
struct iwl_mvm_time_event_data time_event_data;
struct iwl_mvm_time_event_data hs_time_event_data;
enum iwl_roc_activity roc_activity;
bool p2p_in_binding;
/* TCP Checksum Offload */
netdev_features_t features;
@ -1646,6 +1649,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm);
/* Utils */
u8 iwl_mvm_rate_idx_to_plcp(int idx);
int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
enum nl80211_band band);
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
@ -1653,7 +1657,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
enum nl80211_band band,
struct ieee80211_tx_rate *r);
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx);
u8 iwl_mvm_rate_idx_to_fw_idx(const struct iwl_fw *fw, int rate_idx);
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -1669,16 +1673,16 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2,
u32 iwl_mvm_get_systime(struct iwl_mvm *mvm);
/* Tx / Host Commands */
int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,
struct iwl_host_cmd *cmd);
int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
u32 flags, u16 len, const void *data);
int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,
struct iwl_host_cmd *cmd,
u32 *status);
int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,
u16 len, const void *data,
u32 *status);
int iwl_mvm_send_cmd(struct iwl_mvm *mvm,
struct iwl_host_cmd *cmd);
int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
u32 flags, u16 len, const void *data);
int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,
struct iwl_host_cmd *cmd,
u32 *status);
int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,
u16 len, const void *data,
u32 *status);
int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_sta *sta);
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@ -88,6 +88,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
} else {
iwl_mvm_rm_p2p_bcast_sta(mvm, vif);
iwl_mvm_binding_remove_vif(mvm, vif);
mvmvif->p2p_in_binding = false;
}
/* Do not remove the PHY context as removing and adding

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -268,7 +268,6 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
int rate_idx)
{
u32 rate_flags = 0;
u8 rate_plcp;
bool is_cck;
/* if the rate isn't a well known legacy rate, take the lowest one */
@ -277,8 +276,9 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
info,
info->control.vif);
/* Get PLCP rate for tx_cmd->rate_n_flags */
rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate_idx);
/* Get FW rate for tx_cmd->rate_n_flags */
rate_flags |= iwl_mvm_rate_idx_to_fw_idx(mvm->fw, rate_idx);
is_cck = (rate_idx >= IWL_FIRST_CCK_RATE) &&
(rate_idx <= IWL_LAST_CCK_RATE);
@ -288,7 +288,7 @@ static u32 iwl_mvm_convert_rate_idx(struct iwl_mvm *mvm,
else
rate_flags |= RATE_MCS_MOD_TYPE_CCK;
return (u32)rate_plcp | rate_flags;
return rate_flags;
}
static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm,

View File

@ -14,6 +14,30 @@
#include "fw/api/rs.h"
#include "fw/img.h"
#define IWL_DECLARE_RATE_INFO(r) \
[IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
/* Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP */
static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO(1),
IWL_DECLARE_RATE_INFO(2),
IWL_DECLARE_RATE_INFO(5),
IWL_DECLARE_RATE_INFO(11),
IWL_DECLARE_RATE_INFO(6),
IWL_DECLARE_RATE_INFO(9),
IWL_DECLARE_RATE_INFO(12),
IWL_DECLARE_RATE_INFO(18),
IWL_DECLARE_RATE_INFO(24),
IWL_DECLARE_RATE_INFO(36),
IWL_DECLARE_RATE_INFO(48),
IWL_DECLARE_RATE_INFO(54),
};
u8 iwl_mvm_rate_idx_to_plcp(int idx)
{
return fw_rate_idx_to_plcp[idx];
}
/*
* Will return 0 even if the cmd failed when RFKILL is asserted unless
* CMD_WANT_SKB is set in cmd->flags.
@ -151,13 +175,13 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
if (band != NL80211_BAND_2GHZ)
band_offset = IWL_FIRST_OFDM_RATE;
for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
if (iwl_fw_rate_idx_to_plcp(idx) == rate)
if (iwl_mvm_rate_idx_to_plcp(idx) == rate)
return idx - band_offset;
return -1;
}
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
u8 iwl_mvm_rate_idx_to_fw_idx(const struct iwl_fw *fw, int rate_idx)
{
return rate_idx >= IWL_FIRST_OFDM_RATE ?
rate_idx - IWL_FIRST_OFDM_RATE :
@ -1243,7 +1267,7 @@ static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
for (idx = offset; idx < last; idx++)
if (iwl_fw_rate_idx_to_plcp(idx) == rate)
if (iwl_mvm_rate_idx_to_plcp(idx) == rate)
return idx - offset;
return IWL_RATE_INVALID;
}
@ -1353,7 +1377,7 @@ __le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver)
rate_idx = u32_get_bits(rate, RATE_LEGACY_RATE_MSK);
if (!(result & RATE_MCS_CCK_MSK_V1))
rate_idx += IWL_FIRST_OFDM_RATE;
result |= u32_encode_bits(iwl_fw_rate_idx_to_plcp(rate_idx),
result |= u32_encode_bits(iwl_mvm_rate_idx_to_plcp(rate_idx),
RATE_LEGACY_RATE_MSK_V1);
break;
case RATE_MCS_MOD_TYPE_HT:

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2005-2014, 2018-2025 Intel Corporation
* Copyright (C) 2005-2014, 2018-2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -1016,6 +1016,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
/* GF RF */
IWL_DEV_INFO(iwl_rf_gf, iwl_ax211_name, RF_TYPE(GF)),
IWL_DEV_INFO(iwl_rf_ot, iwl_ax231_name, RF_TYPE(GF), SUBDEV(0x0294)),
IWL_DEV_INFO(iwl_rf_gf, iwl_ax411_name, RF_TYPE(GF), CDB),
IWL_DEV_INFO(iwl_rf_gf, iwl_ax210_name, DEVICE(0x2725)),

View File

@ -1203,6 +1203,7 @@ void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs,
u32 *val);
bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans);
void __releases(nic_access_nobh)
iwl_trans_pcie_release_nic_access(struct iwl_trans *trans);
void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power);

View File

@ -376,6 +376,7 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 step_reg;
iwl_pcie_reset_ict(trans);
@ -404,10 +405,13 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
iwl_pcie_get_rf_name(trans);
mutex_unlock(&trans_pcie->mutex);
if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
trans->step_urm = !!(iwl_read_prph(trans,
CNVI_PMU_STEP_FLOW) &
CNVI_PMU_STEP_FLOW_FORCE_URM);
if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
return;
step_reg = trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC ?
CNVI_PMU_STEP_FLOW_SC : CNVI_PMU_STEP_FLOW_BZ;
trans->step_urm = !!(iwl_read_prph(trans, step_reg) &
CNVI_PMU_STEP_FLOW_FORCE_URM);
}
static bool iwl_pcie_set_ltr(struct iwl_trans *trans)

View File

@ -521,7 +521,6 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
#define HW_READY_TIMEOUT (50)
/* Note: returns poll_bit return value, which is >= 0 if success */
static int iwl_pcie_set_hw_ready(struct iwl_trans *trans)
{
int ret;
@ -2424,7 +2423,7 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
return false;
}
static void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans)
void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@ -2591,7 +2590,7 @@ int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx)
struct iwl_txq *txq;
unsigned long now = jiffies;
bool overflow_tx;
u8 wr_ptr;
int wr_ptr;
/* Make sure the NIC is still alive in the bus */
if (test_bit(STATUS_TRANS_DEAD, &trans->status))
@ -2614,7 +2613,7 @@ int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx)
overflow_tx) &&
!time_after(jiffies,
now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
u8 write_ptr = READ_ONCE(txq->write_ptr);
int write_ptr = READ_ONCE(txq->write_ptr);
/*
* If write pointer moved during the wait, warn only