* [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18
@ 2026-03-18 20:54 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 01/15] wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2 Miri Korenblit
` (14 more replies)
0 siblings, 15 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless
Hi,
features and cleanups from our internal tree.
Thanks,
Miri
---
Emmanuel Grumbach (9):
wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2
wifi: iwlwifi: ensure we don't read SAR values past the limit
wifi: iwlwifi: uefi: decouple UEFI and firmware APIs
wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define
wifi: iwlwifi: uefi: open code the PPAG table store operation
wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm
wifi: iwlwifi: regulatory: support a new command for PPAG
wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables
wifi: iwlwifi: acpi: add support for PPAG rev5
Ilan Peer (2):
wifi: iwlwifi: mld: Refactor scan command handling
wifi: iwlwifi: mld: Introduce scan command version 18
Johannes Berg (1):
wifi: iwlwifi: mld: correctly set wifi generation data
Miri Korenblit (1):
wifi: iwlwifi: mld: add support for sta command version 3
Nidhish A N (1):
wifi: iwlwifi: mvm: cleanup some more MLO code
Pagadala Yesu Anjaneyulu (1):
wifi: iwlwifi: mld: remove unused scan expire time constants
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 31 +-
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 21 +-
.../wireless/intel/iwlwifi/fw/api/mac-cfg.h | 94 +++++-
.../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 14 +-
.../net/wireless/intel/iwlwifi/fw/api/power.h | 8 +
.../net/wireless/intel/iwlwifi/fw/api/scan.h | 45 +++
.../wireless/intel/iwlwifi/fw/regulatory.c | 151 ++-------
.../wireless/intel/iwlwifi/fw/regulatory.h | 10 +-
.../net/wireless/intel/iwlwifi/fw/runtime.h | 8 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 60 +++-
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 32 +-
.../wireless/intel/iwlwifi/mld/constants.h | 1 -
drivers/net/wireless/intel/iwlwifi/mld/fw.c | 2 +-
.../net/wireless/intel/iwlwifi/mld/iface.c | 101 ++++--
.../net/wireless/intel/iwlwifi/mld/mac80211.c | 19 ++
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 1 -
.../wireless/intel/iwlwifi/mld/regulatory.c | 98 +++++-
.../wireless/intel/iwlwifi/mld/regulatory.h | 2 +-
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 218 ++++++++++---
drivers/net/wireless/intel/iwlwifi/mld/scan.h | 2 +
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 42 ++-
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 153 ++++++++-
.../net/wireless/intel/iwlwifi/mvm/mld-key.c | 46 ---
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 132 --------
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 291 +-----------------
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 -
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 -
27 files changed, 834 insertions(+), 757 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 01/15] wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 02/15] wifi: iwlwifi: ensure we don't read SAR values past the limit Miri Korenblit
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach, Johannes Berg
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
There is a new version of this command to indicate which AP type in
UNII-9 is supported per country.
This adds support for a new UEFI table that will include that data to be
filled in the new AP type table.
Rename the uats_table field in firmware_runtime structure since it
includes now the UATS and the new UNEB table coming from UEFI.
For the same reason, rename iwl_mld_init_uats.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 14 ++++++--
.../net/wireless/intel/iwlwifi/fw/runtime.h | 8 ++---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 36 +++++++++++++++++--
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 11 ++++++
drivers/net/wireless/intel/iwlwifi/mld/fw.c | 2 +-
.../wireless/intel/iwlwifi/mld/regulatory.c | 32 ++++++++++++++---
.../wireless/intel/iwlwifi/mld/regulatory.h | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 24 +++++++------
8 files changed, 102 insertions(+), 27 deletions(-)
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 bd6bf931866f..25c860a05b0e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -701,13 +701,23 @@ struct iwl_pnvm_init_complete_ntfy {
#define UATS_TABLE_COL_SIZE 13
/**
- * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD
+ * struct iwl_mcc_allowed_ap_type_cmd_v1 - struct for MCC_ALLOWED_AP_TYPE_CMD
* @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS)
* @reserved: reserved
*/
-struct iwl_mcc_allowed_ap_type_cmd {
+struct iwl_mcc_allowed_ap_type_cmd_v1 {
u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE];
__le16 reserved;
} __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */
+/**
+ * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD
+ * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS)
+ * @mcc_to_ap_type_unii9_map: mapping an MCC to UNII-9 AP type support allowed
+ */
+struct iwl_mcc_allowed_ap_type_cmd {
+ u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE];
+ u8 mcc_to_ap_type_unii9_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE];
+} __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_2 */
+
#endif /* __iwl_fw_api_nvm_reg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index ff186fb2e0da..411e75b45530 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -106,8 +106,8 @@ struct iwl_txf_iter_data {
* @cur_fw_img: current firmware image, must be maintained by
* the driver by calling &iwl_fw_set_current_image()
* @dump: debug dump data
- * @uats_table: AP type table
- * @uats_valid: is AP type table valid
+ * @ap_type_cmd: AP type tables (for enablement on 6 GHz)
+ * @ap_type_cmd_valid: if &ap_type_cmd is valid
* @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock:
* 0: Unlocked, 1 and 2: Locked.
* Only read the UEFI variables if locked.
@@ -213,8 +213,8 @@ struct iwl_fw_runtime {
u8 ppag_bios_source;
struct iwl_sar_offset_mapping_cmd sgom_table;
bool sgom_enabled;
- struct iwl_mcc_allowed_ap_type_cmd uats_table;
- bool uats_valid;
+ struct iwl_mcc_allowed_ap_type_cmd ap_type_cmd;
+ bool ap_type_cmd_valid;
u8 uefi_tables_lock_status;
struct iwl_phy_specific_cfg phy_filters;
enum bios_source dsm_source;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index a7ba86e06c09..d4e1ab1f7c84 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -402,11 +402,11 @@ static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data,
if (uats_data->revision != 1)
return -EINVAL;
- memcpy(fwrt->uats_table.mcc_to_ap_type_map,
+ memcpy(fwrt->ap_type_cmd.mcc_to_ap_type_map,
uats_data->mcc_to_ap_type_map,
- sizeof(fwrt->uats_table.mcc_to_ap_type_map));
+ sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_map));
- fwrt->uats_valid = true;
+ fwrt->ap_type_cmd_valid = true;
return 0;
}
@@ -429,6 +429,36 @@ void iwl_uefi_get_uats_table(struct iwl_trans *trans,
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table);
+void iwl_uefi_get_uneb_table(struct iwl_trans *trans,
+ struct iwl_fw_runtime *fwrt)
+{
+ struct uefi_cnv_wlan_uneb_data *data;
+
+ data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UNEB_NAME,
+ "UNEB", sizeof(*data), NULL);
+ if (IS_ERR(data))
+ return;
+
+ if (data->revision != 1) {
+ IWL_DEBUG_RADIO(fwrt,
+ "Cannot read UNEB table. rev is invalid\n");
+ goto out;
+ }
+
+ BUILD_BUG_ON(sizeof(data->mcc_to_ap_type_map) !=
+ sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map));
+
+ memcpy(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map,
+ data->mcc_to_ap_type_map,
+ sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map));
+
+ fwrt->ap_type_cmd_valid = true;
+
+out:
+ kfree(data);
+}
+IWL_EXPORT_SYMBOL(iwl_uefi_get_uneb_table);
+
static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt,
struct uefi_sar_profile *uefi_sar_prof,
u8 prof_index, bool enabled)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 349ac1505ad7..99170a72c3f1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -25,6 +25,7 @@
#define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing"
#define IWL_UEFI_DSBR_NAME L"UefiCnvCommonDSBR"
#define IWL_UEFI_WPFC_NAME L"WPFC"
+#define IWL_UEFI_UNEB_NAME L"CnvUefiWlanUNEB"
#define IWL_SGOM_MAP_SIZE 339
@@ -63,6 +64,9 @@ struct uefi_cnv_wlan_uats_data {
u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1];
} __packed;
+/* UNEB's layout is identical to UATS's */
+#define uefi_cnv_wlan_uneb_data uefi_cnv_wlan_uats_data
+
struct uefi_cnv_common_step_data {
u8 revision;
u8 step_mode;
@@ -274,6 +278,8 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt);
void iwl_uefi_get_uats_table(struct iwl_trans *trans,
struct iwl_fw_runtime *fwrt);
+void iwl_uefi_get_uneb_table(struct iwl_trans *trans,
+ struct iwl_fw_runtime *fwrt);
int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt);
int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value);
int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt);
@@ -373,6 +379,11 @@ iwl_uefi_get_uats_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt)
{
}
+static inline void
+iwl_uefi_get_uneb_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt)
+{
+}
+
static inline
int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c
index 19da521a4bab..7b1fb84a641c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c
@@ -513,7 +513,7 @@ static int iwl_mld_config_fw(struct iwl_mld *mld)
return ret;
iwl_mld_init_tas(mld);
- iwl_mld_init_uats(mld);
+ iwl_mld_init_ap_type_tables(mld);
return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index 6ab5a3410353..d1a55b565898 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
@@ -64,6 +64,7 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld)
}
iwl_uefi_get_uats_table(mld->trans, &mld->fwrt);
+ iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt);
iwl_bios_get_phy_filters(&mld->fwrt);
}
@@ -352,21 +353,42 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
ret);
}
-void iwl_mld_init_uats(struct iwl_mld *mld)
+void iwl_mld_init_ap_type_tables(struct iwl_mld *mld)
{
int ret;
struct iwl_host_cmd cmd = {
.id = WIDE_ID(REGULATORY_AND_NVM_GROUP,
MCC_ALLOWED_AP_TYPE_CMD),
- .data[0] = &mld->fwrt.uats_table,
- .len[0] = sizeof(mld->fwrt.uats_table),
+ .data[0] = &mld->fwrt.ap_type_cmd,
+ .len[0] = sizeof(mld->fwrt.ap_type_cmd),
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
- if (!mld->fwrt.uats_valid)
+ if (!mld->fwrt.ap_type_cmd_valid)
return;
- ret = iwl_mld_send_cmd(mld, &cmd);
+ if (iwl_fw_lookup_cmd_ver(mld->fw, cmd.id, 1) == 1) {
+ struct iwl_mcc_allowed_ap_type_cmd_v1 *cmd_v1 =
+ kzalloc(sizeof(*cmd_v1), GFP_KERNEL);
+
+ if (!cmd_v1)
+ return;
+
+ BUILD_BUG_ON(sizeof(mld->fwrt.ap_type_cmd.mcc_to_ap_type_map) !=
+ sizeof(cmd_v1->mcc_to_ap_type_map));
+
+ memcpy(cmd_v1->mcc_to_ap_type_map,
+ mld->fwrt.ap_type_cmd.mcc_to_ap_type_map,
+ sizeof(mld->fwrt.ap_type_cmd.mcc_to_ap_type_map));
+
+ cmd.data[0] = cmd_v1;
+ cmd.len[0] = sizeof(*cmd_v1);
+ ret = iwl_mld_send_cmd(mld, &cmd);
+ kfree(cmd_v1);
+ } else {
+ ret = iwl_mld_send_cmd(mld, &cmd);
+ }
+
if (ret)
IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n",
ret);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
index 3b01c645adda..5498c19789f4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
@@ -9,7 +9,7 @@
void iwl_mld_get_bios_tables(struct iwl_mld *mld);
void iwl_mld_configure_lari(struct iwl_mld *mld);
-void iwl_mld_init_uats(struct iwl_mld *mld);
+void iwl_mld_init_ap_type_tables(struct iwl_mld *mld);
void iwl_mld_init_tas(struct iwl_mld *mld);
int iwl_mld_init_ppag(struct iwl_mld *mld);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 43cf94c9a36b..f5e5c10cc581 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -459,23 +459,18 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm,
static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
{
+ int cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP,
+ MCC_ALLOWED_AP_TYPE_CMD);
+ struct iwl_mcc_allowed_ap_type_cmd_v1 cmd = {};
u8 cmd_ver;
int ret;
- struct iwl_host_cmd cmd = {
- .id = WIDE_ID(REGULATORY_AND_NVM_GROUP,
- MCC_ALLOWED_AP_TYPE_CMD),
- .flags = 0,
- .data[0] = &mvm->fwrt.uats_table,
- .len[0] = sizeof(mvm->fwrt.uats_table),
- .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
- };
if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
return;
}
- cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id,
+ cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id,
IWL_FW_CMD_VER_UNKNOWN);
if (cmd_ver != 1) {
IWL_DEBUG_RADIO(mvm,
@@ -486,10 +481,17 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt);
- if (!mvm->fwrt.uats_valid)
+ if (!mvm->fwrt.ap_type_cmd_valid)
return;
- ret = iwl_mvm_send_cmd(mvm, &cmd);
+ BUILD_BUG_ON(sizeof(mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map) !=
+ sizeof(cmd.mcc_to_ap_type_map));
+
+ memcpy(cmd.mcc_to_ap_type_map,
+ mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map,
+ sizeof(mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map));
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
if (ret < 0)
IWL_ERR(mvm, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n",
ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 02/15] wifi: iwlwifi: ensure we don't read SAR values past the limit
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 01/15] wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2 Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 03/15] wifi: iwlwifi: uefi: decouple UEFI and firmware APIs Miri Korenblit
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
When we fill the SAR values, we read values from the BIOS store in the
firmware runtime object and write them into the command that we send to
the firmware.
We assumed that the size of the firmware command is not longer than the
BIOS tables. This has been true until now, but this is not really safe.
We will soon have an firmware API change that will increase the size of
the table in the command and we want to make sure that we don't have a
buffer overrun when we read the firmware runtime object.
Add this safety measure.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 958e71a3c958..5793c267daf7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -241,6 +241,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b };
int i, j;
+ if (WARN_ON_ONCE(n_subbands >
+ ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands)))
+ return -EINVAL;
+
for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) {
struct iwl_sar_profile *prof;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 03/15] wifi: iwlwifi: uefi: decouple UEFI and firmware APIs
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 01/15] wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 02/15] wifi: iwlwifi: ensure we don't read SAR values past the limit Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 04/15] wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define Miri Korenblit
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
The APIs in uefi.h are not firmware API files nor are they pure software
objects. They really reflect a specific layout we expect to see in the
UEFI tables.
Since the UEFI objects are encoded into the BIOS, we can't use the same
values for the declaration of the UEFI objects and for the pure software
object like iwl_sar_profile in the firmware runtime object.
Decouple the two types.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 23 ++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 99170a72c3f1..c6940a3c03ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -76,13 +76,24 @@ struct uefi_cnv_common_step_data {
u8 radio2;
} __packed;
+#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
+#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
+
+/*
+ * struct uefi_sar_profile_chain - per-chain values of a SAR profile
+ * @subbands: the SAR value for each subband
+ */
+struct uefi_sar_profile_chain {
+ u8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
+};
+
/*
* struct uefi_sar_profile - a SAR profile as defined in UEFI
*
* @chains: a per-chain table of SAR values
*/
struct uefi_sar_profile {
- struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE];
+ struct uefi_sar_profile_chain chains[UEFI_SAR_MAX_CHAINS_PER_PROFILE];
} __packed;
/*
@@ -125,6 +136,14 @@ struct uefi_cnv_var_wgds {
struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
} __packed;
+/*
+ * struct uefi_ppag_chain - PPAG table for a specific chain
+ * @subbands: the PPAG values for band
+ */
+struct uefi_ppag_chain {
+ s8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
+};
+
/*
* struct uefi_cnv_var_ppag - PPAG table as defined in UEFI
* @revision: the revision of the table
@@ -134,7 +153,7 @@ struct uefi_cnv_var_wgds {
struct uefi_cnv_var_ppag {
u8 revision;
u32 ppag_modes;
- struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
+ struct uefi_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
} __packed;
/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (2 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 03/15] wifi: iwlwifi: uefi: decouple UEFI and firmware APIs Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mvm: cleanup some more MLO code Miri Korenblit
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Since we'll have to change things in this area, use the safer option to
define the size of an array.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index de9aef0d924c..b64abb8439b7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -504,7 +504,8 @@ iwl_acpi_parse_chains_table(union acpi_object *table,
u8 num_chains, u8 num_sub_bands)
{
for (u8 chain = 0; chain < num_chains; chain++) {
- for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
+ for (u8 subband = 0;
+ subband < ARRAY_SIZE(chains[chain].subbands);
subband++) {
/* if we don't have the values, use the default */
if (subband >= num_sub_bands) {
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mvm: cleanup some more MLO code
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (3 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 04/15] wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: remove unused scan expire time constants Miri Korenblit
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Nidhish A N, Pagadala Yesu Anjaneyulu
From: Nidhish A N <nidhish.a.n@intel.com>
iwlmld is now the op mode that is used for EHT devices,
so iwlmvm code can never run in MLO.
Clean up some more MLO code.
Signed-off-by: Nidhish A N <nidhish.a.n@intel.com>
Reviewed-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/mvm/mld-key.c | 46 ---
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 132 --------
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 285 ------------------
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 -
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 -
5 files changed, 472 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 9bb253dcf4a7..4869a5fa8abc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -121,52 +121,6 @@ struct iwl_mvm_sta_key_update_data {
int err;
};
-static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- void *_data)
-{
- u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
- struct iwl_mvm_sta_key_update_data *data = _data;
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_sec_key_cmd cmd = {
- .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
- .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
- .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
- .u.modify.key_id = cpu_to_le32(key->keyidx),
- .u.modify.key_flags =
- cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)),
- };
- int err;
-
- /* only need to do this for pairwise keys (link_id == -1) */
- if (sta != data->sta || key->link_id >= 0)
- return;
-
- err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
-
- if (err)
- data->err = err;
-}
-
-int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_mvm_sta_key_update_data data = {
- .sta = sta,
- .old_sta_mask = old_sta_mask,
- .new_sta_mask = new_sta_mask,
- };
-
- ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
- &data);
- return data.err;
-}
-
static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
u32 key_flags, u32 keyidx, u32 flags)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 896ed9823021..f1dbfeae20bc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -886,133 +886,6 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
}
-static int
-iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- u16 old_links, u16 new_links,
- struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
-{
- struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {};
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u16 removed = old_links & ~new_links;
- u16 added = new_links & ~old_links;
- int err, i;
-
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
- break;
-
- if (!(added & BIT(i)))
- continue;
- new_link[i] = kzalloc_obj(*new_link[i]);
- if (!new_link[i]) {
- err = -ENOMEM;
- goto free;
- }
-
- new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
- iwl_mvm_init_link(new_link[i]);
- }
-
- mutex_lock(&mvm->mutex);
-
- /* If we're in RESTART flow, the default link wasn't added in
- * drv_add_interface(), and link[0] doesn't point to it.
- */
- if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
- &mvm->status)) {
- err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
- if (err)
- goto out_err;
- mvmvif->link[0] = NULL;
- }
-
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- if (removed & BIT(i)) {
- struct ieee80211_bss_conf *link_conf = old[i];
-
- err = iwl_mvm_disable_link(mvm, vif, link_conf);
- if (err)
- goto out_err;
- kfree(mvmvif->link[i]);
- mvmvif->link[i] = NULL;
- } else if (added & BIT(i)) {
- struct ieee80211_bss_conf *link_conf;
-
- link_conf = link_conf_dereference_protected(vif, i);
- if (WARN_ON(!link_conf))
- continue;
-
- if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
- &mvm->status))
- mvmvif->link[i] = new_link[i];
- new_link[i] = NULL;
- err = iwl_mvm_add_link(mvm, vif, link_conf);
- if (err)
- goto out_err;
- }
- }
-
- err = 0;
- if (new_links == 0) {
- mvmvif->link[0] = &mvmvif->deflink;
- err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
- }
-
-out_err:
- /* we really don't have a good way to roll back here ... */
- mutex_unlock(&mvm->mutex);
-
-free:
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
- kfree(new_link[i]);
- return err;
-}
-
-static int
-iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links)
-{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-
- guard(mvm)(mvm);
- return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);
-}
-
-static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- u16 desired_links)
-{
- int n_links = hweight16(desired_links);
-
- if (n_links <= 1)
- return true;
-
- WARN_ON(1);
- return false;
-}
-
-static enum ieee80211_neg_ttlm_res
-iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_neg_ttlm *neg_ttlm)
-{
- u16 map;
- u8 i;
-
- /* Verify all TIDs are mapped to the same links set */
- map = neg_ttlm->downlink[0];
- for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
- if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||
- neg_ttlm->uplink[i] != map)
- return NEG_TTLM_RES_REJECT;
- }
-
- return NEG_TTLM_RES_ACCEPT;
-}
-
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.tx = iwl_mvm_mac_tx,
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
@@ -1102,9 +975,4 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,
#endif
.set_hw_timestamp = iwl_mvm_set_hw_timestamp,
-
- .change_vif_links = iwl_mvm_mld_change_vif_links,
- .change_sta_links = iwl_mvm_mld_change_sta_links,
- .can_activate_links = iwl_mvm_mld_can_activate_links,
- .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm,
};
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 3359e02e151f..44e16ee9514e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -913,288 +913,3 @@ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
rcu_read_unlock();
}
-
-static int iwl_mvm_mld_update_sta_queues(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_scd_queue_cfg_cmd cmd = {
- .operation = cpu_to_le32(IWL_SCD_QUEUE_MODIFY),
- .u.modify.old_sta_mask = cpu_to_le32(old_sta_mask),
- .u.modify.new_sta_mask = cpu_to_le32(new_sta_mask),
- };
- struct iwl_host_cmd hcmd = {
- .id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD),
- .len[0] = sizeof(cmd),
- .data[0] = &cmd
- };
- int tid;
- int ret;
-
- lockdep_assert_held(&mvm->mutex);
-
- for (tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) {
- struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[tid];
- int txq_id = tid_data->txq_id;
-
- if (txq_id == IWL_MVM_INVALID_QUEUE)
- continue;
-
- if (tid == IWL_MAX_TID_COUNT)
- cmd.u.modify.tid = cpu_to_le32(IWL_MGMT_TID);
- else
- cmd.u.modify.tid = cpu_to_le32(tid);
-
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int iwl_mvm_mld_update_sta_baids(struct iwl_mvm *mvm,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_rx_baid_cfg_cmd cmd = {
- .action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY),
- .modify.old_sta_id_mask = cpu_to_le32(old_sta_mask),
- .modify.new_sta_id_mask = cpu_to_le32(new_sta_mask),
- };
- u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD);
- int baid;
-
- /* mac80211 will remove sessions later, but we ignore all that */
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
- return 0;
-
- BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid));
-
- for (baid = 0; baid < ARRAY_SIZE(mvm->baid_map); baid++) {
- struct iwl_mvm_baid_data *data;
- int ret;
-
- data = rcu_dereference_protected(mvm->baid_map[baid],
- lockdep_is_held(&mvm->mutex));
- if (!data)
- continue;
-
- if (!(data->sta_mask & old_sta_mask))
- continue;
-
- WARN_ONCE(data->sta_mask != old_sta_mask,
- "BAID data for %d corrupted - expected 0x%x found 0x%x\n",
- baid, old_sta_mask, data->sta_mask);
-
- cmd.modify.tid = cpu_to_le32(data->tid);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_SEND_IN_RFKILL,
- sizeof(cmd), &cmd);
- data->sta_mask = new_sta_mask;
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int iwl_mvm_mld_update_sta_resources(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- int ret;
-
- ret = iwl_mvm_mld_update_sta_queues(mvm, sta,
- old_sta_mask,
- new_sta_mask);
- if (ret)
- return ret;
-
- ret = iwl_mvm_mld_update_sta_keys(mvm, vif, sta,
- old_sta_mask,
- new_sta_mask);
- if (ret)
- return ret;
-
- return iwl_mvm_mld_update_sta_baids(mvm, old_sta_mask, new_sta_mask);
-}
-
-int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links)
-{
- struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm_link_sta *mvm_sta_link;
- struct iwl_mvm_vif_link_info *mvm_vif_link;
- unsigned long links_to_add = ~old_links & new_links;
- unsigned long links_to_rem = old_links & ~new_links;
- unsigned long old_links_long = old_links;
- u32 current_sta_mask = 0, sta_mask_added = 0, sta_mask_to_rem = 0;
- unsigned long link_sta_added_to_fw = 0, link_sta_allocated = 0;
- unsigned int link_id;
- int ret;
-
- lockdep_assert_wiphy(mvm->hw->wiphy);
- lockdep_assert_held(&mvm->mutex);
-
- for_each_set_bit(link_id, &old_links_long,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- if (WARN_ON(!mvm_sta_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- current_sta_mask |= BIT(mvm_sta_link->sta_id);
- if (links_to_rem & BIT(link_id))
- sta_mask_to_rem |= BIT(mvm_sta_link->sta_id);
- }
-
- if (sta_mask_to_rem) {
- ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
- current_sta_mask,
- current_sta_mask &
- ~sta_mask_to_rem);
- if (WARN_ON(ret))
- goto err;
-
- current_sta_mask &= ~sta_mask_to_rem;
- }
-
- for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
- mvm_vif_link = mvm_vif->link[link_id];
-
- if (WARN_ON(!mvm_sta_link || !mvm_vif_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
- if (WARN_ON(ret))
- goto err;
-
- if (vif->type == NL80211_IFTYPE_STATION)
- mvm_vif_link->ap_sta_id = IWL_INVALID_STA;
-
- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
- }
-
- for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
- struct ieee80211_bss_conf *link_conf =
- link_conf_dereference_protected(vif, link_id);
- struct ieee80211_link_sta *link_sta =
- link_sta_dereference_protected(sta, link_id);
- mvm_vif_link = mvm_vif->link[link_id];
-
- if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta)) {
- ret = -EINVAL;
- goto err;
- }
-
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
- struct iwl_mvm_link_sta *mvm_link_sta =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
- u32 sta_id;
-
- if (WARN_ON(!mvm_link_sta)) {
- ret = -EINVAL;
- goto err;
- }
-
- sta_id = mvm_link_sta->sta_id;
-
- rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
- rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id],
- link_sta);
- } else {
- if (WARN_ON(mvm_sta->link[link_id])) {
- ret = -EINVAL;
- goto err;
- }
- ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta,
- link_id);
- if (WARN_ON(ret))
- goto err;
- }
-
- link_sta->agg.max_rc_amsdu_len = 1;
- ieee80211_sta_recalc_aggregates(sta);
-
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- if (WARN_ON(!mvm_sta_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- if (vif->type == NL80211_IFTYPE_STATION)
- iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif_link,
- mvm_sta_link);
-
- link_sta_allocated |= BIT(link_id);
-
- sta_mask_added |= BIT(mvm_sta_link->sta_id);
-
- ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
- mvm_sta_link);
- if (WARN_ON(ret))
- goto err;
-
- link_sta_added_to_fw |= BIT(link_id);
-
- iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link);
-
- iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta,
- link_conf->chanreq.oper.chan->band);
- }
-
- if (sta_mask_added) {
- ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
- current_sta_mask,
- current_sta_mask |
- sta_mask_added);
- if (WARN_ON(ret))
- goto err;
- }
-
- return 0;
-
-err:
- /* remove all already allocated stations in FW */
- for_each_set_bit(link_id, &link_sta_added_to_fw,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
- }
-
- /* remove all already allocated station links in driver */
- for_each_set_bit(link_id, &link_sta_allocated,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
- }
-
- return ret;
-}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 46a9dfa58a53..402ba5dee8b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2450,11 +2450,6 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mvm_vif_link_info *link,
unsigned int link_id);
-int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask);
int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
struct ieee80211_key_conf *keyconf);
u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index c25edc7c1813..ff099aec7886 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -637,10 +637,6 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
struct iwl_mvm_link_sta *mvm_sta_link,
unsigned int link_id);
int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);
-int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links);
u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int filter_link_id);
int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: remove unused scan expire time constants
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (4 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mvm: cleanup some more MLO code Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: Refactor scan command handling Miri Korenblit
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu, Emmanuel Grumbach
From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Remove the unused IWL_MLD_SCAN_EXPIRE_TIME_SEC constant from
constants.h and its corresponding IWL_MLD_SCAN_EXPIRE_TIME
macro definition from mlo.c. These definitions are no longer
referenced.
Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mld/constants.h | 1 -
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
index 5d23a618ae3c..e2a5eecc18c3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
@@ -36,7 +36,6 @@
#define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30
-#define IWL_MLD_SCAN_EXPIRE_TIME_SEC 20
#define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
index f842f5183223..f693f92e42b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
@@ -110,7 +110,6 @@ void iwl_mld_emlsr_tmp_non_bss_done_wk(struct wiphy *wiphy,
}
#define IWL_MLD_TRIGGER_LINK_SEL_TIME (HZ * IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC)
-#define IWL_MLD_SCAN_EXPIRE_TIME (HZ * IWL_MLD_SCAN_EXPIRE_TIME_SEC)
/* Exit reasons that can cause longer EMLSR prevention */
#define IWL_MLD_PREVENT_EMLSR_REASONS (IWL_MLD_EMLSR_EXIT_MISSED_BEACON | \
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: Refactor scan command handling
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (5 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: remove unused scan expire time constants Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: Introduce scan command version 18 Miri Korenblit
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ilan Peer
From: Ilan Peer <ilan.peer@intel.com>
As a preparation for a new scan command version, refactor
the scan command building such that it would allow introducing
new scan command structures in a simpler way.
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 159 ++++++++++++------
drivers/net/wireless/intel/iwlwifi/mld/scan.h | 2 +
2 files changed, 114 insertions(+), 47 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index a1a4cf3ab3d3..7f4679134def 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -116,6 +116,13 @@ struct iwl_mld_scan_params {
u8 bssid[ETH_ALEN] __aligned(2);
};
+struct iwl_scan_req_params_ptrs {
+ struct iwl_scan_general_params_v11 *general_params;
+ struct iwl_scan_channel_params_v7 *channel_params;
+ struct iwl_scan_periodic_parms_v1 *periodic_params;
+ struct iwl_scan_probe_params_v4 *probe_params;
+};
+
struct iwl_mld_scan_respect_p2p_go_iter_data {
struct ieee80211_vif *current_vif;
bool p2p_go;
@@ -512,9 +519,10 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld,
static void
iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld,
- struct iwl_scan_general_params_v11 *gp,
- struct iwl_mld_scan_params *params)
+ struct iwl_mld_scan_params *params,
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
+ struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params;
const struct iwl_mld_scan_timing_params *timing =
&scan_timing[params->type];
@@ -551,9 +559,10 @@ static void
iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_general_params_v11 *gp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
enum iwl_mld_scan_status scan_status)
{
+ struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params;
u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif,
scan_status);
u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif,
@@ -566,7 +575,7 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
gp->flags = cpu_to_le16(gen_flags);
gp->flags2 = gen_flags2;
- iwl_mld_scan_cmd_set_dwell(mld, gp, params);
+ iwl_mld_scan_cmd_set_dwell(mld, params, scan_ptrs);
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1)
gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;
@@ -577,9 +586,12 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
static int
iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params,
- struct iwl_scan_umac_schedule *schedule,
- __le16 *delay)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
+ struct iwl_scan_umac_schedule *schedule =
+ scan_ptrs->periodic_params->schedule;
+ __le16 *delay = &scan_ptrs->periodic_params->delay;
+
if (WARN_ON(!params->n_scan_plans ||
params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
return -EINVAL;
@@ -657,11 +669,12 @@ iwl_mld_scan_cmd_build_ssids(struct iwl_mld_scan_params *params,
static void
iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params,
- struct iwl_scan_probe_params_v4 *pp)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
int j, idex_s = 0, idex_b = 0;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
for (j = 0;
j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE;
@@ -725,13 +738,15 @@ iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params,
static void
iwl_mld_scan_cmd_set_probe_params(struct iwl_mld_scan_params *params,
- struct iwl_scan_probe_params_v4 *pp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
u32 *bitmap_ssid)
{
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
+
pp->preq = params->preq;
if (params->scan_6ghz) {
- iwl_mld_scan_fill_6g_chan_list(params, pp);
+ iwl_mld_scan_fill_6g_chan_list(params, scan_ptrs);
return;
}
@@ -821,10 +836,12 @@ static u32 iwl_mld_scan_ch_n_aps_flag(enum nl80211_iftype vif_type, u8 ch_id)
static void
iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld,
struct ieee80211_channel **channels,
- struct iwl_scan_channel_params_v7 *cp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
int n_channels, u32 flags,
enum nl80211_iftype vif_type)
{
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+
for (int i = 0; i < n_channels; i++) {
enum nl80211_band band = channels[i]->band;
struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i];
@@ -862,10 +879,11 @@ static u8
iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
u32 n_channels,
- struct iwl_scan_probe_params_v4 *pp,
- struct iwl_scan_channel_params_v7 *cp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
enum nl80211_iftype vif_type)
{
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
u32 i;
@@ -1063,25 +1081,23 @@ static int
iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_req_params_v17 *scan_p)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
- struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params;
- struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
/* Explicitly clear the flags since most of them are not
* relevant for 6 GHz scan.
*/
- chan_p->flags = 0;
- chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params,
- params->n_channels,
- probe_p, chan_p,
- vif->type);
- if (!chan_p->count)
+ cp->flags = 0;
+ cp->count = iwl_mld_scan_cfg_channels_6g(mld, params,
+ params->n_channels,
+ scan_ptrs, vif->type);
+ if (!cp->count)
return -EINVAL;
if (!params->n_ssids ||
(params->n_ssids == 1 && !params->ssids[0].ssid_len))
- chan_p->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER;
+ cp->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER;
return 0;
}
@@ -1090,12 +1106,12 @@ static int
iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_req_params_v17 *scan_p,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
bool low_latency,
enum iwl_mld_scan_status scan_status,
u32 channel_cfg_flags)
{
- struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
struct ieee80211_supported_band *sband =
&mld->nvm_data->bands[NL80211_BAND_6GHZ];
@@ -1107,14 +1123,14 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
if (params->scan_6ghz)
return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params,
- vif, scan_p);
+ vif, scan_ptrs);
/* relevant only for 2.4 GHz/5 GHz scan */
cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif,
low_latency);
cp->count = params->n_channels;
- iwl_mld_scan_cmd_set_channels(mld, params->channels, cp,
+ iwl_mld_scan_cmd_set_channels(mld, params->channels, scan_ptrs,
params->n_channels, channel_cfg_flags,
vif->type);
@@ -1144,41 +1160,50 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
return 0;
}
-static int
-iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
+struct iwl_scan_umac_handler {
+ u8 version;
+ int (*handler)(struct iwl_mld *mld, struct ieee80211_vif *vif,
struct iwl_mld_scan_params *params,
enum iwl_mld_scan_status scan_status,
- bool low_latency)
+ int uid, u32 ooc_priority, bool low_latency);
+};
+
+#define IWL_SCAN_UMAC_HANDLER(_ver) { \
+ .version = _ver, \
+ .handler = iwl_mld_scan_umac_v##_ver, \
+}
+
+static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ int uid, u32 ooc_priority, bool low_latency)
{
struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
- struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params;
+ struct iwl_scan_req_params_ptrs scan_ptrs = {
+ .general_params = &cmd->scan_params.general_params,
+ .probe_params = &cmd->scan_params.probe_params,
+ .channel_params = &cmd->scan_params.channel_params,
+ .periodic_params = &cmd->scan_params.periodic_params
+ };
u32 bitmap_ssid = 0;
- int uid, ret;
-
- memset(mld->scan.cmd, 0, mld->scan.cmd_size);
+ int ret;
- /* find a free UID entry */
- uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE);
- if (uid < 0)
- return uid;
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ return -EINVAL;
cmd->uid = cpu_to_le32(uid);
- cmd->ooc_priority =
- cpu_to_le32(iwl_mld_scan_ooc_priority(scan_status));
+ cmd->ooc_priority = cpu_to_le32(ooc_priority);
- iwl_mld_scan_cmd_set_gen_params(mld, params, vif,
- &scan_p->general_params, scan_status);
+ iwl_mld_scan_cmd_set_gen_params(mld, params, vif, &scan_ptrs,
+ scan_status);
- ret = iwl_mld_scan_cmd_set_sched_params(params,
- scan_p->periodic_params.schedule,
- &scan_p->periodic_params.delay);
+ ret = iwl_mld_scan_cmd_set_sched_params(params, &scan_ptrs);
if (ret)
return ret;
- iwl_mld_scan_cmd_set_probe_params(params, &scan_p->probe_params,
- &bitmap_ssid);
+ iwl_mld_scan_cmd_set_probe_params(params, &scan_ptrs, &bitmap_ssid);
- ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_p,
+ ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, &scan_ptrs,
low_latency, scan_status,
bitmap_ssid);
if (ret)
@@ -1187,6 +1212,45 @@ iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
return uid;
}
+static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
+ /* set the newest version first to shorten the list traverse time */
+ IWL_SCAN_UMAC_HANDLER(17),
+};
+
+static int
+iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ bool low_latency)
+{
+ int uid, err;
+ u32 ooc_priority;
+
+ memset(mld->scan.cmd, 0, mld->scan.cmd_size);
+ uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE);
+ if (uid < 0)
+ return uid;
+
+ ooc_priority = iwl_mld_scan_ooc_priority(scan_status);
+
+ for (size_t i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) {
+ const struct iwl_scan_umac_handler *ver_handler =
+ &iwl_scan_umac_handlers[i];
+
+ if (ver_handler->version != mld->scan.cmd_ver)
+ continue;
+
+ err = ver_handler->handler(mld, vif, params, scan_status,
+ uid, ooc_priority, low_latency);
+ return err ? : uid;
+ }
+
+ IWL_ERR(mld, "No handler for UMAC scan cmd version %d\n",
+ mld->scan.cmd_ver);
+
+ return -EINVAL;
+}
+
static bool
iwl_mld_scan_pass_all(struct iwl_mld *mld,
struct cfg80211_sched_scan_request *req)
@@ -2041,6 +2105,7 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld)
return -ENOMEM;
mld->scan.cmd_size = scan_cmd_size;
+ mld->scan.cmd_ver = scan_cmd_ver;
return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
index 69110f0cfc8e..772b3a02c4c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
@@ -109,6 +109,7 @@ enum iwl_mld_traffic_load {
* @traffic_load.status: The current traffic load status, see
* &enum iwl_mld_traffic_load
* @cmd_size: size of %cmd.
+ * @cmd_ver: version of the scan command format.
* @cmd: pointer to scan cmd buffer (allocated once in op mode start).
* @last_6ghz_passive_jiffies: stores the last 6GHz passive scan time
* in jiffies.
@@ -134,6 +135,7 @@ struct iwl_mld_scan {
/* And here fields that survive a fw restart */
size_t cmd_size;
void *cmd;
+ u8 cmd_ver;
unsigned long last_6ghz_passive_jiffies;
unsigned long last_start_time_jiffies;
u64 last_mlo_scan_time;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: Introduce scan command version 18
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (6 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: Refactor scan command handling Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 09/15] wifi: iwlwifi: uefi: open code the PPAG table store operation Miri Korenblit
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ilan Peer
From: Ilan Peer <ilan.peer@intel.com>
The FW scan logic was extended to support new channels in the
7 GHz band, as such, the scan command was modified to support
scanning more PSC channels.
Introduce scan command version 18 handling, which is different
from scan command version 17 only in the number of supported
channel configurations.
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/fw/api/scan.h | 45 ++++++++++
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 87 +++++++++++++++----
2 files changed, 115 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index 60f0a4924ddf..c2bb400c834c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -985,6 +985,7 @@ struct iwl_scan_probe_params_v4 {
} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */
#define SCAN_MAX_NUM_CHANS_V3 67
+#define SCAN_MAX_NUM_CHANS_V4 68
/**
* struct iwl_scan_channel_params_v4 - channel params
@@ -1027,6 +1028,24 @@ struct iwl_scan_channel_params_v7 {
struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3];
} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */
+/**
+ * struct iwl_scan_channel_params_v8 - channel params
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @n_aps_override: override the number of APs the FW uses to calculate dwell
+ * time when adaptive dwell is used.
+ * Channel k will use n_aps_override[i] when BIT(20 + i) is set in
+ * channel_config[k].flags
+ * @channel_config: array of explicit channel configurations
+ * for 2.4Ghz and 5.2Ghz bands
+ */
+struct iwl_scan_channel_params_v8 {
+ u8 flags;
+ u8 count;
+ u8 n_aps_override[2];
+ struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V4];
+} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_8 */
+
/**
* struct iwl_scan_general_params_v11 - channel params
* @flags: &enum iwl_umac_scan_general_flags_v2
@@ -1109,6 +1128,20 @@ struct iwl_scan_req_params_v17 {
struct iwl_scan_probe_params_v4 probe_params;
} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */
+/**
+ * struct iwl_scan_req_params_v18 - scan request parameters (v18)
+ * @general_params: &struct iwl_scan_general_params_v11
+ * @channel_params: &struct iwl_scan_channel_params_v8
+ * @periodic_params: &struct iwl_scan_periodic_parms_v1
+ * @probe_params: &struct iwl_scan_probe_params_v4
+ */
+struct iwl_scan_req_params_v18 {
+ struct iwl_scan_general_params_v11 general_params;
+ struct iwl_scan_channel_params_v8 channel_params;
+ struct iwl_scan_periodic_parms_v1 periodic_params;
+ struct iwl_scan_probe_params_v4 probe_params;
+} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_18 */
+
/**
* struct iwl_scan_req_umac_v12 - scan request command (v12)
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
@@ -1133,6 +1166,18 @@ struct iwl_scan_req_umac_v17 {
struct iwl_scan_req_params_v17 scan_params;
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */
+/**
+ * struct iwl_scan_req_umac_v18 - scan request command (v18)
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @ooc_priority: out of channel priority - &enum iwl_scan_priority
+ * @scan_params: scan parameters
+ */
+struct iwl_scan_req_umac_v18 {
+ __le32 uid;
+ __le32 ooc_priority;
+ struct iwl_scan_req_params_v18 scan_params;
+} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_18 */
+
/**
* struct iwl_umac_scan_abort - scan abort command
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index 7f4679134def..96cd970cceb4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -118,7 +118,7 @@ struct iwl_mld_scan_params {
struct iwl_scan_req_params_ptrs {
struct iwl_scan_general_params_v11 *general_params;
- struct iwl_scan_channel_params_v7 *channel_params;
+ struct iwl_scan_channel_params_v8 *channel_params;
struct iwl_scan_periodic_parms_v1 *periodic_params;
struct iwl_scan_probe_params_v4 *probe_params;
};
@@ -840,7 +840,7 @@ iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld,
int n_channels, u32 flags,
enum nl80211_iftype vif_type)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
for (int i = 0; i < n_channels; i++) {
enum nl80211_band band = channels[i]->band;
@@ -883,7 +883,7 @@ iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld,
enum nl80211_iftype vif_type)
{
struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
u32 i;
@@ -1083,7 +1083,7 @@ iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,
struct ieee80211_vif *vif,
struct iwl_scan_req_params_ptrs *scan_ptrs)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
/* Explicitly clear the flags since most of them are not
* relevant for 6 GHz scan.
@@ -1111,7 +1111,7 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
enum iwl_mld_scan_status scan_status,
u32 channel_cfg_flags)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
struct ieee80211_supported_band *sband =
&mld->nvm_data->bands[NL80211_BAND_6GHZ];
@@ -1173,39 +1173,89 @@ struct iwl_scan_umac_handler {
.handler = iwl_mld_scan_umac_v##_ver, \
}
-static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+static int iwl_mld_scan_umac_common(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
+ enum iwl_mld_scan_status scan_status,
+ bool low_latency)
+{
+ u32 bitmap_ssid = 0;
+ int ret;
+
+ iwl_mld_scan_cmd_set_gen_params(mld, params, vif, scan_ptrs,
+ scan_status);
+
+ ret = iwl_mld_scan_cmd_set_sched_params(params, scan_ptrs);
+ if (ret)
+ return ret;
+
+ iwl_mld_scan_cmd_set_probe_params(params, scan_ptrs, &bitmap_ssid);
+
+ return iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_ptrs,
+ low_latency, scan_status,
+ bitmap_ssid);
+}
+
+static int iwl_mld_scan_umac_v18(struct iwl_mld *mld, struct ieee80211_vif *vif,
struct iwl_mld_scan_params *params,
enum iwl_mld_scan_status scan_status,
int uid, u32 ooc_priority, bool low_latency)
{
- struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
+ struct iwl_scan_req_umac_v18 *cmd = mld->scan.cmd;
struct iwl_scan_req_params_ptrs scan_ptrs = {
.general_params = &cmd->scan_params.general_params,
.probe_params = &cmd->scan_params.probe_params,
.channel_params = &cmd->scan_params.channel_params,
.periodic_params = &cmd->scan_params.periodic_params
};
- u32 bitmap_ssid = 0;
int ret;
- if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V4))
return -EINVAL;
cmd->uid = cpu_to_le32(uid);
cmd->ooc_priority = cpu_to_le32(ooc_priority);
- iwl_mld_scan_cmd_set_gen_params(mld, params, vif, &scan_ptrs,
- scan_status);
-
- ret = iwl_mld_scan_cmd_set_sched_params(params, &scan_ptrs);
+ ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs,
+ scan_status, low_latency);
if (ret)
return ret;
- iwl_mld_scan_cmd_set_probe_params(params, &scan_ptrs, &bitmap_ssid);
+ return uid;
+}
+
+static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ int uid, u32 ooc_priority, bool low_latency)
+{
+ struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
+ struct iwl_scan_req_params_ptrs scan_ptrs = {
+ .general_params = &cmd->scan_params.general_params,
+ .probe_params = &cmd->scan_params.probe_params,
+
+ /* struct iwl_scan_channel_params_v8 and struct
+ * iwl_scan_channel_params_v7 are almost identical. The only
+ * difference is that the newer version allows configuration of
+ * more channels. So casting here is ok as long as we ensure
+ * that we don't exceed the max number of channels supported by
+ * the older version (see the WARN_ON below).
+ */
+ .channel_params = (struct iwl_scan_channel_params_v8 *)
+ &cmd->scan_params.channel_params,
+ .periodic_params = &cmd->scan_params.periodic_params
+ };
+ int ret;
+
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ return -EINVAL;
+
+ cmd->uid = cpu_to_le32(uid);
+ cmd->ooc_priority = cpu_to_le32(ooc_priority);
- ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, &scan_ptrs,
- low_latency, scan_status,
- bitmap_ssid);
+ ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs,
+ scan_status, low_latency);
if (ret)
return ret;
@@ -1214,6 +1264,7 @@ static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
/* set the newest version first to shorten the list traverse time */
+ IWL_SCAN_UMAC_HANDLER(18),
IWL_SCAN_UMAC_HANDLER(17),
};
@@ -2095,6 +2146,8 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld)
if (scan_cmd_ver == 17) {
scan_cmd_size = sizeof(struct iwl_scan_req_umac_v17);
+ } else if (scan_cmd_ver == 18) {
+ scan_cmd_size = sizeof(struct iwl_scan_req_umac_v18);
} else {
IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver);
return -EINVAL;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 09/15] wifi: iwlwifi: uefi: open code the PPAG table store operation
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (7 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: Introduce scan command version 18 Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 10/15] wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm Miri Korenblit
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
The structure in firmware runtime will need to grow because we're adding
a subband for UNII-9.
This means that we will soon no longer be able to just memcpy the data
from the UEFI table. The layout of the array will change.
Tediously copy the data byte-byte to make sure things get to the right
place even when we'll increase the number of subbands.
Make it easier for the uefi_cnv_var_ppag structure to grow by
simpiflying the layout it becomes an array of s8.
The layout of the structure becomes less obvious from the structure's
declaration, but then the code is more flexible.
Don't use UEFI_SAR_MAX_SUB_BANDS_NUM for the number of bands for PPAG.
Of course, SAR related structures will grow in future patches, but
decouple SAR and PPAG to make the work easier.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 23 ++++++++++++++++----
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 16 +++++---------
2 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index d4e1ab1f7c84..38f9d9adf90e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -571,9 +571,11 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_ppag *data;
int ret = 0;
+ int data_sz = sizeof(*data) + sizeof(data->vals[0]) *
+ IWL_NUM_CHAIN_LIMITS * UEFI_PPAG_SUB_BANDS_NUM;
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME,
- "PPAG", sizeof(*data), NULL);
+ "PPAG", data_sz, NULL);
if (IS_ERR(data))
return -EINVAL;
@@ -589,9 +591,22 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,
fwrt->ppag_bios_rev);
- BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains));
- memcpy(&fwrt->ppag_chains, &data->ppag_chains,
- sizeof(data->ppag_chains));
+ /*
+ * Make sure fwrt has enough room to hold
+ * data coming from the UEFI table
+ */
+ BUILD_BUG_ON(ARRAY_SIZE(fwrt->ppag_chains) *
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands) <
+ IWL_NUM_CHAIN_LIMITS * UEFI_PPAG_SUB_BANDS_NUM);
+
+ for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) {
+ for (int subband = 0;
+ subband < UEFI_PPAG_SUB_BANDS_NUM;
+ subband++)
+ fwrt->ppag_chains[chain].subbands[subband] =
+ data->vals[chain * UEFI_PPAG_SUB_BANDS_NUM + subband];
+ }
+
fwrt->ppag_bios_source = BIOS_SOURCE_UEFI;
out:
kfree(data);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index c6940a3c03ea..4f0ce068a589 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -77,6 +77,7 @@ struct uefi_cnv_common_step_data {
} __packed;
#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
+#define UEFI_PPAG_SUB_BANDS_NUM 11
#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
/*
@@ -136,24 +137,19 @@ struct uefi_cnv_var_wgds {
struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
} __packed;
-/*
- * struct uefi_ppag_chain - PPAG table for a specific chain
- * @subbands: the PPAG values for band
- */
-struct uefi_ppag_chain {
- s8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
-};
-
/*
* struct uefi_cnv_var_ppag - PPAG table as defined in UEFI
* @revision: the revision of the table
* @ppag_modes: values from &enum iwl_ppag_flags
- * @ppag_chains: the PPAG values per chain and band
+ * @vals: the PPAG values per chain and band as an array.
+ * vals[chain * num_of_subbands + subband] will return the right value.
+ * num_of_subbands is %UEFI_PPAG_SUB_BANDS_NUM.
+ * the max number of chains is currently 2
*/
struct uefi_cnv_var_ppag {
u8 revision;
u32 ppag_modes;
- struct uefi_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
+ s8 vals[];
} __packed;
/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 10/15] wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (8 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 09/15] wifi: iwlwifi: uefi: open code the PPAG table store operation Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: add support for sta command version 3 Miri Korenblit
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
iwl_fill_ppag_table fills a command that is sent to the firmware. This
command has several versions and handling those different versions is
the responsibility of the op_mode.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../wireless/intel/iwlwifi/fw/regulatory.c | 126 -----------------
.../wireless/intel/iwlwifi/fw/regulatory.h | 4 -
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 129 +++++++++++++++++-
3 files changed, 128 insertions(+), 131 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 5793c267daf7..9e834cc1b054 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -304,132 +304,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
}
IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);
-static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
- int subband)
-{
- s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
-
- if ((subband == 0 &&
- (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
- (subband != 0 &&
- (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
- IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
- return false;
- }
- return true;
-}
-
-/* Utility function for iwlmvm and iwlxvt */
-int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
- union iwl_ppag_table_cmd *cmd, int *cmd_size)
-{
- u8 cmd_ver;
- int i, j, num_sub_bands;
- s8 *gain;
- bool send_ppag_always;
-
- /* many firmware images for JF lie about this */
- if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==
- CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
- return -EOPNOTSUPP;
-
- if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
- IWL_DEBUG_RADIO(fwrt,
- "PPAG capability not supported by FW, command not sent.\n");
- return -EINVAL;
- }
-
- cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
- WIDE_ID(PHY_OPS_GROUP,
- PER_PLATFORM_ANT_GAIN_CMD), 1);
- /*
- * Starting from ver 4, driver needs to send the PPAG CMD regardless
- * if PPAG is enabled/disabled or valid/invalid.
- */
- send_ppag_always = cmd_ver > 3;
-
- /* Don't send PPAG if it is disabled */
- if (!send_ppag_always && !fwrt->ppag_flags) {
- IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
- return -EINVAL;
- }
-
- IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
- if (cmd_ver == 1) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V1;
- gain = cmd->v1.gain[0];
- *cmd_size = sizeof(cmd->v1);
- cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK);
- if (fwrt->ppag_bios_rev >= 1) {
- /* in this case FW supports revision 0 */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table rev is %d, send truncated table\n",
- fwrt->ppag_bios_rev);
- }
- } else if (cmd_ver == 5) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V2;
- gain = cmd->v5.gain[0];
- *cmd_size = sizeof(cmd->v5);
- cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK);
- if (fwrt->ppag_bios_rev == 0) {
- /* in this case FW supports revisions 1,2 or 3 */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table rev is 0, send padded table\n");
- }
- } else if (cmd_ver == 7) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V2;
- gain = cmd->v7.gain[0];
- *cmd_size = sizeof(cmd->v7);
- cmd->v7.ppag_config_info.hdr.table_source =
- fwrt->ppag_bios_source;
- cmd->v7.ppag_config_info.hdr.table_revision =
- fwrt->ppag_bios_rev;
- cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
- } else {
- IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
- return -EINVAL;
- }
-
- /* ppag mode */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG MODE bits were read from bios: %d\n",
- fwrt->ppag_flags);
-
- if (cmd_ver == 1 &&
- !fw_has_capa(&fwrt->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) {
- cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
- IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
- } else {
- IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
- }
-
- /* The 'flags' field is the same in v1 and v5 so we can just
- * use v1 to access it.
- */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG MODE bits going to be sent: %d\n",
- (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
- le32_to_cpu(cmd->v7.ppag_config_info.value));
-
- for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
- for (j = 0; j < num_sub_bands; j++) {
- if (!send_ppag_always &&
- !iwl_ppag_value_valid(fwrt, i, j))
- return -EINVAL;
-
- gain[i * num_sub_bands + j] =
- fwrt->ppag_chains[i].subbands[j];
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table: chain[%d] band[%d]: gain = %d\n",
- i, j, gain[i * num_sub_bands + j]);
- }
- }
-
- return 0;
-}
-IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
-
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
{
if (!dmi_check_system(dmi_ppag_approved_list)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 1489031687b7..8e04b0e2d507 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -190,10 +190,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
__le16 *per_chain, u32 n_tables, u32 n_subbands,
int prof_a, int prof_b);
-int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
- union iwl_ppag_table_cmd *cmd,
- int *cmd_size);
-
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt);
bool iwl_is_tas_approved(void);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index f5e5c10cc581..d46715abd7a5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1034,12 +1034,139 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd);
}
+static bool iwl_mvm_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
+ int subband)
+{
+ s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
+
+ if ((subband == 0 &&
+ (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
+ (subband != 0 &&
+ (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
+ IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
+ return false;
+ }
+ return true;
+}
+
+static int iwl_mvm_fill_ppag_table(struct iwl_fw_runtime *fwrt,
+ union iwl_ppag_table_cmd *cmd,
+ int *cmd_size)
+{
+ u8 cmd_ver;
+ int i, j, num_sub_bands;
+ s8 *gain;
+ bool send_ppag_always;
+
+ /* many firmware images for JF lie about this */
+ if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==
+ CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
+ return -EOPNOTSUPP;
+
+ if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG capability not supported by FW, command not sent.\n");
+ return -EINVAL;
+ }
+
+ cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_PLATFORM_ANT_GAIN_CMD), 1);
+ /*
+ * Starting from ver 4, driver needs to send the PPAG CMD regardless
+ * if PPAG is enabled/disabled or valid/invalid.
+ */
+ send_ppag_always = cmd_ver > 3;
+
+ /* Don't send PPAG if it is disabled */
+ if (!send_ppag_always && !fwrt->ppag_flags) {
+ IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
+ if (cmd_ver == 1) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V1;
+ gain = cmd->v1.gain[0];
+ *cmd_size = sizeof(cmd->v1);
+ cmd->v1.flags =
+ cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK);
+ if (fwrt->ppag_bios_rev >= 1) {
+ /* in this case FW supports revision 0 */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table rev is %d, send truncated table\n",
+ fwrt->ppag_bios_rev);
+ }
+ } else if (cmd_ver == 5) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2;
+ gain = cmd->v5.gain[0];
+ *cmd_size = sizeof(cmd->v5);
+ cmd->v5.flags =
+ cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK);
+ if (fwrt->ppag_bios_rev == 0) {
+ /* in this case FW supports revisions 1,2 or 3 */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table rev is 0, send padded table\n");
+ }
+ } else if (cmd_ver == 7) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2;
+ gain = cmd->v7.gain[0];
+ *cmd_size = sizeof(cmd->v7);
+ cmd->v7.ppag_config_info.hdr.table_source =
+ fwrt->ppag_bios_source;
+ cmd->v7.ppag_config_info.hdr.table_revision =
+ fwrt->ppag_bios_rev;
+ cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
+ } else {
+ IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
+ return -EINVAL;
+ }
+
+ /* ppag mode */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG MODE bits were read from bios: %d\n",
+ fwrt->ppag_flags);
+
+ if (cmd_ver == 1 &&
+ !fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) {
+ cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
+ IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
+ } else {
+ IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
+ }
+
+ /* The 'flags' field is the same in v1 and v5 so we can just
+ * use v1 to access it.
+ */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG MODE bits going to be sent: %d\n",
+ (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
+ le32_to_cpu(cmd->v7.ppag_config_info.value));
+
+ for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
+ for (j = 0; j < num_sub_bands; j++) {
+ if (!send_ppag_always &&
+ !iwl_mvm_ppag_value_valid(fwrt, i, j))
+ return -EINVAL;
+
+ gain[i * num_sub_bands + j] =
+ fwrt->ppag_chains[i].subbands[j];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ i, j, gain[i * num_sub_bands + j]);
+ }
+ }
+
+ return 0;
+}
+
int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
{
union iwl_ppag_table_cmd cmd;
int ret, cmd_size;
- ret = iwl_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size);
+ ret = iwl_mvm_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size);
/* Not supporting PPAG table is a valid scenario */
if (ret < 0)
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: add support for sta command version 3
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (9 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 10/15] wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data Miri Korenblit
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In this version, the link_id becomes a link_mask to support multiple
links that are used to communicate with the station in question.
This is needed for NAN, in which we can communicate on multiple channels
with the same station.
Also add a new STA type - NAN peer.
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../wireless/intel/iwlwifi/fw/api/mac-cfg.h | 94 ++++++++++++++++++-
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 42 +++++++--
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 6 +-
3 files changed, 129 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index c7a833f8041a..444d60a05a98 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -42,7 +42,8 @@ enum iwl_mac_conf_subcmd_ids {
*/
LINK_CONFIG_CMD = 0x9,
/**
- * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd
+ * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd_v1,
+ * &struct iwl_sta_cfg_cmd_v2, or struct iwl_sta_cfg_cmd
*/
STA_CONFIG_CMD = 0xA,
/**
@@ -664,13 +665,21 @@ struct iwl_link_config_cmd {
* power save state and the DTIM timing
* @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
* for the aux sta, so this type is only for driver - internal use.
+ * @STATION_TYPE_NAN_PEER_NMI: NAN management peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
+ * @STATION_TYPE_NAN_PEER_NDI: NAN data peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
*/
enum iwl_fw_sta_type {
STATION_TYPE_PEER,
STATION_TYPE_BCAST_MGMT,
STATION_TYPE_MCAST,
STATION_TYPE_AUX,
-}; /* STATION_TYPE_E_VER_1 */
+ STATION_TYPE_NAN_PEER_NMI,
+ STATION_TYPE_NAN_PEER_NDI,
+}; /* STATION_TYPE_E_VER_1, _VER_2 */
/**
* struct iwl_sta_cfg_cmd_v1 - cmd structure to add a peer sta to the uCode's
@@ -729,7 +738,7 @@ struct iwl_sta_cfg_cmd_v1 {
} __packed; /* STA_CMD_API_S_VER_1 */
/**
- * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * struct iwl_sta_cfg_cmd_v2 - cmd structure to add a peer sta to the uCode's
* station table
* ( STA_CONFIG_CMD = 0xA )
*
@@ -769,7 +778,7 @@ struct iwl_sta_cfg_cmd_v1 {
* @mic_compute_pad_delay: MIC compute time padding
* @reserved: Reserved for alignment
*/
-struct iwl_sta_cfg_cmd {
+struct iwl_sta_cfg_cmd_v2 {
__le32 sta_id;
__le32 link_id;
u8 peer_mld_address[ETH_ALEN];
@@ -799,6 +808,83 @@ struct iwl_sta_cfg_cmd {
u8 reserved[2];
} __packed; /* STA_CMD_API_S_VER_2 */
+/**
+ * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * station table
+ * ( STA_CONFIG_CMD = 0xA )
+ *
+ * @sta_id: index of station in uCode's station table
+ * @link_mask: bitmap of link FW IDs used with this STA
+ * @peer_mld_address: the peers mld address
+ * @reserved_for_peer_mld_address: reserved
+ * @peer_link_address: the address of the link that is used to communicate
+ * with this sta
+ * @reserved_for_peer_link_address: reserved
+ * @station_type: type of this station. See &enum iwl_fw_sta_type
+ * @assoc_id: for GO only
+ * @beamform_flags: beam forming controls
+ * @mfp: indicates whether the STA uses management frame protection or not.
+ * @mimo: indicates whether the sta uses mimo or not
+ * @mimo_protection: indicates whether the sta uses mimo protection or not
+ * @ack_enabled: indicates that the AP supports receiving ACK-
+ * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
+ * @trig_rnd_alloc: indicates that trigger based random allocation
+ * is enabled according to UORA element existence
+ * @tx_ampdu_spacing: minimum A-MPDU spacing:
+ * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density
+ * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K,
+ * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K.
+ * @sp_length: the size of the SP in actual number of frames
+ * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
+ * enabled ACs.
+ * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY
+ * capa
+ * @htc_flags: which features are supported in HTC
+ * @use_ldpc_x2_cw: Indicates whether to use LDPC with double CW
+ * @use_icf: Indicates whether to use ICF instead of RTS
+ * @dps_pad_time: DPS (Dynamic Power Save) padding delay resolution to ensure
+ * proper timing alignment
+ * @dps_trans_delay: DPS minimal time that takes the peer to return to low power
+ * @dps_enabled: flag indicating whether or not DPS is enabled
+ * @mic_prep_pad_delay: MIC prep time padding
+ * @mic_compute_pad_delay: MIC compute time padding
+ * @nmi_sta_id: for an NDI peer STA, the NMI peer STA ID it relates to
+ * @ndi_local_addr: for an NDI peer STA, the local NDI interface MAC address
+ * @reserved: Reserved for alignment
+ */
+struct iwl_sta_cfg_cmd {
+ __le32 sta_id;
+ __le32 link_mask;
+ u8 peer_mld_address[ETH_ALEN];
+ __le16 reserved_for_peer_mld_address;
+ u8 peer_link_address[ETH_ALEN];
+ __le16 reserved_for_peer_link_address;
+ __le32 station_type;
+ __le32 assoc_id;
+ __le32 beamform_flags;
+ __le32 mfp;
+ __le32 mimo;
+ __le32 mimo_protection;
+ __le32 ack_enabled;
+ __le32 trig_rnd_alloc;
+ __le32 tx_ampdu_spacing;
+ __le32 tx_ampdu_max_size;
+ __le32 sp_length;
+ __le32 uapsd_acs;
+ struct iwl_he_pkt_ext_v2 pkt_ext;
+ __le32 htc_flags;
+ u8 use_ldpc_x2_cw;
+ u8 use_icf;
+ u8 dps_pad_time;
+ u8 dps_trans_delay;
+ u8 dps_enabled;
+ u8 mic_prep_pad_delay;
+ u8 mic_compute_pad_delay;
+ u8 nmi_sta_id;
+ u8 ndi_local_addr[ETH_ALEN];
+ u8 reserved[2];
+} __packed; /* STA_CMD_API_S_VER_3 */
+
/**
* struct iwl_aux_sta_cmd - command for AUX STA configuration
* ( AUX_STA_CMD = 0xB )
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 6b7a89e050e6..f40c49377466 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -398,12 +398,42 @@ static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta)
return htc_flags;
}
+/* Note: modifies the command depending on FW command version */
static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
- const struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd *cmd)
{
- int ret = iwl_mld_send_cmd_pdu(mld,
- WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD),
- cmd);
+ int cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
+ int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
+ int len = sizeof(*cmd);
+ int ret;
+
+ if (cmd_ver < 2) {
+ IWL_ERR(mld, "Unsupported STA_CONFIG_CMD version %d\n",
+ cmd_ver);
+ return -EINVAL;
+ } else if (cmd_ver == 2) {
+ struct iwl_sta_cfg_cmd_v2 *cmd_v2 = (void *)cmd;
+
+ if (WARN_ON(cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) ||
+ cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) ||
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1))
+ return -EINVAL;
+ /*
+ * These fields are located in a different place in the struct of v2.
+ * The assumption is that UHR won't be used with FW that has v2.
+ */
+ if (WARN_ON(cmd->mic_prep_pad_delay || cmd->mic_compute_pad_delay))
+ return -EINVAL;
+
+ len = sizeof(struct iwl_sta_cfg_cmd_v2);
+ cmd_v2->link_id = cpu_to_le32(__ffs(le32_to_cpu(cmd->link_mask)));
+ } else if (WARN_ON(cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) &&
+ cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) &&
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1)) {
+ return -EINVAL;
+ }
+
+ ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, len);
if (ret)
IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret);
return ret;
@@ -431,8 +461,8 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
return -EINVAL;
cmd.sta_id = cpu_to_le32(fw_id);
+ cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id));
cmd.station_type = cpu_to_le32(mld_sta->sta_type);
- cmd.link_id = cpu_to_le32(mld_link->fw_id);
memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN);
@@ -982,7 +1012,7 @@ iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld,
return iwl_mld_send_aux_sta_cmd(mld, internal_sta);
cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id);
- cmd.link_id = cpu_to_le32(fw_link_id);
+ cmd.link_mask = cpu_to_le32(BIT(fw_link_id));
cmd.station_type = cpu_to_le32(internal_sta->sta_type);
/* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP.
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 44e16ee9514e..da7ed4639a93 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -20,7 +20,7 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
- struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd_v2 *cmd)
{
u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ?
@@ -41,7 +41,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta,
const u8 *addr, int link_id)
{
- struct iwl_sta_cfg_cmd cmd;
+ struct iwl_sta_cfg_cmd_v2 cmd;
lockdep_assert_held(&mvm->mutex);
@@ -416,7 +416,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_vif_link_info *link_info =
mvm_vif->link[link_conf->link_id];
- struct iwl_sta_cfg_cmd cmd = {
+ struct iwl_sta_cfg_cmd_v2 cmd = {
.sta_id = cpu_to_le32(mvm_link_sta->sta_id),
.station_type = cpu_to_le32(mvm_sta->sta_type),
};
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (10 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: add support for sta command version 3 Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG Miri Korenblit
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
In each MAC context, the firmware expects the wifi generation
data, i.e. whether or not HE/EHT (and in the future UHR) is
enabled on that MAC.
However, this is currently handled wrong in two ways:
- EHT is only enabled when the interface is also an MLD, but
we currently allow (despite the spec) connecting with EHT
but without MLO.
- when HE or EHT are used by TDLS peers, the firmware needs
to have them enabled regardless of the AP
Fix this by iterating setting up the data depending on the
interface type:
- for AP, just set it according to the BSS configuration
- for monitor, set it according to HW capabilities
- otherwise, particularly for client, iterate all stations
and then their links on the interface in question and set
according to their capabilities, this handles the AP and
TDLS peers. Re-calculate this whenever a TDLS station is
marked associated or removed so that it's kept updated,
for the AP it's already updated on assoc/disassoc.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/mld/iface.c | 101 ++++++++++++------
.../net/wireless/intel/iwlwifi/mld/mac80211.c | 19 ++++
2 files changed, 88 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index 29df747c8938..9215fc7e2eca 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
IEEE80211_HE_MAC_CAP2_ACK_EN);
}
-static void iwl_mld_set_he_support(struct iwl_mld *mld,
- struct ieee80211_vif *vif,
- struct iwl_mac_config_cmd *cmd)
+struct iwl_mld_mac_wifi_gen_sta_iter_data {
+ struct ieee80211_vif *vif;
+ struct iwl_mac_wifi_gen_support *support;
+};
+
+static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
+ struct ieee80211_sta *sta)
{
- if (vif->type == NL80211_IFTYPE_AP)
- cmd->wifi_gen.he_ap_support = 1;
- else
- cmd->wifi_gen.he_support = 1;
+ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ if (mld_sta->vif != data->vif)
+ return;
+
+ for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
+ if (link_sta->he_cap.has_he)
+ data->support->he_support = 1;
+ if (link_sta->eht_cap.has_eht)
+ data->support->eht_support = 1;
+ }
+}
+
+static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_wifi_gen_support *support)
+{
+ struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
+ .vif = vif,
+ .support = support,
+ };
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MONITOR:
+ /* for sniffer, set to HW capabilities */
+ support->he_support = 1;
+ support->eht_support = mld->trans->cfg->eht_supported;
+ break;
+ case NL80211_IFTYPE_AP:
+ /* for AP set according to the link configs */
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ support->he_ap_support |= link_conf->he_support;
+ support->eht_support |= link_conf->eht_support;
+ }
+ break;
+ default:
+ /*
+ * If we have MLO enabled, then the firmware needs to enable
+ * address translation for the station(s) we add. That depends
+ * on having EHT enabled in firmware, which in turn depends on
+ * mac80211 in the iteration below.
+ * However, mac80211 doesn't enable capabilities on the AP STA
+ * until it has parsed the association response successfully,
+ * so set EHT (and HE as a pre-requisite for EHT) when the vif
+ * is an MLD.
+ */
+ if (ieee80211_vif_is_mld(vif)) {
+ support->he_support = 1;
+ support->eht_support = 1;
+ }
+
+ ieee80211_iterate_stations_mtx(mld->hw,
+ iwl_mld_mac_wifi_gen_sta_iter,
+ &sta_iter_data);
+ break;
+ }
}
/* fill the common part for all interface types */
@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
u32 action)
{
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
- struct ieee80211_bss_conf *link_conf;
- unsigned int link_id;
lockdep_assert_wiphy(mld->wiphy);
@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
cmd->nic_not_ack_enabled =
cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
- /* If we have MLO enabled, then the firmware needs to enable
- * address translation for the station(s) we add. That depends
- * on having EHT enabled in firmware, which in turn depends on
- * mac80211 in the code below.
- * However, mac80211 doesn't enable HE/EHT until it has parsed
- * the association response successfully, so just skip all that
- * and enable both when we have MLO.
- */
- if (ieee80211_vif_is_mld(vif)) {
- iwl_mld_set_he_support(mld, vif, cmd);
- cmd->wifi_gen.eht_support = 1;
- return;
- }
-
- for_each_vif_active_link(vif, link_conf, link_id) {
- if (!link_conf->he_support)
- continue;
-
- iwl_mld_set_he_support(mld, vif, cmd);
-
- /* EHT, if supported, was already set above */
- break;
- }
+ iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
}
static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 0c53d6bd9651..71a9a72c9ac0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1761,6 +1761,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mld_link_set_2mhz_block(mld, vif, sta);
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on association to the AP via the
+ * vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
+
/* Now the link_sta's capabilities are set, update the FW */
iwl_mld_config_tlc(mld, vif, sta);
@@ -1873,6 +1883,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
/* just removed last TDLS STA, so enable PM */
iwl_mld_update_mac_power(mld, vif, false);
}
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on disassociation to the AP via
+ * the vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
} else {
return -EINVAL;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (11 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5 Miri Korenblit
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Per Platform Antenna Gain is getting support for UNII-9.
Add a new version of PER_PLATFORM_ANT_GAIN_CMD.
This requires to increase the number of subbands in the firmware runtime
object.
Pass the number of subbands to iwl_bios_print_ppag to avoid printing
invalid values.
Introduce BIOS_PPAG_MAX_SUB_BANDS_NUM to avoid impacting
BIOS_SAR_MAX_SUB_BANDS_NUM which was used until now for PPAG as well.
SAR will get support for the new subband in future patches.
While at it, print the PPAG table as it was read from BIOS.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 1 +
.../net/wireless/intel/iwlwifi/fw/api/power.h | 8 +++
.../wireless/intel/iwlwifi/fw/regulatory.c | 21 ++++++
.../wireless/intel/iwlwifi/fw/regulatory.h | 6 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 1 +
.../wireless/intel/iwlwifi/mld/regulatory.c | 66 +++++++++++++++----
6 files changed, 91 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index b64abb8439b7..d00191e84f20 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -981,6 +981,7 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
}
}
+ iwl_bios_print_ppag(fwrt, num_sub_bands);
fwrt->ppag_bios_source = BIOS_SOURCE_ACPI;
ret = 0;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index 0cd8a12e0f7c..118c08f95649 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -269,6 +269,7 @@ enum iwl_dev_tx_power_cmd_mode {
#define IWL_NUM_CHAIN_LIMITS 2
#define IWL_NUM_SUB_BANDS_V1 5
#define IWL_NUM_SUB_BANDS_V2 11
+#define IWL_NUM_SUB_BANDS_V3 12
/**
* struct iwl_dev_tx_power_common - Common part of the TX power reduction cmd
@@ -573,6 +574,7 @@ enum iwl_ppag_flags {
* @v1: command version 1 structure.
* @v5: command version 5 structure.
* @v7: command version 7 structure.
+ * @v8: command version 8 structure.
* @v1.flags: values from &enum iwl_ppag_flags
* @v1.gain: table of antenna gain values per chain and sub-band
* @v1.reserved: reserved
@@ -581,6 +583,8 @@ enum iwl_ppag_flags {
* @v7.ppag_config_info: see @struct bios_value_u32
* @v7.gain: table of antenna gain values per chain and sub-band
* @v7.reserved: reserved
+ * @v8.ppag_config_info: see @struct bios_value_u32
+ * @v8.gain: table of antenna gain values per chain and sub-band
*/
union iwl_ppag_table_cmd {
struct {
@@ -598,6 +602,10 @@ union iwl_ppag_table_cmd {
s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2];
s8 reserved[2];
} __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */
+ struct {
+ struct bios_value_u32 ppag_config_info;
+ s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3];
+ } __packed v8; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_8 */
} __packed;
#define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 9e834cc1b054..55128caac7ed 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -318,6 +318,27 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
+/* Print the PPAG table as read from BIOS */
+void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands)
+{
+ int i, j;
+
+ IWL_DEBUG_RADIO(fwrt, "PPAG table as read from BIOS:\n");
+ IWL_DEBUG_RADIO(fwrt, "PPAG revision = %d\n", fwrt->ppag_bios_rev);
+ IWL_DEBUG_RADIO(fwrt, "PPAG flags = 0x%x\n", fwrt->ppag_flags);
+
+ if (WARN_ON_ONCE(n_subbands >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands)))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(fwrt->ppag_chains); i++)
+ for (j = 0; j < n_subbands; j++)
+ IWL_DEBUG_RADIO(fwrt,
+ "ppag_chains[%d].subbands[%d] = %d\n",
+ i, j,
+ fwrt->ppag_chains[i].subbands[j]);
+}
+
bool iwl_is_tas_approved(void)
{
return dmi_check_system(dmi_tas_approved_list);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 8e04b0e2d507..446c8a2c4f9d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -22,6 +22,7 @@
#define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4
#define BIOS_SAR_NUM_CHAINS 2
#define BIOS_SAR_MAX_SUB_BANDS_NUM 11
+#define BIOS_PPAG_MAX_SUB_BANDS_NUM 12
#define BIOS_GEO_NUM_CHAINS 2
#define BIOS_GEO_MAX_NUM_BANDS 3
@@ -100,7 +101,7 @@ struct iwl_geo_profile {
/* Same thing as with SAR, all revisions fit in revision 2 */
struct iwl_ppag_chain {
- s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM];
+ s8 subbands[BIOS_PPAG_MAX_SUB_BANDS_NUM];
};
struct iwl_tas_data {
@@ -180,6 +181,9 @@ enum iwl_dsm_masks_reg {
struct iwl_fw_runtime;
+/* Print the PPAG table as read from BIOS */
+void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands);
+
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt);
int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 38f9d9adf90e..fba41976be6b 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -607,6 +607,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
data->vals[chain * UEFI_PPAG_SUB_BANDS_NUM + subband];
}
+ iwl_bios_print_ppag(fwrt, UEFI_PPAG_SUB_BANDS_NUM);
fwrt->ppag_bios_source = BIOS_SOURCE_UEFI;
out:
kfree(data);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index d1a55b565898..27059ec93847 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
@@ -166,30 +166,74 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld)
{
struct iwl_fw_runtime *fwrt = &mld->fwrt;
union iwl_ppag_table_cmd cmd = {
- .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source,
- .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev,
- .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags),
+ /* v7 and v8 have the same layout for the ppag_config_info */
+ .v8.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source,
+ .v8.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev,
+ .v8.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags),
};
+ int cmd_ver =
+ iwl_fw_lookup_cmd_ver(mld->fw,
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_PLATFORM_ANT_GAIN_CMD), 1);
+ int cmd_len = sizeof(cmd.v8);
int ret;
+ BUILD_BUG_ON(offsetof(typeof(cmd), v8.ppag_config_info.hdr) !=
+ offsetof(typeof(cmd), v7.ppag_config_info.hdr));
+ BUILD_BUG_ON(offsetof(typeof(cmd), v8.gain) !=
+ offsetof(typeof(cmd), v7.gain));
+
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain) > ARRAY_SIZE(fwrt->ppag_chains));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain[0]) >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain) > ARRAY_SIZE(fwrt->ppag_chains));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain[0]) >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands));
+
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits going to be sent: %d\n",
fwrt->ppag_flags);
- for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) {
- for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) {
- cmd.v7.gain[chain][subband] =
- fwrt->ppag_chains[chain].subbands[subband];
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table: chain[%d] band[%d]: gain = %d\n",
- chain, subband, cmd.v7.gain[chain][subband]);
+ /* Since ver 7 will be deprecated at some point, don't bother making
+ * this code generic for both ver 7 and ver 8: duplicate the code.
+ */
+ if (cmd_ver == 7) {
+ for (int chain = 0; chain < ARRAY_SIZE(cmd.v7.gain); chain++) {
+ for (int subband = 0;
+ subband < ARRAY_SIZE(cmd.v7.gain[0]);
+ subband++) {
+ cmd.v7.gain[chain][subband] =
+ fwrt->ppag_chains[chain].subbands[subband];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ chain, subband,
+ cmd.v7.gain[chain][subband]);
+ }
}
+ cmd_len = sizeof(cmd.v7);
+ } else if (cmd_ver == 8) {
+ for (int chain = 0; chain < ARRAY_SIZE(cmd.v8.gain); chain++) {
+ for (int subband = 0;
+ subband < ARRAY_SIZE(cmd.v8.gain[0]);
+ subband++) {
+ cmd.v8.gain[chain][subband] =
+ fwrt->ppag_chains[chain].subbands[subband];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ chain, subband,
+ cmd.v8.gain[chain][subband]);
+ }
+ }
+ } else {
+ WARN(1, "Bad version for PER_PLATFORM_ANT_GAIN_CMD %d\n",
+ cmd_ver);
+ return -EINVAL;
}
IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n");
ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
- &cmd, sizeof(cmd.v7));
+ &cmd, cmd_len);
if (ret < 0)
IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n",
ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (12 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5 Miri Korenblit
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
We need to make sure we don't have a buffer overflow while reading the
PPAG tables from ACPI into the firmware runtime object.
Add an ACPI specific define for the number of chains in order to
decouple the ACPI layout from the other objects.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 11 ++++++++++-
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 +++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index d00191e84f20..de30799519cd 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -951,6 +951,15 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
goto out_free;
read_table:
+ if (WARN_ON_ONCE(num_sub_bands >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands))) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ BUILD_BUG_ON(ACPI_PPAG_NUM_CHAINS >
+ ARRAY_SIZE(fwrt->ppag_chains));
+
fwrt->ppag_bios_rev = tbl_rev;
flags = &wifi_pkg->package.elements[1];
@@ -967,7 +976,7 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
* first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
* following sub-bands to High-Band (5GHz).
*/
- for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
+ for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) {
for (j = 0; j < num_sub_bands; j++) {
union acpi_object *ent;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index 06cece4ea6d9..c34dc17ff608 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -96,9 +96,10 @@
*/
#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX)
-#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \
+#define ACPI_PPAG_NUM_CHAINS 2
+#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((ACPI_PPAG_NUM_CHAINS * \
IWL_NUM_SUB_BANDS_V1) + 2)
-#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \
+#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((ACPI_PPAG_NUM_CHAINS * \
IWL_NUM_SUB_BANDS_V2) + 2)
#define IWL_SAR_ENABLE_MSK BIT(0)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
` (13 preceding siblings ...)
2026-03-18 20:54 ` [PATCH iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables Miri Korenblit
@ 2026-03-18 20:54 ` Miri Korenblit
14 siblings, 0 replies; 16+ messages in thread
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This adds support for UNII9 which requires to add a subband.
Just increase the number of subbands that we need to read.
Replace the usage of the IWL_NUM_SUB_BANDS_VX macros in acpi.h since
those macros are defined in the firmware API and ACPI declarations have
nothing to do the firmware API.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 16 ++++++++++++++++
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 16 +++++++++-------
2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index de30799519cd..4d0a93832336 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -916,6 +916,22 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
if (IS_ERR(data))
return PTR_ERR(data);
+ /* try to read ppag table rev 5 */
+ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
+ ACPI_PPAG_WIFI_DATA_SIZE_V3, &tbl_rev);
+ if (!IS_ERR(wifi_pkg)) {
+ if (tbl_rev == 5) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V3;
+ IWL_DEBUG_RADIO(fwrt,
+ "Reading PPAG table (tbl_rev=%d)\n",
+ tbl_rev);
+ goto read_table;
+ } else {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
/* try to read ppag table rev 1 to 4 (all have the same data size) */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index c34dc17ff608..138fdb9a5273 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -8,11 +8,6 @@
#include <linux/acpi.h>
#include "fw/regulatory.h"
-#include "fw/api/commands.h"
-#include "fw/api/power.h"
-#include "fw/api/phy.h"
-#include "fw/api/nvm-reg.h"
-#include "fw/api/config.h"
#include "fw/img.h"
#include "iwl-trans.h"
@@ -97,10 +92,17 @@
#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX)
#define ACPI_PPAG_NUM_CHAINS 2
+#define ACPI_PPAG_NUM_BANDS_V1 5
+#define ACPI_PPAG_NUM_BANDS_V2 11
+#define ACPI_PPAG_NUM_BANDS_V3 12
#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((ACPI_PPAG_NUM_CHAINS * \
- IWL_NUM_SUB_BANDS_V1) + 2)
+ ACPI_PPAG_NUM_BANDS_V1) + 2)
#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((ACPI_PPAG_NUM_CHAINS * \
- IWL_NUM_SUB_BANDS_V2) + 2)
+ ACPI_PPAG_NUM_BANDS_V2) + 2)
+
+/* used for ACPI PPAG table rev 5 */
+#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
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-03-18 20:55 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-18 20:54 [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2025-03-18 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 01/15] wifi: iwlwifi: mld: add support for iwl_mcc_allowed_ap_type_cmd v2 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 02/15] wifi: iwlwifi: ensure we don't read SAR values past the limit Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 03/15] wifi: iwlwifi: uefi: decouple UEFI and firmware APIs Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 04/15] wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mvm: cleanup some more MLO code Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: remove unused scan expire time constants Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: Refactor scan command handling Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: Introduce scan command version 18 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 09/15] wifi: iwlwifi: uefi: open code the PPAG table store operation Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 10/15] wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: add support for sta command version 3 Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables Miri Korenblit
2026-03-18 20:54 ` [PATCH iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5 Miri Korenblit
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox