diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index ecb4f81a99f5..606362463dc7 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index e8968b3051d3..946975294b4f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -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" diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c index 294cf25ae2a6..35b1618f3474 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c index 99a5110924cd..8b63cdb3d66c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c @@ -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)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 6aaa49aeec99..e8240c1782ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -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" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index abd259350589..f76f76e54c4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h index 1fc65469990e..84fa5ff7a57f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h @@ -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__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index e494e5b18d22..c8eb016e1a7e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 61a850de26fc..382d1c2581ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -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; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index ae6be3ed32f8..f1254546cc9d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -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 - * 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); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 069c3bad6f29..6621ef9358bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 197c88c25f72..a26ed82a8106 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 75b1344f6cbe..95b45a253641 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/rs.c b/drivers/net/wireless/intel/iwlwifi/fw/rs.c index 2aa300b26158..ccdd6856572b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/rs.c @@ -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]; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 30d5ec31b9c3..6a3539ad7331 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -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) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 488524529538..842586d4fc5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -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; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 6ca1f51b69a1..50acfe0d4f79 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -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 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 0009488ca51b..73aae1125042 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -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) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 3ae840e546e8..c581cc8f5bcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index fc0a5871df2f..458a668ba916 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index 234821f6a441..96e06940b34c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -3,6 +3,8 @@ * Copyright (C) 2024-2026 Intel Corporation */ +#include + #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, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h index f1997e280058..7b56819d45fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 92858b8f7395..56e0c19e0f81 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -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; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index d34a9a2cbeae..dbe7a54a38b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -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; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index b3836423e53e..d80a1cfc2ed5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -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 @@ -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 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 77eeeed66116..e18d86f021dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c index 69d222a8194c..73c2b7b3c9de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c index 69a0d67858bf..a4e5f2be499f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/link.c @@ -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 @@ -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), {}, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c index cb1968b07452..fdeab7082e78 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c @@ -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(); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h index edf8eef4e81a..7cc8cb6eedd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.h @@ -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 * diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index edf9c735dd67..b6c2fa3664cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 1e8716cbb4ce..2185dade95f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c index 58e9a940024d..0812522edea0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c @@ -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 #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; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 8ffa72aca3cf..d6a8624b1ae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c256cbc6602e..74bd4038fd56 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index be89b84204fb..683cac56822c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 2b52a4f3bff9..1692b6e75f57 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -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 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bca13417e82c..dc69c71faa76 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index f052537e9567..2e12f93ad32b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -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: diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 608100bc6b11..5eb09ee24944 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -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)), diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index abc0c831d1ca..d84c7c1efee1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c index 0e324aeb9055..f41cbe62e7aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c @@ -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) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 1c4ee76d8387..28b276c65952 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -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