summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorPagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>2026-09-26 20:17:23 +0300
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>2026-10-11 13:07:48 +0300
commitca406928eb7e2d2f41b85ea3077bb2ddd0ced887 (patch)
treea5587b380ec9d58f372c1974a9d82541b56e59aa /drivers/net
parentea0bd01bc8bc5fd9b9e262e258606e20b2cb667b (diff)
downloadlinux-next-ca406928eb7e2d2f41b85ea3077bb2ddd0ced887.tar.gz
linux-next-ca406928eb7e2d2f41b85ea3077bb2ddd0ced887.zip
wifi: iwlwifi: send standalone SAR to firmware
Plumb the standalone WRSS/EWSS SAR data and send the standalone profile to firmware. Add REDUCE_TX_POWER_CMD version 12 support with the IWL_TX_POWER_MODE_SET_STANDALONE_CHAINS set_mode, and rename iwl_dev_tx_power_cmd_v11 to iwl_dev_tx_power_cmd_v12 to match the updated command layout. This enables higher transmit power limits for standalone firmware operation while preserving the existing concurrent SAR handling. Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com> Link: https://patch.msgid.link/20260926201527.d5315e93c1ce.Ic02190e91e795dcfe660710721b47de71f2b2c86@changeid Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/regulatory.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/regulatory.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/power.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/regulatory.c80
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/regulatory.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c3
7 files changed, 107 insertions, 26 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index 115e65ba19f8..4d54a95b98ca 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -300,7 +300,8 @@ enum iwl_dev_tx_power_cmd_mode {
IWL_TX_POWER_MODE_SET_ACK = 3,
IWL_TX_POWER_MODE_SET_SAR_TIMER = 4,
IWL_TX_POWER_MODE_SET_SAR_TIMER_DEFAULT_TABLE = 5,
-}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_5 */;
+ IWL_TX_POWER_MODE_SET_STANDALONE_CHAINS = 8, /* cmd ver 12+ */
+}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */;
#define IWL_NUM_CHAIN_TABLES 1
#define IWL_NUM_CHAIN_TABLES_V2 2
@@ -464,31 +465,34 @@ struct iwl_dev_tx_power_cmd_v10 {
__le32 flags;
} __packed; /* TX_REDUCED_POWER_API_S_VER_10 */
-struct iwl_dev_tx_power_cmd_v11 {
+struct iwl_dev_tx_power_cmd_v12 {
__le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3];
u8 per_chain_restriction_changed;
u8 reserved;
__le32 timer_period;
__le32 flags;
-} __packed; /* TX_REDUCED_POWER_API_S_VER_11 */
+} __packed; /* TX_REDUCED_POWER_API_S_VER_11
+ * TX_REDUCED_POWER_API_S_VER_12
+ */
/*
* struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion)
* @common: common part of the command
* @v9: version 9 part of the command
* @v10: version 10 part of the command
- * @v11: version 11 part of the command
+ * @v12: version 12 part of the command (also covers v11)
*/
struct iwl_dev_tx_power_cmd {
struct iwl_dev_tx_power_common common;
union {
struct iwl_dev_tx_power_cmd_v9 v9;
struct iwl_dev_tx_power_cmd_v10 v10;
- struct iwl_dev_tx_power_cmd_v11 v11;
+ struct iwl_dev_tx_power_cmd_v12 v12;
};
} __packed; /* TX_REDUCED_POWER_API_S_VER_9
* TX_REDUCED_POWER_API_S_VER_10
* TX_REDUCED_POWER_API_S_VER_11
+ * TX_REDUCED_POWER_API_S_VER_12
*/
#define IWL_NUM_GEO_PROFILES 3
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 137303e4a29b..27a5804dbd73 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -247,17 +247,22 @@ IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table);
static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
__le16 *per_chain, u32 n_subbands,
- int prof_a, int prof_b)
+ int prof_a, int prof_b,
+ const struct iwl_sar_profile *profiles,
+ bool is_standalone)
{
int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b };
int i, j;
+ BUILD_BUG_ON(ARRAY_SIZE(fwrt->sar_standalone_profiles[0].chains[0].subbands) !=
+ ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands));
+
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;
+ const struct iwl_sar_profile *prof;
/* don't allow SAR to be disabled (profile 0 means disable) */
if (profs[i] == 0)
@@ -268,11 +273,13 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
return -EINVAL;
/* profiles go from 1 to 4, so decrement to access the array */
- prof = &fwrt->sar_profiles[profs[i] - 1];
+ prof = &profiles[profs[i] - 1];
/* if the profile is disabled, do nothing */
if (!prof->enabled) {
- IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
+ IWL_DEBUG_RADIO(fwrt,
+ "SAR %sprofile %d is disabled.\n",
+ is_standalone ? "standalone " : "",
profs[i]);
/*
* if one of the profiles is disabled, we
@@ -282,8 +289,8 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
return 1;
}
- IWL_DEBUG_INFO(fwrt,
- "SAR EWRD: chain %d profile index %d\n",
+ IWL_DEBUG_INFO(fwrt, "SAR %s: chain %d profile index %d\n",
+ is_standalone ? "standalone" : "EWRD",
i, profs[i]);
IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i);
for (j = 0; j < n_subbands; j++) {
@@ -299,14 +306,17 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
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 prof_a, int prof_b,
+ const struct iwl_sar_profile *profiles,
+ bool is_standalone)
{
int i, ret = 0;
for (i = 0; i < n_tables; i++) {
ret = iwl_sar_fill_table(fwrt,
&per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS],
- n_subbands, prof_a, prof_b);
+ n_subbands, prof_a, prof_b, profiles,
+ is_standalone);
if (ret)
break;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index bd7ea0ff3d19..e32e107812b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -210,7 +210,9 @@ int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,
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 prof_a, int prof_b,
+ const struct iwl_sar_profile *profiles,
+ bool is_standalone);
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/power.c b/drivers/net/wireless/intel/iwlwifi/mld/power.c
index 2387f3da5185..6fcbb1a2e8a8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/power.c
@@ -525,7 +525,7 @@ int iwl_mld_set_tx_power(struct iwl_mld *mld,
.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK),
.common.pwr_restriction = cpu_to_le16(u_tx_power),
};
- int len = sizeof(cmd.common) + sizeof(cmd.v11);
+ int len = sizeof(cmd.common) + sizeof(cmd.v12);
if (iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 10) == 10)
len = sizeof(cmd.common) + sizeof(cmd.v10);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index 9f395a1fd12a..8a20d7622329 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
@@ -74,6 +74,21 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld)
"EWRD SAR BIOS table invalid or unavailable. (%d)\n",
ret);
+ ret = iwl_bios_get_wsss_table(&mld->fwrt);
+ if (ret < 0)
+ IWL_DEBUG_RADIO(mld,
+ "WSSS (WRDS Standalone) SAR BIOS table invalid or unavailable. (%d)\n",
+ ret);
+
+ if (!ret) {
+ /* EWSS only extends the standalone SAR profiles from WSSS. */
+ ret = iwl_bios_get_ewss_table(&mld->fwrt);
+ if (ret < 0)
+ IWL_DEBUG_RADIO(mld,
+ "EWSS (EWRD Standalone) SAR BIOS table invalid or unavailable. (%d)\n",
+ ret);
+ }
+
ret = iwl_bios_get_wgds_table(&mld->fwrt);
if (ret < 0)
IWL_DEBUG_RADIO(mld,
@@ -135,7 +150,9 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld)
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)
+static int
+iwl_mld_config_sar_concurrent_profile(struct iwl_mld *mld, int prof_a,
+ int prof_b)
{
struct iwl_dev_tx_power_cmd cmd = {
.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),
@@ -152,8 +169,9 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b)
num_subbands = IWL_NUM_SUB_BANDS_V2;
break;
case 11:
- cmd.v11.flags = cpu_to_le32(mld->fwrt.reduced_power_flags);
- cmd_size = sizeof(cmd.common) + sizeof(cmd.v11);
+ case 12:
+ cmd.v12.flags = cpu_to_le32(mld->fwrt.reduced_power_flags);
+ cmd_size = sizeof(cmd.common) + sizeof(cmd.v12);
num_subbands = IWL_NUM_SUB_BANDS_V3;
break;
default:
@@ -163,12 +181,13 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b)
}
/* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */
- /* v10 and v11 have the same position for per_chain */
- BUILD_BUG_ON(offsetof(typeof(cmd), v11.per_chain) !=
+ /* v10 and v12 have the same position for per_chain */
+ BUILD_BUG_ON(offsetof(typeof(cmd), v12.per_chain) !=
offsetof(typeof(cmd), v10.per_chain));
- ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v11.per_chain[0][0][0],
+ ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v12.per_chain[0][0][0],
IWL_NUM_CHAIN_TABLES, num_subbands,
- prof_a, prof_b);
+ prof_a, prof_b,
+ mld->fwrt.sar_profiles, false);
/* return on error or if the profile is disabled (positive number) */
if (ret)
return ret;
@@ -176,6 +195,51 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b)
return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd, cmd_size);
}
+static int iwl_mld_config_sar_standalone_profile(struct iwl_mld *mld,
+ int prof_a, int prof_b)
+{
+ struct iwl_dev_tx_power_cmd cmd = {
+ .common.set_mode =
+ cpu_to_le32(IWL_TX_POWER_MODE_SET_STANDALONE_CHAINS),
+ };
+ int ret;
+
+ /* standalone per-chain SAR limits require cmd version 12 */
+ if (iwl_fw_lookup_cmd_ver(mld->fw, REDUCE_TX_POWER_CMD, 10) != 12)
+ return 0;
+
+ ret = iwl_sar_fill_profile(&mld->fwrt,
+ &cmd.v12.per_chain[0][0][0],
+ IWL_NUM_CHAIN_TABLES,
+ IWL_NUM_SUB_BANDS_V3,
+ prof_a, prof_b,
+ mld->fwrt.sar_standalone_profiles,
+ true);
+ /* return on error or if the standalone profile is disabled */
+ if (ret)
+ return ret;
+
+ return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd,
+ sizeof(cmd.common) + sizeof(cmd.v12));
+}
+
+int iwl_mld_config_sar_profiles(struct iwl_mld *mld, int prof_a, int prof_b)
+{
+ int ret;
+
+ ret = iwl_mld_config_sar_concurrent_profile(mld, prof_a, prof_b);
+ /* return on error or if the profile is disabled (positive number) */
+ if (ret)
+ return ret;
+
+ ret = iwl_mld_config_sar_standalone_profile(mld, prof_a, prof_b);
+ /* standalone profile is optional and may be disabled (positive number) */
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
int iwl_mld_init_sar(struct iwl_mld *mld)
{
int chain_a_prof = 1;
@@ -190,7 +254,7 @@ int iwl_mld_init_sar(struct iwl_mld *mld)
chain_b_prof = mld->fwrt.sar_chain_b_profile;
}
- ret = iwl_mld_config_sar_profile(mld, chain_a_prof, chain_b_prof);
+ ret = iwl_mld_config_sar_profiles(mld, chain_a_prof, chain_b_prof);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
index 5498c19789f4..0877b951f2e2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
*/
#ifndef __iwl_mld_regulatory_h__
#define __iwl_mld_regulatory_h__
@@ -18,6 +18,6 @@ int iwl_mld_init_sgom(struct iwl_mld *mld);
int iwl_mld_init_sar(struct iwl_mld *mld);
-int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b);
+int iwl_mld_config_sar_profiles(struct iwl_mld *mld, int prof_a, int prof_b);
#endif /* __iwl_mld_regulatory_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 0b5b41223a8a..c3402f5e47a0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -911,7 +911,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
ret = iwl_sar_fill_profile(&mvm->fwrt, per_chain,
IWL_NUM_CHAIN_TABLES,
- n_subbands, prof_a, prof_b);
+ n_subbands, prof_a, prof_b,
+ mvm->fwrt.sar_profiles, false);
/* return on error or if the profile is disabled (positive number) */
if (ret)