From: Emmanuel Grumbach Date: Thu, 19 Mar 2026 18:48:52 +0000 (+0200) Subject: wifi: iwlwifi: support PER_CHAIN_LIMIT_OFFSET_CMD v6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f863093a914c4b371f5c82a173d5b804318c91ef;p=thirdparty%2Flinux.git wifi: iwlwifi: support PER_CHAIN_LIMIT_OFFSET_CMD v6 This includes support for UNII-9. Store the source of the WGDS table in the firmware runtime object to be able to pass the information to the firmware. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260319204647.eaff31760dd7.Ic7f56fbbe310833723094f965e7ba3f8624d0ef9@changeid --- diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 16d91c6915f08..bf0f851a90755 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -973,6 +973,7 @@ read_table: } fwrt->geo_num_profiles = num_profiles; + fwrt->geo_bios_source = BIOS_SOURCE_ACPI; fwrt->geo_enabled = true; ret = 0; out_free: diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index ec923162a44bb..a3f916630df2b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -457,6 +457,7 @@ struct iwl_dev_tx_power_cmd { #define IWL_NUM_GEO_PROFILES_V3 8 #define IWL_NUM_BANDS_PER_CHAIN_V1 2 #define IWL_NUM_BANDS_PER_CHAIN_V2 3 +#define IWL_NUM_BANDS_PER_CHAIN_V6 4 /** * enum iwl_geo_per_chain_offset_operation - type of operation @@ -538,12 +539,25 @@ struct iwl_geo_tx_power_profiles_cmd_v5 { __le32 table_revision; } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_5 */ +/** + * struct iwl_geo_tx_power_profiles_cmd_v6 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation + * @table: offset profile per band. + * @bios_hdr: describes the revision and the source of the BIOS + */ +struct iwl_geo_tx_power_profiles_cmd_v6 { + __le32 ops; + struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES_V3][IWL_NUM_BANDS_PER_CHAIN_V6]; + struct iwl_bios_config_hdr bios_hdr; +} __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_6 */ + union iwl_geo_tx_power_profiles_cmd { struct iwl_geo_tx_power_profiles_cmd_v1 v1; struct iwl_geo_tx_power_profiles_cmd_v2 v2; struct iwl_geo_tx_power_profiles_cmd_v3 v3; struct iwl_geo_tx_power_profiles_cmd_v4 v4; struct iwl_geo_tx_power_profiles_cmd_v5 v5; + struct iwl_geo_tx_power_profiles_cmd_v6 v6; }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 411e75b45530a..d80ae610e56c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -113,6 +113,7 @@ struct iwl_txf_iter_data { * Only read the UEFI variables if locked. * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables * @geo_profiles: geographic profiles as read from WGDS BIOS table + * @geo_bios_source: see &enum bios_source * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source @@ -204,6 +205,7 @@ struct iwl_fw_runtime { u8 sar_chain_b_profile; u8 reduced_power_flags; struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; + enum bios_source geo_bios_source; u32 geo_rev; u32 geo_num_profiles; bool geo_enabled; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index f73340c7d5379..2ef0a7a920adb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -644,6 +644,7 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) } fwrt->geo_rev = data->revision; + fwrt->geo_bios_source = BIOS_SOURCE_UEFI; profile_size = 3 * n_subbands; for (int prof = 0; prof < data->num_profiles; prof++) { const u8 *val = &data->vals[profile_size * prof]; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index f009c884e6cdb..2486d78d6fc38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -73,16 +73,36 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) { u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); /* Only set to South Korea if the table revision is 1 */ - __le32 sk = cpu_to_le32(mld->fwrt.geo_rev == 1 ? 1 : 0); + u8 sk = mld->fwrt.geo_rev == 1 ? 1 : 0; union iwl_geo_tx_power_profiles_cmd cmd = { .v5.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), - .v5.table_revision = sk, }; + u32 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); + int n_subbands; + int cmd_size; int ret; - ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v5.table[0][0], - ARRAY_SIZE(cmd.v5.table[0]), - BIOS_GEO_MAX_PROFILE_NUM); + switch (cmd_ver) { + case 5: + n_subbands = ARRAY_SIZE(cmd.v5.table[0]); + cmd.v5.table_revision = cpu_to_le32(sk); + cmd_size = sizeof(cmd.v5); + break; + case 6: + n_subbands = ARRAY_SIZE(cmd.v6.table[0]); + cmd.v6.bios_hdr.table_revision = mld->fwrt.geo_rev; + cmd.v6.bios_hdr.table_source = mld->fwrt.geo_bios_source; + cmd_size = sizeof(cmd.v6); + break; + default: + WARN(false, "unsupported version: %d", cmd_ver); + return -EINVAL; + } + + BUILD_BUG_ON(offsetof(typeof(cmd), v6.table) != + offsetof(typeof(cmd), v5.table)); + ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v6.table[0][0], + n_subbands, BIOS_GEO_MAX_PROFILE_NUM); /* It is a valid scenario to not support SAR, or miss wgds table, * but in that case there is no need to send the command. @@ -90,7 +110,7 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) if (ret) return 0; - return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, sizeof(cmd.v5)); + return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, cmd_size); } int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b)