summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-28 16:45:40 +0100
committerMark Brown <broonie@kernel.org>2026-07-28 16:45:40 +0100
commit85dd03c6583eb82b1dc526b7b9b8aae74212265a (patch)
tree47a5b35f977a894a960fa23f49fbb49f4298ea3c /drivers/net/wireless
parenta4bd046b8582921af7d9a496e3501a31e7334216 (diff)
parent4a0bd262df757b25fc4e2a53c947317c119ced4e (diff)
downloadlinux-next-85dd03c6583eb82b1dc526b7b9b8aae74212265a.tar.gz
linux-next-85dd03c6583eb82b1dc526b7b9b8aae74212265a.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/bz.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/dr.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/sc.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/main.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/tx.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h51
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dump.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/error-dump.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/pnvm.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/regulatory.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c33
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/main.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/agg.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/d3.c136
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/hcmd.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mac80211.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mac80211.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mcc.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/notif.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/regulatory.c90
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/scan.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/sta.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c36
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h23
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c54
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c11
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_ioctl.c12
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/scan.c3
46 files changed, 552 insertions, 183 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index 606362463dc7..1099d8cfe6aa 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -10,7 +10,7 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
-#define IWL_BZ_UCODE_CORE_MAX 106
+#define IWL_BZ_UCODE_CORE_MAX 107
/* Lowest firmware core release supported */
#define IWL_BZ_UCODE_CORE_MIN 102
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index 946975294b4f..a89a2c75687f 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -9,7 +9,7 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
-#define IWL_DR_UCODE_CORE_MAX 106
+#define IWL_DR_UCODE_CORE_MAX 107
/* Lowest firmware core release supported */
#define IWL_DR_UCODE_CORE_MIN 102
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index e8240c1782ac..16abf0147fe4 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -10,7 +10,7 @@
#include "fw/api/txq.h"
/* Highest firmware core release supported */
-#define IWL_SC_UCODE_CORE_MAX 106
+#define IWL_SC_UCODE_CORE_MAX 107
/* Lowest firmware core release supported */
#define IWL_SC_UCODE_CORE_MIN 102
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index ca5a8140908a..6bd5b6d84b2a 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1511,10 +1511,10 @@ out_destroy_workqueue:
priv->workqueue = NULL;
out_uninit_drv:
iwl_uninit_drv(priv);
-out_free_eeprom_blob:
- kfree(priv->eeprom_blob);
out_free_eeprom:
kfree(priv->nvm_data);
+out_free_eeprom_blob:
+ kfree(priv->eeprom_blob);
out_leave_trans:
iwl_trans_op_mode_leave(priv->trans);
out_free_hw:
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
index a7806776a51e..1a0167f67c7b 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
@@ -604,8 +604,10 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
}
ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
- if (ret)
+ if (ret) {
+ iwlagn_dealloc_agg_txq(priv, txq_id);
return ret;
+ }
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index 430a7642e01a..71e0950d0193 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2019-2025 Intel Corporation
+ * Copyright (C) 2019-2026 Intel Corporation
*/
#include <linux/uuid.h>
#include "iwl-drv.h"
@@ -181,6 +181,7 @@ static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt)
fwrt->dsm_revision = ACPI_DSM_REV;
fwrt->dsm_source = BIOS_SOURCE_ACPI;
+ fwrt->dsm_values[DSM_FUNC_QUERY] = (u32)query_func_val;
IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
(u32)query_func_val);
@@ -246,7 +247,7 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
- if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func))
+ if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values)))
return -EINVAL;
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
@@ -1193,6 +1194,8 @@ int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
*value = wifi_pkg->package.elements[1].integer.value &
IWL_ACPI_WBEM_REV0_MASK;
+ fwrt->wbem_source = BIOS_SOURCE_ACPI;
+ fwrt->wbem_revision = tbl_rev;
IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n");
ret = 0;
out_free:
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index 51a57e57de7a..45eb35ffb637 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2023, 2025 Intel Corporation
+ * Copyright (C) 2018-2023, 2025-2026 Intel Corporation
*/
#ifndef __iwl_fw_acpi__
#define __iwl_fw_acpi__
@@ -111,9 +111,6 @@
#define ACPI_PPAG_WIFI_DATA_SIZE_V3 ((ACPI_PPAG_NUM_CHAINS * \
ACPI_PPAG_NUM_BANDS_V3) + 2)
-#define IWL_SAR_ENABLE_MSK BIT(0)
-#define IWL_REDUCE_POWER_FLAGS_POS 1
-
/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */
#define UEFI_WIFI_GUID_UNLOCKED 0
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
index 0172c0747a47..47fe1dc9d835 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -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
*/
@@ -47,6 +47,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids {
MCC_ALLOWED_AP_TYPE_CMD = 0x5,
/**
+ * @LARI_CONFIG_EXTENSION: &struct iwl_lari_config_extension_cmd
+ */
+ LARI_CONFIG_EXTENSION = 0x8,
+
+ /**
* @PNVM_INIT_COMPLETE_NTFY: &struct iwl_pnvm_init_complete_ntfy
*/
PNVM_INIT_COMPLETE_NTFY = 0xFE,
@@ -433,7 +438,10 @@ struct iwl_mcc_chub_notif {
__le16 mcc;
u8 source_id;
u8 reserved1;
-} __packed; /* LAR_MCC_NOTIFY_S */
+} __packed;
+/* LAR_MCC_NOTIFY_S_VER_1
+ * LAR_MCC_NOTIFY_S_VER_2
+ */
enum iwl_mcc_update_status {
MCC_RESP_NEW_CHAN_PROFILE,
@@ -542,6 +550,27 @@ struct iwl_bios_config_hdr {
} __packed; /* BIOS_CONFIG_HDR_API_S_VER_1 */
/**
+ * struct iwl_lari_config_extension_cmd - extend LARI configuration
+ *
+ * LARI_CONFIG_CHANGE's version must remain stable for frozen firmware.
+ * Because the driver might not know this version but still load that
+ * frozen FW and then send some default old version of LARI, causing the FW to
+ * assert about the bad size of it. To handle this, we do the following:
+ * 1. For newer firmware: increase the LARI_CONFIG_CHANGE version to support the
+ * new firmware API with extra UHB bits.
+ * 2. For frozen firmware: add a special alternative API that doesn't require
+ * modifying the frozen LARI_CONFIG_CHANGE's version.
+ * @dsm_table_hdr: BIOS DSM table source and revision
+ * @oem_uhb_allow_extension_bitmap: extension bitmap for OEM UHB config
+ * @reserved: reserved
+ */
+struct iwl_lari_config_extension_cmd {
+ struct iwl_bios_config_hdr dsm_table_hdr;
+ __le32 oem_uhb_allow_extension_bitmap;
+ __le32 reserved[10];
+} __packed; /* LARI_CONFIG_EXTENSION_CMD_API_S_VER_1 */
+
+/**
* struct bios_value_u32 - BIOS configuration.
* @hdr: bios config header
* @value: value in bios.
@@ -689,6 +718,14 @@ struct iwl_lari_config_change_cmd_v8 {
* get the data from the BIOS.
* @oem_unii9_enable: UNII-9 enablement as read from the BIOS
* @bios_hdr: bios config header
+ * @oem_uhb_allow_extension_bitmap: DSM Function 4 data as an extension of UHB
+ * enabled MCC sets
+ * @bios_wcpe_hdr: puncturing config header
+ * @wcpe_bitmap: bitmap of puncturing enablement per MCC
+ * @bios_wbem_hdr: 320 MHz per-MCC WBEM config header
+ * @reserved: reserved
+ * @oem_supported_dsm_bitmap: DSM function 0 bitmap describing supported
+ * DSM function indices
*/
struct iwl_lari_config_change_cmd {
__le32 config_bitmap;
@@ -706,9 +743,19 @@ struct iwl_lari_config_change_cmd {
__le32 oem_unii9_enable;
/* since version 13 */
struct iwl_bios_config_hdr bios_hdr;
+ /* All the below are since version 14 */
+ __le32 oem_uhb_allow_extension_bitmap;
+ struct iwl_bios_config_hdr bios_wcpe_hdr;
+ __le32 wcpe_bitmap;
+ struct iwl_bios_config_hdr bios_wbem_hdr;
+ __le32 reserved[10];
+ /* since version 15 */
+ __le32 oem_supported_dsm_bitmap;
} __packed;
/* LARI_CHANGE_CONF_CMD_S_VER_12
* LARI_CHANGE_CONF_CMD_S_VER_13
+ * LARI_CHANGE_CONF_CMD_S_VER_14
+ * LARI_CHANGE_CONF_CMD_S_VER_15
*/
/* Activate UNII-1 (5.2GHz) for World Wide */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
index c2af66899a78..bbbf3669a555 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -369,7 +369,7 @@ static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)
void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
{
struct iwl_pc_data *pc_data;
- u8 count;
+ u32 count;
if (!iwl_trans_device_enabled(fwrt->trans)) {
IWL_ERR(fwrt,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
index 07f1240df866..692bb17dfc33 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
@@ -352,7 +352,7 @@ struct iwl_fw_ini_error_dump_register {
* struct iwl_fw_ini_dump_cfg_name - configuration name
* @image_type: image type the configuration is related to
* @cfg_name_len: length of the configuration name
- * @cfg_name: name of the configuraiton
+ * @cfg_name: name of the configuration
*/
struct iwl_fw_ini_dump_cfg_name {
__le32 image_type;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index a26ed82a8106..664ac25754e9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -448,8 +448,9 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT: external FSEQ image support
* @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed
* during assert handling even if the dump isn't split
- * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of
- * handling raw DSM table data.
+ * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware can handle raw DSM
+ * table data. For LARI_CONFIG_CHANGE command version 13 and above, this
+ * capability is obsolete since raw DSM values are accepted by default.
* @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization
*
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
index ec0ff58ab312..545a213df71d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
@@ -205,6 +205,12 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
IWL_DEBUG_FW(trans,
"Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
tlv_len);
+ if (tlv_len < sizeof(*tlv_sku_id)) {
+ IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
+ tlv_len);
+ return -EINVAL;
+ }
+
IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
le32_to_cpu(tlv_sku_id->data[0]),
le32_to_cpu(tlv_sku_id->data[1]),
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 6fffc032efd3..22c97c75b83c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2023-2025 Intel Corporation
+ * Copyright (C) 2023-2026 Intel Corporation
*/
#ifndef __fw_regulatory_h__
@@ -30,6 +30,7 @@
#define BIOS_GEO_MIN_PROFILE_NUM 3
#define IWL_SAR_ENABLE_MSK BIT(0)
+#define IWL_REDUCE_POWER_FLAGS_POS 1
/* PPAG gain value bounds in 1/8 dBm */
#define IWL_PPAG_MIN_LB -16
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index d80ae610e56c..ac01ac0092ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
*/
#ifndef __iwl_fw_runtime_h__
#define __iwl_fw_runtime_h__
@@ -144,6 +144,11 @@ struct iwl_txf_iter_data {
* @tpc_enabled: TPC enabled
* @dsm_source: one of &enum bios_source. UEFI, ACPI or NONE
* @dsm_revision: the revision of the DSM table
+ * @wbem_source: one of &enum bios_source for the WBEM table
+ * @wbem_revision: the revision of the WBEM table
+ * @puncturing_source: one of &enum bios_source for the puncturing table
+ * @puncturing_revision: the revision of the puncturing table
+ * @bios_puncturing: per-country puncturing enablement bitmap from BIOS
*/
struct iwl_fw_runtime {
struct iwl_trans *trans;
@@ -226,6 +231,12 @@ struct iwl_fw_runtime {
u32 dsm_funcs_valid;
u32 dsm_values[DSM_FUNC_NUM_FUNCS];
#endif
+
+ enum bios_source wbem_source;
+ u8 wbem_revision;
+ enum bios_source puncturing_source;
+ u8 puncturing_revision;
+ u32 bios_puncturing;
};
void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 014f22c42f41..bf6a31e6f149 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright(c) 2021-2025 Intel Corporation
+ * Copyright(c) 2021-2026 Intel Corporation
*/
#include "iwl-drv.h"
@@ -248,6 +248,12 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
IWL_DEBUG_FW(trans,
"Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
tlv_len);
+ if (tlv_len < sizeof(*tlv_sku_id)) {
+ IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
+ tlv_len);
+ return -EINVAL;
+ }
+
IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
le32_to_cpu(tlv_sku_id->data[0]),
le32_to_cpu(tlv_sku_id->data[1]),
@@ -884,6 +890,8 @@ int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
goto out;
}
*value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK;
+ fwrt->wbem_source = BIOS_SOURCE_UEFI;
+ fwrt->wbem_revision = data->revision;
IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n");
out:
kfree(data);
@@ -919,7 +927,7 @@ static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt)
*/
fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
- for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
+ for (int func = 0; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",
func, fwrt->dsm_funcs_valid);
@@ -970,29 +978,29 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_puncturing_data *data;
- /* default value is not enabled if there is any issue in reading
- * uefi variable or revision is not supported
- */
- int puncturing = 0;
+ int ret = 0;
data = iwl_uefi_get_verified_variable(fwrt->trans,
IWL_UEFI_PUNCTURING_NAME,
"UefiCnvWlanPuncturing",
sizeof(*data), NULL);
if (IS_ERR(data))
- return puncturing;
+ return -EINVAL;
if (data->revision != IWL_UEFI_PUNCTURING_REVISION) {
IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n",
data->revision);
+ ret = -EINVAL;
} else {
- puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK;
+ fwrt->puncturing_source = BIOS_SOURCE_UEFI;
+ fwrt->puncturing_revision = data->revision;
+ fwrt->bios_puncturing = data->puncturing;
IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n",
- puncturing);
+ fwrt->bios_puncturing);
}
kfree(data);
- return puncturing;
+ return ret;
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 474f06db4d43..386ca3744408 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright(c) 2021-2025 Intel Corporation
+ * Copyright(c) 2021-2026 Intel Corporation
*/
#ifndef __iwl_fw_uefi__
#define __iwl_fw_uefi__
@@ -275,8 +275,6 @@ enum iwl_uefi_cnv_puncturing_flags {
IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK = BIT(1),
};
-#define IWL_UEFI_PUNCTURING_REV0_MASK (IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK | \
- IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK)
/**
* struct uefi_cnv_var_puncturing_data - controlling channel
* puncturing for few countries.
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index b1a55909f0d4..11763dec77ec 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
*/
#include <linux/firmware.h>
#include "iwl-drv.h"
@@ -611,6 +611,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))
return 0;
+ if (!fw_mon_cfg->req_size)
+ return -EIO;
+
num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num);
if (fwrt->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
@@ -621,6 +624,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
return -EIO;
}
+ if (!num_frags)
+ return -EIO;
+
remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size),
PAGE_SIZE);
num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index bd5353fdde81..863d5e358152 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -225,6 +225,18 @@ enum iwl_reg_capa_flags_v5 {
REG_CAPA_V5_11BN_DISABLED = BIT(17),
}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4, 5 */
+/**
+ * enum iwl_reg_capa_flags_v6 - global capability flags,
+ * applicable from MCC response version 10 onwards.
+ * Response v6 includes all members of iwl_reg_capa_flags_v5; only v6-specific
+ * additions are listed here.
+ * @REG_CAPA_V6_EHT_PUNCTURING_ENABLED: EHT puncturing is enabled for this
+ * regulatory domain.
+ */
+enum iwl_reg_capa_flags_v6 {
+ REG_CAPA_V6_EHT_PUNCTURING_ENABLED = BIT(18),
+}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_6 */
+
/*
* API v2 for reg_capa_flags is relevant from version 6 and onwards of the
* MCC update command response.
@@ -236,6 +248,11 @@ enum iwl_reg_capa_flags_v5 {
*/
#define REG_CAPA_V4_RESP_VER 8
+/* API v6 for reg_capa_flags is relevant from version 10 and onwards of the
+ * MCC update command response.
+ */
+#define REG_CAPA_V6_RESP_VER 10
+
static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level,
int chan, u32 flags)
{
@@ -697,7 +714,8 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
.mac.mac_cap = {
[0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP |
IEEE80211_UHR_MAC_CAP0_DPS_SUPP,
- [1] = IEEE80211_UHR_MAC_CAP1_DUO_SUPP,
+ [1] = IEEE80211_UHR_MAC_CAP1_DUO_SUPP |
+ IEEE80211_UHR_MAC_CAP1_DBE_SUPP,
},
},
},
@@ -1687,6 +1705,13 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver)
{
struct iwl_reg_capa reg_capa = {};
+ if (resp_ver >= REG_CAPA_V6_RESP_VER) {
+ if (flags & REG_CAPA_V6_EHT_PUNCTURING_ENABLED)
+ reg_capa.puncturing_status = IWL_PUNCTURING_STATUS_ENABLED;
+ else
+ reg_capa.puncturing_status = IWL_PUNCTURING_STATUS_DISABLED;
+ }
+
if (resp_ver >= REG_CAPA_V4_RESP_VER) {
reg_capa.allow_40mhz = true;
reg_capa.allow_80mhz = flags & REG_CAPA_V5_80MHZ_ALLOWED;
@@ -1713,7 +1738,8 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver)
struct ieee80211_regdomain *
iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
int num_of_ch, __le32 *channels, u16 fw_mcc,
- u16 geo_info, u32 cap, u8 resp_ver)
+ u16 geo_info, u32 cap, u8 resp_ver,
+ enum iwl_puncturing_status *puncturing_status)
{
const struct iwl_rf_cfg *cfg = trans->cfg;
struct device *dev = trans->dev;
@@ -1776,6 +1802,9 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
/* parse regulatory capability flags */
reg_capa = iwl_get_reg_capa(cap, resp_ver);
+ if (puncturing_status)
+ *puncturing_status = reg_capa.puncturing_status;
+
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
enum nl80211_band band =
iwl_nl80211_band_from_channel_idx(ch_idx);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
index e676d7c2d6cc..9ebb72d3726a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2015, 2018-2025 Intel Corporation
+ * Copyright (C) 2005-2015, 2018-2026 Intel Corporation
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#ifndef __iwl_nvm_parse_h__
@@ -22,6 +22,19 @@ enum iwl_nvm_sbands_flags {
};
/**
+ * enum iwl_puncturing_status - EHT puncturing status from MCC capabilities
+ * @IWL_PUNCTURING_STATUS_UNKNOWN: puncturing status is not provided by FW
+ * or is not initialized yet
+ * @IWL_PUNCTURING_STATUS_ENABLED: puncturing is enabled for the current MCC
+ * @IWL_PUNCTURING_STATUS_DISABLED: puncturing is disabled for the current MCC
+ */
+enum iwl_puncturing_status {
+ IWL_PUNCTURING_STATUS_UNKNOWN,
+ IWL_PUNCTURING_STATUS_ENABLED,
+ IWL_PUNCTURING_STATUS_DISABLED,
+};
+
+/**
* struct iwl_reg_capa - struct for global regulatory capabilities, Used for
* handling the different APIs of reg_capa_flags.
*
@@ -36,6 +49,8 @@ enum iwl_nvm_sbands_flags {
* @disable_11ax: 11ax is forbidden for this regulatory domain.
* @disable_11be: 11be is forbidden for this regulatory domain.
* @disable_11bn: UHR/11bn is not allowed for this regulatory domain
+ * @puncturing_status: EHT puncturing status for the current MCC.
+ * See &enum iwl_puncturing_status.
*/
struct iwl_reg_capa {
bool allow_40mhz;
@@ -45,6 +60,7 @@ struct iwl_reg_capa {
bool disable_11ax;
bool disable_11be;
bool disable_11bn;
+ enum iwl_puncturing_status puncturing_status;
};
/**
@@ -131,11 +147,13 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
* @geo_info: geo info value
* @cap: capability
* @resp_ver: FW response version
+ * @puncturing_status: FW puncturing status for current MCC, when available
*/
struct ieee80211_regdomain *
iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
int num_of_ch, __le32 *channels, u16 fw_mcc,
- u16 geo_info, u32 cap, u8 resp_ver);
+ u16 geo_info, u32 cap, u8 resp_ver,
+ enum iwl_puncturing_status *puncturing_status);
/**
* struct iwl_nvm_section - describes an NVM section in memory.
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index c5ff1b1b720f..ce92e26c42d7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021-2024 Intel Corporation
+ * Copyright (C) 2026 Intel Corporation
*/
#include <linux/etherdevice.h>
@@ -457,7 +458,7 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev,
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF];
q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
- ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr, q_sz);
+ ret = iwl_mei_write_cyclic_buf(cldev, notif_q, q_head, hdr, q_sz);
if (ret < 0)
return ret;
@@ -1040,11 +1041,14 @@ static void iwl_mei_read_from_q(const u8 *q_head, u32 q_sz,
u32 rd = *_rd;
if (rd + len <= q_sz) {
- memcpy(buf, q_head + rd, len);
+ if (buf)
+ memcpy(buf, q_head + rd, len);
rd += len;
} else {
- memcpy(buf, q_head + rd, q_sz - rd);
- memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
+ if (buf) {
+ memcpy(buf, q_head + rd, q_sz - rd);
+ memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
+ }
rd = len - (q_sz - rd);
}
@@ -1085,24 +1089,29 @@ static void iwl_mei_handle_sap_data(struct mei_cl_device *cldev,
break;
}
+ valid_rx_sz -= len;
+
if (len < sizeof(*ethhdr)) {
dev_err(&cldev->dev,
"Data len is smaller than an ethernet header? len = %d\n",
len);
+ iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
+ continue;
}
- valid_rx_sz -= len;
-
if (le16_to_cpu(hdr.type) != SAP_MSG_DATA_PACKET) {
dev_err(&cldev->dev, "Unsupported Rx data: type %d, len %d\n",
le16_to_cpu(hdr.type), len);
+ iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
continue;
}
/* We need enough room for the WiFi header + SNAP + IV */
skb = netdev_alloc_skb(netdev, len + QOS_HDR_IV_SNAP_LEN);
- if (!skb)
+ if (!skb) {
+ iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
continue;
+ }
skb_reserve(skb, QOS_HDR_IV_SNAP_LEN);
ethhdr = skb_push(skb, sizeof(*ethhdr));
@@ -1147,6 +1156,11 @@ static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev,
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, hdr, sizeof(*hdr));
valid_rx_sz -= sizeof(*hdr);
len = le16_to_cpu(hdr->len);
+ if (len + sizeof(*hdr) > PAGE_SIZE) {
+ dev_err(&cldev->dev,
+ "SAP message is too big: %u\n", len);
+ break;
+ }
if (valid_rx_sz < len)
break;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
index a464ebdec57f..96102d2af2cf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
@@ -200,11 +200,11 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
struct iwl_mld_baid_data *baid_data;
struct iwl_mld_reorder_buffer *buffer;
struct iwl_mld_reorder_buf_entry *entries;
- struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
struct iwl_mld_link_sta *mld_link_sta;
u32 reorder = le32_to_cpu(desc->reorder_data);
bool amsdu, last_subframe, is_old_sn, is_dup;
u8 tid = ieee80211_get_tid(hdr);
+ struct iwl_mld_sta *mld_sta;
u8 baid;
u16 nssn, sn;
u32 sta_mask = 0;
@@ -228,10 +228,13 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
return IWL_MLD_PASS_SKB;
/* no sta yet */
- if (WARN_ONCE(!sta,
- "Got valid BAID without a valid station assigned\n"))
+ if (IWL_FW_CHECK(mld, !sta,
+ "Got valid BAID without a valid station assigned - %d\n",
+ baid))
return IWL_MLD_PASS_SKB;
+ mld_sta = iwl_mld_sta_from_mac80211(sta);
+
/* not a data packet */
if (!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index 458a668ba916..55f9b809e764 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -59,6 +59,30 @@ struct iwl_mld_suspend_key_iter_data {
__le32 bigtk_cipher;
};
+struct iwl_mld_wake_pkt_iter_data {
+ bool multicast;
+ u32 ivlen;
+ u32 icvlen;
+};
+
+static void
+iwl_mld_wake_pkt_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key, void *_data)
+{
+ struct iwl_mld_wake_pkt_iter_data *data = _data;
+ bool is_group_key = !sta;
+
+ /* ignore anything that is not a PTK / GTK */
+ if (key->keyidx > 3)
+ return;
+ if (is_group_key != data->multicast)
+ return;
+
+ data->ivlen = key->iv_len;
+ data->icvlen = key->icv_len;
+}
+
struct iwl_mld_mcast_key_data {
u8 key[WOWLAN_KEY_MAX_SIZE];
u8 len;
@@ -573,18 +597,42 @@ iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5,
}
}
-static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld,
- u32 len,
- u32 expected_len,
- u8 num_mlo_keys,
+static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, u32 len,
+ const void *notif_data,
int version)
{
u32 len_with_mlo_keys;
+ u32 expected_len;
+ u8 num_mlo_keys;
+
+ /* Extract num_mlo_keys from the void pointer based on version */
+ if (version == 5) {
+ const struct iwl_wowlan_info_notif_v5 *notif_v5 = notif_data;
+
+ expected_len = sizeof(*notif_v5);
+
+ if (IWL_FW_CHECK(mld, len < expected_len,
+ "Invalid wowlan_info_notif v5 (expected=%u got=%u)\n",
+ expected_len, len))
+ return false;
+
+ num_mlo_keys = notif_v5->num_mlo_link_keys;
+ } else if (version == 6) {
+ const struct iwl_wowlan_info_notif *notif = notif_data;
- if (IWL_FW_CHECK(mld, len < expected_len,
- "Invalid wowlan_info_notif v%d (expected=%u got=%u)\n",
- version, expected_len, len))
+ expected_len = sizeof(*notif);
+
+ if (IWL_FW_CHECK(mld, len < expected_len,
+ "Invalid wowlan_info_notif v6 (expected=%u got=%u)\n",
+ expected_len, len))
+ return false;
+
+ num_mlo_keys = notif->num_mlo_link_keys;
+ } else {
+ IWL_WARN(mld, "Unsupported wowlan_info_notif version %d\n",
+ version);
return false;
+ }
len_with_mlo_keys = expected_len +
(num_mlo_keys * sizeof(struct iwl_wowlan_mlo_gtk));
@@ -616,16 +664,14 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
if (wowlan_info_ver == 5) {
/* v5 format - validate before conversion */
- const struct iwl_wowlan_info_notif_v5 *notif_v5 = (void *)pkt->data;
+ const struct iwl_wowlan_info_notif_v5 *_notif =
+ (void *)pkt->data;
- if (!iwl_mld_validate_wowlan_notif_size(mld, len,
- sizeof(*notif_v5),
- notif_v5->num_mlo_link_keys,
- 5))
+ if (!iwl_mld_validate_wowlan_notif_size(mld, len, _notif, 5))
return true;
converted_notif = kzalloc_flex(*converted_notif, mlo_gtks,
- notif_v5->num_mlo_link_keys,
+ _notif->num_mlo_link_keys,
GFP_ATOMIC);
if (!converted_notif) {
IWL_ERR(mld,
@@ -633,15 +679,12 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
return true;
}
- iwl_mld_convert_wowlan_notif_v5(notif_v5,
- converted_notif);
+ iwl_mld_convert_wowlan_notif_v5(_notif, converted_notif);
notif = converted_notif;
} else if (wowlan_info_ver == 6) {
notif = (void *)pkt->data;
- if (!iwl_mld_validate_wowlan_notif_size(mld, len,
- sizeof(*notif),
- notif->num_mlo_link_keys,
- 6))
+
+ if (!iwl_mld_validate_wowlan_notif_size(mld, len, notif, 6))
return true;
} else {
/* smaller versions are not supported */
@@ -686,7 +729,7 @@ iwl_mld_handle_wake_pkt_notif(struct iwl_mld *mld,
{
const struct iwl_wowlan_wake_pkt_notif *notif = (void *)pkt->data;
u32 actual_size, len = iwl_rx_packet_payload_len(pkt);
- u32 expected_size = le32_to_cpu(notif->wake_packet_length);
+ u32 expected_size;
if (IWL_FW_CHECK(mld, len < sizeof(*notif),
"Invalid WoWLAN wake packet notification (expected size=%zu got=%u)\n",
@@ -699,6 +742,7 @@ iwl_mld_handle_wake_pkt_notif(struct iwl_mld *mld,
wowlan_status->wakeup_reasons))
return true;
+ expected_size = le32_to_cpu(notif->wake_packet_length);
actual_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif,
wake_packet);
@@ -723,11 +767,17 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
struct cfg80211_wowlan_wakeup *wakeup,
struct sk_buff **_pkt)
{
- int pkt_bufsize = wowlan_status->wake_packet_bufsize;
- int expected_pktlen = wowlan_status->wake_packet_length;
+ u32 pkt_bufsize = wowlan_status->wake_packet_bufsize;
+ u32 expected_pktlen = wowlan_status->wake_packet_length;
const u8 *pktdata = wowlan_status->wake_packet;
const struct ieee80211_hdr *hdr = (const void *)pktdata;
- int truncated = expected_pktlen - pkt_bufsize;
+ u32 truncated;
+
+ if (IWL_FW_CHECK(mld, pkt_bufsize < sizeof(*hdr),
+ "pkt_bufsize is too short: %u\n", pkt_bufsize))
+ return;
+
+ truncated = expected_pktlen - pkt_bufsize;
if (ieee80211_is_data(hdr->frame_control)) {
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -738,9 +788,18 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
if (!pkt)
return;
- skb_put_data(pkt, pktdata, hdrlen);
- pktdata += hdrlen;
- pkt_bufsize -= hdrlen;
+ if (ieee80211_has_protected(hdr->frame_control)) {
+ struct iwl_mld_wake_pkt_iter_data iter_data = {
+ .multicast =
+ is_multicast_ether_addr(hdr->addr1),
+ };
+
+ ieee80211_iter_keys(mld->hw, vif,
+ iwl_mld_wake_pkt_key_iter,
+ &iter_data);
+ ivlen = iter_data.ivlen;
+ icvlen += iter_data.icvlen;
+ }
/* if truncated, FCS/ICV is (partially) gone */
if (truncated >= icvlen) {
@@ -751,6 +810,13 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
truncated = 0;
}
+ if (IWL_FW_CHECK(mld, pkt_bufsize <= hdrlen + ivlen + icvlen,
+ "pkt_bufsize is too small %u\n", pkt_bufsize))
+ return;
+
+ skb_put_data(pkt, pktdata, hdrlen);
+ pktdata += hdrlen;
+ pkt_bufsize -= hdrlen;
pkt_bufsize -= ivlen + icvlen;
pktdata += ivlen;
@@ -772,6 +838,11 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
fcslen -= truncated;
truncated = 0;
}
+
+ if (IWL_FW_CHECK(mld, pkt_bufsize <= fcslen,
+ "pkt_bufsize is too small %u\n", pkt_bufsize))
+ return;
+
pkt_bufsize -= fcslen;
wakeup->packet = wowlan_status->wake_packet;
wakeup->packet_present_len = pkt_bufsize;
@@ -1449,8 +1520,16 @@ static bool iwl_mld_handle_d3_notif(struct iwl_notif_wait_data *notif_wait,
}
case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
struct iwl_d3_end_notif *notif = (void *)pkt->data;
+ u32 len = iwl_rx_packet_payload_len(pkt);
+
+ if (IWL_FW_CHECK(mld, len < sizeof(*notif),
+ "Invalid D3_END notification (expected=%zu got=%u)\n",
+ sizeof(*notif), len)) {
+ resume_data->notif_handling_err = true;
+ } else {
+ resume_data->d3_end_flags = le32_to_cpu(notif->flags);
+ }
- resume_data->d3_end_flags = le32_to_cpu(notif->flags);
resume_data->notifs_received |= IWL_D3_NOTIF_D3_END_NOTIF;
break;
}
@@ -2140,6 +2219,9 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld)
ret = iwl_mld_wait_d3_notif(mld, &resume_data, true);
if (ret) {
IWL_ERR(mld, "Couldn't get the d3 notifs %d\n", ret);
+
+ if (bss_vif->cfg.assoc)
+ ieee80211_resume_disconnect(bss_vif);
goto err;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c
index 81df3fdfcbf5..a4b8037b5c76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c
@@ -459,3 +459,24 @@ void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld)
mld->ftm_initiator.req, GFP_KERNEL);
iwl_mld_ftm_reset(mld);
}
+
+void iwl_mld_ftm_abort(struct iwl_mld *mld, struct cfg80211_pmsr_request *req)
+{
+ struct iwl_tof_range_abort_cmd cmd = {
+ .request_id = req->cookie,
+ };
+
+ lockdep_assert_wiphy(mld->wiphy);
+
+ if (req != mld->ftm_initiator.req)
+ return;
+
+ if (iwl_mld_send_cmd_pdu(mld, WIDE_ID(LOCATION_GROUP,
+ TOF_RANGE_ABORT_CMD),
+ &cmd))
+ IWL_ERR(mld, "failed to abort FTM process\n");
+
+ iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_FTM_REQ,
+ mld->ftm_initiator.req->cookie);
+ iwl_mld_ftm_reset(mld);
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h
index 3fab25a52508..e82237b31467 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h
@@ -25,5 +25,6 @@ int iwl_mld_ftm_start(struct iwl_mld *mld, struct ieee80211_vif *vif,
void iwl_mld_handle_ftm_resp_notif(struct iwl_mld *mld,
struct iwl_rx_packet *pkt);
void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld);
+void iwl_mld_ftm_abort(struct iwl_mld *mld, struct cfg80211_pmsr_request *req);
#endif /* __iwl_mld_ftm_initiator_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h b/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h
index 64a8d4248324..19e1c9e509cf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/hcmd.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_hcmd_h__
#define __iwl_mld_hcmd_h__
@@ -42,7 +42,12 @@ __iwl_mld_send_cmd_with_flags_pdu(struct iwl_mld *mld, u32 id,
#define _iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len, \
ignored...) \
- __iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len)
+ ({ \
+ BUILD_BUG_ON(__builtin_constant_p(len) && \
+ (u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
+ __iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, \
+ data, len); \
+ })
#define iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len...) \
_iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, ##len, \
sizeof(*(data)))
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 9ac17be30400..3a4c8fda68d0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -543,8 +543,7 @@ iwl_mld_mac80211_tx(struct ieee80211_hw *hw,
iwl_mld_tx_skb(mld, skb, NULL);
}
-static void
-iwl_mld_restart_cleanup(struct iwl_mld *mld)
+void iwl_mld_restart_cleanup(struct iwl_mld *mld)
{
iwl_cleanup_mld(mld);
@@ -1281,11 +1280,13 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mld_tlc_update_phy(mld, vif, link);
/* in the non-MLO case, remove/re-add the link to clean up FW state.
- * In MLO, it'll be done in drv_change_vif_link
+ * In MLO, it'll be done in drv_change_vif_link.
+ * Do not do so during restart or in case the device is dead.
*/
if (!ieee80211_vif_is_mld(vif) && !mld_vif->ap_sta &&
!WARN_ON_ONCE(vif->cfg.assoc) &&
- vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart) {
+ vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart &&
+ !iwl_trans_is_dead(mld->trans)) {
iwl_mld_remove_link(mld, link);
iwl_mld_add_link(mld, link);
}
@@ -2853,6 +2854,15 @@ static int iwl_mld_start_pmsr(struct ieee80211_hw *hw,
return iwl_mld_ftm_start(mld, vif, request);
}
+static void iwl_mld_abort_pmsr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_pmsr_request *request)
+{
+ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+
+ iwl_mld_ftm_abort(mld, request);
+}
+
static enum ieee80211_neg_ttlm_res
iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_neg_ttlm *neg_ttlm)
@@ -2974,6 +2984,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
.prep_add_interface = iwl_mld_prep_add_interface,
.set_hw_timestamp = iwl_mld_set_hw_timestamp,
.start_pmsr = iwl_mld_start_pmsr,
+ .abort_pmsr = iwl_mld_abort_pmsr,
.can_neg_ttlm = iwl_mld_can_neg_ttlm,
.start_nan = iwl_mld_start_nan,
.stop_nan = iwl_mld_stop_nan,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.h b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.h
index aad04d7b2617..f3302997b28f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2026 Intel Corporation
*/
#ifndef __iwl_mld_mac80211_h__
#define __iwl_mld_mac80211_h__
@@ -9,5 +10,6 @@
int iwl_mld_register_hw(struct iwl_mld *mld);
void iwl_mld_recalc_multicast_filter(struct iwl_mld *mld);
+void iwl_mld_restart_cleanup(struct iwl_mld *mld);
#endif /* __iwl_mld_mac80211_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
index 830c251f43af..b4657e82468c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
@@ -95,6 +95,8 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
struct iwl_mcc_update_resp_v8 *resp;
u8 resp_ver = iwl_fw_lookup_notif_ver(mld->fw, IWL_ALWAYS_LONG_GROUP,
MCC_UPDATE_CMD, 0);
+ enum iwl_puncturing_status puncturing_status;
+ u16 mcc;
IWL_DEBUG_LAR(mld, "Getting regdomain data for %s from FW\n", alpha2);
@@ -116,12 +118,13 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
}
IWL_DEBUG_LAR(mld, "MCC update response version: %d\n", resp_ver);
+ mcc = le16_to_cpu(resp->mcc);
regd = iwl_parse_nvm_mcc_info(mld->trans,
__le32_to_cpu(resp->n_channels),
- resp->channels,
- __le16_to_cpu(resp->mcc),
+ resp->channels, mcc,
__le16_to_cpu(resp->geo_info),
- le32_to_cpu(resp->cap), resp_ver);
+ le32_to_cpu(resp->cap), resp_ver,
+ &puncturing_status);
if (IS_ERR(regd)) {
IWL_DEBUG_LAR(mld, "Could not get parse update from FW %ld\n",
@@ -135,18 +138,25 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
mld->mcc_src = resp->source_id;
+ if (puncturing_status == IWL_PUNCTURING_STATUS_ENABLED)
+ __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
+ mld->hw->flags);
+ else if (puncturing_status == IWL_PUNCTURING_STATUS_DISABLED)
+ ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
+
+ if (resp_ver >= 10)
+ goto out;
+
/* FM follows BIOS/MCC policy, WH disallows puncturing only in US/CA. */
if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM) {
- if (!iwl_puncturing_is_allowed_in_bios(mld->bios_enable_puncturing,
- le16_to_cpu(resp->mcc)))
+ if (!iwl_puncturing_is_allowed_in_bios(mld->fwrt.bios_puncturing,
+ mcc))
ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
else
__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
mld->hw->flags);
} else if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) ==
- IWL_CFG_RF_TYPE_WH) {
- u16 mcc = le16_to_cpu(resp->mcc);
-
+ IWL_CFG_RF_TYPE_WH) {
if (mcc == IWL_MCC_US || mcc == IWL_MCC_CANADA)
ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
else
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 78c78cf891cd..6e991fb99ff3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
@@ -212,6 +212,7 @@ static const struct iwl_hcmd_names iwl_mld_reg_and_nvm_names[] = {
HCMD_NAME(TAS_CONFIG),
HCMD_NAME(SAR_OFFSET_MAPPING_TABLE_CMD),
HCMD_NAME(MCC_ALLOWED_AP_TYPE_CMD),
+ HCMD_NAME(PNVM_INIT_COMPLETE_NTFY),
};
/* Please keep this array *SORTED* by hex value.
@@ -418,8 +419,6 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
iwl_mld_construct_fw_runtime(mld, trans, fw, dbgfs_dir);
iwl_mld_get_bios_tables(mld);
- iwl_uefi_get_sgom_table(trans, &mld->fwrt);
- mld->bios_enable_puncturing = iwl_uefi_get_puncturing(&mld->fwrt);
iwl_mld_hw_set_regulatory(mld);
@@ -446,6 +445,8 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
}
if (ret) {
+ /* wiphy memory is about to be freed, we should cancel any pending work */
+ wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk);
wiphy_unlock(mld->wiphy);
rtnl_unlock();
goto err;
@@ -511,6 +512,7 @@ iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode)
iwl_mld_thermal_exit(mld);
wiphy_lock(mld->wiphy);
+ wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk);
iwl_mld_low_latency_stop(mld);
iwl_mld_deinit_time_sync(mld);
wiphy_unlock(mld->wiphy);
@@ -745,6 +747,7 @@ static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode)
wiphy_lock(mld->wiphy);
iwl_mld_stop_fw(mld);
+ iwl_mld_restart_cleanup(mld);
mld->fw_status.in_d3 = false;
wiphy_unlock(mld->wiphy);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h
index 922aa3dbff54..37f41b504b54 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h
@@ -172,7 +172,6 @@
* @debug_max_sleep: maximum sleep time in D3 (for debug purposes)
* @led: the led device
* @mcc_src: the source id of the MCC, comes from the firmware
- * @bios_enable_puncturing: is puncturing enabled by bios
* @fw_id_to_ba: maps a fw (BA) id to a corresponding Block Ack session data.
* @num_rx_ba_sessions: tracks the number of active Rx Block Ack (BA) sessions.
* the driver ensures that new BA sessions are blocked once the maximum
@@ -279,7 +278,6 @@ struct iwl_mld {
struct led_classdev led;
#endif
enum iwl_mcc_source mcc_src;
- bool bios_enable_puncturing;
struct iwl_mld_baid_data __rcu *fw_id_to_ba[IWL_MAX_BAID];
u8 num_rx_ba_sessions;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
index 7574689e4088..90733bbaf733 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
@@ -298,7 +298,8 @@ CMD_VERSIONS(channel_survey_notif,
CMD_VERSIONS(mfuart_notif,
CMD_VER_ENTRY(2, iwl_mfuart_load_notif))
CMD_VERSIONS(update_mcc,
- CMD_VER_ENTRY(1, iwl_mcc_chub_notif))
+ CMD_VER_ENTRY(1, iwl_mcc_chub_notif)
+ CMD_VER_ENTRY(2, iwl_mcc_chub_notif))
CMD_VERSIONS(session_prot_notif,
CMD_VER_ENTRY(3, iwl_session_prot_notif))
CMD_VERSIONS(missed_beacon_notif,
@@ -517,7 +518,7 @@ iwl_mld_notif_is_valid(struct iwl_mld *mld, struct iwl_rx_packet *pkt,
handler->cmd_id, notif_ver,
handler->sizes[handler->n_sizes - 1].ver);
- return size < handler->sizes[handler->n_sizes - 1].size;
+ return false;
}
struct iwl_async_handler_entry {
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index 659243ada86c..533870cf443f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
@@ -13,6 +13,26 @@
#include "mld.h"
#include "hcmd.h"
+static ssize_t iwl_mld_get_lari_config_cmd_size(u8 cmd_ver)
+{
+ switch (cmd_ver) {
+ case 15:
+ return sizeof(struct iwl_lari_config_change_cmd);
+ case 14:
+ return offsetof(struct iwl_lari_config_change_cmd,
+ oem_supported_dsm_bitmap);
+ case 13:
+ return offsetof(struct iwl_lari_config_change_cmd,
+ oem_uhb_allow_extension_bitmap);
+ case 12:
+ return offsetof(struct iwl_lari_config_change_cmd,
+ oem_11bn_allow_bitmap);
+ default:
+ WARN(true, "unsupported version: %d", cmd_ver);
+ return -EINVAL;
+ }
+}
+
void iwl_mld_get_bios_tables(struct iwl_mld *mld)
{
int ret;
@@ -67,6 +87,9 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld)
iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt);
iwl_bios_get_phy_filters(&mld->fwrt);
+
+ iwl_uefi_get_sgom_table(mld->trans, &mld->fwrt);
+ iwl_uefi_get_puncturing(&mld->fwrt);
}
static int iwl_mld_geo_sar_init(struct iwl_mld *mld)
@@ -325,11 +348,23 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
struct iwl_lari_config_change_cmd cmd = {
.config_bitmap = iwl_mld_get_lari_config_bitmap(fwrt),
};
- bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
+ u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw,
+ WIDE_ID(REGULATORY_AND_NVM_GROUP,
+ LARI_CONFIG_CHANGE), 12);
+ /*
+ * For LARI_CONFIG_CHANGE command version 13 and above, firmware accepts
+ * raw DSM values by default and this TLV is no longer needed.
+ */
+ bool has_raw_dsm_capa = cmd_ver >= 13 ||
+ fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
+ ssize_t cmd_len = iwl_mld_get_lari_config_cmd_size(cmd_ver);
int ret;
u32 value;
+ if (cmd_len < 0)
+ return;
+
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
if (!ret) {
if (!has_raw_dsm_capa)
@@ -371,8 +406,11 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
}
ret = iwl_bios_get_wbem(fwrt, &value);
- if (!ret)
+ if (!ret) {
cmd.oem_320mhz_allow_bitmap = cpu_to_le32(value);
+ cmd.bios_wbem_hdr.table_source = fwrt->wbem_source;
+ cmd.bios_wbem_hdr.table_revision = fwrt->wbem_revision;
+ }
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
if (!ret)
@@ -386,8 +424,21 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
if (!ret)
cmd.oem_unii9_enable = cpu_to_le32(value);
+ ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &value);
+ if (!ret)
+ cmd.oem_uhb_allow_extension_bitmap = cpu_to_le32(value);
+
+ ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_QUERY, &value);
+ if (!ret)
+ cmd.oem_supported_dsm_bitmap = cpu_to_le32(value);
+
+ cmd.bios_wcpe_hdr.table_source = fwrt->puncturing_source;
+ cmd.bios_wcpe_hdr.table_revision = fwrt->puncturing_revision;
+ cmd.wcpe_bitmap = cpu_to_le32(fwrt->bios_puncturing);
+
if (!cmd.config_bitmap &&
!cmd.oem_uhb_allow_bitmap &&
+ !cmd.oem_uhb_allow_extension_bitmap &&
!cmd.oem_11ax_allow_bitmap &&
!cmd.oem_unii4_allow_bitmap &&
!cmd.chan_state_active_bitmap &&
@@ -396,7 +447,9 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
!cmd.oem_320mhz_allow_bitmap &&
!cmd.oem_11be_allow_bitmap &&
!cmd.oem_11bn_allow_bitmap &&
- !cmd.oem_unii9_enable)
+ !cmd.oem_unii9_enable &&
+ !cmd.wcpe_bitmap &&
+ !cmd.oem_supported_dsm_bitmap)
return;
cmd.bios_hdr.table_source = fwrt->dsm_source;
@@ -415,6 +468,9 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
le32_to_cpu(cmd.oem_uhb_allow_bitmap),
le32_to_cpu(cmd.force_disable_channels_bitmap));
IWL_DEBUG_RADIO(mld,
+ "sending LARI_CONFIG_CHANGE, oem_uhb_allow_extension_bitmap=0x%x\n",
+ le32_to_cpu(cmd.oem_uhb_allow_extension_bitmap));
+ IWL_DEBUG_RADIO(mld,
"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
le32_to_cpu(cmd.edt_bitmap),
le32_to_cpu(cmd.oem_320mhz_allow_bitmap));
@@ -427,22 +483,16 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
IWL_DEBUG_RADIO(mld,
"sending LARI_CONFIG_CHANGE, oem_unii9_enable=0x%x\n",
le32_to_cpu(cmd.oem_unii9_enable));
+ IWL_DEBUG_RADIO(mld,
+ "sending LARI_CONFIG_CHANGE, wcpe_bitmap=0x%x\n",
+ le32_to_cpu(cmd.wcpe_bitmap));
+ IWL_DEBUG_RADIO(mld,
+ "sending LARI_CONFIG_CHANGE, oem_supported_dsm_bitmap=0x%x\n",
+ le32_to_cpu(cmd.oem_supported_dsm_bitmap));
- if (iwl_fw_lookup_cmd_ver(mld->fw,
- WIDE_ID(REGULATORY_AND_NVM_GROUP,
- LARI_CONFIG_CHANGE), 12) == 12) {
- int cmd_size = offsetof(typeof(cmd), oem_11bn_allow_bitmap);
-
- ret = iwl_mld_send_cmd_pdu(mld,
- WIDE_ID(REGULATORY_AND_NVM_GROUP,
- LARI_CONFIG_CHANGE),
- &cmd, cmd_size);
- } else {
- ret = iwl_mld_send_cmd_pdu(mld,
- WIDE_ID(REGULATORY_AND_NVM_GROUP,
- LARI_CONFIG_CHANGE),
- &cmd);
- }
+ ret = iwl_mld_send_cmd_pdu(mld,
+ WIDE_ID(REGULATORY_AND_NVM_GROUP,
+ LARI_CONFIG_CHANGE), &cmd, cmd_len);
if (ret)
IWL_DEBUG_RADIO(mld,
"Failed to send LARI_CONFIG_CHANGE (%d)\n",
@@ -488,6 +538,8 @@ void iwl_mld_init_ap_type_tables(struct iwl_mld *mld)
if (ret)
IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n",
ret);
+ else
+ IWL_DEBUG_RADIO(mld, "MCC_ALLOWED_AP_TYPE_CMD sent to FW\n");
}
void iwl_mld_init_tas(struct iwl_mld *mld)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index d80a1cfc2ed5..0faca402bc14 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -1681,7 +1681,8 @@ out:
static int
iwl_mld_scan_abort(struct iwl_mld *mld, int type, int uid, bool *wait)
{
- enum iwl_umac_scan_abort_status status;
+ enum iwl_umac_scan_abort_status status =
+ IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;
int ret;
*wait = true;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index e18d86f021dc..7957ac11b0cd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -355,10 +355,9 @@ static void iwl_mld_fill_pkt_ext(struct iwl_mld *mld,
for (int i = 0; i < MAX_HE_SUPP_NSS; i++) {
for (int bw = 0;
- bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]);
+ bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);
bw++) {
- u8 *qam_th =
- &pkt_ext->pkt_ext_qam_th[i][bw][0];
+ u8 *qam_th = pkt_ext->pkt_ext_qam_th[i][bw];
IWL_DEBUG_HT(mld,
"PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index fa523be91d8a..43a7230f1ab4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1517,12 +1517,48 @@ static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt,
return 0;
}
+static void iwl_mvm_send_lari_cfg_extension(struct iwl_mvm *mvm)
+{
+ struct iwl_fw_runtime *fwrt = &mvm->fwrt;
+ struct iwl_lari_config_extension_cmd cmd = {};
+ u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP,
+ LARI_CONFIG_EXTENSION);
+ u32 value;
+ int ret;
+
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) < 1)
+ return;
+
+ ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &value);
+ if (ret)
+ return;
+
+ cmd.dsm_table_hdr.table_source = fwrt->dsm_source;
+ cmd.dsm_table_hdr.table_revision = fwrt->dsm_revision;
+ cmd.oem_uhb_allow_extension_bitmap = cpu_to_le32(value);
+
+ IWL_DEBUG_RADIO(mvm,
+ "sending LARI_CONFIG_EXTENSION, oem_uhb_allow_extension_bitmap=0x%x\n",
+ le32_to_cpu(cmd.oem_uhb_allow_extension_bitmap));
+ ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
+ if (ret < 0)
+ IWL_DEBUG_RADIO(mvm,
+ "Failed to send LARI_CONFIG_EXTENSION (%d)\n",
+ ret);
+}
+
static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
struct iwl_lari_config_change_cmd cmd;
size_t cmd_size;
int ret;
+ /*
+ * LARI_CONFIG_CHANGE triggers a profile update, so send
+ * LARI_CONFIG_EXTENSION first to make sure its data is applied
+ * in the same update.
+ */
+ iwl_mvm_send_lari_cfg_extension(mvm);
ret = iwl_mvm_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size);
if (!ret) {
ret = iwl_mvm_send_cmd_pdu(mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 3e73a6195fd9..5bd246e37943 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -152,7 +152,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
resp->channels,
__le16_to_cpu(resp->mcc),
__le16_to_cpu(resp->geo_info),
- le32_to_cpu(resp->cap), resp_ver);
+ le32_to_cpu(resp->cap), resp_ver, NULL);
/* Store the return source id */
src_id = resp->source_id;
if (IS_ERR_OR_NULL(regd)) {
@@ -1127,7 +1127,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
}
-static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
+void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
iwl_mvm_stop_device(mvm);
@@ -2350,10 +2350,9 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,
int bw;
for (bw = 0;
- bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]);
+ bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);
bw++) {
- u8 *qam_th =
- &pkt_ext->pkt_ext_qam_th[i][bw][0];
+ u8 *qam_th = pkt_ext->pkt_ext_qam_th[i][bw];
IWL_DEBUG_HT(mvm,
"PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 31912f4d0175..c64e4ed00986 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1657,6 +1657,7 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
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);
+void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm);
static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
{
@@ -1672,14 +1673,24 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm);
/* Tx / Host Commands */
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_pdu(struct iwl_mvm *mvm, u32 id,
+ u32 flags, u16 len, const void *data);
+#define iwl_mvm_send_cmd_pdu(mvm, id, flags, len, data) ({ \
+ BUILD_BUG_ON(__builtin_constant_p(len) && \
+ (u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
+ _iwl_mvm_send_cmd_pdu(mvm, id, flags, len, 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_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,
+ u16 len, const void *data,
+ u32 *status);
+#define iwl_mvm_send_cmd_pdu_status(mvm, id, len, data, status) ({ \
+ BUILD_BUG_ON(__builtin_constant_p(len) && \
+ (u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
+ _iwl_mvm_send_cmd_pdu_status(mvm, id, len, data, 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);
@@ -2392,14 +2403,12 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
bool sync,
const void *data, u32 size);
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
-struct ieee80211_vif *iwl_mvm_get_vif_by_macid(struct iwl_mvm *mvm, u32 macid);
bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm);
#define MVM_TCM_PERIOD_MSEC 500
#define MVM_TCM_PERIOD (HZ * MVM_TCM_PERIOD_MSEC / 1000)
#define MVM_LL_PERIOD (10 * HZ)
void iwl_mvm_tcm_work(struct work_struct *work);
-void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm);
void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel);
void iwl_mvm_resume_tcm(struct iwl_mvm *mvm);
void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 2297392db955..1dd27292af9b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -155,8 +155,8 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,
if (notif->type != cpu_to_le32(IWL_DP_MON_NOTIF_TYPE_EXT_CCA))
return;
- /* FIXME: should fetch the link and not the vif */
- vif = iwl_mvm_get_vif_by_macid(mvm, notif->link_id);
+ /* mac_id = link_id since we don't support MLO */
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, notif->link_id, false);
if (!vif || vif->type != NL80211_IFTYPE_STATION)
return;
@@ -707,6 +707,7 @@ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = {
HCMD_NAME(NVM_ACCESS_COMPLETE),
HCMD_NAME(NVM_GET_INFO),
HCMD_NAME(TAS_CONFIG),
+ HCMD_NAME(LARI_CONFIG_EXTENSION),
};
/* Please keep this array *SORTED* by hex value.
@@ -954,7 +955,7 @@ static void iwl_mvm_frob_txf_key_iter(struct ieee80211_hw *hw,
}
match++;
if (match == keylen) {
- memset(txf->buf + i - keylen, 0xAA, keylen);
+ memset(txf->buf + i + 1 - keylen, 0xAA, keylen);
match = 0;
}
}
@@ -1535,6 +1536,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)
iwl_fw_cancel_timestamp(&mvm->fwrt);
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
+ mvm->sf_state = SF_UNINIT;
iwl_mvm_pause_tcm(mvm, false);
@@ -2090,7 +2092,7 @@ static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode)
mutex_lock(&mvm->mutex);
clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
- iwl_mvm_stop_device(mvm);
+ iwl_mvm_restart_cleanup(mvm);
mvm->fast_resume = false;
mutex_unlock(&mvm->mutex);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h
index 2cfd0fb5e781..7bdbacb64078 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2026 Intel Corporation
*/
#ifndef __TIME_SYNC_H__
#define __TIME_SYNC_H__
@@ -19,6 +20,9 @@ int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr,
static inline
bool iwl_mvm_time_sync_frame(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *addr)
{
+ if (!mvm->time_sync.active)
+ return false;
+
if (ether_addr_equal(mvm->time_sync.peer_addr, addr) &&
(ieee80211_is_timing_measurement(skb) || ieee80211_is_ftm(skb))) {
skb_queue_tail(&mvm->time_sync.frame_list, skb);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 2e12f93ad32b..2fd4a9961145 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -73,8 +73,8 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
return ret;
}
-int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
- u32 flags, u16 len, const void *data)
+int _iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
+ u32 flags, u16 len, const void *data)
{
struct iwl_host_cmd cmd = {
.id = id,
@@ -137,8 +137,8 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
/*
* We assume that the caller set the status to the sucess value
*/
-int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,
- const void *data, u32 *status)
+int _iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,
+ const void *data, u32 *status)
{
struct iwl_host_cmd cmd = {
.id = id,
@@ -689,36 +689,6 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
return bss_iter_data.vif;
}
-struct iwl_bss_find_iter_data {
- struct ieee80211_vif *vif;
- u32 macid;
-};
-
-static void iwl_mvm_bss_find_iface_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_bss_find_iter_data *data = _data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- if (mvmvif->id == data->macid)
- data->vif = vif;
-}
-
-struct ieee80211_vif *iwl_mvm_get_vif_by_macid(struct iwl_mvm *mvm, u32 macid)
-{
- struct iwl_bss_find_iter_data data = {
- .macid = macid,
- };
-
- lockdep_assert_held(&mvm->mutex);
-
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_bss_find_iface_iterator, &data);
-
- return data.vif;
-}
-
struct iwl_sta_iter_data {
bool assoc;
};
@@ -1055,7 +1025,7 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
/*
* If the current load isn't low we need to force re-evaluation
* in the TCM period, so that we can return to low load if there
- * was no traffic at all (and thus iwl_mvm_recalc_tcm didn't get
+ * was no traffic at all (and thus iwl_mvm_tcm_work() didn't get
* triggered by traffic).
*/
if (load != IWL_MVM_TRAFFIC_LOW)
@@ -1081,8 +1051,11 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
return 0;
}
-void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
+void iwl_mvm_tcm_work(struct work_struct *work)
{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,
+ tcm.work);
unsigned long ts = jiffies;
bool handle_uapsd =
time_after(ts, mvm->tcm.uapsd_nonagg_ts +
@@ -1119,15 +1092,6 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
iwl_mvm_tcm_results(mvm);
}
-void iwl_mvm_tcm_work(struct work_struct *work)
-{
- struct delayed_work *delayed_work = to_delayed_work(work);
- struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,
- tcm.work);
-
- iwl_mvm_recalc_tcm(mvm);
-}
-
void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel)
{
spin_lock_bh(&mvm->tcm.lock);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 7a7b10152e5a..a3e6c9e09a3b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -548,6 +548,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_mac_cfg)},
{IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_mac_cfg)},
{IWL_PCI_DEVICE(0xD240, PCI_ANY_ID, iwl_sc_mac_cfg)},
+ {IWL_PCI_DEVICE(0x9327, PCI_ANY_ID, iwl_sc_mac_cfg)},
#endif /* CONFIG_IWLMVM || CONFIG_IWLMLD */
{0}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c
index bda9f807321e..27f4973791d0 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c
@@ -773,6 +773,8 @@ int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb,
tfd = iwl_txq_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta);
if (!tfd) {
+ txq->entries[idx].skb = NULL;
+ txq->entries[idx].cmd = NULL;
spin_unlock(&txq->lock);
return -1;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c
index fdb3ba4f63c0..dc2fe0c4f68c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2003-2014, 2018-2021, 2023-2025 Intel Corporation
+ * Copyright (C) 2003-2014, 2018-2021, 2023-2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -1149,10 +1149,17 @@ bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
unsigned int wdg_timeout)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id];
+ struct iwl_txq *txq;
int fifo = -1;
bool scd_bug = false;
+ if (WARN_ONCE(txq_id < 0 ||
+ txq_id >= trans->mac_cfg->base->num_of_queues,
+ "queue %d out of range", txq_id))
+ return false;
+
+ txq = trans_pcie->txqs.txq[txq_id];
+
if (test_and_set_bit(txq_id, trans_pcie->txqs.queue_used))
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index a8eab6b1e63b..c8df3edff675 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -1550,7 +1550,7 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
adapter->workqueue =
alloc_workqueue("MWIFIEX_WORK_QUEUE",
- WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
+ WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!adapter->workqueue)
goto err_kmalloc;
@@ -1716,7 +1716,7 @@ mwifiex_add_card(void *card, struct completion *fw_done,
adapter->workqueue =
alloc_workqueue("MWIFIEX_WORK_QUEUE",
- WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
+ WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!adapter->workqueue)
goto err_kmalloc;
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index 9460d5352b23..19196848778c 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -57,6 +57,18 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
status);
mwifiex_cancel_all_pending_cmd(adapter);
+
+ /* The command response path writes through cmd_node->data_buf.
+ * On an interrupted wait, the caller can return and release a
+ * stack-allocated data_buf before a late firmware response is
+ * processed. Detach the caller-owned buffer from the current
+ * command so a late response cannot corrupt freed stack memory.
+ */
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
+ if (adapter->curr_cmd == cmd_queued)
+ adapter->curr_cmd->data_buf = NULL;
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
+
return status;
}
diff --git a/drivers/net/wireless/nxp/nxpwifi/scan.c b/drivers/net/wireless/nxp/nxpwifi/scan.c
index bb3ce2b6f4b9..b77056983e83 100644
--- a/drivers/net/wireless/nxp/nxpwifi/scan.c
+++ b/drivers/net/wireless/nxp/nxpwifi/scan.c
@@ -1255,6 +1255,9 @@ int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter,
(u16)(current_ptr - bss_entry->beacon_buf);
break;
case WLAN_EID_EXTENSION:
+ if (!element_len)
+ return -EINVAL;
+
elem = (struct element *)current_ptr;
switch (elem->data[0]) {