* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: acpi: add support for WRDS rev 3 table
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach, Johannes Berg
In-Reply-To: <20260319184855.1981384-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This table includes another sub-band for UNII-9.
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>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 25 +++++++++++++++++++-
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 3 +++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index 4d0a93832336..debbba22a909 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -535,7 +535,23 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
if (IS_ERR(data))
return PTR_ERR(data);
- /* start by trying to read revision 2 */
+ /* start by trying to read revision 3 */
+ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
+ ACPI_WRDS_WIFI_DATA_SIZE_REV3,
+ &tbl_rev);
+ if (!IS_ERR(wifi_pkg)) {
+ if (tbl_rev != 3) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ num_chains = ACPI_SAR_NUM_CHAINS_REV2;
+ num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3;
+
+ goto read_table;
+ }
+
+ /* then try revision 2 */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_WRDS_WIFI_DATA_SIZE_REV2,
&tbl_rev);
@@ -592,6 +608,13 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}
+ if (WARN_ON(num_chains * num_sub_bands >
+ ARRAY_SIZE(fwrt->sar_profiles[0].chains) *
+ ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
flags = wifi_pkg->package.elements[1].integer.value;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index 138fdb9a5273..ec6af1b58098 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -39,6 +39,7 @@
#define ACPI_SAR_NUM_SUB_BANDS_REV0 5
#define ACPI_SAR_NUM_SUB_BANDS_REV1 11
#define ACPI_SAR_NUM_SUB_BANDS_REV2 11
+#define ACPI_SAR_NUM_SUB_BANDS_REV3 12
#define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \
ACPI_SAR_NUM_SUB_BANDS_REV0 + 2)
@@ -46,6 +47,8 @@
ACPI_SAR_NUM_SUB_BANDS_REV1 + 2)
#define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \
ACPI_SAR_NUM_SUB_BANDS_REV2 + 2)
+#define ACPI_WRDS_WIFI_DATA_SIZE_REV3 (ACPI_SAR_NUM_CHAINS_REV2 * \
+ ACPI_SAR_NUM_SUB_BANDS_REV3 + 2)
#define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \
ACPI_SAR_NUM_CHAINS_REV0 * \
ACPI_SAR_NUM_SUB_BANDS_REV0 + 3)
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: uefi: support the new WRDS and EWRD tables
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach, Johannes Berg
In-Reply-To: <20260319184855.1981384-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Those tables now have support for UNII-9 subband.
Refactor iwl_uefi_set_sar_profile to get an array of values that makes
it easier to use when the number of subbands can vary.
Revamp a bit the code that fetches the tables to ask for the smaller
table, then we can check the size of the object that we got and compare
to the expected sizes to determine what revision to expect.
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/regulatory.h | 2 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 92 +++++++++++++++----
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 62 ++++++++-----
3 files changed, 116 insertions(+), 40 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 446c8a2c4f9d..a3684514c904 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -21,7 +21,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_SAR_MAX_SUB_BANDS_NUM 12
#define BIOS_PPAG_MAX_SUB_BANDS_NUM 12
#define BIOS_GEO_NUM_CHAINS 2
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 84b6f8b7eda9..3d3d698bacd0 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -460,11 +460,30 @@ void iwl_uefi_get_uneb_table(struct iwl_trans *trans,
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)
+ const u8 *vals, u8 prof_index,
+ u8 num_subbands, bool enabled)
{
- memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof,
- sizeof(struct uefi_sar_profile));
+ struct iwl_sar_profile *sar_prof = &fwrt->sar_profiles[prof_index];
+
+ /*
+ * Make sure fwrt has enough room to hold the data
+ * coming from the UEFI table
+ */
+ if (WARN_ON(ARRAY_SIZE(sar_prof->chains) *
+ ARRAY_SIZE(sar_prof->chains[0].subbands) <
+ UEFI_SAR_MAX_CHAINS_PER_PROFILE * num_subbands))
+ return;
+
+ BUILD_BUG_ON(ARRAY_SIZE(sar_prof->chains) !=
+ UEFI_SAR_MAX_CHAINS_PER_PROFILE);
+
+ for (int chain = 0;
+ chain < UEFI_SAR_MAX_CHAINS_PER_PROFILE;
+ chain++) {
+ for (int subband = 0; subband < num_subbands; subband++)
+ sar_prof->chains[chain].subbands[subband] =
+ vals[chain * num_subbands + subband];
+ }
fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK;
}
@@ -472,24 +491,46 @@ static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt,
int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_wrds *data;
+ unsigned long size;
+ unsigned long expected_size;
+ int num_subbands;
int ret = 0;
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME,
- "WRDS", sizeof(*data), NULL);
+ "WRDS",
+ UEFI_SAR_WRDS_TABLE_SIZE_REV2,
+ &size);
+
if (IS_ERR(data))
return -EINVAL;
- if (data->revision != IWL_UEFI_WRDS_REVISION) {
- ret = -EINVAL;
- IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n",
+ switch (data->revision) {
+ case 2:
+ expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV2;
+ num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2;
+ break;
+ case 3:
+ expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV3;
+ num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3;
+ break;
+ default:
+ IWL_DEBUG_RADIO(fwrt,
+ "Unsupported UEFI WRDS revision:%d\n",
data->revision);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (size != expected_size) {
+ ret = -EINVAL;
goto out;
}
/* The profile from WRDS is officially profile 1, but goes
* into sar_profiles[0] (because we don't have a profile 0).
*/
- iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode);
+ iwl_uefi_set_sar_profile(fwrt, data->vals, 0,
+ num_subbands, data->mode);
out:
kfree(data);
return ret;
@@ -498,21 +539,40 @@ int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt)
int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_ewrd *data;
+ unsigned long expected_size;
int i, ret = 0;
+ unsigned long size;
+ int num_subbands;
+ int profile_size;
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME,
- "EWRD", sizeof(*data), NULL);
+ "EWRD",
+ UEFI_SAR_EWRD_TABLE_SIZE_REV2,
+ &size);
if (IS_ERR(data))
return -EINVAL;
- if (data->revision != IWL_UEFI_EWRD_REVISION) {
- ret = -EINVAL;
- IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n",
+ switch (data->revision) {
+ case 2:
+ expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV2;
+ num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2;
+ profile_size = UEFI_SAR_PROFILE_SIZE_REV2;
+ break;
+ case 3:
+ expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV3;
+ num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3;
+ profile_size = UEFI_SAR_PROFILE_SIZE_REV3;
+ break;
+ default:
+ IWL_DEBUG_RADIO(fwrt,
+ "Unsupported UEFI EWRD revision:%d\n",
data->revision);
+ ret = -EINVAL;
goto out;
}
- if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
+ if (size != expected_size ||
+ data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
ret = -EINVAL;
goto out;
}
@@ -522,8 +582,8 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
* save them in sar_profiles[1-3] (because we don't
* have profile 0). So in the array we start from 1.
*/
- iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1,
- data->mode);
+ iwl_uefi_set_sar_profile(fwrt, &data->vals[i * profile_size],
+ i + 1, num_subbands, data->mode);
out:
kfree(data);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 5046b6a45419..aa5a4c5a7392 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -31,8 +31,6 @@
#define IWL_SGOM_MAP_SIZE 339
#define IWL_UATS_MAP_SIZE 339
-#define IWL_UEFI_WRDS_REVISION 2
-#define IWL_UEFI_EWRD_REVISION 2
#define IWL_UEFI_WGDS_REVISION 3
#define IWL_UEFI_MIN_WTAS_REVISION 1
#define IWL_UEFI_MAX_WTAS_REVISION 2
@@ -74,56 +72,74 @@ struct uefi_cnv_common_step_data {
u8 radio2;
} __packed;
-#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
#define UEFI_PPAG_SUB_BANDS_NUM_REV4 11
#define UEFI_PPAG_SUB_BANDS_NUM_REV5 12
#define UEFI_PPAG_NUM_CHAINS 2
-#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];
-};
+#define UEFI_SAR_SUB_BANDS_NUM_REV2 11
+#define UEFI_SAR_SUB_BANDS_NUM_REV3 12
-/*
- * struct uefi_sar_profile - a SAR profile as defined in UEFI
- *
- * @chains: a per-chain table of SAR values
- */
-struct uefi_sar_profile {
- struct uefi_sar_profile_chain chains[UEFI_SAR_MAX_CHAINS_PER_PROFILE];
-} __packed;
+#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
/*
* struct uefi_cnv_var_wrds - WRDS table as defined in UEFI
*
* @revision: the revision of the table
* @mode: is WRDS enbaled/disabled
- * @sar_profile: sar profile #1
+ * @vals: values for sar profile #1 as an array:
+ * vals[chain * num_of_subbands + subband] will return the right value.
+ * num_of_subbands depends on the revision. For revision 3, it is
+ * %UEFI_SAR_SUB_BANDS_NUM_REV3, for earlier revision, it is
+ * %UEFI_SAR_SUB_BANDS_NUM_REV2.
+ * The max number of chains is currently 2
*/
struct uefi_cnv_var_wrds {
u8 revision;
u32 mode;
- struct uefi_sar_profile sar_profile;
+ u8 vals[];
} __packed;
+#define UEFI_SAR_PROFILE_SIZE_REV2 \
+ (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \
+ UEFI_SAR_SUB_BANDS_NUM_REV2)
+
+#define UEFI_SAR_PROFILE_SIZE_REV3 \
+ (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \
+ UEFI_SAR_SUB_BANDS_NUM_REV3)
+
+#define UEFI_SAR_WRDS_TABLE_SIZE_REV2 \
+ (offsetof(struct uefi_cnv_var_wrds, vals) + \
+ UEFI_SAR_PROFILE_SIZE_REV2)
+
+#define UEFI_SAR_WRDS_TABLE_SIZE_REV3 \
+ (offsetof(struct uefi_cnv_var_wrds, vals) + \
+ UEFI_SAR_PROFILE_SIZE_REV3)
+
/*
* struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI
* @revision: the revision of the table
* @mode: is WRDS enbaled/disabled
* @num_profiles: how many additional profiles we have in this table (0-3)
- * @sar_profiles: the additional SAR profiles (#2-#4)
+ * @vals: the additional SAR profiles (#2-#4) as an array of SAR profiles.
+ * A SAR profile is defined the &struct uefi_cnv_var_wrds::vals. The size
+ * of each profile depends on the number of subbands which depends on the
+ * revision. This is explained in &struct uefi_cnv_var_wrds.
*/
struct uefi_cnv_var_ewrd {
u8 revision;
u32 mode;
u32 num_profiles;
- struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1];
+ u8 vals[];
} __packed;
+#define UEFI_SAR_EWRD_TABLE_SIZE_REV2 \
+ (offsetof(struct uefi_cnv_var_ewrd, vals) + \
+ UEFI_SAR_PROFILE_SIZE_REV2 * (BIOS_SAR_MAX_PROFILE_NUM - 1))
+
+#define UEFI_SAR_EWRD_TABLE_SIZE_REV3 \
+ (offsetof(struct uefi_cnv_var_ewrd, vals) + \
+ UEFI_SAR_PROFILE_SIZE_REV3 * (BIOS_SAR_MAX_PROFILE_NUM - 1))
+
/*
* struct uefi_cnv_var_wgds - WGDS table as defined in UEFI
* @revision: the revision of the table
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 03/15] wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach, Johannes Berg
In-Reply-To: <20260319184855.1981384-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Otherwise we may send garbage.
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>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index d46715abd7a5..0c643f0b7105 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -908,7 +908,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
{
- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd;
+ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {};
struct iwl_geo_tx_power_profiles_resp *resp;
u16 len;
int ret;
@@ -960,7 +960,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
{
u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD);
- union iwl_geo_tx_power_profiles_cmd cmd;
+ union iwl_geo_tx_power_profiles_cmd cmd = {};
u16 len;
u32 n_bands;
u32 n_profiles;
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 01/15] wifi: iwlwifi: uefi: add support for PPAG table rev5
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260319184855.1981384-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This table has another subband for UNII-9.
Add defines for the sizes of rev4 and rev5 to easily know how much data
to ask from iwl_uefi_get_verified_variable.
In case rev5 doesn't exist, fallback to rev4.
Check that the revision advertised by the fetched table matches the size
that we got.
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 | 66 +++++++++++++-------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 17 +++--
2 files changed, 57 insertions(+), 26 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index fba41976be6b..84b6f8b7eda9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -570,44 +570,66 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt)
int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_ppag *data;
+ int n_subbands;
+ u32 valid_rev;
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", data_sz, NULL);
- if (IS_ERR(data))
- return -EINVAL;
+ "PPAG", UEFI_PPAG_DATA_SIZE_V5,
+ NULL);
+ if (!IS_ERR(data)) {
+ n_subbands = UEFI_PPAG_SUB_BANDS_NUM_REV5;
+ valid_rev = BIT(5);
+
+ goto parse_table;
+ }
+
+ data = iwl_uefi_get_verified_variable(fwrt->trans,
+ IWL_UEFI_PPAG_NAME,
+ "PPAG",
+ UEFI_PPAG_DATA_SIZE_V4,
+ NULL);
+ if (!IS_ERR(data)) {
+ n_subbands = UEFI_PPAG_SUB_BANDS_NUM_REV4;
+ /* revisions 1-4 have all the same size */
+ valid_rev = BIT(1) | BIT(2) | BIT(3) | BIT(4);
- if (data->revision < IWL_UEFI_MIN_PPAG_REV ||
- data->revision > IWL_UEFI_MAX_PPAG_REV) {
+ goto parse_table;
+ }
+
+ return -EINVAL;
+
+parse_table:
+ if (!(BIT(data->revision) & valid_rev)) {
ret = -EINVAL;
- IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n",
+ IWL_DEBUG_RADIO(fwrt,
+ "Unsupported UEFI PPAG revision:%d\n",
data->revision);
goto out;
}
- fwrt->ppag_bios_rev = data->revision;
- fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,
- fwrt->ppag_bios_rev);
-
/*
* 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++)
+ if (WARN_ON(ARRAY_SIZE(fwrt->ppag_chains) *
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands) <
+ UEFI_PPAG_NUM_CHAINS * n_subbands)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fwrt->ppag_bios_rev = data->revision;
+ fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,
+ fwrt->ppag_bios_rev);
+
+ for (int chain = 0; chain < UEFI_PPAG_NUM_CHAINS; chain++) {
+ for (int subband = 0; subband < n_subbands; subband++)
fwrt->ppag_chains[chain].subbands[subband] =
- data->vals[chain * UEFI_PPAG_SUB_BANDS_NUM + subband];
+ data->vals[chain * n_subbands + subband];
}
- iwl_bios_print_ppag(fwrt, UEFI_PPAG_SUB_BANDS_NUM);
+ iwl_bios_print_ppag(fwrt, n_subbands);
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 4f0ce068a589..5046b6a45419 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -34,8 +34,6 @@
#define IWL_UEFI_WRDS_REVISION 2
#define IWL_UEFI_EWRD_REVISION 2
#define IWL_UEFI_WGDS_REVISION 3
-#define IWL_UEFI_MIN_PPAG_REV 1
-#define IWL_UEFI_MAX_PPAG_REV 4
#define IWL_UEFI_MIN_WTAS_REVISION 1
#define IWL_UEFI_MAX_WTAS_REVISION 2
#define IWL_UEFI_SPLC_REVISION 0
@@ -77,7 +75,9 @@ struct uefi_cnv_common_step_data {
} __packed;
#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
-#define UEFI_PPAG_SUB_BANDS_NUM 11
+#define UEFI_PPAG_SUB_BANDS_NUM_REV4 11
+#define UEFI_PPAG_SUB_BANDS_NUM_REV5 12
+#define UEFI_PPAG_NUM_CHAINS 2
#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
/*
@@ -143,7 +143,9 @@ struct uefi_cnv_var_wgds {
* @ppag_modes: values from &enum iwl_ppag_flags
* @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.
+ * num_of_subbands depends on the revision. For revision 5, it is
+ * %UEFI_PPAG_SUB_BANDS_NUM_REV5, for earlier revision it is
+ * %UEFI_PPAG_SUB_BANDS_NUM_REV4.
* the max number of chains is currently 2
*/
struct uefi_cnv_var_ppag {
@@ -152,6 +154,13 @@ struct uefi_cnv_var_ppag {
s8 vals[];
} __packed;
+#define UEFI_PPAG_DATA_SIZE_V4 \
+ (offsetof(struct uefi_cnv_var_ppag, vals) + \
+ sizeof(s8) * UEFI_PPAG_NUM_CHAINS * UEFI_PPAG_SUB_BANDS_NUM_REV4)
+#define UEFI_PPAG_DATA_SIZE_V5 \
+ (offsetof(struct uefi_cnv_var_ppag, vals) + \
+ sizeof(s8) * UEFI_PPAG_NUM_CHAINS * UEFI_PPAG_SUB_BANDS_NUM_REV5)
+
/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI
* @revision: the revision of the table
* @tas_selection: different options of TAS enablement.
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 02/15] wifi: iwlwifi: restrict TOP reset to some devices
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260319184855.1981384-1-miriam.rachel.korenblit@intel.com>
From: Johannes Berg <johannes.berg@intel.com>
Due to the Bluetooth implementation needing to match, not all
devices can actually do TOP reset. Restrict it to Sc2/Sc2f or
later, with Wh RF or later.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 10 +++++-----
drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 18 ++++++++++++++++++
.../wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 2 +-
3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 89901786fd68..16b2c313e72b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -138,7 +138,7 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans)
IWL_RESET_MODE_FUNC_RESET,
IWL_RESET_MODE_PROD_RESET,
};
- static const enum iwl_reset_mode escalation_list_sc[] = {
+ static const enum iwl_reset_mode escalation_list_top[] = {
IWL_RESET_MODE_SW_RESET,
IWL_RESET_MODE_REPROBE,
IWL_RESET_MODE_REPROBE,
@@ -159,14 +159,14 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans)
if (trans->request_top_reset) {
trans->request_top_reset = 0;
- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC)
+ if (iwl_trans_is_top_reset_supported(trans))
return IWL_RESET_MODE_TOP_RESET;
return IWL_RESET_MODE_PROD_RESET;
}
- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) {
- escalation_list = escalation_list_sc;
- escalation_list_size = ARRAY_SIZE(escalation_list_sc);
+ if (iwl_trans_is_top_reset_supported(trans)) {
+ escalation_list = escalation_list_top;
+ escalation_list_size = ARRAY_SIZE(escalation_list_top);
} else {
escalation_list = escalation_list_old;
escalation_list_size = ARRAY_SIZE(escalation_list_old);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index aa0952a011e0..61e4f4776dcb 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -1258,4 +1258,22 @@ bool iwl_trans_is_pm_supported(struct iwl_trans *trans);
bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans);
+static inline bool iwl_trans_is_top_reset_supported(struct iwl_trans *trans)
+{
+ /* not supported before Sc family */
+ if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC)
+ return false;
+
+ /* for Sc family only supported for Sc2/Sc2f */
+ if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC &&
+ CSR_HW_REV_TYPE(trans->info.hw_rev) == IWL_CFG_MAC_TYPE_SC)
+ return false;
+
+ /* so far these numbers are increasing - not before Pe */
+ if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) < IWL_CFG_RF_TYPE_PE)
+ return false;
+
+ return true;
+}
+
#endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
index 4560d92d76fe..a05f60f9224b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
@@ -3197,7 +3197,7 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file,
if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
return -EINVAL;
if (mode == IWL_RESET_MODE_TOP_RESET) {
- if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC)
+ if (!iwl_trans_is_top_reset_supported(trans))
return -EINVAL;
trans->request_top_reset = 1;
}
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2026-03-19
From: Miri Korenblit @ 2026-03-19 18:48 UTC (permalink / raw)
To: linux-wireless
Hi,
features and cleanups from our internal tree.
Thanks,
Miri
---
Emmanuel Grumbach (14):
wifi: iwlwifi: uefi: add support for PPAG table rev5
wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending
wifi: iwlwifi: uefi: support the new WRDS and EWRD tables
wifi: iwlwifi: acpi: add support for WRDS rev 3 table
wifi: iwlwifi: acpi: add support for EWRD rev 3 table
wifi: iwlwifi: mld: support version 11 of REDUCE_TX_POWER_CMD
wifi: iwlwifi: uefi: open code the parsing of the WGDS table
wifi: iwlwifi: uefi: add support for WGDS rev4
wifi: iwlwifi: acpi: validate the WGDS table
wifi: iwlwifi: acpi: add support for WGDS revision 4
wifi: iwlwifi: support PER_CHAIN_LIMIT_OFFSET_CMD v6
wifi: iwlwifi: uefi: mode the comments valid kerneldoc comments
wifi: iwlwifi: remove IWL_MAX_WD_TIMEOUT
wifi: iwlwifi: mld: remove SCAN_TIMEOUT_MSEC
Johannes Berg (1):
wifi: iwlwifi: restrict TOP reset to some devices
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 101 +++++++--
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 7 +
.../net/wireless/intel/iwlwifi/fw/api/power.h | 29 ++-
.../wireless/intel/iwlwifi/fw/regulatory.h | 4 +-
.../net/wireless/intel/iwlwifi/fw/runtime.h | 2 +
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 210 ++++++++++++++----
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 133 +++++++----
.../net/wireless/intel/iwlwifi/iwl-config.h | 1 -
.../net/wireless/intel/iwlwifi/iwl-trans.c | 10 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 18 ++
.../net/wireless/intel/iwlwifi/mld/power.c | 5 +-
.../wireless/intel/iwlwifi/mld/regulatory.c | 64 +++++-
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 2 -
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 +-
.../intel/iwlwifi/pcie/gen1_2/trans.c | 2 +-
15 files changed, 468 insertions(+), 124 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v7 1/3] wifi: iwlwifi: pcie: migrate to modern pci_alloc_irq_vectors API
From: Adrián García Casado @ 2026-03-19 18:29 UTC (permalink / raw)
To: Miri Korenblit
Cc: linux-wireless, linux-kernel, Miguel Ojeda,
Adrián García Casado
Johannes Berg suggested using pci_alloc_irq_vectors() and delegating
affinity management to the kernel. This patch replaces
pci_enable_msix_range() with the modern API and leverages
PCI_IRQ_AFFINITY. The manual affinity loop is removed as it's now
redundant.
Signed-off-by: Adrián García Casado <adriangarciacasado42@gmail.com>
---
.../intel/iwlwifi/pcie/gen1_2/trans.c | 46 ++++++-------------
1 file changed, 13 insertions(+), 33 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
index 4560d92d76fe0..e4808cfe1caef 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
@@ -1274,7 +1274,7 @@ void iwl_pcie_synchronize_irqs(struct iwl_trans *trans)
int i;
for (i = 0; i < trans_pcie->alloc_vecs; i++)
- synchronize_irq(trans_pcie->msix_entries[i].vector);
+ synchronize_irq(pci_irq_vector(trans_pcie->pci_dev, i));
} else {
synchronize_irq(trans_pcie->pci_dev->irq);
}
@@ -1608,18 +1608,20 @@ iwl_pcie_set_interrupt_capa(struct pci_dev *pdev,
max_rx_queues = IWL_9000_MAX_RX_HW_QUEUES;
max_irqs = min_t(u32, num_online_cpus() + 2, max_rx_queues);
- for (i = 0; i < max_irqs; i++)
- trans_pcie->msix_entries[i].entry = i;
-
- num_irqs = pci_enable_msix_range(pdev, trans_pcie->msix_entries,
- MSIX_MIN_INTERRUPT_VECTORS,
- max_irqs);
+ num_irqs = pci_alloc_irq_vectors(pdev, MSIX_MIN_INTERRUPT_VECTORS,
+ max_irqs, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
if (num_irqs < 0) {
IWL_DEBUG_INFO(trans,
"Failed to enable msi-x mode (ret %d). Moving to msi mode.\n",
num_irqs);
goto enable_msi;
}
+
+ trans_pcie->msix_enabled = true;
+ trans_pcie->alloc_vecs = num_irqs;
+ for (i = 0; i < num_irqs; i++)
+ trans_pcie->msix_entries[i].entry = i;
+
trans_pcie->def_irq = (num_irqs == max_irqs) ? num_irqs - 1 : 0;
IWL_DEBUG_INFO(trans,
@@ -1671,28 +1673,7 @@ iwl_pcie_set_interrupt_capa(struct pci_dev *pdev,
static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans,
struct iwl_trans_info *info)
{
-#if defined(CONFIG_SMP)
- int iter_rx_q, i, ret, cpu, offset;
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
- i = trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS ? 0 : 1;
- iter_rx_q = info->num_rxqs - 1 + i;
- offset = 1 + i;
- for (; i < iter_rx_q ; i++) {
- /*
- * Get the cpu prior to the place to search
- * (i.e. return will be > i - 1).
- */
- cpu = cpumask_next(i - offset, cpu_online_mask);
- cpumask_set_cpu(cpu, &trans_pcie->affinity_mask[i]);
- ret = irq_set_affinity_hint(trans_pcie->msix_entries[i].vector,
- &trans_pcie->affinity_mask[i]);
- if (ret)
- IWL_ERR(trans_pcie->trans,
- "Failed to set affinity mask for IRQ %d\n",
- trans_pcie->msix_entries[i].vector);
- }
-#endif
+ /* Handled by PCI_IRQ_AFFINITY in pci_alloc_irq_vectors() */
}
static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
@@ -1703,15 +1684,14 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
for (i = 0; i < trans_pcie->alloc_vecs; i++) {
int ret;
- struct msix_entry *msix_entry;
+ struct msix_entry *msix_entry = &trans_pcie->msix_entries[i];
const char *qname = queue_name(&pdev->dev, trans_pcie, i);
if (!qname)
return -ENOMEM;
- msix_entry = &trans_pcie->msix_entries[i];
ret = devm_request_threaded_irq(&pdev->dev,
- msix_entry->vector,
+ pci_irq_vector(pdev, i),
iwl_pcie_msix_isr,
(i == trans_pcie->def_irq) ?
iwl_pcie_irq_msix_handler :
@@ -1988,7 +1968,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
if (trans_pcie->msix_enabled) {
for (i = 0; i < trans_pcie->alloc_vecs; i++) {
irq_set_affinity_hint(
- trans_pcie->msix_entries[i].vector,
+ pci_irq_vector(trans_pcie->pci_dev, i),
NULL);
}
base-commit: f338e77383789c0cae23ca3d48adcc5e9e137e3c
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v6] wifi: iwlwifi: pcie: optimize MSI-X interrupt affinity
From: Johannes Berg @ 2026-03-19 18:00 UTC (permalink / raw)
To: Adrián García Casado, Miri Korenblit
Cc: linux-wireless, linux-kernel, Miguel Ojeda
In-Reply-To: <20260319173821.15470-1-adriangarciacasado42@gmail.com>
On Thu, 2026-03-19 at 18:38 +0100, Adrián García Casado wrote:
> Balanced distribution: skip CPU0 for high-rate RSS queues to avoid contention with system housekeeping. Use a stateful last_cpu approach to ensure unique core assignment when skipping CPU0. This avoids mapping multiple queues to the same core.
>
> Addressing kbuild robot warning: remove unused 'offset' variable.
You might do well to address human reviewer feedback as well, really
_first_. You're just digging a deeper and deeper hole for yourself here.
johannes
^ permalink raw reply
* [PATCH v6] wifi: iwlwifi: pcie: optimize MSI-X interrupt affinity
From: Adrián García Casado @ 2026-03-19 17:38 UTC (permalink / raw)
To: Miri Korenblit
Cc: linux-wireless, linux-kernel, Miguel Ojeda,
Adrián García Casado
Balanced distribution: skip CPU0 for high-rate RSS queues to avoid contention with system housekeeping. Use a stateful last_cpu approach to ensure unique core assignment when skipping CPU0. This avoids mapping multiple queues to the same core.
Addressing kbuild robot warning: remove unused 'offset' variable.
Signed-off-by: Adrián García Casado <adriangarciacasado42@gmail.com>
---
.../intel/iwlwifi/pcie/gen1_2/trans.c | 20 ++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
index 4560d92d76fe0..1d0dcf0bc7686 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
@@ -1672,18 +1672,28 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans,
struct iwl_trans_info *info)
{
#if defined(CONFIG_SMP)
- int iter_rx_q, i, ret, cpu, offset;
+ int iter_rx_q, i, ret, cpu, last_cpu;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
i = trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS ? 0 : 1;
iter_rx_q = info->num_rxqs - 1 + i;
- offset = 1 + i;
+ last_cpu = -1;
for (; i < iter_rx_q ; i++) {
/*
- * Get the cpu prior to the place to search
- * (i.e. return will be > i - 1).
+ * Balanced distribution: skip CPU0 for high-rate RSS queues
+ * to avoid contention with system housekeeping.
*/
- cpu = cpumask_next(i - offset, cpu_online_mask);
+ cpu = cpumask_next(last_cpu, cpu_online_mask);
+ if (cpu >= nr_cpu_ids)
+ cpu = cpumask_first(cpu_online_mask);
+
+ if (cpu == 0 && num_online_cpus() > 1) {
+ cpu = cpumask_next(0, cpu_online_mask);
+ if (cpu >= nr_cpu_ids)
+ cpu = cpumask_first(cpu_online_mask);
+ }
+ last_cpu = cpu;
+
cpumask_set_cpu(cpu, &trans_pcie->affinity_mask[i]);
ret = irq_set_affinity_hint(trans_pcie->msix_entries[i].vector,
&trans_pcie->affinity_mask[i]);
base-commit: f338e77383789c0cae23ca3d48adcc5e9e137e3c
--
2.47.3
^ permalink raw reply related
* Re: [PATCH ath-current] wifi: ath12k: prepare REO update element only for primary link
From: Vasanthakumar Thiagarajan @ 2026-03-19 16:23 UTC (permalink / raw)
To: Jeff Johnson, Baochen Qiang, Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <1a037a6b-f39d-4624-8f3d-1298da8c50bf@oss.qualcomm.com>
On 3/19/2026 7:44 PM, Jeff Johnson wrote:
> On 3/18/2026 8:46 PM, Vasanthakumar Thiagarajan wrote:
>>
>>
>> On 2/10/2026 8:37 AM, Baochen Qiang wrote:
>>> Commit [1] introduces dp->reo_cmd_update_rx_queue_list for the purpose
>>> of tracking all pending REO queue flush commands. The helper
>>> ath12k_dp_prepare_reo_update_elem() allocates an element and populates
>>> it with REO queue information, then add it to the list. The element would
>>> be helpful during clean up stage to finally unmap/free the corresponding
>>> REO queue buffer.
>>>
>>> In MLO scenarios with more than one links, for non dp_primary_link_only
>>> chips like WCN7850, that helper is called for each link peer. This
>>> results in multiple elements added to the list but all of them pointing
>>> to the same REO queue buffer. Consequently the same buffer gets
>>> unmap/freed multiple times:
>>>
>>> BUG kmalloc-2k (Tainted: G B W O ): Object already free
>>> -----------------------------------------------------------------------------
>>> Allocated in ath12k_wifi7_dp_rx_assign_reoq+0xce/0x280 [ath12k_wifi7] age=7436 cpu=10 pid=16130
>>> __kmalloc_noprof
>>> ath12k_wifi7_dp_rx_assign_reoq
>>> ath12k_dp_rx_peer_tid_setup
>>> ath12k_dp_peer_setup
>>> ath12k_mac_station_add
>>> ath12k_mac_op_sta_state
>>> [...]
>>> Freed in ath12k_dp_rx_tid_cleanup.part.0+0x25/0x40 [ath12k] age=1 cpu=27 pid=16137
>>> kfree
>>> ath12k_dp_rx_tid_cleanup.part.0
>>> ath12k_dp_rx_reo_cmd_list_cleanup
>>> ath12k_dp_cmn_device_deinit
>>> ath12k_core_stop
>>> ath12k_core_hw_group_cleanup
>>> ath12k_pci_remove
>>>
>>> Fix this by allowing list addition for primary link only. Note
>>> dp_primary_link_only chips like QCN9274 are not affected by this change,
>>> because that's what they were doing in the first place.
>>>
>>> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
>>>
>>> Fixes: 3bf2e57e7d6c ("wifi: ath12k: Add Retry Mechanism for REO RX Queue Update Failures") # [1]
>>> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221011
>>> Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
>>
>> Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
>
> Was there supposed to be a tag in front of that?
>
Oops, sorry!
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next v4] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Jeff Johnson @ 2026-03-19 15:59 UTC (permalink / raw)
To: Nicolas Escande, Rameshkumar Sundaram, ath12k; +Cc: linux-wireless
In-Reply-To: <DH6U1JMUQXVM.287BFERLLK9KK@gmail.com>
On 3/19/2026 7:35 AM, Nicolas Escande wrote:
> On Thu Mar 19, 2026 at 12:08 PM CET, Rameshkumar Sundaram wrote:
>>
>> Since CONFIG_ATH12K is tristate, a built-in boot can continue past a
>> failed ath12k_init() and still run ath12k_wifi7_init().
>>
> I genuinely thought the kernel prevented this. I was wrong.
>
>> Please ensure that later initialization path is guarded against
>> allocation failure.
>>
> I can add a flag like so to be able to check from ath12k_wifi7_init() if the
> init finished ok. Something in the lines of
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 6c034071cc6d..742fb33f41ff 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -34,6 +34,9 @@ module_param_named(ftm_mode, ath12k_ftm_mode, bool, 0444);
> MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
> EXPORT_SYMBOL(ath12k_ftm_mode);
>
> +bool ath12k_init_ok = false;
> +EXPORT_SYMBOL(ath12k_init_ok);
> +
> /* protected with ath12k_hw_group_mutex */
> static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
>
> @@ -2323,7 +2326,14 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>
> static int ath12k_init(void)
> {
> - return ath12k_wmi_alloc();
> + int ret;
> +
> + ret = ath12k_wmi_alloc();
> + if (ret)
> + return -ENOMEM;
> +
> + ath12k_init_ok = true;
> + return 0;
> }
>
> static void ath12k_exit(void)
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 59c193b24764..f35571b1a541 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -101,6 +101,8 @@ enum ath12k_crypt_mode {
> ATH12K_CRYPT_MODE_SW,
> };
>
> +extern bool ath12k_init_ok;
> +
> static inline enum wme_ac ath12k_tid_to_ac(u32 tid)
> {
> return (((tid == 0) || (tid == 3)) ? WME_AC_BE :
> diff --git a/drivers/net/wireless/ath/ath12k/wifi7/core.c b/drivers/net/wireless/ath/ath12k/wifi7/core.c
> index a02c57acf137..542ec10fabf1 100644
> --- a/drivers/net/wireless/ath/ath12k/wifi7/core.c
> +++ b/drivers/net/wireless/ath/ath12k/wifi7/core.c
> @@ -38,6 +38,9 @@ void ath12k_wifi7_arch_deinit(struct ath12k_base *ab)
>
> static int ath12k_wifi7_init(void)
> {
> + if (!ath12k_init_ok)
> + return -ENOTSUPP;
> +
> ahb_err = ath12k_wifi7_ahb_init();
> if (ahb_err)
> pr_warn("Failed to initialize ath12k Wi-Fi 7 AHB device: %d\n",
>
>
> I don't like it much but it is easy enough.
> But I don't know if there is a more idiomatic way of doing things
I'd prefer to expose a function rather than a global variable.
In other words keep the flag static, and expose a function that returns the
value of the flag, i.e.:
bool ath12k_core_initialized(void)
{
return ath12k_init_ok;
}
EXPORT_SYMBOL(ath12k_core_initialized);
>
>> Or may be have this allocated on first device probe and free it on last
>> device deinit ?
>
> That seems even more involved. It would be easier to go back to the previous
> version and simply, alloc it once per ath12k_base
>
> What do you guys think ?
>
Going back to that may be the better solution. It isn't nice that this current
solution may allocate memory when the driver isn't actually used. But I'll let
others on the team weigh in as well.
/jeff
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH net-next v2 08/13] bnxt: use snapshot in bnxt_cfg_rx_mode
From: Stanislav Fomichev @ 2026-03-19 15:54 UTC (permalink / raw)
To: Loktionov, Aleksandr
Cc: Stanislav Fomichev, netdev@vger.kernel.org, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, corbet@lwn.net, skhan@linuxfoundation.org,
andrew+netdev@lunn.ch, michael.chan@broadcom.com,
pavan.chebbi@broadcom.com, Nguyen, Anthony L, Kitszel, Przemyslaw,
saeedm@nvidia.com, tariqt@nvidia.com, mbloch@nvidia.com,
alexanderduyck@fb.com, kernel-team@meta.com,
johannes@sipsolutions.net, sd@queasysnail.net, jianbol@nvidia.com,
dtatulea@nvidia.com, mohsin.bashr@gmail.com, Keller, Jacob E,
willemb@google.com, skhawaja@google.com, bestswngs@gmail.com,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
intel-wired-lan@lists.osuosl.org, linux-rdma@vger.kernel.org,
linux-wireless@vger.kernel.org, linux-kselftest@vger.kernel.org,
leon@kernel.org
In-Reply-To: <IA3PR11MB89866985981DB64EFEBDF0ACE54FA@IA3PR11MB8986.namprd11.prod.outlook.com>
On 03/19, Loktionov, Aleksandr wrote:
>
>
> > -----Original Message-----
> > From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> > Of Stanislav Fomichev
> > Sent: Wednesday, March 18, 2026 4:03 PM
> > To: netdev@vger.kernel.org
> > Cc: davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> > pabeni@redhat.com; horms@kernel.org; corbet@lwn.net;
> > skhan@linuxfoundation.org; andrew+netdev@lunn.ch;
> > michael.chan@broadcom.com; pavan.chebbi@broadcom.com; Nguyen, Anthony
> > L <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw
> > <przemyslaw.kitszel@intel.com>; saeedm@nvidia.com; tariqt@nvidia.com;
> > mbloch@nvidia.com; alexanderduyck@fb.com; kernel-team@meta.com;
> > johannes@sipsolutions.net; sd@queasysnail.net; jianbol@nvidia.com;
> > dtatulea@nvidia.com; sdf@fomichev.me; mohsin.bashr@gmail.com; Keller,
> > Jacob E <jacob.e.keller@intel.com>; willemb@google.com;
> > skhawaja@google.com; bestswngs@gmail.com; linux-doc@vger.kernel.org;
> > linux-kernel@vger.kernel.org; intel-wired-lan@lists.osuosl.org; linux-
> > rdma@vger.kernel.org; linux-wireless@vger.kernel.org; linux-
> > kselftest@vger.kernel.org; leon@kernel.org
> > Subject: [Intel-wired-lan] [PATCH net-next v2 08/13] bnxt: use
> > snapshot in bnxt_cfg_rx_mode
> >
> > With the introduction of ndo_set_rx_mode_async (as discussed in [0])
> > we can call bnxt_cfg_rx_mode directly. Convert bnxt_cfg_rx_mode to use
> > uc/mc snapshots and move its call in bnxt_sp_task to the section that
> > resets BNXT_STATE_IN_SP_TASK. Switch to direct call in
> > bnxt_set_rx_mode.
> >
> > 0:
> > https://lore.kernel.org/netdev/CACKFLi=5vj8hPqEUKDd8RTw3au5G+zRgQEqjF+
> > 6NZnyoNm90KA@mail.gmail.com/
> >
> > Cc: Michael Chan <michael.chan@broadcom.com>
> > Cc: Pavan Chebbi <pavan.chebbi@broadcom.com>
> > Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
> > ---
> > drivers/net/ethernet/broadcom/bnxt/bnxt.c | 24 ++++++++++++++--------
> > -
> > 1 file changed, 15 insertions(+), 9 deletions(-)
>
> ...
>
> > -static int bnxt_cfg_rx_mode(struct bnxt *bp)
> > +static int bnxt_cfg_rx_mode(struct bnxt *bp, struct
> > netdev_hw_addr_list *uc,
> > + struct netdev_hw_addr_list *mc)
> > {
> > struct net_device *dev = bp->dev;
> > struct bnxt_vnic_info *vnic = &bp-
> > >vnic_info[BNXT_VNIC_DEFAULT];
> > @@ -13623,7 +13625,7 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)
> > bool uc_update;
> >
> > netif_addr_lock_bh(dev);
> > - uc_update = bnxt_uc_list_updated(bp, &dev->uc);
> > + uc_update = bnxt_uc_list_updated(bp, uc);
> > netif_addr_unlock_bh(dev);
> >
> > if (!uc_update)
> > @@ -13642,7 +13644,7 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)
> > if (netdev_uc_count(dev) > (BNXT_MAX_UC_ADDRS - 1)) {
> > vnic->rx_mask |=
> > CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
> This limit check uses the live device list, dev->uc.
> In the new async model, the live list can differ from the snapshot.
Oh, yes, good catch! Will do s/netdev_uc_count/netdev_hw_addr_list_count(uc).
^ permalink raw reply
* Re: [GIT PULL] wireless-next-2026-03-19
From: patchwork-bot+netdevbpf @ 2026-03-19 14:40 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260319082439.79875-3-johannes@sipsolutions.net>
Hello:
This pull request was applied to netdev/net-next.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Thu, 19 Mar 2026 09:22:16 +0100 you wrote:
> Hi,
>
> We have only a couple of things for -next right now, though I think
> we'll have a bigger pull request soon with NAN and ranging APIs and
> likely driver work. But I want to be able to get the cross-merge in
> since the ranging will depend on that, so here is this for now.
>
> [...]
Here is the summary with links:
- [GIT,PULL] wireless-next-2026-03-19
https://git.kernel.org/netdev/net-next/c/9ac76f3d0bb2
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH ath-next v4] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-03-19 14:35 UTC (permalink / raw)
To: Rameshkumar Sundaram, Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <36c1cae8-d6c0-4432-bc8e-57216c5ea3fd@oss.qualcomm.com>
On Thu Mar 19, 2026 at 12:08 PM CET, Rameshkumar Sundaram wrote:
>
> Since CONFIG_ATH12K is tristate, a built-in boot can continue past a
> failed ath12k_init() and still run ath12k_wifi7_init().
>
I genuinely thought the kernel prevented this. I was wrong.
> Please ensure that later initialization path is guarded against
> allocation failure.
>
I can add a flag like so to be able to check from ath12k_wifi7_init() if the
init finished ok. Something in the lines of
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 6c034071cc6d..742fb33f41ff 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -34,6 +34,9 @@ module_param_named(ftm_mode, ath12k_ftm_mode, bool, 0444);
MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
EXPORT_SYMBOL(ath12k_ftm_mode);
+bool ath12k_init_ok = false;
+EXPORT_SYMBOL(ath12k_init_ok);
+
/* protected with ath12k_hw_group_mutex */
static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
@@ -2323,7 +2326,14 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
static int ath12k_init(void)
{
- return ath12k_wmi_alloc();
+ int ret;
+
+ ret = ath12k_wmi_alloc();
+ if (ret)
+ return -ENOMEM;
+
+ ath12k_init_ok = true;
+ return 0;
}
static void ath12k_exit(void)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 59c193b24764..f35571b1a541 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -101,6 +101,8 @@ enum ath12k_crypt_mode {
ATH12K_CRYPT_MODE_SW,
};
+extern bool ath12k_init_ok;
+
static inline enum wme_ac ath12k_tid_to_ac(u32 tid)
{
return (((tid == 0) || (tid == 3)) ? WME_AC_BE :
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/core.c b/drivers/net/wireless/ath/ath12k/wifi7/core.c
index a02c57acf137..542ec10fabf1 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/core.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/core.c
@@ -38,6 +38,9 @@ void ath12k_wifi7_arch_deinit(struct ath12k_base *ab)
static int ath12k_wifi7_init(void)
{
+ if (!ath12k_init_ok)
+ return -ENOTSUPP;
+
ahb_err = ath12k_wifi7_ahb_init();
if (ahb_err)
pr_warn("Failed to initialize ath12k Wi-Fi 7 AHB device: %d\n",
I don't like it much but it is easy enough.
But I don't know if there is a more idiomatic way of doing things
> Or may be have this allocated on first device probe and free it on last
> device deinit ?
That seems even more involved. It would be easier to go back to the previous
version and simply, alloc it once per ath12k_base
What do you guys think ?
^ permalink raw reply related
* Re: [PATCH v2 2/4] wifi: ath: Use the unified QMI service ID instead of defining it locally
From: Jeff Johnson @ 2026-03-19 14:26 UTC (permalink / raw)
To: Daniel Lezcano, konradybcio, andersson
Cc: linux-kernel, Alex Elder, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jeff Johnson,
Mathieu Poirier, Srinivas Kandagatla, Jaroslav Kysela,
Takashi Iwai, Kees Cook, Greg Kroah-Hartman, Arnd Bergmann,
Mark Brown, Wesley Cheng, netdev, linux-wireless, ath10k, ath11k,
ath12k, linux-arm-msm, linux-remoteproc, linux-sound,
Dmitry Baryshkov
In-Reply-To: <20260316171419.2619620-3-daniel.lezcano@oss.qualcomm.com>
On 3/16/2026 10:14 AM, Daniel Lezcano wrote:
> Instead of defining a local macro with a custom name for the QMI
> service identifier, use the one provided in qmi.h and remove the
> locally defined macro.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
Bjorn,
Feel free to take this through your tree since I don't think it will conflict
with anything in mine and it will take time for the definition to propagate
back to my tree via the normal workflow (which I would prefer over merging the
immutable branch).
Acked-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-current] wifi: ath12k: prepare REO update element only for primary link
From: Jeff Johnson @ 2026-03-19 14:14 UTC (permalink / raw)
To: Vasanthakumar Thiagarajan, Baochen Qiang, Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <8056cb5f-cdde-4890-b8cf-3b37d1c3483f@oss.qualcomm.com>
On 3/18/2026 8:46 PM, Vasanthakumar Thiagarajan wrote:
>
>
> On 2/10/2026 8:37 AM, Baochen Qiang wrote:
>> Commit [1] introduces dp->reo_cmd_update_rx_queue_list for the purpose
>> of tracking all pending REO queue flush commands. The helper
>> ath12k_dp_prepare_reo_update_elem() allocates an element and populates
>> it with REO queue information, then add it to the list. The element would
>> be helpful during clean up stage to finally unmap/free the corresponding
>> REO queue buffer.
>>
>> In MLO scenarios with more than one links, for non dp_primary_link_only
>> chips like WCN7850, that helper is called for each link peer. This
>> results in multiple elements added to the list but all of them pointing
>> to the same REO queue buffer. Consequently the same buffer gets
>> unmap/freed multiple times:
>>
>> BUG kmalloc-2k (Tainted: G B W O ): Object already free
>> -----------------------------------------------------------------------------
>> Allocated in ath12k_wifi7_dp_rx_assign_reoq+0xce/0x280 [ath12k_wifi7] age=7436 cpu=10 pid=16130
>> __kmalloc_noprof
>> ath12k_wifi7_dp_rx_assign_reoq
>> ath12k_dp_rx_peer_tid_setup
>> ath12k_dp_peer_setup
>> ath12k_mac_station_add
>> ath12k_mac_op_sta_state
>> [...]
>> Freed in ath12k_dp_rx_tid_cleanup.part.0+0x25/0x40 [ath12k] age=1 cpu=27 pid=16137
>> kfree
>> ath12k_dp_rx_tid_cleanup.part.0
>> ath12k_dp_rx_reo_cmd_list_cleanup
>> ath12k_dp_cmn_device_deinit
>> ath12k_core_stop
>> ath12k_core_hw_group_cleanup
>> ath12k_pci_remove
>>
>> Fix this by allowing list addition for primary link only. Note
>> dp_primary_link_only chips like QCN9274 are not affected by this change,
>> because that's what they were doing in the first place.
>>
>> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
>>
>> Fixes: 3bf2e57e7d6c ("wifi: ath12k: Add Retry Mechanism for REO RX Queue Update Failures") # [1]
>> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221011
>> Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
>
> Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Was there supposed to be a tag in front of that?
^ permalink raw reply
* Re: [PATCH 12/61] quota: Prefer IS_ERR_OR_NULL over manual NULL check
From: Jan Kara @ 2026-03-19 14:13 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Jan Kara
In-Reply-To: <20260310-b4-is_err_or_null-v1-12-bd63b656022d@avm.de>
On Tue 10-03-26 12:48:38, Philipp Hahn wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Jan Kara <jack@suse.com>
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Thanks for the patch but frankly I find the original variant clearer wrt
what is going on. So I prefer to keep the code as is.
Honza
> ---
> fs/quota/quota.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 33bacd70758007129e0375bab44d7431195ec441..2e09fc247d0cf45b9e83a4f8a0be7ea694c8c2a1 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -965,7 +965,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
> else
> drop_super_exclusive(sb);
> out:
> - if (pathp && !IS_ERR(pathp))
> + if (!IS_ERR_OR_NULL(pathp))
> path_put(pathp);
> return ret;
> }
>
> --
> 2.43.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH v2] wifi: ath10k: add channel 177 for 5 GHz band
From: Paweł Owoc @ 2026-03-19 12:26 UTC (permalink / raw)
To: Kalle Valo
Cc: Jeff Johnson, Jeff Johnson, linux-wireless, ath10k, linux-kernel
In-Reply-To: <CAKEyCaAaJGUX56Xp57KWkouCgpOyPNTqysRZyGtfsyoJ+ERMpA@mail.gmail.com>
On Wed, Sep 17, 2025 at 6:17 PM Paweł Owoc <frut3k7@gmail.com> wrote:
>
> The changes are added in the ath10k-ct driver:
> https://github.com/greearb/ath10k-ct/commit/8f2254b8e0554e78efcef5fb752be0eb3573d281
> Is there a chance they will be accepted here as well?
Kindly asking if this change can be accepted?
^ permalink raw reply
* Re: [PATCH] wifi: mac80211: fix monitor mode frame capture for real chanctx drivers
From: Óscar Alfonso Díaz @ 2026-03-19 11:40 UTC (permalink / raw)
To: Johannes Berg
Cc: 傅继晗, linux-wireless, linux-kernel, stable
In-Reply-To: <CA+bbHrX+xby2_drzo0457raoz-kgQ6eTCCHU91pR5BkvzMiq_A@mail.gmail.com>
Hi, I've sent earlier an email to show on screenshots the results of
my testing but it was rejected as the email distribution lists just
support plaintext emails. So I'm sending it again this time explaining
the results without the visual proof.
I was testing this patch using Mediatek MT7921U chipset:
https://lore.kernel.org/linux-wireless/20260308164510.5927-1-fjhhz1997@gmail.com/raw
It didn't work properly. The test consisted in split the Mediatek
adapter into two adapters (enabling VIF), and then try injection using
a test aireplay command:
iw phy phy3 interface add mon0 type monitor
ip link set mon0 up
aireplay-ng -9
Apart of that test, I also tested it creating an Evil Twin attack
using VIF feature and trying DoS at the same time as creating an AP.
On Mediatek, with the patched kernel, the test resulted in a totally
hang of the Kali VM
Let me know if I can help further or test another patch.
Thanks and regards.
--
Oscar
OpenPGP Key: DA9C60E9 ||
https://pgp.mit.edu/pks/lookup?op=get&search=0x79B17260DA9C60E9
4F74 B302 354D 817D DE38 0A43 79B1 7260 DA9C 60E9
--
El jue, 19 mar 2026 a las 12:30, Óscar Alfonso Díaz
(<oscar.alfonso.diaz@gmail.com>) escribió:
>
> Hello, I was testing this patch using Mediatek MT7921U chipset:
>
> https://lore.kernel.org/linux-wireless/20260308164510.5927-1-fjhhz1997@gmail.com/raw
>
> It didn't work properly:
>
>
>
> As you know, expected result is like this:
>
>
>
> Note the difference from the first screenshot, kernel is custom compiled 6.18.12 and the second one is the default kali linux 6.18.12 (6.18.12+kali-amd64) and using a non-Mediatek chipset to show that how it should be when it works correctly.
>
> Apart of the test of the screenshots, I also tested it creating an Evil Twin attack using VIF feature and trying DoS at the same time as creating an AP. On Mediatek, with the patched kernel, the test resulted in a totally hang of the Kali VM
>
> Let me know if I can help further or test another patch.
>
> Thanks and regards.
> --
> Oscar
>
> OpenPGP Key: DA9C60E9 || https://pgp.mit.edu/pks/lookup?op=get&search=0x79B17260DA9C60E9
> 4F74 B302 354D 817D DE38 0A43 79B1 7260 DA9C 60E9
> --
>
>
> El lun, 16 mar 2026 a las 11:38, Johannes Berg (<johannes@sipsolutions.net>) escribió:
>>
>> On Mon, 2026-03-09 at 10:45 +0000, 傅继晗 wrote:
>> >
>> > I see the key difference between our approaches: your v2 iterates
>> > the chanctx_list and only proceeds when there is exactly one entry
>> > (going to fail_rcu if more than one exists), while mine blindly takes
>> > the first entry via list_first_entry_or_null(). Your approach is
>> > clearly safer -- in a multi-chanctx scenario, there is no way to know
>> > which channel the user intends to inject on, so refusing is the
>> > correct behaviour.
>>
>> Oh, right, I hadn't even realised that at first.
>>
>> > I have tested my patch on an MT7921AU (mt76, USB) adapter across
>> > v6.13, v6.19, and v7.0-rc2 with managed + monitor coexistence, and
>> > have not observed any crashes. However, my testing was limited to a
>> > single-chanctx scenario (one managed interface + one monitor
>> > interface), so it does not rule out crashes in multi-chanctx
>> > configurations.
>>
>> Maybe Óscar can comment on which device/version he tested and got the
>> crash with? I just would like to avoid having crashes because of this,
>> but generally think that - perhaps optionally - we could have code like
>> this, since people _do_ want injection to work.
>>
>> > Could you share some details about the crashes that were reported
>> > with your v2? For example, which devices/drivers were affected and
>> > what the crash signature looked like? That would help me understand
>> > whether the issue was specific to multi-chanctx usage or something
>> > more fundamental with accessing the chanctx_list in this code path.
>>
>> No, it was specific to some driver implementation, but I don't have any
>> more information now.
>>
>> > If you agree, I would like to send a v2 that combines both approaches:
>> > use list_first_entry_or_null() for simplicity, but add a
>> > list_is_singular() guard so we only proceed when there is exactly one
>> > chanctx -- matching the safety constraint from your v2:
>> >
>> > --- a/net/mac80211/tx.c
>> > +++ b/net/mac80211/tx.c
>> > @@ -2399,10 +2399,24 @@
>> > - if (chanctx_conf)
>> > + if (chanctx_conf) {
>> > chandef = &chanctx_conf->def;
>> > - else if (local->emulate_chanctx)
>> > + } else if (local->emulate_chanctx) {
>> > chandef = &local->hw.conf.chandef;
>> > - else
>> > - goto fail_rcu;
>> > + } else {
>> > + struct ieee80211_chanctx *ctx;
>> > +
>> > + ctx = list_first_entry_or_null(&local->chanctx_list,
>> > + struct ieee80211_chanctx,
>> > + list);
>> > + if (ctx && list_is_singular(&local->chanctx_list))
>> > + chandef = &ctx->conf.def;
>> > + else
>> > + goto fail_rcu;
>> > + }
>> >
>> > This avoids the ambiguity of picking an arbitrary chanctx in
>> > multi-chanctx scenarios while still fixing the common single-chanctx
>> > case (e.g. one managed + one monitor interface).
>>
>> Seems reasonable, I think we could even drop the "if (emulate) part
>> (since in that case the list should always be singular). Just like I
>> said above - would like to understand the issue that had appeared with
>> it.
>>
>> johannes
^ permalink raw reply
* Re: [PATCH 1/1] wifi: brcmfmac: silence warning for non-existent, optional firmware
From: Alexander Stein @ 2026-03-19 11:23 UTC (permalink / raw)
To: Christian Hewitt
Cc: Arend van Spriel, linux-wireless, brcm80211,
brcm80211-dev-list.pdl, linux-kernel
In-Reply-To: <48BB2A8D-D969-4686-9B30-11331FB14C56@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3560 bytes --]
Hi,
Am Mittwoch, 18. März 2026, 08:42:55 CET schrieb Christian Hewitt:
> > On 17 Mar 2026, at 3:12 pm, Alexander Stein <alexander.stein@ew.tq-group.com> wrote:
> >
> > The driver tries to load optional firmware files, specific to
> > the actual board compatible. These might not exist resulting in a warning
> > like this:
> > brcmfmac mmc2:0001:1: Direct firmware load for brcm/brcmfmac4373-sdio.tq,imx93-tqma9352-mba93xxla-mini.bin failed with error -2
> >
> > Silence this by using firmware_request_nowait_nowarn() for all firmware
> > loads which use brcmf_fw_request_done_alt_path() as callback. This one
> > handles optional firmware files.
> >
> > Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
>
> On behalf of all distro maintainers receiving end-user issue reports
> that wrongly finger-point to “missing firmware” as the cause of all
> brcmfmac wifi problems:
>
> Tested-by: Christian Hewitt <christianshewitt@gmail.com>
Thanks.
> Before and After below:
>
> VIM1S:~ # dmesg | grep brcmfmac
> [ 12.687679] brcmfmac: F1 signature read @0x18000000=0x15294345
> [ 12.727469] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43456-sdio for chip BCM4345/9
> [ 12.727947] brcmfmac mmc2:0001:1: Direct firmware load for brcm/brcmfmac43456-sdio.khadas,vim1s.bin failed with error -2
> [ 12.813544] brcmfmac mmc2:0001:1: Direct firmware load for brcm/brcmfmac43456-sdio.clm_blob failed with error -2
> [ 13.157373] brcmfmac: brcmf_c_process_clm_blob: no clm_blob available (err=-2), device may have limited channels available
> [ 13.157423] brcmfmac: brcmf_c_process_txcap_blob: no txcap_blob available (err=-2)
> [ 13.159391] brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4345/9 wl0: Jun 16 2017 12:38:26 version 7.45.96.2 (66c4e21@sh-git) (r) FWID 01-1813af84
>
> VIM1S:~ # dmesg | grep brcmfmac
> [ 12.218764] brcmfmac: F1 signature read @0x18000000=0x15294345
> [ 12.283612] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43456-sdio for chip BCM4345/9
> [ 12.382176] brcmfmac mmc2:0001:1: Direct firmware load for brcm/brcmfmac43456-sdio.clm_blob failed with error -2
> [ 12.678015] brcmfmac: brcmf_c_process_clm_blob: no clm_blob available (err=-2), device may have limited channels available
> [ 12.678066] brcmfmac: brcmf_c_process_txcap_blob: no txcap_blob available (err=-2)
> [ 12.680092] brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4345/9 wl0: Jun 16 2017 12:38:26 version 7.45.96.2 (66c4e21@sh-git) (r) FWID 01-1813af84
>
> Is there any chance the same change can be done for the clm_blob and
> txcap_blob error messages? (for the same reason). Other than for RPi
> boards I’ve never seen these files available and used with any large
> scale Linux distro and there are none in the upstream linux-firmware
> repo; thus these files are only being packaged by specialist distros
> or images targeting a specific or limited set of hardware devices. For
> everyone else running a mainstream distro image these errors are just
> log-noise, and while they are harmless and technically correct, end-
> users constantly misinterpret them.
Well, my platform doesn't generate errors/warnings for clm_blob and
txcap_blob, so I don't know which code path triffers them, nor car I test
them.
Best regards,
Alexander
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH ath-next v4] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Rameshkumar Sundaram @ 2026-03-19 11:08 UTC (permalink / raw)
To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260317084740.3756880-1-nico.escande@gmail.com>
On 3/17/2026 2:17 PM, Nicolas Escande wrote:
> On each WMI message received from the hardware, we alloc a temporary array
> of WMI_TAG_MAX entries of type void *. This array is then populated with
> pointers of parsed structs depending on the WMI type, and then freed. This
> alloc can fail when memory pressure in the system is high enough.
>
> Given the fact that it is scheduled in softirq with the system_bh_wq, we
> should not be able to parse more than one WMI message per CPU at any time.
>
> So instead lets move to a per cpu allocated array, that is reused across
> calls: ath12K_wmi_tb that lives in wmi.c of the ath12K module. To alloc &
> free we added two new module_init/exit functions for the module and two
> new wmi functions to alloc/free this memory.
>
> ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
> together as it no longer allocs mem but returns the existing per-cpu one.
>
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
> changes from v3:
> - simplified ath12k_core_init() with a single statement
> - move perpcu.h include directly to wmi.c
>
> changes from v2:
> - removed now superfluous return in ath12k_wmi_event_teardown_complete()
> - moved ath12k_wmi_tb declaration to wmi.c & added two functions to
> alloc / free it
> - removed useless error message on memory allocation failure
>
> changes from v1:
> - rebased on ath-next 27401c9b1432
> - changed wording according to Jeff's comment
> - moved alloc/cleanup to new module_init/exit functions in the
> ath12k module as per Baochen's comment
>
> changes from RFC:
> - rebased on ath-next 8e0ab5b9adb7
> - converted missing call sites ath12k_wmi_obss_color_collision_event()
> & ath12k_wmi_pdev_temperature_event()
> - changed alloc order & cleanup path in ath12k_core_alloc() as it seems
> it confused people
> - used sizeof(*tb) in ath12k_wmi_tlv_parse()
> ---
> drivers/net/wireless/ath/ath12k/core.c | 13 ++
> drivers/net/wireless/ath/ath12k/wmi.c | 201 ++++++++-----------------
> drivers/net/wireless/ath/ath12k/wmi.h | 3 +
> 3 files changed, 78 insertions(+), 139 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index c31c47fb5a73..6c034071cc6d 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -2321,5 +2321,18 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
> return NULL;
> }
>
> +static int ath12k_init(void)
> +{
> + return ath12k_wmi_alloc();
Since CONFIG_ATH12K is tristate, a built-in boot can continue past a
failed ath12k_init() and still run ath12k_wifi7_init().
Please ensure that later initialization path is guarded against
allocation failure.
Or may be have this allocated on first device probe and free it on last
device deinit ?
> +}
> +
> +static void ath12k_exit(void)
> +{
> + ath12k_wmi_free();
> +}
> +
> +module_init(ath12k_init);
> +module_exit(ath12k_exit);
> +
> MODULE_DESCRIPTION("Driver support for Qualcomm Technologies WLAN devices");
> MODULE_LICENSE("Dual BSD/GPL");
--
Ramesh
^ permalink raw reply
* [PATCH v2 iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5
From: Miri Korenblit @ 2026-03-19 9:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260319090927.1090112-1-miriam.rachel.korenblit@intel.com>
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
* [PATCH v2 iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables
From: Miri Korenblit @ 2026-03-19 9:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260319090927.1090112-1-miriam.rachel.korenblit@intel.com>
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
* [PATCH v2 iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG
From: Miri Korenblit @ 2026-03-19 9:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260319090927.1090112-1-miriam.rachel.korenblit@intel.com>
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
* [PATCH v2 iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data
From: Miri Korenblit @ 2026-03-19 9:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260319090927.1090112-1-miriam.rachel.korenblit@intel.com>
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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox