From 37ff03b356ef9d2e960c07596e6fa9276198206d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:22 +0300 Subject: wifi: iwlwifi: align the name of iwl_alive_ntf_v6 to the convention This struct rperesent versions 6 and 7. The convention is to name an API struct with the last version it represent, so rename to iwl_alive_ntf_v7. Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.81240e1d4df3.I2c1264a49b9f0fc160f960cf3c5dc4cedf6ceb6d@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/alive.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 2 +- drivers/net/wireless/intel/iwlwifi/mld/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h index ad5b95cad0bf..ea2ba4b4cb7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h @@ -88,7 +88,7 @@ struct iwl_imr_alive_info { __le32 enabled; } __packed; /* IMR_ALIVE_INFO_API_S_VER_1 */ -struct iwl_alive_ntf_v6 { +struct iwl_alive_ntf_v7 { __le16 status; __le16 flags; struct iwl_lmac_alive lmac_data[2]; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 997b0c9ce984..8d64a271bb94 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -60,7 +60,7 @@ enum iwl_legacy_cmds { * @UCODE_ALIVE_NTFY: * Alive data from the firmware, as described in * &struct iwl_alive_ntf_v3 or &struct iwl_alive_ntf_v4 or - * &struct iwl_alive_ntf_v5 or &struct iwl_alive_ntf_v6. + * &struct iwl_alive_ntf_v5 or &struct iwl_alive_ntf_v7. */ UCODE_ALIVE_NTFY = 0x1, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index b372173c4a79..bdb69c098fd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -126,7 +126,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, switch (version) { case 6: case 7: - expected_sz = sizeof(struct iwl_alive_ntf_v6); + expected_sz = sizeof(struct iwl_alive_ntf_v7); break; case 8: expected_sz = sizeof(struct iwl_alive_ntf); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 865f973f677d..6b76ce35443d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -115,7 +115,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, if (version >= 6) { - struct iwl_alive_ntf_v6 *palive; + struct iwl_alive_ntf_v7 *palive; if (pkt_len < sizeof(*palive)) return false; -- cgit v1.2.3 From 9dc6e9dfdf9d9efe5afd2322e450b83a449993db Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:23 +0300 Subject: wifi: iwlwifi: mld: remove support from of alive notif version 6 The last FW API that supports version 6 is 97. Since this API is no longer supported on any device that loads iwlmld, we can remove support of it. Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.4923c981b0bf.Iff598c6d109fdbf0d5a5bab59d53485478ecc125@changeid --- drivers/net/wireless/intel/iwlwifi/mld/fw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index bdb69c098fd1..b3abfa1ec810 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -124,7 +124,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, u16 status; switch (version) { - case 6: case 7: expected_sz = sizeof(struct iwl_alive_ntf_v7); break; @@ -188,9 +187,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, le32_to_cpu(umac->umac_major), le32_to_cpu(umac->umac_minor)); - if (version >= 7) - IWL_DEBUG_FW(mld, "FW alive flags 0x%x\n", - le16_to_cpu(palive->flags)); + IWL_DEBUG_FW(mld, "FW alive flags 0x%x\n", + le16_to_cpu(palive->flags)); if (version >= 8) IWL_DEBUG_FW(mld, "platform_id 0x%llx\n", -- cgit v1.2.3 From 5c0251598f29646a19a7232c9437b6faa22ab4c2 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:24 +0300 Subject: wifi: iwlwifi: mld: reschedule check_tpt_wk also not in EMLSR When the throughput count reaches the threshold, EMLSR is no longer blocked by throughput. This doesn't mean that EMLSR will be activated immediately, since there might be other reasons that block EMLSR. When the throughput blocker is not set, check_tpt_wk should run every 5 seconds and check if the throughput blocker should be set (if the throughtput counter dropped). If not, it should reschedule itself. In the current code, the worker will reschedule itself only if we are in EMLSR. This is wrong, since we might be in a case where the throughput blocker is not set but we are not in EMLSR, and then we will never check again the throughput counters (and block EMLSR if needed). Fix this by rescheduling the worker also when EMLSR is not active. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.2a9cf2b2529d.I8284c0da9597e4c963e38ae133384f6f42044499@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index 241a6271d13d..fa04fbe06656 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -603,7 +603,7 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) /* EMLSR is not active */ if (sec_link_id == -1) - return; + goto schedule; IWL_DEBUG_INFO(mld, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", sec_link_id, sec_link_tx, sec_link_rx); @@ -625,6 +625,7 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) return; } +schedule: /* Check again when the next window ends */ wiphy_delayed_work_queue(mld_vif->mld->wiphy, &mld_vif->emlsr.check_tpt_wk, -- cgit v1.2.3 From eade5cacc95c3d8b2e88a694a6a0a42dc0dc1819 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 15 Sep 2025 11:34:25 +0300 Subject: wifi: iwlwifi: mvm: move rate conversions to utils.c These aren't really related to rate scaling, they're just firmware API functions. Try to keep rs.c more for scaling and move these out. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.547129c7732e.I12c40876537722680d069b4bb5fc058206ba63d4@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 164 ------------------------- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 3 - drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 164 +++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 167 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b515028adc8f..301d590fe0bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2894,4 +2894,9 @@ iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, void iwl_mvm_smps_workaround(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool update); + +/* rate_n_flags conversion */ +u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver); +__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver); + #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 5802ed80a9ca..d1619a229d8f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -4178,167 +4178,3 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, else return rs_drv_tx_protection(mvm, mvmsta, enable); } - -static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags) -{ - int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1; - int idx; - bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1); - int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0; - int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE; - - for (idx = offset; idx < last; idx++) - if (iwl_fw_rate_idx_to_plcp(idx) == rate) - return idx - offset; - return IWL_RATE_INVALID; -} - -u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver) -{ - u32 rate_v3 = 0, rate_v1; - u32 dup = 0; - - if (rate_ver > 1) - return iwl_v3_rate_from_v2_v3(rate, rate_ver >= 3); - - rate_v1 = le32_to_cpu(rate); - if (rate_v1 == 0) - return rate_v1; - /* convert rate */ - if (rate_v1 & RATE_MCS_HT_MSK_V1) { - u32 nss; - - rate_v3 |= RATE_MCS_MOD_TYPE_HT; - rate_v3 |= - rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1; - nss = u32_get_bits(rate_v1, RATE_HT_MCS_MIMO2_MSK); - rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); - } else if (rate_v1 & RATE_MCS_VHT_MSK_V1 || - rate_v1 & RATE_MCS_HE_MSK_V1) { - u32 nss = u32_get_bits(rate_v1, RATE_VHT_MCS_NSS_MSK); - - rate_v3 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK; - - rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); - - if (rate_v1 & RATE_MCS_HE_MSK_V1) { - u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1; - u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1; - u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >> - RATE_MCS_HE_106T_POS_V1; - u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >> - RATE_MCS_HE_GI_LTF_POS; - - if ((he_type_bits == RATE_MCS_HE_TYPE_SU || - he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) && - he_gi_ltf == RATE_MCS_HE_SU_4_LTF) - /* the new rate have an additional bit to - * represent the value 4 rather then using SGI - * bit for this purpose - as it was done in the - * old rate - */ - he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >> - RATE_MCS_SGI_POS_V1; - - rate_v3 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS; - rate_v3 |= he_type << RATE_MCS_HE_TYPE_POS; - rate_v3 |= he_106t << RATE_MCS_HE_106T_POS; - rate_v3 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK; - rate_v3 |= RATE_MCS_MOD_TYPE_HE; - } else { - rate_v3 |= RATE_MCS_MOD_TYPE_VHT; - } - /* if legacy format */ - } else { - u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1); - - if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID)) - legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ? - IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE; - - rate_v3 |= legacy_rate; - if (!(rate_v1 & RATE_MCS_CCK_MSK_V1)) - rate_v3 |= RATE_MCS_MOD_TYPE_LEGACY_OFDM; - } - - /* convert flags */ - if (rate_v1 & RATE_MCS_LDPC_MSK_V1) - rate_v3 |= RATE_MCS_LDPC_MSK; - rate_v3 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) | - (rate_v1 & RATE_MCS_ANT_AB_MSK) | - (rate_v1 & RATE_MCS_STBC_MSK) | - (rate_v1 & RATE_MCS_BF_MSK); - - dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1; - if (dup) { - rate_v3 |= RATE_MCS_DUP_MSK; - rate_v3 |= dup << RATE_MCS_CHAN_WIDTH_POS; - } - - if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) && - (rate_v1 & RATE_MCS_SGI_MSK_V1)) - rate_v3 |= RATE_MCS_SGI_MSK; - - return rate_v3; -} - -__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver) -{ - u32 result = 0; - int rate_idx; - - if (rate_ver > 1) - return iwl_v3_rate_to_v2_v3(rate, rate_ver > 2); - - switch (rate & RATE_MCS_MOD_TYPE_MSK) { - case RATE_MCS_MOD_TYPE_CCK: - result = RATE_MCS_CCK_MSK_V1; - fallthrough; - case RATE_MCS_MOD_TYPE_LEGACY_OFDM: - rate_idx = u32_get_bits(rate, RATE_LEGACY_RATE_MSK); - if (!(result & RATE_MCS_CCK_MSK_V1)) - rate_idx += IWL_FIRST_OFDM_RATE; - result |= u32_encode_bits(iwl_fw_rate_idx_to_plcp(rate_idx), - RATE_LEGACY_RATE_MSK_V1); - break; - case RATE_MCS_MOD_TYPE_HT: - result = RATE_MCS_HT_MSK_V1; - result |= u32_encode_bits(u32_get_bits(rate, - RATE_HT_MCS_CODE_MSK), - RATE_HT_MCS_RATE_CODE_MSK_V1); - result |= u32_encode_bits(u32_get_bits(rate, - RATE_MCS_NSS_MSK), - RATE_HT_MCS_MIMO2_MSK); - break; - case RATE_MCS_MOD_TYPE_VHT: - result = RATE_MCS_VHT_MSK_V1; - result |= u32_encode_bits(u32_get_bits(rate, - RATE_VHT_MCS_NSS_MSK), - RATE_MCS_CODE_MSK); - result |= u32_encode_bits(u32_get_bits(rate, RATE_MCS_NSS_MSK), - RATE_VHT_MCS_NSS_MSK); - break; - case RATE_MCS_MOD_TYPE_HE: /* not generated */ - default: - WARN_ONCE(1, "bad modulation type %d\n", - u32_get_bits(rate, RATE_MCS_MOD_TYPE_MSK)); - return 0; - } - - if (rate & RATE_MCS_LDPC_MSK) - result |= RATE_MCS_LDPC_MSK_V1; - WARN_ON_ONCE(u32_get_bits(rate, RATE_MCS_CHAN_WIDTH_MSK) > - RATE_MCS_CHAN_WIDTH_160_VAL); - result |= (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) | - (rate & RATE_MCS_ANT_AB_MSK) | - (rate & RATE_MCS_STBC_MSK) | - (rate & RATE_MCS_BF_MSK); - - /* not handling DUP since we don't use it */ - WARN_ON_ONCE(rate & RATE_MCS_DUP_MSK); - - if (rate & RATE_MCS_SGI_MSK) - result |= RATE_MCS_SGI_MSK_V1; - - return cpu_to_le32(result); -} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index dfb062b7c5c2..34c957bef6f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -425,9 +425,6 @@ void iwl_mvm_rate_control_unregister(void); struct iwl_mvm_sta; -u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver); -__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver); - int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 22602c32faa5..aa7af04d914e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1237,3 +1237,167 @@ bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif) return false; } + +static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags) +{ + int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1; + int idx; + bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1); + int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0; + int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE; + + for (idx = offset; idx < last; idx++) + if (iwl_fw_rate_idx_to_plcp(idx) == rate) + return idx - offset; + return IWL_RATE_INVALID; +} + +u32 iwl_mvm_v3_rate_from_fw(__le32 rate, u8 rate_ver) +{ + u32 rate_v3 = 0, rate_v1; + u32 dup = 0; + + if (rate_ver > 1) + return iwl_v3_rate_from_v2_v3(rate, rate_ver >= 3); + + rate_v1 = le32_to_cpu(rate); + if (rate_v1 == 0) + return rate_v1; + /* convert rate */ + if (rate_v1 & RATE_MCS_HT_MSK_V1) { + u32 nss; + + rate_v3 |= RATE_MCS_MOD_TYPE_HT; + rate_v3 |= + rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1; + nss = u32_get_bits(rate_v1, RATE_HT_MCS_MIMO2_MSK); + rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); + } else if (rate_v1 & RATE_MCS_VHT_MSK_V1 || + rate_v1 & RATE_MCS_HE_MSK_V1) { + u32 nss = u32_get_bits(rate_v1, RATE_VHT_MCS_NSS_MSK); + + rate_v3 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK; + + rate_v3 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); + + if (rate_v1 & RATE_MCS_HE_MSK_V1) { + u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1; + u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1; + u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >> + RATE_MCS_HE_106T_POS_V1; + u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >> + RATE_MCS_HE_GI_LTF_POS; + + if ((he_type_bits == RATE_MCS_HE_TYPE_SU || + he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) && + he_gi_ltf == RATE_MCS_HE_SU_4_LTF) + /* the new rate have an additional bit to + * represent the value 4 rather then using SGI + * bit for this purpose - as it was done in the + * old rate + */ + he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >> + RATE_MCS_SGI_POS_V1; + + rate_v3 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS; + rate_v3 |= he_type << RATE_MCS_HE_TYPE_POS; + rate_v3 |= he_106t << RATE_MCS_HE_106T_POS; + rate_v3 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK; + rate_v3 |= RATE_MCS_MOD_TYPE_HE; + } else { + rate_v3 |= RATE_MCS_MOD_TYPE_VHT; + } + /* if legacy format */ + } else { + u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1); + + if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID)) + legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ? + IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE; + + rate_v3 |= legacy_rate; + if (!(rate_v1 & RATE_MCS_CCK_MSK_V1)) + rate_v3 |= RATE_MCS_MOD_TYPE_LEGACY_OFDM; + } + + /* convert flags */ + if (rate_v1 & RATE_MCS_LDPC_MSK_V1) + rate_v3 |= RATE_MCS_LDPC_MSK; + rate_v3 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) | + (rate_v1 & RATE_MCS_ANT_AB_MSK) | + (rate_v1 & RATE_MCS_STBC_MSK) | + (rate_v1 & RATE_MCS_BF_MSK); + + dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1; + if (dup) { + rate_v3 |= RATE_MCS_DUP_MSK; + rate_v3 |= dup << RATE_MCS_CHAN_WIDTH_POS; + } + + if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) && + (rate_v1 & RATE_MCS_SGI_MSK_V1)) + rate_v3 |= RATE_MCS_SGI_MSK; + + return rate_v3; +} + +__le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver) +{ + u32 result = 0; + int rate_idx; + + if (rate_ver > 1) + return iwl_v3_rate_to_v2_v3(rate, rate_ver > 2); + + switch (rate & RATE_MCS_MOD_TYPE_MSK) { + case RATE_MCS_MOD_TYPE_CCK: + result = RATE_MCS_CCK_MSK_V1; + fallthrough; + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: + rate_idx = u32_get_bits(rate, RATE_LEGACY_RATE_MSK); + if (!(result & RATE_MCS_CCK_MSK_V1)) + rate_idx += IWL_FIRST_OFDM_RATE; + result |= u32_encode_bits(iwl_fw_rate_idx_to_plcp(rate_idx), + RATE_LEGACY_RATE_MSK_V1); + break; + case RATE_MCS_MOD_TYPE_HT: + result = RATE_MCS_HT_MSK_V1; + result |= u32_encode_bits(u32_get_bits(rate, + RATE_HT_MCS_CODE_MSK), + RATE_HT_MCS_RATE_CODE_MSK_V1); + result |= u32_encode_bits(u32_get_bits(rate, + RATE_MCS_NSS_MSK), + RATE_HT_MCS_MIMO2_MSK); + break; + case RATE_MCS_MOD_TYPE_VHT: + result = RATE_MCS_VHT_MSK_V1; + result |= u32_encode_bits(u32_get_bits(rate, + RATE_VHT_MCS_NSS_MSK), + RATE_MCS_CODE_MSK); + result |= u32_encode_bits(u32_get_bits(rate, RATE_MCS_NSS_MSK), + RATE_VHT_MCS_NSS_MSK); + break; + case RATE_MCS_MOD_TYPE_HE: /* not generated */ + default: + WARN_ONCE(1, "bad modulation type %d\n", + u32_get_bits(rate, RATE_MCS_MOD_TYPE_MSK)); + return 0; + } + + if (rate & RATE_MCS_LDPC_MSK) + result |= RATE_MCS_LDPC_MSK_V1; + WARN_ON_ONCE(u32_get_bits(rate, RATE_MCS_CHAN_WIDTH_MSK) > + RATE_MCS_CHAN_WIDTH_160_VAL); + result |= (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) | + (rate & RATE_MCS_ANT_AB_MSK) | + (rate & RATE_MCS_STBC_MSK) | + (rate & RATE_MCS_BF_MSK); + + /* not handling DUP since we don't use it */ + WARN_ON_ONCE(rate & RATE_MCS_DUP_MSK); + + if (rate & RATE_MCS_SGI_MSK) + result |= RATE_MCS_SGI_MSK_V1; + + return cpu_to_le32(result); +} -- cgit v1.2.3 From ba85816979360b78a40a3dd0cb8e6f57d6b22456 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:26 +0300 Subject: wifi: iwlwifi: iwlmld is always used for wifi7 devices iwlmld is used since API 97 and for wifi7 devices. Since APIs < 97 are no longer supported on such devices, we can remove the API check and always load iwlmld for the wifi7 devices. Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.45ab33fcdc00.Ia3a40b687b75c872cf7e7a19331a014bccf5f2d6@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 607fcea6f4ef..7d58e294618d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -179,7 +179,8 @@ static inline char iwl_drv_get_step(int step) static bool iwl_drv_is_wifi7_supported(struct iwl_trans *trans) { - return CSR_HW_RFID_TYPE(trans->info.hw_rf_id) >= IWL_CFG_RF_TYPE_FM; + return trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && + CSR_HW_RFID_TYPE(trans->info.hw_rf_id) >= IWL_CFG_RF_TYPE_FM; } const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) @@ -427,7 +428,6 @@ struct iwl_firmware_pieces { size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv; size_t n_mem_tlv; - u32 major; }; static void alloc_sec_data(struct iwl_firmware_pieces *pieces, @@ -1069,19 +1069,19 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, break; case IWL_UCODE_TLV_FW_VERSION: { const __le32 *ptr = (const void *)tlv_data; - u32 minor; + u32 major, minor; u8 local_comp; if (tlv_len != sizeof(u32) * 3) goto invalid_tlv_len; - pieces->major = le32_to_cpup(ptr++); + major = le32_to_cpup(ptr++); minor = le32_to_cpup(ptr++); local_comp = le32_to_cpup(ptr); snprintf(drv->fw.fw_version, sizeof(drv->fw.fw_version), - "%u.%08x.%u %s", pieces->major, minor, + "%u.%08x.%u %s", major, minor, local_comp, iwl_reduced_fw_name(drv)); break; } @@ -1589,8 +1589,6 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) } } -#define IWL_MLD_SUPPORTED_FW_VERSION 97 - /* * iwl_req_fw_callback - callback when firmware was loaded * @@ -1859,12 +1857,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) } #if IS_ENABLED(CONFIG_IWLMLD) - if (pieces->major >= IWL_MLD_SUPPORTED_FW_VERSION && - iwl_drv_is_wifi7_supported(drv->trans)) + if (iwl_drv_is_wifi7_supported(drv->trans)) op = &iwlwifi_opmode_table[MLD_OP_MODE]; #else - if (pieces->major >= IWL_MLD_SUPPORTED_FW_VERSION && - iwl_drv_is_wifi7_supported(drv->trans)) { + if (iwl_drv_is_wifi7_supported(drv->trans)) { IWL_ERR(drv, "IWLMLD needs to be compiled to support this firmware\n"); mutex_unlock(&iwlwifi_opmode_table_mtx); -- cgit v1.2.3 From 30d47d8fe781469ebd4e38240999767f139effb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 15 Sep 2025 11:34:27 +0300 Subject: wifi: iwlwifi: cfg: add new device names Add a couple of device names so that these new devices will be shown correctly. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.1cbc0251532f.I6183a6a08a7998e598042a50c7d7a6b82f9fa58e@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c | 1 + drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c index 97735175cb0e..b8c6b06e7099 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c @@ -13,3 +13,4 @@ const char iwl_killer_be1775i_name[] = const char iwl_be211_name[] = "Intel(R) Wi-Fi 7 BE211 320MHz"; const char iwl_be213_name[] = "Intel(R) Wi-Fi 7 BE213 160MHz"; +const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index a607e7ab914b..cfd1629f0016 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -688,6 +688,7 @@ extern const char iwl_killer_bn1850i_name[]; extern const char iwl_bn201_name[]; extern const char iwl_be221_name[]; extern const char iwl_be223_name[]; +extern const char iwl_ax221_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_rf_cfg iwl5300_agn_cfg; extern const struct iwl_rf_cfg iwl5350_agn_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index b21a4d8eb105..de04a84def0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1061,11 +1061,14 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* WH RF */ IWL_DEV_INFO(iwl_rf_wh, iwl_be211_name, RF_TYPE(WH)), + IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x0514)), + IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x4514)), IWL_DEV_INFO(iwl_rf_wh_160mhz, iwl_be213_name, RF_TYPE(WH), BW_LIMITED), /* PE RF */ IWL_DEV_INFO(iwl_rf_pe, iwl_bn201_name, RF_TYPE(PE)), IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x0524)), + IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x4524)), IWL_DEV_INFO(iwl_rf_pe, iwl_be221_name, RF_TYPE(PE), SUBDEV(0x0324)), /* Killer */ -- cgit v1.2.3 From ef56bbed4c03fc272c65da821d31094b63a8461e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 15 Sep 2025 11:34:28 +0300 Subject: wifi: iwlwifi: tests: check listed PCI IDs have configs Add a test that checks, for the old pre-CNVI devices, that PCI IDs listed in the PCI IDs table will also match in the config table. Newer ones we test against our database of devices, but the current database doesn't go back that far, so at least this checks against the PCI IDs the driver has. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.eb728b270d46.Ie5754f4201b807eb0d55feb339a728fc0b42e8bf@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 1 + drivers/net/wireless/intel/iwlwifi/tests/devinfo.c | 27 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 3e6206e739f6..18c9244ee8ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -90,6 +90,7 @@ const struct iwl_mac_cfg iwl_bz_mac_cfg = { .low_latency_xtal = true, .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_bz_mac_cfg); const struct iwl_mac_cfg iwl_gl_mac_cfg = { .device_family = IWL_DEVICE_FAMILY_BZ, diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index c31bbd4e7a4a..3054bc0a9c67 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -265,6 +265,32 @@ static void devinfo_api_range(struct kunit *test) } } +static void devinfo_pci_ids_config(struct kunit *test) +{ + for (int i = 0; iwl_hw_card_ids[i].vendor; i++) { + const struct pci_device_id *s = &iwl_hw_card_ids[i]; + const struct iwl_dev_info *di; + + if (s->device == PCI_ANY_ID || s->subdevice == PCI_ANY_ID) + continue; + + /* + * The check below only works for old (pre-CNVI) devices. Most + * new have subdevice==ANY, so are already skipped, but for some + * Bz platform(s) we list all the RF PCI IDs. Skip those too. + */ + if (s->driver_data == (kernel_ulong_t)&iwl_bz_mac_cfg) + continue; + + di = iwl_pci_find_dev_info(s->device, s->subdevice, + 0, 0, 0, 0, true); + + KUNIT_EXPECT_PTR_NE_MSG(test, di, NULL, + "PCI ID %04x:%04x not found\n", + s->device, s->subdevice); + } +} + static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_table_order), KUNIT_CASE(devinfo_discrete_match), @@ -276,6 +302,7 @@ static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_pci_ids), KUNIT_CASE(devinfo_no_mac_cfg_dups), KUNIT_CASE(devinfo_api_range), + KUNIT_CASE(devinfo_pci_ids_config), {} }; -- cgit v1.2.3 From 58a4ebe3168813a04bef08f7858a63b199e866e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 15 Sep 2025 11:34:29 +0300 Subject: wifi: iwlwifi: fix remaining kernel-doc warnings Fix the remaining kernel-doc warnings across the driver. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.f94b6d4ef142.I91007eed4cf37125ca7a012f2021615b4fa9eb66@changeid --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 1 + drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h | 4 +- drivers/net/wireless/intel/iwlwifi/fw/api/coex.h | 4 +- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 14 ++-- drivers/net/wireless/intel/iwlwifi/fw/api/debug.h | 2 +- .../net/wireless/intel/iwlwifi/fw/api/location.h | 8 +-- drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 5 +- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 78 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/fw/api/sta.h | 6 +- drivers/net/wireless/intel/iwlwifi/fw/api/stats.h | 39 +++++------ drivers/net/wireless/intel/iwlwifi/fw/api/tx.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 4 +- drivers/net/wireless/intel/iwlwifi/fw/file.h | 74 ++++++++++++++------ drivers/net/wireless/intel/iwlwifi/fw/img.h | 12 ++-- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 22 +++++- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 4 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 4 +- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 17 +++-- drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h | 1 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 6 +- 22 files changed, 194 insertions(+), 118 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 20bc6671f4eb..06cece4ea6d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -151,6 +151,7 @@ union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev, * @mcc: output buffer (3 bytes) that will get the MCC * * This function tries to read the current MCC from ACPI if available. + * Return: 0 on success, or a negative error code */ int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h index d130d4f85444..073f003bdc5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014 Intel Corporation + * Copyright (C) 2005-2014, 2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -98,7 +98,7 @@ struct iwl_cmd_header { } __packed; /** - * struct iwl_cmd_header_wide + * struct iwl_cmd_header_wide - wide command header * * This header format appears in the beginning of each command sent from the * driver, and each response/notification received from uCode. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index ddc84430d895..616f00a8b603 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2023-2024 Intel Corporation + * Copyright (C) 2023-2025 Intel Corporation * Copyright (C) 2013-2014, 2018-2019 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH @@ -52,7 +52,7 @@ struct iwl_bt_coex_cmd { } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /** - * struct iwl_bt_coex_reduced_txp_update_cmd + * struct iwl_bt_coex_reduced_txp_update_cmd - reduced TX power command * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the * bits are the sta_id (value) */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 3173fa96cb48..b62f0687327a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -16,7 +16,7 @@ #define IWL_FW_INI_PRESET_DISABLE 0xff /** - * struct iwl_fw_ini_hcmd + * struct iwl_fw_ini_hcmd - debug configuration host command * * @id: the debug configuration command type for instance: 0xf6 / 0xf5 / DHC * @group: the desired cmd group @@ -199,7 +199,7 @@ struct iwl_fw_ini_region_tlv { } __packed; /* FW_TLV_DEBUG_REGION_API_S_VER_1 */ /** - * struct iwl_fw_ini_debug_info_tlv + * struct iwl_fw_ini_debug_info_tlv - debug info TLV * * debug configuration name for a specific image * @@ -311,7 +311,7 @@ struct iwl_fw_ini_conf_set_tlv { } __packed; /* FW_TLV_DEBUG_CONFIG_SET_API_S_VER_1 */ /** - * enum iwl_fw_ini_config_set_type + * enum iwl_fw_ini_config_set_type - configuration set type * * @IWL_FW_INI_CONFIG_SET_TYPE_INVALID: invalid config set * @IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_PERIPHERY_MAC: for PERIPHERY MAC configuration @@ -337,7 +337,7 @@ enum iwl_fw_ini_config_set_type { } __packed; /** - * enum iwl_fw_ini_allocation_id + * enum iwl_fw_ini_allocation_id - allocation ID * * @IWL_FW_INI_ALLOCATION_INVALID: invalid * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration @@ -356,7 +356,7 @@ enum iwl_fw_ini_allocation_id { }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ /** - * enum iwl_fw_ini_buffer_location + * enum iwl_fw_ini_buffer_location - buffer location * * @IWL_FW_INI_LOCATION_INVALID: invalid * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location @@ -373,7 +373,7 @@ enum iwl_fw_ini_buffer_location { }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ /** - * enum iwl_fw_ini_region_type + * enum iwl_fw_ini_region_type - region type * * @IWL_FW_INI_REGION_INVALID: invalid * @IWL_FW_INI_REGION_TLV: uCode and debug TLVs @@ -437,7 +437,7 @@ enum iwl_fw_ini_region_device_memory_subtype { }; /* FW_TLV_DEBUG_REGION_DEVICE_MEMORY_SUBTYPE_API_E */ /** - * enum iwl_fw_ini_time_point + * enum iwl_fw_ini_time_point - time point type * * Hard coded time points in which the driver can send hcmd or perform dump * collection diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 0cf1e5124fba..61a850de26fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -421,7 +421,7 @@ struct iwl_dbgc1_info { } __packed; /* INIT_DRAM_FRAGS_ALLOCATIONS_S_VER_1 */ /** - * struct iwl_dbg_host_event_cfg_cmd + * struct iwl_dbg_host_event_cfg_cmd - host event config command * @enabled_severities: enabled severities */ struct iwl_dbg_host_event_cfg_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 33541f92c7c7..2ee3a48aa5df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -1092,7 +1092,7 @@ struct iwl_tof_range_req_ap_entry { } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */ /** - * enum iwl_tof_response_mode + * enum iwl_tof_response_mode - TOF response mode * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as * possible (not supported for this release) * @IWL_MVM_TOF_RESPONSE_TIMEOUT: report all AP measurements as a batch upon @@ -1108,7 +1108,7 @@ enum iwl_tof_response_mode { }; /** - * enum iwl_tof_initiator_flags + * enum iwl_tof_initiator_flags - TOF initiator flags * * @IWL_TOF_INITIATOR_FLAGS_FAST_ALGO_DISABLED: disable fast algo, meaning run * the algo on ant A+B, instead of only one of them. @@ -1409,7 +1409,7 @@ enum iwl_tof_range_request_status { }; /** - * enum iwl_tof_entry_status + * enum iwl_tof_entry_status - TOF entry status * * @IWL_TOF_ENTRY_SUCCESS: successful measurement. * @IWL_TOF_ENTRY_GENERAL_FAILURE: General failure. @@ -1856,7 +1856,7 @@ struct iwl_tof_mcsi_notif { } __packed; /** - * struct iwl_tof_range_abort_cmd + * struct iwl_tof_range_abort_cmd - TOF range abort command * @request_id: corresponds to a range request * @reserved: reserved */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 5eb8d10678fd..535864e22626 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -620,7 +620,7 @@ struct iwl_sar_offset_mapping_cmd { } __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/ /** - * struct iwl_beacon_filter_cmd + * struct iwl_beacon_filter_cmd - beacon filter command * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last @@ -762,7 +762,7 @@ enum iwl_6ghz_ap_type { }; /* PHY_AP_TYPE_API_E_VER_1 */ /** - * struct iwl_txpower_constraints_cmd + * struct iwl_txpower_constraints_cmd - TX power constraints command * AP_TX_POWER_CONSTRAINTS_CMD * Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels * @link_id: linkId @@ -786,4 +786,5 @@ struct iwl_txpower_constraints_cmd { __s8 psd_pwr[IWL_MAX_TX_EIRP_PSD_PWR_MAX_SIZE]; u8 reserved[3]; } __packed; /* PHY_AP_TX_POWER_CONSTRAINTS_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_power_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index f486d624500b..60f0a4924ddf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -129,7 +129,7 @@ struct iwl_scan_offload_profile { } __packed; /** - * struct iwl_scan_offload_profile_cfg_data + * struct iwl_scan_offload_profile_cfg_data - scan offload profile configs * @blocklist_len: length of blocklist * @num_profiles: num of profiles in the list * @match_notify: clients waiting for match found notification @@ -159,7 +159,7 @@ struct iwl_scan_offload_profile_cfg_v1 { } __packed; /* SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1-2*/ /** - * struct iwl_scan_offload_profile_cfg + * struct iwl_scan_offload_profile_cfg - scan offload profile config * @profiles: profiles to search for match * @data: the rest of the data for profile_cfg */ @@ -507,7 +507,7 @@ enum iwl_uhb_chan_cfg_flags { IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE = BIT(26), }; /** - * struct iwl_scan_dwell + * struct iwl_scan_dwell - scan dwell configuration * @active: default dwell time for active scan * @passive: default dwell time for passive scan * @fragmented: default dwell time for fragmented scan @@ -728,7 +728,7 @@ enum iwl_umac_scan_general_params_flags2 { }; /** - * struct iwl_scan_channel_cfg_umac + * struct iwl_scan_channel_cfg_umac - scan channel config * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. * @v1: command version 1 @@ -774,7 +774,7 @@ struct iwl_scan_channel_cfg_umac { } __packed; /** - * struct iwl_scan_umac_schedule + * struct iwl_scan_umac_schedule - scan schedule parameters * @interval: interval in seconds between scan iterations * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop * @reserved: for alignment and future use @@ -815,7 +815,7 @@ struct iwl_scan_req_umac_tail_v2 { } __packed; /** - * struct iwl_scan_umac_chan_param + * struct iwl_scan_umac_chan_param - scan channel parameters * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @reserved: for future use and alignment @@ -827,33 +827,37 @@ struct iwl_scan_umac_chan_param { } __packed; /*SCAN_CHANNEL_PARAMS_API_S_VER_1 */ /** - * struct iwl_scan_req_umac + * struct iwl_scan_req_umac - scan request command * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @general_flags: &enum iwl_umac_scan_general_flags + * @reserved: reserved * @scan_start_mac_id: report the scan start TSF time according to this mac TSF - * @extended_dwell: dwell time for channels 1, 6 and 11 - * @active_dwell: dwell time for active scan per LMAC - * @passive_dwell: dwell time for passive scan per LMAC - * @fragmented_dwell: dwell time for fragmented passive scan - * @adwell_default_n_aps: for adaptive dwell the default number of APs + * @v1: version 1 command data + * @v6: version 6 command data + * @v7: version 7 command data + * @v8: version 8 command data + * @v9: version 9 command data + * @v1.extended_dwell: dwell time for channels 1, 6 and 11 + * @v1.active_dwell: dwell time for active scan per LMAC + * @v1.passive_dwell: dwell time for passive scan per LMAC + * @v1.fragmented_dwell: dwell time for fragmented passive scan + * @v7.adwell_default_n_aps: for adaptive dwell the default number of APs * per channel - * @adwell_default_n_aps_social: for adaptive dwell the default + * @v7.adwell_default_n_aps_social: for adaptive dwell the default * number of APs per social (1,6,11) channel - * @general_flags2: &enum iwl_umac_scan_general_flags2 - * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added - * to total scan time - * @max_out_time: max out of serving channel time, per LMAC - for CDB there - * are 2 LMACs - * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs - * @scan_priority: scan internal prioritization &enum iwl_scan_priority - * @num_of_fragments: Number of fragments needed for full coverage per band. + * @v8.general_flags2: &enum iwl_umac_scan_general_flags2 + * @v7.adwell_max_budget: for adaptive dwell the maximal budget of TU to be + * added to total scan time + * @v1.max_out_time: max out of serving channel time, per LMAC - for CDB + * there are 2 LMACs + * @v1.suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs + * @v1.scan_priority: scan internal prioritization &enum iwl_scan_priority + * @v8.num_of_fragments: Number of fragments needed for full coverage per band. * Relevant only for fragmented scan. - * @channel: &struct iwl_scan_umac_chan_param - * @reserved: for future use and alignment - * @reserved3: for future use and alignment - * @data: &struct iwl_scan_channel_cfg_umac and + * @v1.channel: &struct iwl_scan_umac_chan_param + * @v1.data: &struct iwl_scan_channel_cfg_umac and * &struct iwl_scan_req_umac_tail */ struct iwl_scan_req_umac { @@ -939,7 +943,7 @@ struct iwl_scan_req_umac { #define IWL_SCAN_REQ_UMAC_SIZE_V1 36 /** - * struct iwl_scan_probe_params_v3 + * struct iwl_scan_probe_params_v3 - scan probe parameters * @preq: scan probe request params * @ssid_num: number of valid SSIDs in direct scan array * @short_ssid_num: number of valid short SSIDs in short ssid array @@ -961,7 +965,7 @@ struct iwl_scan_probe_params_v3 { } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */ /** - * struct iwl_scan_probe_params_v4 + * struct iwl_scan_probe_params_v4 - scan probe parameters * @preq: scan probe request params * @short_ssid_num: number of valid short SSIDs in short ssid array * @bssid_num: number of valid bssid in bssids array @@ -983,7 +987,7 @@ struct iwl_scan_probe_params_v4 { #define SCAN_MAX_NUM_CHANS_V3 67 /** - * struct iwl_scan_channel_params_v4 + * struct iwl_scan_channel_params_v4 - channel params * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @num_of_aps_override: override the number of APs the FW uses to calculate @@ -1006,7 +1010,7 @@ struct iwl_scan_channel_params_v4 { SCAN_CHANNEL_PARAMS_API_S_VER_5 */ /** - * struct iwl_scan_channel_params_v7 + * struct iwl_scan_channel_params_v7 - channel params * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @n_aps_override: override the number of APs the FW uses to calculate dwell @@ -1024,7 +1028,7 @@ struct iwl_scan_channel_params_v7 { } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ /** - * struct iwl_scan_general_params_v11 + * struct iwl_scan_general_params_v11 - channel params * @flags: &enum iwl_umac_scan_general_flags_v2 * @reserved: reserved for future * @scan_start_mac_or_link_id: report the scan start TSF time according to this @@ -1066,7 +1070,7 @@ struct iwl_scan_general_params_v11 { } __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_12, *_VER_11 and *_VER_10 */ /** - * struct iwl_scan_periodic_parms_v1 + * struct iwl_scan_periodic_parms_v1 - periodicity parameters * @schedule: can scheduling parameter * @delay: initial delay of the periodic scan in seconds * @reserved: reserved for future @@ -1078,7 +1082,7 @@ struct iwl_scan_periodic_parms_v1 { } __packed; /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ /** - * struct iwl_scan_req_params_v12 + * struct iwl_scan_req_params_v12 - scan request parameters (v12) * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v4 * @periodic_params: &struct iwl_scan_periodic_parms_v1 @@ -1106,7 +1110,7 @@ struct iwl_scan_req_params_v17 { } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */ /** - * struct iwl_scan_req_umac_v12 + * struct iwl_scan_req_umac_v12 - scan request command (v12) * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters @@ -1130,7 +1134,7 @@ struct iwl_scan_req_umac_v17 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */ /** - * struct iwl_umac_scan_abort + * struct iwl_umac_scan_abort - scan abort command * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @flags: reserved */ @@ -1140,7 +1144,7 @@ struct iwl_umac_scan_abort { } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ /** - * enum iwl_umac_scan_abort_status + * enum iwl_umac_scan_abort_status - scan abort status * * @IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS: scan was successfully aborted * @IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS: scan abort is in progress @@ -1153,7 +1157,7 @@ enum iwl_umac_scan_abort_status { }; /** - * struct iwl_umac_scan_complete + * struct iwl_umac_scan_complete - scan complete notification * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @last_schedule: last scheduling line * @last_iter: last scan iteration number diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index ecbcd5084cd8..e6f9abdfa546 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2021, 2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021, 2023, 2025 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -428,7 +428,7 @@ struct iwl_mvm_rm_sta_cmd { } __packed; /* REMOVE_STA_CMD_API_S_VER_2 */ /** - * struct iwl_mvm_mgmt_mcast_key_cmd_v1 + * struct iwl_mvm_mgmt_mcast_key_cmd_v1 - IGTK command * ( MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: IGTK key material @@ -449,7 +449,7 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ /** - * struct iwl_mvm_mgmt_mcast_key_cmd + * struct iwl_mvm_mgmt_mcast_key_cmd - IGTK command * ( MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: IGTK master key diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index 00713a991879..8d9a5058d5a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h @@ -26,7 +26,7 @@ struct mvm_statistics_div { } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ /** - * struct mvm_statistics_rx_non_phy + * struct mvm_statistics_rx_non_phy - non-PHY RX statistics * @bogus_cts: CTS received when not expecting CTS * @bogus_ack: ACK received when not expecting ACK * @non_channel_beacons: beacons with our bss id but not on our serving channel @@ -456,7 +456,7 @@ struct iwl_system_statistics_cmd { } __packed; /* STATISTICS_FW_CMD_API_S_VER_1 */ /** - * enum iwl_fw_statistics_type + * enum iwl_fw_statistics_type - statistics type * * @FW_STATISTICS_OPERATIONAL: operational statistics * @FW_STATISTICS_PHY: phy statistics @@ -478,7 +478,7 @@ enum iwl_fw_statistics_type { #define IWL_STATISTICS_TYPE_MSK 0x7f /** - * struct iwl_statistics_ntfy_hdr + * struct iwl_statistics_ntfy_hdr - statistics notification header * * @type: struct type * @version: version of the struct @@ -491,7 +491,7 @@ struct iwl_statistics_ntfy_hdr { }; /* STATISTICS_NTFY_HDR_API_S_VER_1 */ /** - * struct iwl_stats_ntfy_per_link + * struct iwl_stats_ntfy_per_link - per-link statistics * * @beacon_filter_average_energy: Average energy [-dBm] of the 2 * antennas. @@ -514,7 +514,7 @@ struct iwl_stats_ntfy_per_link { } __packed; /* STATISTICS_NTFY_PER_LINK_API_S_VER_1 */ /** - * struct iwl_stats_ntfy_part1_per_link + * struct iwl_stats_ntfy_part1_per_link - part1 per link statistics * * @rx_time: rx time * @tx_time: tx time @@ -533,7 +533,7 @@ struct iwl_stats_ntfy_part1_per_link { } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_PER_LINK_API_S_VER_1 */ /** - * struct iwl_stats_ntfy_per_mac + * struct iwl_stats_ntfy_per_mac - per MAC statistics * * @beacon_filter_average_energy: Average energy [-dBm] of the 2 * antennas. @@ -556,7 +556,8 @@ struct iwl_stats_ntfy_per_mac { } __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */ #define IWL_STATS_MAX_BW_INDEX 5 -/** struct iwl_stats_ntfy_per_phy +/** + * struct iwl_stats_ntfy_per_phy - per PHY statistics * @channel_load: channel load * @channel_load_by_us: device contribution to MCLM * @channel_load_not_by_us: other devices' contribution to MCLM @@ -588,7 +589,7 @@ struct iwl_stats_ntfy_per_phy { #define IWL_STATS_UNKNOWN_CHANNEL_LOAD 0xffffffff /** - * struct iwl_stats_ntfy_per_sta + * struct iwl_stats_ntfy_per_sta - per STA statistics * * @average_energy: in fact it is minus the energy.. */ @@ -600,7 +601,7 @@ struct iwl_stats_ntfy_per_sta { #define IWL_STATS_MAX_FW_LINKS (IWL_FW_MAX_LINK_ID + 1) /** - * struct iwl_system_statistics_notif_oper + * struct iwl_system_statistics_notif_oper - statistics notification * * @time_stamp: time when the notification is sent from firmware * @per_link: per link statistics, &struct iwl_stats_ntfy_per_link @@ -615,7 +616,7 @@ struct iwl_system_statistics_notif_oper { } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */ /** - * struct iwl_system_statistics_part1_notif_oper + * struct iwl_system_statistics_part1_notif_oper - part1 stats notification * * @time_stamp: time when the notification is sent from firmware * @per_link: per link statistics &struct iwl_stats_ntfy_part1_per_link @@ -628,7 +629,7 @@ struct iwl_system_statistics_part1_notif_oper { } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */ /** - * struct iwl_system_statistics_end_notif + * struct iwl_system_statistics_end_notif - statistics end notification * * @time_stamp: time when the notification is sent from firmware */ @@ -637,7 +638,7 @@ struct iwl_system_statistics_end_notif { } __packed; /* STATISTICS_FW_NTFY_END_API_S_VER_1 */ /** - * struct iwl_statistics_operational_ntfy + * struct iwl_statistics_operational_ntfy - operational stats notification * * @hdr: general statistics header * @flags: bitmap of possible notification structures @@ -662,7 +663,7 @@ struct iwl_statistics_operational_ntfy { } __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_15 */ /** - * struct iwl_statistics_operational_ntfy_ver_14 + * struct iwl_statistics_operational_ntfy_ver_14 - operational stats notification * * @hdr: general statistics header * @flags: bitmap of possible notification structures @@ -707,7 +708,7 @@ struct iwl_statistics_operational_ntfy_ver_14 { } __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_14 */ /** - * struct iwl_statistics_phy_ntfy + * struct iwl_statistics_phy_ntfy - PHY statistics notification * * @hdr: general statistics header * RX PHY related statistics @@ -808,7 +809,7 @@ struct iwl_statistics_phy_ntfy { } __packed; /* STATISTICS_PHY_NTFY_API_S_VER_1 */ /** - * struct iwl_statistics_mac_ntfy + * struct iwl_statistics_mac_ntfy - MAC statistics notification * * @hdr: general statistics header * @bcast_filter_passed_per_mac: bcast filter passed per mac @@ -827,7 +828,7 @@ struct iwl_statistics_mac_ntfy { } __packed; /* STATISTICS_MAC_NTFY_API_S_VER_1 */ /** - * struct iwl_statistics_rx_ntfy + * struct iwl_statistics_rx_ntfy - RX statistics notification * * @hdr: general statistics header * @rx_agg_mpdu_cnt: aggregation frame count (number of @@ -867,7 +868,7 @@ struct iwl_statistics_rx_ntfy { } __packed; /* STATISTICS_RX_NTFY_API_S_VER_1 */ /** - * struct iwl_statistics_tx_ntfy + * struct iwl_statistics_tx_ntfy - TX statistics notification * * @hdr: general statistics header * @cts_timeout: timeout when waiting for CTS @@ -976,7 +977,7 @@ struct iwl_statistics_tx_ntfy { } __packed; /* STATISTICS_TX_NTFY_API_S_VER_1 */ /** - * struct iwl_statistics_duration_ntfy + * struct iwl_statistics_duration_ntfy - burst/duration statistics * * @hdr: general statistics header * @cont_burst_chk_cnt: number of times continuation or @@ -995,7 +996,7 @@ struct iwl_statistics_duration_ntfy { } __packed; /* STATISTICS_DURATION_NTFY_API_S_VER_1 */ /** - * struct iwl_statistics_he_ntfy + * struct iwl_statistics_he_ntfy - HE statistics * * @hdr: general statistics header * received HE frames diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 26d2013905ed..31d3336726b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -963,7 +963,7 @@ struct iwl_scd_txq_cfg_cmd { } __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ /** - * struct iwl_scd_txq_cfg_rsp + * struct iwl_scd_txq_cfg_rsp - scheduler TXQ configuration response * @token: taken from the command * @sta_id: station id from the command * @tid: tid from the command diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index c2a73cc85eff..525a82030daa 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -266,7 +266,7 @@ struct iwl_fw_ini_error_dump_data { } __packed; /** - * struct iwl_fw_ini_dump_entry + * struct iwl_fw_ini_dump_entry - dump entry descriptor * @list: list of dump entries * @size: size of the data * @data: entry data @@ -305,7 +305,7 @@ struct iwl_fw_ini_fifo_hdr { * @dram_base_addr: base address of dram monitor range * @page_num: page number of memory range * @fifo_hdr: fifo header of memory range - * @fw_pkt: FW packet header of memory range + * @fw_pkt_hdr: FW packet header of memory range * @data: the actual memory */ struct iwl_fw_ini_error_dump_range { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index b7c1ab7a3006..b9e0b69c6680 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -222,7 +222,10 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL: support for adaptive dwell in scanning + * @IWL_UCODE_TLV_API_OCE: support for OCE + * @IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE: new beacon template * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used + * @IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL: WoWLAN key material support * @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field * indicating low latency direction. * @IWL_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is @@ -245,6 +248,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S. * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of * STA_CONTEXT_DOT11AX_API_S + * @IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE: WoWLAN TCP-SYN wake support * @IWL_UCODE_TLV_API_FTM_RTT_ACCURACY: version 7 of the range response API * is supported by FW, this indicates the RTT confidence value * @IWL_UCODE_TLV_API_SAR_TABLE_VER: This ucode supports different sar @@ -253,6 +257,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * SCAN_CONFIG_DB_CMD_API_S. * @IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP: support for setting adaptive dwell * number of APs in the 5 GHz band + * @IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER: extended channel config in scan * @IWL_UCODE_TLV_API_BAND_IN_RX_DATA: FW reports band number in RX notification * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx * logic. @@ -352,16 +357,24 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT: the firmware supports setting * stabilization latency for SoCs. * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification + * @IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT: binding CDB support + * @IWL_UCODE_TLV_CAPA_CDB_SUPPORT: CDB support + * @IWL_UCODE_TLV_CAPA_D0I3_END_FIRST: D0I3 end command comes first * @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm * @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2 - * IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command + * @IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command * @IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band * (6 GHz). * @IWL_UCODE_TLV_CAPA_CS_MODIFY: firmware supports modify action CSA command + * @IWL_UCODE_TLV_CAPA_SET_LTR_GEN2: LTR gen2 support + * @IWL_UCODE_TLV_CAPA_TAS_CFG: TAS configuration support + * @IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD: session protection command + * @IWL_UCODE_TLV_CAPA_SET_PPAG: PPAG support * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT + * @IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT: MQ RX support * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA * countdown offloading. Beacon notifications are not sent to the host. * The fw also offloads TBTT alignment. @@ -383,23 +396,46 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * command size (command version 4) that supports toggling ACK TX * power reduction. * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3 + * @IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT: LED command support * @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax * capability. * @IWL_UCODE_TLV_CAPA_CSI_REPORTING: firmware is capable of being configured * to report the CSI information with (certain) RX frames + * @IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP: suspend/resume command + * @IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP: support for DBGC + * buffer allocation command * @IWL_UCODE_TLV_CAPA_FTM_CALIBRATED: has FTM calibrated and thus supports both * initiator and responder * @IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA: supports (de)activating UNII-4 * for US/CA/WW from BIOS + * @IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT: supports PSC channels + * @IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT: BIGTK support * @IWL_UCODE_TLV_CAPA_PROTECTED_TWT: Supports protection of TWT action frames * @IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE: Supports the firmware handshake in * reset flow * @IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN: Support for passive scan on 6GHz PSC * channels even when these are not enabled. + * @IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN: hidden SSID 6 GHz scan support + * @IWL_UCODE_TLV_CAPA_BROADCAST_TWT: broadcast TWT support + * @IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO: support for BT-coex high + * priority for 802.1X/4-way-HS + * @IWL_UCODE_TLV_CAPA_BAID_ML_SUPPORT: multi-link BAID support + * @IWL_UCODE_TLV_CAPA_SYNCED_TIME: synced time command support + * @IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM: time sync support + * @IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT: BIGTK TX support + * @IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT: MLD API support + * @IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT: fixed antenna scan support + * @IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT: PPAG China BIOS support + * @IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT: BTM protocol offload support + * @IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT: STA command MFP support + * @IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT: sniffer validate bits support + * @IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT: China 2022 regulator support * @IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT: Support for indicating dump collection * complete to FW. * @IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT: Support SPP (signaling and payload * protected) A-MSDU. + * @IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT: support for DBGC fragmented + * DRAM buffers * @IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT: Support secure LTF measurement. * @IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS: Support monitor mode on otherwise * passive channels @@ -407,6 +443,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * for CA from BIOS. * @IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT: supports %TAS_UHB_ALLOWED_CANADA * @IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT: external FSEQ image support + * @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed + * during assert handling even if the dump isn't split * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of * handling raw DSM table data. * @@ -487,12 +525,7 @@ enum iwl_ucode_tlv_capa { /* set 3 */ IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA = (__force iwl_ucode_tlv_capa_t)96, - - /* - * @IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT: supports PSC channels - */ IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98, - IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100, IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT = (__force iwl_ucode_tlv_capa_t)103, IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104, @@ -514,11 +547,8 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT = (__force iwl_ucode_tlv_capa_t)125, /* set 4 */ - /** - * @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed - * during assert handling even if the dump isn't split - */ - IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), + + IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1), NUM_IWL_UCODE_TLV_CAPA /* @@ -852,6 +882,8 @@ struct iwl_fw_dbg_trigger_low_rssi { * @start_assoc_denied: number of denied association to start recording * @start_assoc_timeout: number of association timeout to start recording * @start_connection_loss: number of connection loss to start recording + * @reserved: reserved + * @reserved2: reserved */ struct iwl_fw_dbg_trigger_mlme { u8 stop_auth_denied; @@ -885,6 +917,7 @@ struct iwl_fw_dbg_trigger_mlme { * @p2p_device: timeout for the queues of a P2P device in ms * @ibss: timeout for the queues of an IBSS in ms * @tdls: timeout for the queues of a TDLS station in ms + * @reserved: reserved */ struct iwl_fw_dbg_trigger_txq_timer { __le32 command_queue; @@ -900,7 +933,7 @@ struct iwl_fw_dbg_trigger_txq_timer { /** * struct iwl_fw_dbg_trigger_time_event - configures a time event trigger - * time_Events: a list of tuples . The driver will issue a + * @time_events: a list of tuples . The driver will issue a * trigger each time a time event notification that relates to time event * id with one of the actions in the bitmap is received and * BIT(notif->status) is set in status_bitmap. @@ -916,19 +949,19 @@ struct iwl_fw_dbg_trigger_time_event { /** * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger - * rx_ba_start: tid bitmap to configure on what tid the trigger should occur + * @rx_ba_start: tid bitmap to configure on what tid the trigger should occur * when an Rx BlockAck session is started. - * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur + * @rx_ba_stop: tid bitmap to configure on what tid the trigger should occur * when an Rx BlockAck session is stopped. - * tx_ba_start: tid bitmap to configure on what tid the trigger should occur + * @tx_ba_start: tid bitmap to configure on what tid the trigger should occur * when a Tx BlockAck session is started. - * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur + * @tx_ba_stop: tid bitmap to configure on what tid the trigger should occur * when a Tx BlockAck session is stopped. - * rx_bar: tid bitmap to configure on what tid the trigger should occur + * @rx_bar: tid bitmap to configure on what tid the trigger should occur * when a BAR is received (for a Tx BlockAck session). - * tx_bar: tid bitmap to configure on what tid the trigger should occur + * @tx_bar: tid bitmap to configure on what tid the trigger should occur * when a BAR is send (for an Rx BlocAck session). - * frame_timeout: tid bitmap to configure on what tid the trigger should occur + * @frame_timeout: tid bitmap to configure on what tid the trigger should occur * when a frame times out in the reordering buffer. */ struct iwl_fw_dbg_trigger_ba { @@ -946,6 +979,7 @@ struct iwl_fw_dbg_trigger_ba { * @action_bitmap: the TDLS action to trigger the collection upon * @peer_mode: trigger on specific peer or all * @peer: the TDLS peer to trigger the collection on + * @reserved: reserved */ struct iwl_fw_dbg_trigger_tdls { u8 action_bitmap; @@ -958,6 +992,7 @@ struct iwl_fw_dbg_trigger_tdls { * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response * status. * @statuses: the list of statuses to trigger the collection on + * @reserved: reserved */ struct iwl_fw_dbg_trigger_tx_status { struct tx_status { @@ -971,6 +1006,7 @@ struct iwl_fw_dbg_trigger_tx_status { * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration. * @id: conf id * @usniffer: should the uSniffer image be used + * @reserved: reserved * @num_of_hcmds: how many HCMDs to send are present here * @hcmd: a variable length host command to be sent to apply the configuration. * If there is more than one HCMD to send, they will appear one after the diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 5256f20623e9..045a3e009429 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -14,14 +14,13 @@ #include "error-dump.h" /** - * enum iwl_ucode_type - * - * The type of ucode. + * enum iwl_ucode_type - type of ucode * * @IWL_UCODE_REGULAR: Normal runtime ucode * @IWL_UCODE_INIT: Initial ucode * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image + * @IWL_UCODE_TYPE_MAX: (internal value) */ enum iwl_ucode_type { IWL_UCODE_REGULAR, @@ -122,7 +121,7 @@ struct fw_img { #define FW_ADDR_CACHE_CONTROL 0xC0000000UL /** - * struct iwl_fw_paging + * struct iwl_fw_paging - FW paging descriptor * @fw_paging_phys: page phy pointer * @fw_paging_block: pointer to the allocated block * @fw_paging_size: page size @@ -197,6 +196,11 @@ struct iwl_dump_exclude { * @dump_excl_wowlan: image dump exclusion areas for WoWLAN image * @pnvm_data: PNVM data embedded in the .ucode file, if any * @pnvm_size: size of the embedded PNVM data + * @dbg: debug data, see &struct iwl_fw_dbg + * @default_calib: default calibration data + * @phy_config: PHY configuration flags + * @valid_rx_ant: valid RX antenna bitmap + * @valid_tx_ant: valid TX antenna bitmap */ struct iwl_fw { u32 ucode_ver; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 806f9bcdf4f5..57570ff15622 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -45,6 +45,8 @@ struct iwl_fwrt_shared_mem_cfg { * struct iwl_fwrt_dump_data - dump data * @trig: trigger the worker was scheduled upon * @fw_pkt: packet received from FW + * @desc: dump descriptor + * @monitor_only: only dump for monitor * * Note that the decision which part of the union is used * is based on iwl_trans_dbg_ini_valid(): the 'trig' part @@ -68,6 +70,7 @@ struct iwl_fwrt_dump_data { * struct iwl_fwrt_wk_data - dump worker data struct * @idx: index of the worker * @wk: worker + * @dump_data: dump data */ struct iwl_fwrt_wk_data { u8 idx; @@ -91,8 +94,8 @@ struct iwl_txf_iter_data { /** * struct iwl_fw_runtime - runtime data for firmware + * @trans: transport pointer * @fw: firmware image - * @cfg: NIC configuration * @dev: device pointer * @ops: user ops * @ops_ctx: user ops context @@ -117,6 +120,23 @@ struct iwl_txf_iter_data { * zero (default initialization) means it hasn't been read yet, * and BIT(0) is set when it has since function 0 also has this * bitmap and is always supported + * @geo_enabled: WGDS table is present + * @geo_num_profiles: number of geo profiles + * @geo_rev: geo profiles table revision + * @ppag_chains: PPAG table data + * @ppag_flags: PPAG flags + * @reduced_power_flags: reduced power flags + * @sanitize_ctx: context for dump sanitizer + * @sanitize_ops: dump sanitizer ops + * @sar_chain_a_profile: SAR chain A profile + * @sar_chain_b_profile: SAR chain B profile + * @sgom_enabled: SGOM enabled + * @sgom_table: SGOM table + * @timestamp: timestamp marker data + * @timestamp.wk: timestamp marking worker + * @timestamp.seq: timestamp marking sequence + * @timestamp.delay: timestamp marking worker delay + * @tpc_enabled: TPC enabled */ struct iwl_fw_runtime { struct iwl_trans *trans; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index cfd1629f0016..0b34c9f90b3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -385,7 +385,7 @@ struct iwl_mac_cfg { #define IWL_NUM_RBDS_EHT (512 * 8) /** - * struct iwl_rf_cfg + * struct iwl_rf_cfg - RF/CRF configuration data * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The * filename is constructed as -.ucode. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 7ed6329fd8ca..fe4e46a0edbd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2023, 2025 Intel Corporation */ #ifndef __iwl_dbg_tlv_h__ #define __iwl_dbg_tlv_h__ @@ -32,7 +32,7 @@ union iwl_dbg_tlv_tp_data { }; /** - * struct iwl_dbg_tlv_time_point_data + * struct iwl_dbg_tlv_time_point_data - debug time point data * @trig_list: list of triggers * @active_trig_list: list of active triggers * @hcmd_list: list of host commands diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 595300a14639..a0b67e8aba8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -62,7 +62,8 @@ struct iwl_rf_cfg; * starts the driver: fetches the firmware. This should be called by bus * specific system flows implementations. For example, the bus specific probe * function should do bus related operations only, and then call to this - * function. It returns the driver object or %NULL if an error occurred. + * function. + * Return: the driver object or %NULL if an error occurred. */ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 21eabfc3ffc8..0476df7b7f17 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022, 2024 Intel Corporation + * Copyright (C) 2005-2014, 2018-2022, 2024-2025 Intel Corporation */ #ifndef __iwl_modparams_h__ #define __iwl_modparams_h__ @@ -42,7 +42,7 @@ enum iwl_uapsd_disable { }; /** - * struct iwl_mod_params + * struct iwl_mod_params - module parameters for iwlwifi * * Holds the module parameters * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index cbc92abf9f87..12f28bb0e859 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -115,11 +115,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, * iwl_parse_nvm_mcc_info - parse MCC (mobile country code) info coming from FW * * This function parses the regulatory channel data received as a - * MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain, - * to be fed into the regulatory core. In case the geo_info is set handle - * accordingly. An ERR_PTR is returned on error. - * If not given to the regulatory core, the user is responsible for freeing - * the regdomain returned here with kfree. + * MCC_UPDATE_CMD command. + * + * Return: a newly allocation regulatory domain, to be given to the regulatory + * core. In case the geo_info is set handle accordingly. An ERR_PTR is + * returned on error. If not given to the regulatory core, the user is + * responsible for freeing the regdomain returned here with kfree(). * * @trans: the transport * @num_of_ch: the number of channels @@ -140,6 +141,8 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans, * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD, * and saved for later use by the driver. Not all NVM sections are saved * this way, only the needed ones. + * @length: length of the section + * @data: section data */ struct iwl_nvm_section { u16 length; @@ -148,6 +151,10 @@ struct iwl_nvm_section { /** * iwl_read_external_nvm - Reads external NVM from a file into nvm_sections + * @trans: the transport + * @nvm_file_name: the filename to request + * @nvm_sections: sections data to fill + * Return: 0 on success or an error code */ int iwl_read_external_nvm(struct iwl_trans *trans, const char *nvm_file_name, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index a146d0e399f2..df6341dfc4a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -185,6 +185,7 @@ void iwl_opmode_deregister(const char *name); /** * struct iwl_op_mode - operational mode * @ops: pointer to its own ops + * @op_mode_specific: per-opmode data * * This holds an implementation of the mac80211 / fw API. */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a0cc5d7745e8..a552669db6e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -121,7 +121,7 @@ enum CMD_MODE { #define DEF_CMD_PAYLOAD_SIZE 320 /** - * struct iwl_device_cmd + * struct iwl_device_cmd - device command structure * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for commands that @@ -516,7 +516,7 @@ enum iwl_trans_state { */ /** - * enum iwl_ini_cfg_state + * enum iwl_ini_cfg_state - debug config state * @IWL_INI_CFG_STATE_NOT_LOADED: no debug cfg was given * @IWL_INI_CFG_STATE_LOADED: debug cfg was found and loaded * @IWL_INI_CFG_STATE_CORRUPTED: debug cfg was found and some of the TLVs @@ -532,7 +532,7 @@ enum iwl_ini_cfg_state { #define IWL_TRANS_NMI_TIMEOUT (HZ / 4) /** - * struct iwl_dram_data + * struct iwl_dram_data - DRAM data descriptor * @physical: page phy pointer * @block: pointer to the allocated block/page * @size: size of the block/page -- cgit v1.2.3 From d852e72d9425ef1401442c0226cd7b936c02a0ca Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:30 +0300 Subject: wifi: iwlwifi: mvm: cleanup unsupported phy command versions The iwlmvm op mode is used for pre EHT HWs. Those HWs doesn't have wider OFDMA, so phy command versions 5+ (that added support for wider OFDMA) are not supported. Remove support for them. This means that we also don't need to set the IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW, as we don't care about the ap chandef anyway. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.e7e26fe71132.I8ec95ff86521661118782ecee1be20ef6e8e48e1@changeid --- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 24 ++++++---------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index b1dca76b7141..380b6f8a53fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -102,9 +102,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, mvm->csme_vif = vif; } - if (vif->p2p || iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) < 5) - vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW; - return 0; out_free_bf: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 5e7e2926be0c..4f4111055ddd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -202,17 +202,13 @@ int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, const struct cfg80211_chan_def *chandef, - const struct cfg80211_chan_def *ap, u8 chains_static, u8 chains_dynamic, u32 action) { int ret; int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1); - if (ver < 5 || !ap || !ap->chan) - ap = NULL; - - if (ver >= 3 && ver <= 6) { + if (ver >= 3 && ver <= 4) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ @@ -223,14 +219,6 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, chains_static, chains_dynamic); - if (ap) { - cmd.sbb_bandwidth = iwl_mvm_get_channel_width(ap); - cmd.sbb_ctrl_channel_loc = iwl_mvm_get_ctrl_pos(ap); - } - - if (ver == 6) - cmd.puncture_mask = cpu_to_le16(chandef->punctured); - ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } else if (ver < 3) { @@ -284,7 +272,7 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, FW_CTXT_ACTION_ADD); @@ -342,7 +330,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, int ret; /* ... remove it here ...*/ - ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, NULL, + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, FW_CTXT_ACTION_REMOVE); if (ret) @@ -356,7 +344,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->width = chandef->width; ctxt->center_freq1 = chandef->center_freq1; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, ap, + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, action); } @@ -376,7 +364,7 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) cfg80211_chandef_create(&chandef, ctxt->channel, NL80211_CHAN_NO_HT); - iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, NULL, 1, 1, + iwl_mvm_phy_ctxt_apply(mvm, ctxt, &chandef, 1, 1, FW_CTXT_ACTION_REMOVE); } -- cgit v1.2.3 From 355431679a910eedc3d1a01cfffaec590a02033b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 15 Sep 2025 11:34:31 +0300 Subject: wifi: iwlwifi: mld: support get/set_antenna This allows to set the antennas from user space. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.5a45baf9513c.I5912e6b6d9a9ae6530d0ac45e9517d07f98b8d05@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 34 +++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mld/mld.h | 11 ++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 5725104a53bf..98d47fed8421 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -23,6 +23,7 @@ #include "roc.h" #include "mlo.h" #include "stats.h" +#include "iwl-nvm-parse.h" #include "ftm-initiator.h" #include "low_latency.h" #include "fw/api/scan.h" @@ -2591,11 +2592,44 @@ iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return NEG_TTLM_RES_ACCEPT; } +static int iwl_mld_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + *tx_ant = iwl_mld_get_valid_tx_ant(mld); + *rx_ant = iwl_mld_get_valid_rx_ant(mld); + + return 0; +} + +static int iwl_mld_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + if (WARN_ON(!mld->nvm_data)) + return -EBUSY; + + /* mac80211 ensures the device is not started, + * so the firmware cannot be running + */ + + mld->set_tx_ant = tx_ant; + mld->set_rx_ant = rx_ant; + + iwl_reinit_cab(mld->trans, mld->nvm_data, tx_ant, rx_ant, mld->fw); + + return 0; +} + const struct ieee80211_ops iwl_mld_hw_ops = { .tx = iwl_mld_mac80211_tx, .start = iwl_mld_mac80211_start, .stop = iwl_mld_mac80211_stop, .config = iwl_mld_mac80211_config, + .get_antenna = iwl_mld_get_antenna, + .set_antenna = iwl_mld_set_antenna, .add_interface = iwl_mld_mac80211_add_interface, .remove_interface = iwl_mld_mac80211_remove_interface, .conf_tx = iwl_mld_mac80211_conf_tx, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 94dc9da6360d..b1d44fdaa61b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -180,6 +180,8 @@ * @mcast_filter_cmd: pointer to the multicast filter command. * @mgmt_tx_ant: stores the last TX antenna index; used for setting * TX rate_n_flags for non-STA mgmt frames (toggles on every TX failure). + * @set_tx_ant: stores the last TX antenna bitmask set by user space (if any) + * @set_rx_ant: stores the last RX antenna bitmask set by user space (if any) * @fw_rates_ver_3: FW rates are in version 3 * @low_latency: low-latency manager. * @tzone: thermal zone device's data @@ -279,6 +281,9 @@ struct iwl_mld { u8 mgmt_tx_ant; + u8 set_tx_ant; + u8 set_rx_ant; + bool fw_rates_ver_3; struct iwl_mld_low_latency low_latency; @@ -374,6 +379,9 @@ static inline u8 iwl_mld_get_valid_tx_ant(const struct iwl_mld *mld) if (mld->nvm_data && mld->nvm_data->valid_tx_ant) tx_ant &= mld->nvm_data->valid_tx_ant; + if (mld->set_tx_ant) + tx_ant &= mld->set_tx_ant; + return tx_ant; } @@ -384,6 +392,9 @@ static inline u8 iwl_mld_get_valid_rx_ant(const struct iwl_mld *mld) if (mld->nvm_data && mld->nvm_data->valid_rx_ant) rx_ant &= mld->nvm_data->valid_rx_ant; + if (mld->set_rx_ant) + rx_ant &= mld->set_rx_ant; + return rx_ant; } -- cgit v1.2.3 From d676e01357682c966b5e135aa3359fd90be85be9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 15 Sep 2025 11:34:32 +0300 Subject: wifi: iwlwifi: mld: set wiphy::iftype_ext_capab dynamically Instead of having a static const array for each possible combination of features, build the extended capabilities dynamically. With this we will also stop setting EHT capabilities when it might actually be disabled. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250915113137.b3c03b56d5a3.I38eaf8ebaf3256e78b4643bef7e3a54aeb4989df@changeid --- drivers/net/wireless/intel/iwlwifi/mld/constants.h | 2 + drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 63 +++++++++++----------- drivers/net/wireless/intel/iwlwifi/mld/mld.h | 4 ++ 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h index 49accf96f44b..5d23a618ae3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h @@ -75,5 +75,7 @@ #define IWL_MLD_FTM_RESP_LMR_FEEDBACK_SUPPORT true #define IWL_MLD_FTM_NON_TB_MIN_TIME_BETWEEN_MSR 7 #define IWL_MLD_FTM_NON_TB_MAX_TIME_BETWEEN_MSR 1000 +#define IWL_MLD_STA_EXT_CAPA_SIZE 9 +#define IWL_MLD_EXT_CAPA_NUM_IFTYPES 1 #endif /* __iwl_mld_constants_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 98d47fed8421..5323c73ac827 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -76,13 +76,12 @@ iwl_mld_iface_combinations[] = { }, }; -static const u8 if_types_ext_capa_sta[] = { - [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, - [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, - [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | - WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB, - [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB, - [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, +static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | + WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB, + [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB, }; #define IWL_MLD_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \ @@ -95,18 +94,6 @@ static const u8 if_types_ext_capa_sta[] = { IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \ IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT) -static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { - { - .iftype = NL80211_IFTYPE_STATION, - .extended_capabilities = if_types_ext_capa_sta, - .extended_capabilities_mask = if_types_ext_capa_sta, - .extended_capabilities_len = sizeof(if_types_ext_capa_sta), - /* relevant only if EHT is supported */ - .eml_capabilities = IWL_MLD_EMLSR_CAPA, - .mld_capa_and_ops = IWL_MLD_CAPA_OPS, - }, -}; - static void iwl_mld_hw_set_addresses(struct iwl_mld *mld) { struct wiphy *wiphy = mld->wiphy; @@ -336,21 +323,37 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PROTECTED_TWT); - wiphy->iftype_ext_capab = NULL; - wiphy->num_iftype_ext_capab = 0; - - if (!iwlwifi_mod_params.disable_11ax) { - wiphy->iftype_ext_capab = iftypes_ext_capa; - wiphy->num_iftype_ext_capab = ARRAY_SIZE(iftypes_ext_capa); - - ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); - ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); - } - if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* We are done for non-HE */ + if (iwlwifi_mod_params.disable_11ax) + return; + + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); + + wiphy->iftype_ext_capab = mld->ext_capab; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(mld->ext_capab); + + BUILD_BUG_ON(sizeof(mld->sta_ext_capab) < sizeof(ext_capa_base)); + + memcpy(mld->sta_ext_capab, ext_capa_base, sizeof(ext_capa_base)); + + mld->ext_capab[0].iftype = NL80211_IFTYPE_STATION; + mld->ext_capab[0].extended_capabilities = mld->sta_ext_capab; + mld->ext_capab[0].extended_capabilities_mask = mld->sta_ext_capab; + mld->ext_capab[0].extended_capabilities_len = sizeof(mld->sta_ext_capab); + + if (!mld->nvm_data->sku_cap_11be_enable || + iwlwifi_mod_params.disable_11be) + return; + + mld->ext_capab[0].eml_capabilities = IWL_MLD_EMLSR_CAPA; + mld->ext_capab[0].mld_capa_and_ops = IWL_MLD_CAPA_OPS; + } static void iwl_mac_hw_set_misc(struct iwl_mld *mld) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index b1d44fdaa61b..ceda12c1672d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -134,6 +134,8 @@ * @fw: a pointer to the fw object * @hw: pointer to the hw object. * @wiphy: a pointer to the wiphy struct, for easier access to it. + * @ext_capab: extended capabilities that will be set to wiphy on registration. + * @sta_ext_capab: extended capabilities for the station interface. * @nvm_data: pointer to the nvm_data that includes all our capabilities * @fwrt: fw runtime data * @debugfs_dir: debugfs directory @@ -227,6 +229,8 @@ struct iwl_mld { const struct iwl_fw *fw; struct ieee80211_hw *hw; struct wiphy *wiphy; + struct wiphy_iftype_ext_capab ext_capab[IWL_MLD_EXT_CAPA_NUM_IFTYPES]; + u8 sta_ext_capab[IWL_MLD_STA_EXT_CAPA_SIZE]; struct iwl_nvm_data *nvm_data; struct iwl_fw_runtime fwrt; struct dentry *debugfs_dir; -- cgit v1.2.3 From 92e87cee465cb5c293aa0a88c4cb5fe5e618583c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:02 +0300 Subject: wifi: iwlwifi: mld: update to new sniffer API This will break current sniffer functionality for firmware versions that don't have the new API, but supporting both would be very complex. Convert the code to use only the new sniffer notification. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.85b75a084a2f.I4a18b2043703c1f9a8f55c108dcaaeca7891e19c@changeid --- .../net/wireless/intel/iwlwifi/fw/api/datapath.h | 5 + drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 286 ++++ drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 6 +- drivers/net/wireless/intel/iwlwifi/mld/mld.c | 1 + drivers/net/wireless/intel/iwlwifi/mld/mld.h | 10 +- drivers/net/wireless/intel/iwlwifi/mld/notif.c | 4 +- drivers/net/wireless/intel/iwlwifi/mld/rx.c | 1649 ++++++++++---------- drivers/net/wireless/intel/iwlwifi/mld/rx.h | 5 +- 8 files changed, 1171 insertions(+), 795 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index b1c6ee8ae2df..6a6e11a57dbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -123,6 +123,11 @@ enum iwl_data_path_subcmd_ids { */ BEACON_FILTER_IN_NOTIF = 0xF8, + /** + * @PHY_AIR_SNIFFER_NOTIF: &struct iwl_rx_phy_air_sniffer_ntfy + */ + PHY_AIR_SNIFFER_NOTIF = 0xF9, + /** * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index d751789998ac..3ed7e0807b90 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -262,6 +262,7 @@ enum iwl_rx_mpdu_reorder_data { }; enum iwl_rx_mpdu_phy_info { + IWL_RX_MPDU_PHY_EOF_INDICATION = BIT(0), IWL_RX_MPDU_PHY_AMPDU = BIT(5), IWL_RX_MPDU_PHY_AMPDU_TOGGLE = BIT(6), IWL_RX_MPDU_PHY_SHORT_PREAMBLE = BIT(7), @@ -1041,4 +1042,289 @@ struct iwl_beacon_filter_notif { __le32 link_id; } __packed; /* BEACON_FILTER_IN_NTFY_API_S_VER_2 */ +union iwl_legacy_sig { +#define OFDM_RX_LEGACY_LENGTH 0x00000fff +#define OFDM_RX_RATE 0x0000f000 + __le32 ofdm; +#define CCK_CRFR_SHORT_PREAMBLE 0x00000040 + __le32 cck; +}; + +struct iwl_ht_sigs { +#define OFDM_RX_FRAME_HT_MCS 0x0000007f +#define OFDM_RX_FRAME_HT_BANDWIDTH 0x00000080 +#define OFDM_RX_FRAME_HT_LENGTH 0x03ffff00 + __le32 a1; + __le32 a2; +}; + +struct iwl_vht_sigs { +#define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM 0x000007ff +#define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID 0x80000000 + __le32 a0; + __le32 a1, a2; +}; + +struct iwl_he_sigs { +#define OFDM_RX_FRAME_HE_BEAM_CHANGE 0x00000001 +#define OFDM_RX_FRAME_HE_UL_FLAG 0x00000002 +#define OFDM_RX_FRAME_HE_MCS 0x0000003c +#define OFDM_RX_FRAME_HE_DCM 0x00000040 +#define OFDM_RX_FRAME_HE_BSS_COLOR 0x00001f80 +#define OFDM_RX_FRAME_HE_SPATIAL_REUSE 0x0001e000 +#define OFDM_RX_FRAME_HE_BANDWIDTH 0x00060000 +#define OFDM_RX_FRAME_HE_SU_EXT_BW10 0x00080000 +#define OFDM_RX_FRAME_HE_GI_LTF_TYPE 0x00700000 +#define OFDM_RX_FRAME_HE_NSTS 0x03800000 +#define OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE 0x0c000000 + __le32 a1; +#define OFDM_RX_FRAME_HE_TXOP_DURATION 0x0000007f +#define OFDM_RX_FRAME_HE_CODING 0x00000080 +#define OFDM_RX_FRAME_HE_CODING_EXTRA_SYM 0x00000100 +#define OFDM_RX_FRAME_HE_STBC 0x00000200 +#define OFDM_RX_FRAME_HE_BF 0x00000400 +#define OFDM_RX_FRAME_HE_PRE_FEC_PAD_FACTOR 0x00001800 +#define OFDM_RX_FRAME_HE_PE_DISAMBIG 0x00002000 +#define OFDM_RX_FRAME_HE_DOPPLER 0x00004000 +#define OFDM_RX_FRAME_HE_TYPE 0x00038000 +#define OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM 0x003c0000 +#define OFDM_RX_FRAME_HE_MU_SIGB_COMP 0x00400000 +#define OFDM_RX_FRAME_HE_MU_NUM_OF_LTF_SYM 0x03800000 + __le32 a2; +#define OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM 0x000007ff +#define OFDM_RX_FRAME_HE_PE_DURATION 0x00003800 +#define OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM_VALID 0x80000000 + __le32 a3; +#define OFDM_RX_FRAME_HE_SIGB_STA_ID_FOUND 0x00000001 +#define OFDM_RX_FRAME_HE_SIGB_STA_ID_INDX 0x0000000e +#define OFDM_RX_FRAME_HE_SIGB_NSTS 0x00000070 +#define OFDM_RX_FRAME_HE_SIGB_BF 0x00000080 +#define OFDM_RX_FRAME_HE_SIGB_MCS 0x00000f00 +#define OFDM_RX_FRAME_HE_SIGB_DCM 0x00001000 +#define OFDM_RX_FRAME_HE_SIGB_CODING 0x00002000 +#define OFDM_RX_FRAME_HE_SIGB_SPATIAL_CONFIG 0x0003c000 +#define OFDM_RX_FRAME_HE_SIGB_STA_RU 0x03fc0000 +#define OFDM_RX_FRAME_HE_SIGB_NUM_OF_SYM 0x3c000000 +#define OFDM_RX_FRAME_HE_SIGB_CRC_OK 0x40000000 + __le32 b; +/* index 0 */ +#define OFDM_RX_FRAME_HE_RU_ALLOC_0_A1 0x000000ff +#define OFDM_RX_FRAME_HE_RU_ALLOC_0_A2 0x0000ff00 +#define OFDM_RX_FRAME_HE_RU_ALLOC_0_B1 0x00ff0000 +#define OFDM_RX_FRAME_HE_RU_ALLOC_0_B2 0xff000000 +/* index 1 */ +#define OFDM_RX_FRAME_HE_RU_ALLOC_1_C1 0x000000ff +#define OFDM_RX_FRAME_HE_RU_ALLOC_1_C2 0x0000ff00 +#define OFDM_RX_FRAME_HE_RU_ALLOC_1_D1 0x00ff0000 +#define OFDM_RX_FRAME_HE_RU_ALLOC_1_D2 0xff000000 +/* index 2 */ +#define OFDM_RX_FRAME_HE_CENTER_RU_CC1 0x00000001 +#define OFDM_RX_FRAME_HE_CENTER_RU_CC2 0x00000002 +#define OFDM_RX_FRAME_HE_COMMON_CC1_CRC_OK 0x00000004 +#define OFDM_RX_FRAME_HE_COMMON_CC2_CRC_OK 0x00000008 + __le32 cmn[3]; +}; + +struct iwl_he_tb_sigs { +#define OFDM_RX_HE_TRIG_FORMAT 0x00000001 +#define OFDM_RX_HE_TRIG_BSS_COLOR 0x0000007e +#define OFDM_RX_HE_TRIG_SPATIAL_REUSE_1 0x00000780 +#define OFDM_RX_HE_TRIG_SPATIAL_REUSE_2 0x00007800 +#define OFDM_RX_HE_TRIG_SPATIAL_REUSE_3 0x00078000 +#define OFDM_RX_HE_TRIG_SPATIAL_REUSE_4 0x00780000 +#define OFDM_RX_HE_TRIG_BANDWIDTH 0x03000000 + __le32 a1; +#define OFDM_RX_HE_TRIG_TXOP_DURATION 0x0000007f +#define OFDM_RX_HE_TRIG_SIG2_RESERVED 0x0000ff80 +#define OFDM_RX_HE_TRIG_FORMAT_ERR 0x08000000 +#define OFDM_RX_HE_TRIG_BW_ERR 0x10000000 +#define OFDM_RX_HE_TRIG_LEGACY_LENGTH_ERR 0x20000000 +#define OFDM_RX_HE_TRIG_CRC_OK 0x40000000 + __le32 a2; +#define OFDM_UCODE_TRIG_BASE_RX_LGCY_LENGTH 0x00000fff +#define OFDM_UCODE_TRIG_BASE_RX_BANDWIDTH 0x00007000 +#define OFDM_UCODE_TRIG_BASE_PS160 0x00008000 +#define OFDM_UCODE_EHT_TRIG_CONTROL_CHANNEL 0x000f0000 + __le32 tb_rx0; +#define OFDM_UCODE_TRIG_BASE_RX_MCS 0x0000000f +#define OFDM_UCODE_TRIG_BASE_RX_DCM 0x00000010 +#define OFDM_UCODE_TRIG_BASE_RX_GI_LTF_TYPE 0x00000060 +#define OFDM_UCODE_TRIG_BASE_RX_NSTS 0x00000380 +#define OFDM_UCODE_TRIG_BASE_RX_CODING 0x00000400 +#define OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM 0x00000800 +#define OFDM_UCODE_TRIG_BASE_RX_STBC 0x00001000 +#define OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR 0x00006000 +#define OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG 0x00008000 +#define OFDM_UCODE_TRIG_BASE_RX_DOPPLER 0x00010000 +#define OFDM_UCODE_TRIG_BASE_RX_RU 0x01fe0000 +#define OFDM_UCODE_TRIG_BASE_RX_RU_P80 0x00020000 +#define OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM 0x0e000000 +#define OFDM_UCODE_TRIG_BASE_RX_LTF_PILOT_TYPE 0x10000000 +#define OFDM_UCODE_TRIG_BASE_RX_LOWEST_SS_ALLOCATION 0xe0000000 + __le32 tb_rx1; +}; + +struct iwl_eht_sigs { +#define OFDM_RX_FRAME_ENHANCED_WIFI_VER_ID 0x00000007 +#define OFDM_RX_FRAME_ENHANCED_WIFI_BANDWIDTH 0x00000038 +#define OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG 0x00000040 +#define OFDM_RX_FRAME_ENHANCED_WIFI_BSS_COLOR 0x00001f80 +#define OFDM_RX_FRAME_ENHANCED_WIFI_TXOP_DURATION 0x000fe000 +#define OFDM_RX_FRAME_EHT_USIG1_DISREGARD 0x01f00000 +#define OFDM_RX_FRAME_EHT_USIG1_VALIDATE 0x02000000 +#define OFDM_RX_FRAME_EHT_BW320_SLOT 0x04000000 +#define OFDM_RX_FRAME_EHT_TYPE 0x18000000 +#define OFDM_RX_FRAME_ENHANCED_ER_NO_STREAMS 0x20000000 + __le32 usig_a1; +#define OFDM_RX_FRAME_EHT_PPDU_TYPE 0x00000003 +#define OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2 0x00000004 +#define OFDM_RX_FRAME_EHT_PUNC_CHANNEL 0x000000f8 +#define OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B8 0x00000100 +#define OFDM_RX_FRAME_EHT_SIG_MCS 0x00000600 +#define OFDM_RX_FRAME_EHT_SIG_SYM_NUM 0x0000f800 +#define OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_1 0x000f0000 +#define OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_2 0x00f00000 +#define OFDM_RX_FRAME_EHT_TRIG_USIG2_DISREGARD 0x1f000000 +#define OFDM_RX_FRAME_EHT_TRIG_NO_STREAMS 0x20000000 +#define OFDM_RX_USIG_CRC_OK 0x40000000 + __le32 usig_a2_eht; +#define OFDM_RX_FRAME_EHT_SPATIAL_REUSE 0x0000000f +#define OFDM_RX_FRAME_EHT_GI_LTF_TYPE 0x00000030 +#define OFDM_RX_FRAME_EHT_NUM_OF_LTF_SYM 0x000001c0 +#define OFDM_RX_FRAME_EHT_CODING_EXTRA_SYM 0x00000200 +#define OFDM_RX_FRAME_EHT_PRE_FEC_PAD_FACTOR 0x00000c00 +#define OFDM_RX_FRAME_EHT_PE_DISAMBIG 0x00001000 +#define OFDM_RX_FRAME_EHT_USIG_OVF_DISREGARD 0x0001e000 +#define OFDM_RX_FRAME_EHT_NUM_OF_USERS 0x000e0000 +#define OFDM_RX_FRAME_EHT_NSTS 0x00f00000 +#define OFDM_RX_FRAME_EHT_BF 0x01000000 +#define OFDM_RX_FRAME_EHT_USIG_OVF_NDP_DISREGARD 0x06000000 +#define OFDM_RX_FRAME_EHTSIG_COMM_CC1_CRC_OK 0x08000000 +#define OFDM_RX_FRAME_EHTSIG_COMM_CC2_CRC_OK 0x10000000 +#define OFDM_RX_FRAME_EHT_NON_VALID_RU_ALLOC 0x20000000 +#define OFDM_RX_FRAME_EHT_NO_STREAMS 0x40000000 + __le32 b1; +#define OFDM_RX_FRAME_EHT_MATCH_ID_FOUND 0x00000001 +#define OFDM_RX_FRAME_EHT_ID_INDX 0x0000000e +#define OFDM_RX_FRAME_EHT_MCS 0x000000f0 +#define OFDM_RX_FRAME_EHT_CODING 0x00000100 +#define OFDM_RX_FRAME_EHT_SPATIAL_CONFIG 0x00007e00 +#define OFDM_RX_FRAME_EHT_STA_RU 0x007f8000 +#define OFDM_RX_FRAME_EHT_STA_RU_P80 0x00008000 +#define OFDM_RX_FRAME_EHT_STA_RU_PS160 0x00800000 +#define OFDM_RX_FRAME_EHT_USER_FIELD_CRC_OK 0x40000000 + __le32 b2; +#define OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM 0x000007ff +#define OFDM_RX_FRAME_EHT_PE_DURATION 0x00003800 +#define OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM_VALID 0x80000000 + __le32 sig2; +#define OFDM_RX_FRAME_EHT_RU_ALLOC_0_A1 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_0_A2 0x0003fe00 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_0_A3 0x07fc0000 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_1_B1 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_1_B2 0x0003fe00 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_1_B3 0x07fc0000 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_2_C1 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_2_C2 0x0003fe00 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_2_C3 0x07fc0000 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_3_D1 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_3_D2 0x0003fe00 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_3_D3 0x07fc0000 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_4_A4 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_4_B4 0x0003fe00 +#define OFDM_RX_FRAME_EHT_RU_ALLOC_5_C4 0x000001ff +#define OFDM_RX_FRAME_EHT_RU_ALLOC_5_D4 0x0003fe00 + __le32 cmn[6]; +#define OFDM_RX_FRAME_EHT_USER_FIELD_ID 0x000007ff + __le32 user_id; +}; + +struct iwl_eht_tb_sigs { + /* same as non-TB above */ + __le32 usig_a1, usig_a2_eht; + /* same as HE TB above */ + __le32 tb_rx0, tb_rx1; +}; + +struct iwl_uhr_sigs { + __le32 usig_a1, usig_a1_uhr, usig_a2_uhr, b1, b2; + __le32 sig2; + __le32 cmn[6]; + __le32 user_id; +}; + +struct iwl_uhr_tb_sigs { + __le32 usig_a1, usig_a2_uhr, tb_rx0, tb_rx1; +}; + +struct iwl_uhr_elr_sigs { + __le32 usig_a1, usig_a2_uhr; + __le32 uhr_sig_elr1, uhr_sig_elr2; +}; + +union iwl_sigs { + struct iwl_ht_sigs ht; + struct iwl_vht_sigs vht; + struct iwl_he_sigs he; + struct iwl_he_tb_sigs he_tb; + struct iwl_eht_sigs eht; + struct iwl_eht_tb_sigs eht_tb; + struct iwl_uhr_sigs uhr; + struct iwl_uhr_tb_sigs uhr_tb; + struct iwl_uhr_elr_sigs uhr_elr; +}; + +enum iwl_sniffer_status { + IWL_SNIF_STAT_PLCP_RX_OK = 0, + IWL_SNIF_STAT_AID_NOT_FOR_US = 1, + IWL_SNIF_STAT_PLCP_RX_LSIG_ERR = 2, + IWL_SNIF_STAT_PLCP_RX_SIGA_ERR = 3, + IWL_SNIF_STAT_PLCP_RX_SIGB_ERR = 4, + IWL_SNIF_STAT_UNEXPECTED_TB = 5, + IWL_SNIF_STAT_UNSUPPORTED_RATE = 6, + IWL_SNIF_STAT_UNKNOWN_ERROR = 7, +}; /* AIR_SNIFFER_STATUS_E_VER_1 */ + +enum iwl_sniffer_flags { + IWL_SNIF_FLAG_VALID_TB_RX = BIT(0), + IWL_SNIF_FLAG_VALID_RU = BIT(1), +}; /* AIR_SNIFFER_FLAGS_E_VER_1 */ + +/** + * struct iwl_rx_phy_air_sniffer_ntfy - air sniffer notification + * + * @status: &enum iwl_sniffer_status + * @flags: &enum iwl_sniffer_flags + * @reserved1: reserved + * @rssi_a: energy chain-A in negative dBm, measured at FINA time + * @rssi_b: energy chain-B in negative dBm, measured at FINA time + * @channel: channel number + * @band: band information, PHY_BAND_* + * @on_air_rise_time: GP2 at on air rise + * @frame_time: frame time in us + * @rate: RATE_MCS_* + * @bytecount: byte count for legay and HT, otherwise number of symbols + * @legacy_sig: CCK signal information if %RATE_MCS_MOD_TYPE_MSK in @rate is + * %RATE_MCS_MOD_TYPE_CCK, otherwise OFDM signal information + * @sigs: PHY signal information, depending on %RATE_MCS_MOD_TYPE_MSK in @rate + * @reserved2: reserved + * + * Sent for every frame and before the normal RX command if data is included. + */ +struct iwl_rx_phy_air_sniffer_ntfy { + u8 status; + u8 flags; + u8 reserved1[2]; + u8 rssi_a, rssi_b; + u8 channel, band; + __le32 on_air_rise_time; + __le32 frame_time; + /* note: MCS in rate is not valid for MU-VHT */ + __le32 rate; + __le32 bytecount; + union iwl_legacy_sig legacy_sig; + union iwl_sigs sigs; + __le32 reserved2; +}; /* RX_PHY_AIR_SNIFFER_NTFY_API_S_VER_1 */ + #endif /* __iwl_fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 5323c73ac827..55b484c16280 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -397,11 +397,9 @@ static int iwl_mld_hw_verify_preconditions(struct iwl_mld *mld) TLC_MNG_UPDATE_NOTIF, 0) >= 4) + (iwl_fw_lookup_notif_ver(mld->fw, LEGACY_GROUP, REPLY_RX_MPDU_CMD, 0) >= 6) + - (iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP, - RX_NO_DATA_NOTIF, 0) >= 4) + (iwl_fw_lookup_notif_ver(mld->fw, LONG_GROUP, TX_CMD, 0) >= 9); - if (ratecheck != 0 && ratecheck != 5) { + if (ratecheck != 0 && ratecheck != 4) { IWL_ERR(mld, "Firmware has inconsistent rates\n"); return -EINVAL; } @@ -684,6 +682,8 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, #endif iwl_mld_rm_vif(mld, vif); + + mld->monitor.phy.valid = false; } struct iwl_mld_mc_iter_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index a6962256bdd1..8a4c96385640 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -259,6 +259,7 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(TLC_MNG_UPDATE_NOTIF), HCMD_NAME(BEACON_FILTER_IN_NOTIF), + HCMD_NAME(PHY_AIR_SNIFFER_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index ceda12c1672d..22efe8e10f53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -118,7 +118,11 @@ * @monitor.cur_bssid: current bssid tracked by the sniffer * @monitor.ptp_time: set the Rx mactime using the device's PTP clock time * @monitor.p80: primary channel position relative to he whole bandwidth, in - * steps of 80 MHz + * steps of 80 MHz + * @monitor.phy: PHY data information + * @monitor.phy.data: PHY data (&struct iwl_rx_phy_air_sniffer_ntfy) received + * @monitor.phy.valid: PHY data is valid (was received) + * @monitor.phy.used: PHY data was used by an RX * @fw_id_to_link_sta: maps a fw id of a sta to the corresponding * ieee80211_link_sta. This is not cleaned up on restart since we want to * preserve the fw sta ids during a restart (for SN/PN restoring). @@ -209,6 +213,10 @@ struct iwl_mld { u32 ampdu_ref; bool ampdu_toggle; u8 p80; + struct { + struct iwl_rx_phy_air_sniffer_ntfy data; + u8 valid:1, used:1; + } phy; #ifdef CONFIG_IWLWIFI_DEBUGFS __le16 cur_aid; u8 cur_bssid[ETH_ALEN]; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 884973d0b344..4cf3920b005f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -589,8 +589,8 @@ void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi, else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP, RX_QUEUES_NOTIFICATION))) iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0); - else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF)) - iwl_mld_rx_monitor_no_data(mld, napi, pkt, 0); + else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, PHY_AIR_SNIFFER_NOTIF)) + iwl_mld_handle_phy_air_sniffer_notif(mld, napi, pkt); else iwl_mld_rx_notif(mld, rxb, pkt); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 20d866dd92c2..052a19bb85b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -18,41 +18,32 @@ /* stores relevant PHY data fields extracted from iwl_rx_mpdu_desc */ struct iwl_mld_rx_phy_data { - enum iwl_rx_phy_info_type info_type; - __le32 data0; - __le32 data1; - __le32 data2; - __le32 data3; - __le32 eht_data4; - __le32 data5; - __le16 data4; + struct iwl_rx_phy_air_sniffer_ntfy *ntfy; bool first_subframe; bool with_data; - __le32 rx_vec[4]; u32 rate_n_flags; u32 gp2_on_air_rise; + /* phy_info is only valid when we have a frame, i.e. with_data=true */ u16 phy_info; u8 energy_a, energy_b; }; static void -iwl_mld_fill_phy_data(struct iwl_mld *mld, - struct iwl_rx_mpdu_desc *desc, - struct iwl_mld_rx_phy_data *phy_data) +iwl_mld_fill_phy_data_from_mpdu(struct iwl_mld *mld, + struct iwl_rx_mpdu_desc *desc, + struct iwl_mld_rx_phy_data *phy_data) { + if (unlikely(mld->monitor.phy.valid)) { + mld->monitor.phy.used = true; + phy_data->ntfy = &mld->monitor.phy.data; + } + phy_data->phy_info = le16_to_cpu(desc->phy_info); phy_data->rate_n_flags = iwl_v3_rate_from_v2_v3(desc->v3.rate_n_flags, mld->fw_rates_ver_3); phy_data->gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise); phy_data->energy_a = desc->v3.energy_a; phy_data->energy_b = desc->v3.energy_b; - phy_data->data0 = desc->v3.phy_data0; - phy_data->data1 = desc->v3.phy_data1; - phy_data->data2 = desc->v3.phy_data2; - phy_data->data3 = desc->v3.phy_data3; - phy_data->data4 = desc->phy_data4; - phy_data->eht_data4 = desc->phy_eht_data4; - phy_data->data5 = desc->v3.phy_data5; phy_data->with_data = true; } @@ -217,26 +208,19 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, } static void -iwl_mld_decode_he_phy_ru_alloc(struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_radiotap_he *he, - struct ieee80211_radiotap_he_mu *he_mu, - struct ieee80211_rx_status *rx_status) +iwl_mld_he_set_ru_alloc(struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_he *he, + u8 ru_with_p80) { - /* Unfortunately, we have to leave the mac80211 data - * incorrect for the case that we receive an HE-MU - * transmission and *don't* have the HE phy data (due - * to the bits being used for TSF). This shouldn't - * happen though as management frames where we need - * the TSF/timers are not be transmitted in HE-MU. - */ - u8 ru = le32_get_bits(phy_data->data1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK); - u32 rate_n_flags = phy_data->rate_n_flags; - u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + u8 ru = ru_with_p80 >> 1; + u8 p80 = ru_with_p80 & 1; u8 offs = 0; rx_status->bw = RATE_INFO_BW_HE_RU; he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); switch (ru) { case 0 ... 36: @@ -266,227 +250,262 @@ iwl_mld_decode_he_phy_ru_alloc(struct iwl_mld_rx_phy_data *phy_data, rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; break; } + he->data2 |= le16_encode_bits(offs, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); - he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); - if (phy_data->data1 & cpu_to_le32(IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80)) - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - -#define CHECK_BW(bw) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ - RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS); \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ - RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) - CHECK_BW(20); - CHECK_BW(40); - CHECK_BW(80); - CHECK_BW(160); - if (he_mu) - he_mu->flags2 |= - le16_encode_bits(u32_get_bits(rate_n_flags, - RATE_MCS_CHAN_WIDTH_MSK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); - else if (he_type == RATE_MCS_HE_TYPE_TRIG) - he->data6 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | - le16_encode_bits(u32_get_bits(rate_n_flags, - RATE_MCS_CHAN_WIDTH_MSK), - IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); + he->data2 |= le16_encode_bits(p80, IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); } +#define RTAP_ENC_HE(src, src_msk, dst_msk) \ + le16_encode_bits(le32_get_bits(src, src_msk), dst_msk) + static void -iwl_mld_decode_he_mu_ext(struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_radiotap_he_mu *he_mu) +iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_he *he, + struct ieee80211_radiotap_he_mu *he_mu, + struct ieee80211_rx_status *rx_status) { - u32 phy_data2 = le32_to_cpu(phy_data->data2); - u32 phy_data3 = le32_to_cpu(phy_data->data3); - u16 phy_data4 = le16_to_cpu(phy_data->data4); u32 rate_n_flags = phy_data->rate_n_flags; - if (u32_get_bits(phy_data4, IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK)) { + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_DCM, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_MCS, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_MU_SIGB_COMP, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); + + if (phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU && + le32_get_bits(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_COMMON_CC1_CRC_OK)) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN); he_mu->flags1 |= - le16_encode_bits(u32_get_bits(phy_data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); - - he_mu->ru_ch1[0] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0); - he_mu->ru_ch1[1] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1); - he_mu->ru_ch1[2] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2); - he_mu->ru_ch1[3] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3); + RTAP_ENC_HE(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_CENTER_RU_CC1, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); + + he_mu->ru_ch1[0] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_A1); + he_mu->ru_ch1[1] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_C1); + he_mu->ru_ch1[2] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_A2); + he_mu->ru_ch1[3] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_C2); } - if (u32_get_bits(phy_data4, IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK) && + if (phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU && + le32_get_bits(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_COMMON_CC2_CRC_OK) && (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); he_mu->flags2 |= - le16_encode_bits(u32_get_bits(phy_data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); - - he_mu->ru_ch2[0] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0); - he_mu->ru_ch2[1] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1); - he_mu->ru_ch2[2] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2); - he_mu->ru_ch2[3] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3); + RTAP_ENC_HE(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_CENTER_RU_CC2, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); + + he_mu->ru_ch2[0] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_B1); + he_mu->ru_ch2[1] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_D1); + he_mu->ru_ch2[2] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_B2); + he_mu->ru_ch2[3] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_D2); } + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + + he_mu->flags2 |= + le16_encode_bits(u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); + + iwl_mld_he_set_ru_alloc(rx_status, he, + le32_get_bits(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_STA_RU)); +} + +static void +iwl_mld_decode_he_tb_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_he *he, + struct ieee80211_rx_status *rx_status) +{ + u32 rate_n_flags = phy_data->rate_n_flags; + u32 nsts; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); + + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_1, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_2, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_3, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_4, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_BSS_COLOR, + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + + he->data6 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | + le16_encode_bits(u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK), + IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); + + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) + return; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_DOPPLER, + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG, + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a2, + OFDM_RX_HE_TRIG_TXOP_DURATION, + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + + iwl_mld_he_set_ru_alloc(rx_status, he, + le32_get_bits(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU)); + + nsts = le32_get_bits(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NSTS) + 1; + rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); } static void iwl_mld_decode_he_phy_data(struct iwl_mld_rx_phy_data *phy_data, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, - struct ieee80211_rx_status *rx_status, - int queue) + struct ieee80211_rx_status *rx_status) { - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_NONE: - case IWL_RX_PHY_INFO_TYPE_CCK: - case IWL_RX_PHY_INFO_TYPE_OFDM_LGCY: - case IWL_RX_PHY_INFO_TYPE_HT: - case IWL_RX_PHY_INFO_TYPE_VHT_SU: - case IWL_RX_PHY_INFO_TYPE_VHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT: - return; - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_SU: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_TB: - /* HE common */ - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); - he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK), - IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); - if (phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB && - phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB_EXT) { - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_UPLINK), - IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - } - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM), - IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK), - IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_PE_DISAMBIG), - IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK), - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); - he->data6 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK), - IEEE80211_RADIOTAP_HE_DATA6_TXOP); - he->data6 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_DOPPLER), - IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); - break; - } + u32 rate_n_flags = phy_data->rate_n_flags; + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + u32 nsts; - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_SU: - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK), - IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); - break; - default: - /* nothing here */ - break; - } + switch (he_type) { + case RATE_MCS_HE_TYPE_TRIG: + iwl_mld_decode_he_tb_phy_data(phy_data, he, rx_status); + /* that's it, below is only for SU/MU */ + return; + case RATE_MCS_HE_TYPE_MU: + iwl_mld_decode_he_mu(phy_data, he, he_mu, rx_status); - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - he_mu->flags1 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); - he_mu->flags2 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - iwl_mld_decode_he_mu_ext(phy_data, he_mu); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_MU: - he_mu->flags2 |= - le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags2 |= - le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_TB: - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - iwl_mld_decode_he_phy_ru_alloc(phy_data, he, he_mu, rx_status); + nsts = le32_get_bits(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_NSTS) + 1; break; - case IWL_RX_PHY_INFO_TYPE_HE_SU: + case RATE_MCS_HE_TYPE_SU: + case RATE_MCS_HE_TYPE_EXT_SU: he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_BEAM_CHNG), - IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); - break; - default: - /* nothing */ + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_BEAM_CHANGE, + IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); + + nsts = le32_get_bits(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_NSTS) + 1; break; } + + rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_PE_DISAMBIG, + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_MU_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_TXOP_DURATION, + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_DOPPLER, + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_BSS_COLOR, + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_UL_FLAG, + IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_SPATIAL_REUSE, + IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); } -static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) +static void iwl_mld_rx_he(struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_he *he = NULL; @@ -510,48 +529,28 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; - u16 phy_info = phy_data->phy_info; he = skb_put_data(skb, &known, sizeof(known)); rx_status->flag |= RX_FLAG_RADIOTAP_HE; - if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU || - phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) { - he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); - rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; - } - - /* report the AMPDU-EOF bit on single frames */ - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - iwl_mld_decode_he_phy_data(phy_data, he, he_mu, rx_status, - queue); - - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && - (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (he_type == RATE_MCS_HE_TYPE_EXT_SU && - rate_n_flags & RATE_MCS_HE_106T_MSK) { - rx_status->bw = RATE_INFO_BW_HE_RU; - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - } - - /* actually data is filled in mac80211 */ - if (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_EXT_SU) + switch (he_type) { + case RATE_MCS_HE_TYPE_EXT_SU: + /* + * Except for this special case we won't have + * HE RU allocation info outside of monitor mode + * since we don't get the PHY notif. + */ + if (rate_n_flags & RATE_MCS_HE_106T_MSK) { + rx_status->bw = RATE_INFO_BW_HE_RU; + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + } + fallthrough; + case RATE_MCS_HE_TYPE_SU: + /* actual data is filled in mac80211 */ he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + break; + } #define CHECK_TYPE(F) \ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ @@ -567,8 +566,7 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, if (rate_n_flags & RATE_MCS_BF_MSK) he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); - switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> - RATE_MCS_HE_GI_LTF_POS) { + switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { case 0: if (he_type == RATE_MCS_HE_TYPE_TRIG) rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; @@ -609,37 +607,52 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + + if (likely(!phy_data->ntfy)) + return; + + if (he_type == RATE_MCS_HE_TYPE_MU) { + he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); + rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; + } + + iwl_mld_decode_he_phy_data(phy_data, he, he_mu, rx_status); } static void iwl_mld_decode_lsig(struct sk_buff *skb, struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; struct ieee80211_radiotap_lsig *lsig; + u32 lsig_len, rate; - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HT: - case IWL_RX_PHY_INFO_TYPE_VHT_SU: - case IWL_RX_PHY_INFO_TYPE_VHT_MU: - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_SU: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT: - lsig = skb_put(skb, sizeof(*lsig)); - lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN); - lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_LSIG_LEN_MASK), - IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH); - rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; - break; - default: - break; - } + if (likely(!phy_data->ntfy)) + return; + + /* + * Technically legacy CCK/OFDM frames don't have an L-SIG + * since that's the compat format for HT (non-greenfield) + * and up. However, it's meant to be compatible with the + * LENGTH and RATE fields in Clause 17 and 18 OFDM frames + * so include the field for any non-CCK frame. For CCK it + * cannot work, since the LENGTH field for them is 16-bit + * and the radiotap field only has 12 bits. + */ + if (format == RATE_MCS_MOD_TYPE_CCK) + return; + + lsig_len = le32_get_bits(phy_data->ntfy->legacy_sig.ofdm, + OFDM_RX_LEGACY_LENGTH); + rate = le32_get_bits(phy_data->ntfy->legacy_sig.ofdm, OFDM_RX_RATE); + + lsig = skb_put(skb, sizeof(*lsig)); + lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN) | + cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_RATE_KNOWN); + lsig->data2 = le16_encode_bits(lsig_len, + IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH) | + le16_encode_bits(rate, IEEE80211_RADIOTAP_LSIG_DATA2_RATE); + rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; } /* Put a TLV on the skb and return data pointer @@ -667,209 +680,144 @@ iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) (_usig)->value |= LE32_DEC_ENC(in_value, dec_bits, _enc_bits); \ } while (0) -#define __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ - eht->data[(rt_data)] |= \ - (cpu_to_le32 \ - (IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \ - LE32_DEC_ENC(data ## fw_data, \ - IWL_RX_PHY_DATA ## fw_data ## _EHT_MU_EXT_RU_ALLOC_ ## fw_ru, \ - IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru)) +static void iwl_mld_decode_eht_usig_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.eht_tb.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht_tb.usig_a2_eht; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PPDU_TYPE, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_1, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_2, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_USIG2_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD); +} -#define _IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ - __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) +static void iwl_mld_decode_eht_usig_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.eht.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht.usig_a2_eht; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, + IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PPDU_TYPE, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PUNC_CHANNEL, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B8, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_SIG_MCS, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_SIG_SYM_NUM, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); +} -#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1 -#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2 -#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2 -#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2 -#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3 -#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3 -#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3 -#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4 +static void iwl_mld_decode_eht_usig(struct iwl_mld_rx_phy_data *phy_data, + struct sk_buff *skb) +{ + u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; + __le32 usig_a1 = phy_data->ntfy->sigs.eht.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht.usig_a2_eht; + struct ieee80211_radiotap_eht_usig *usig; + u32 bw; -#define IWL_RX_RU_DATA_A1 2 -#define IWL_RX_RU_DATA_A2 2 -#define IWL_RX_RU_DATA_B1 2 -#define IWL_RX_RU_DATA_B2 4 -#define IWL_RX_RU_DATA_C1 3 -#define IWL_RX_RU_DATA_C2 3 -#define IWL_RX_RU_DATA_D1 4 -#define IWL_RX_RU_DATA_D2 4 + usig = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, + sizeof(*usig)); -#define IWL_MLD_ENC_EHT_RU(rt_ru, fw_ru) \ - _IWL_MLD_ENC_EHT_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \ - rt_ru, \ - IWL_RX_RU_DATA_ ## fw_ru, \ - fw_ru) + BUILD_BUG_ON(offsetof(union iwl_sigs, eht.usig_a1) != + offsetof(union iwl_sigs, eht_tb.usig_a1)); + BUILD_BUG_ON(offsetof(union iwl_sigs, eht.usig_a2_eht) != + offsetof(union iwl_sigs, eht_tb.usig_a2_eht)); -static void iwl_mld_decode_eht_ext_mu(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) -{ - if (phy_data->with_data) { - __le32 data1 = phy_data->data1; - __le32 data2 = phy_data->data2; - __le32 data3 = phy_data->data3; - __le32 data4 = phy_data->eht_data4; - __le32 data5 = phy_data->data5; - u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_MU_PUNC_CH_CODE, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data4, - IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); - IWL_MLD_ENC_USIG_VALUE_MASK - (usig, data1, IWL_RX_PHY_DATA1_EHT_MU_NUM_SIG_SYM_USIGA2, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN); - eht->user_info[0] |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) | - LE32_DEC_ENC(data5, IWL_RX_PHY_DATA5_EHT_MU_STA_ID_USR, - IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID); +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_ ## bw ## _VAL) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_320MHZ_1 != + RATE_MCS_CHAN_WIDTH_320_VAL); + bw = u32_get_bits(phy_data->rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK); + /* specific handling for 320MHz-1/320MHz-2 */ + if (bw == RATE_MCS_CHAN_WIDTH_320_VAL) + bw += le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_BW320_SLOT); + usig->common |= le32_encode_bits(bw, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW); - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M); - eht->data[7] |= LE32_DEC_ENC - (data5, IWL_RX_PHY_DATA5_EHT_MU_NUM_USR_NON_OFDMA, - IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS); + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_BSS_COLOR, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - /* - * Hardware labels the content channels/RU allocation values - * as follows: - * Content Channel 1 Content Channel 2 - * 20 MHz: A1 - * 40 MHz: A1 B1 - * 80 MHz: A1 C1 B1 D1 - * 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2 - * 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4 - * - * However firmware can only give us A1-D2, so the higher - * frequencies are missing. - */ + if (le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_USIG1_VALIDATE) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B8)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); - switch (phy_bw) { - case RATE_MCS_CHAN_WIDTH_320: - /* additional values are missing in RX metadata */ - fallthrough; - case RATE_MCS_CHAN_WIDTH_160: - /* content channel 1 */ - IWL_MLD_ENC_EHT_RU(1_2_1, A2); - IWL_MLD_ENC_EHT_RU(1_2_2, C2); - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_2_1, B2); - IWL_MLD_ENC_EHT_RU(2_2_2, D2); - fallthrough; - case RATE_MCS_CHAN_WIDTH_80: - /* content channel 1 */ - IWL_MLD_ENC_EHT_RU(1_1_2, C1); - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_1_2, D1); - fallthrough; - case RATE_MCS_CHAN_WIDTH_40: - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_1_1, B1); - fallthrough; - case RATE_MCS_CHAN_WIDTH_20: - IWL_MLD_ENC_EHT_RU(1_1_1, A1); - break; - } - } else { - __le32 usig_a1 = phy_data->rx_vec[0]; - __le32 usig_a2 = phy_data->rx_vec[1]; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_VALIDATE, - IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PPDU_TYPE, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PUNC_CHANNEL, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_SIG_MCS, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); - IWL_MLD_ENC_USIG_VALUE_MASK - (usig, usig_a2, IWL_RX_USIG_A2_EHT_SIG_SYM_NUM, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_CRC_OK, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC); - } -} + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_TXOP_DURATION, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); -static void iwl_mld_decode_eht_ext_tb(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) -{ - if (phy_data->with_data) { - __le32 data5 = phy_data->data5; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE1, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); - } else { - __le32 usig_a1 = phy_data->rx_vec[0]; - __le32 usig_a2 = phy_data->rx_vec[1]; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PPDU_TYPE, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_CRC_OK, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC); - } + if (!le32_get_bits(usig_a2, OFDM_RX_USIG_CRC_OK)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); + + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN); + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_VER_ID, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER); + + if (he_type == RATE_MCS_HE_TYPE_TRIG) + iwl_mld_decode_eht_usig_tb(phy_data, usig); + else + iwl_mld_decode_eht_usig_non_tb(phy_data, usig); } -static void iwl_mld_decode_eht_ru(struct iwl_mld *mld, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht) +static void +iwl_mld_eht_set_ru_alloc(struct ieee80211_rx_status *rx_status, + u32 ru_with_p80) { - u32 ru = le32_get_bits(eht->data[8], - IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); enum nl80211_eht_ru_alloc nl_ru; + u32 ru = ru_with_p80 >> 1; - /* Using D1.5 Table 9-53a - Encoding of PS160 and RU Allocation subfields - * in an EHT variant User Info field + /* + * HW always uses trigger frame format: + * + * Draft PIEEE802.11be D7.0 Table 9-46l - Encoding of the PS160 and + * RU Allocation subfields in an EHT variant User Info field */ switch (ru) { @@ -929,135 +877,228 @@ static void iwl_mld_decode_eht_ru(struct iwl_mld *mld, rx_status->eht.ru = nl_ru; } -static void iwl_mld_decode_eht_phy_data(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) - +static void iwl_mld_decode_eht_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) { - __le32 data0 = phy_data->data0; - __le32 data1 = phy_data->data1; - __le32 usig_a1 = phy_data->rx_vec[0]; - u8 info_type = phy_data->info_type; - - /* Not in EHT range */ - if (info_type < IWL_RX_PHY_INFO_TYPE_EHT_MU || - info_type > IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT) + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) return; - usig->common |= cpu_to_le32 - (IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN | - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN); - if (phy_data->with_data) { - usig->common |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_EHT_UPLINK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); - usig->common |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - } else { - usig->common |= LE32_DEC_ENC(usig_a1, - IWL_RX_USIG_A1_UL_FLAG, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); - usig->common |= LE32_DEC_ENC(usig_a1, - IWL_RX_USIG_A1_BSS_COLOR, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - } + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT | + IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF | + IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80); - usig->common |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED); - usig->common |= - LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_VALIDATE, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); - - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE); - eht->data[0] |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK, - IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE); - - /* All RU allocating size/index is in TB format */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT); - eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160, + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_PS160, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0, - IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7, + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0 | IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG, + IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF); + eht->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_RX_RU_P80, + IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); - iwl_mld_decode_eht_ru(mld, rx_status, eht); - - /* We only get here in case of IWL_RX_MPDU_PHY_TSF_OVERLOAD is set - * which is on only in case of monitor mode so no need to check monitor - * mode - */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80); - eht->data[1] |= - le32_encode_bits(mld->monitor.p80, - IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); - - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN); - if (phy_data->with_data) - usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); - else - usig->common |= LE32_DEC_ENC(usig_a1, IWL_RX_USIG_A1_TXOP_DURATION, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); + iwl_mld_eht_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU)); +} - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_LDPC_EXT_SYM, - IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); +static void iwl_mld_eht_decode_user_ru(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht *eht) +{ + u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PRE_FEC_PAD_MASK, - IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU)) + return; - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PE_DISAMBIG, - IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); +#define __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ + eht->data[(rt_data)] |= \ + (cpu_to_le32(IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \ + LE32_DEC_ENC(phy_data->ntfy->sigs.eht.cmn[fw_data], \ + OFDM_RX_FRAME_EHT_RU_ALLOC_ ## fw_data ## _ ## fw_ru, \ + IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru)) - /* TODO: what about IWL_RX_PHY_DATA0_EHT_BW320_SLOT */ +#define _IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ + __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) - if (!le32_get_bits(data0, IWL_RX_PHY_DATA0_EHT_SIGA_CRC_OK)) - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); +#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_5 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_5 6 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_6 6 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_6 6 + +#define IWL_RX_RU_DATA_A1 0 +#define IWL_RX_RU_DATA_A2 0 +#define IWL_RX_RU_DATA_A3 0 +#define IWL_RX_RU_DATA_A4 4 +#define IWL_RX_RU_DATA_B1 1 +#define IWL_RX_RU_DATA_B2 1 +#define IWL_RX_RU_DATA_B3 1 +#define IWL_RX_RU_DATA_B4 4 +#define IWL_RX_RU_DATA_C1 2 +#define IWL_RX_RU_DATA_C2 2 +#define IWL_RX_RU_DATA_C3 2 +#define IWL_RX_RU_DATA_C4 5 +#define IWL_RX_RU_DATA_D1 3 +#define IWL_RX_RU_DATA_D2 3 +#define IWL_RX_RU_DATA_D3 3 +#define IWL_RX_RU_DATA_D4 5 - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN); - usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PHY_VER, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER); +#define IWL_MLD_ENC_EHT_RU(rt_ru, fw_ru) \ + _IWL_MLD_ENC_EHT_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \ + rt_ru, \ + IWL_RX_RU_DATA_ ## fw_ru, \ + fw_ru) /* - * TODO: what about TB - IWL_RX_PHY_DATA1_EHT_TB_PILOT_TYPE, - * IWL_RX_PHY_DATA1_EHT_TB_LOW_SS + * Hardware labels the content channels/RU allocation values + * as follows: + * + * Content Channel 1 Content Channel 2 + * 20 MHz: A1 + * 40 MHz: A1 B1 + * 80 MHz: A1 C1 B1 D1 + * 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2 + * 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4 */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF); - eht->data[0] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM, + switch (phy_bw) { + case RATE_MCS_CHAN_WIDTH_320: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_2_3, A3); + IWL_MLD_ENC_EHT_RU(1_2_4, C3); + IWL_MLD_ENC_EHT_RU(1_2_5, A4); + IWL_MLD_ENC_EHT_RU(1_2_6, C4); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_2_3, B3); + IWL_MLD_ENC_EHT_RU(2_2_4, D3); + IWL_MLD_ENC_EHT_RU(2_2_5, B4); + IWL_MLD_ENC_EHT_RU(2_2_6, D4); + fallthrough; + case RATE_MCS_CHAN_WIDTH_160: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_2_1, A2); + IWL_MLD_ENC_EHT_RU(1_2_2, C2); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_2_1, B2); + IWL_MLD_ENC_EHT_RU(2_2_2, D2); + fallthrough; + case RATE_MCS_CHAN_WIDTH_80: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_1_2, C1); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_1_2, D1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_40: + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_1_1, B1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_20: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_1_1, A1); + break; + } +} + +static void iwl_mld_decode_eht_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) +{ + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE | + /* All RU allocating size/index is in TB format */ + IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT | + IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF | + IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80 | + IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M); + + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_SPATIAL_REUSE, + IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE); + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU_PS160, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0 | + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_PE_DISAMBIG, + IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NUM_OF_LTF_SYM, IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF); + eht->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU_P80, + IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); + eht->data[7] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NUM_OF_USERS, + IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS); + + iwl_mld_eht_decode_user_ru(phy_data, eht); + + iwl_mld_eht_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU)); +} - if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT || - info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB) - iwl_mld_decode_eht_ext_tb(mld, phy_data, rx_status, eht, usig); +static void iwl_mld_decode_eht_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) +{ + u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; - if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT || - info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU) - iwl_mld_decode_eht_ext_mu(mld, phy_data, rx_status, eht, usig); + if (he_type == RATE_MCS_HE_TYPE_TRIG) + iwl_mld_decode_eht_tb(phy_data, rx_status, eht); + else + iwl_mld_decode_eht_non_tb(phy_data, rx_status, eht); } static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) + struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_eht *eht; - struct ieee80211_radiotap_eht_usig *usig; size_t eht_len = sizeof(*eht); - u32 rate_n_flags = phy_data->rate_n_flags; u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; /* EHT and HE have the same values for LTF */ u8 ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN; - u16 phy_info = phy_data->phy_info; - u32 bw; /* u32 for 1 user_info */ if (phy_data->with_data) @@ -1065,50 +1106,7 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); - usig = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, - sizeof(*usig)); rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; - usig->common |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN); - - /* specific handling for 320MHz */ - bw = u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK); - if (bw == RATE_MCS_CHAN_WIDTH_320_VAL) - bw += le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_EHT_BW320_SLOT); - - usig->common |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW, bw)); - - /* report the AMPDU-EOF bit on single frames */ - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & - cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && - (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & - cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - iwl_mld_decode_eht_phy_data(mld, phy_data, rx_status, eht, usig); - -#define CHECK_TYPE(F) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ - (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS)) - - CHECK_TYPE(SU); - CHECK_TYPE(EXT_SU); - CHECK_TYPE(MU); - CHECK_TYPE(TRIG); switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { case 0: @@ -1144,20 +1142,18 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) { eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI); - eht->data[0] |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_LTF, - ltf) | - FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_GI, - rx_status->eht.gi)); + eht->data[0] |= le32_encode_bits(ltf, + IEEE80211_RADIOTAP_EHT_DATA0_LTF) | + le32_encode_bits(rx_status->eht.gi, + IEEE80211_RADIOTAP_EHT_DATA0_GI); } if (!phy_data->with_data) { eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NSS_S | IEEE80211_RADIOTAP_EHT_KNOWN_BEAMFORMED_S); - eht->data[7] |= - le32_encode_bits(le32_get_bits(phy_data->rx_vec[2], - RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK), - IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); + eht->data[7] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NSTS, + IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); if (rate_n_flags & RATE_MCS_BF_MSK) eht->data[7] |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_DATA7_BEAMFORMED_S); @@ -1177,14 +1173,28 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, eht->user_info[0] |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING); - eht->user_info[0] |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS, - u32_get_bits(rate_n_flags, - RATE_VHT_MCS_RATE_CODE_MSK)) | - FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O, - u32_get_bits(rate_n_flags, - RATE_MCS_NSS_MSK))); + eht->user_info[0] |= + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_VHT_MCS_RATE_CODE_MSK), + IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) | + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_MCS_NSS_MSK), + IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O); } + + if (likely(!phy_data->ntfy)) + return; + + if (phy_data->with_data) { + eht->user_info[0] |= + cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) | + LE32_DEC_ENC(phy_data->ntfy->sigs.eht.user_id, + OFDM_RX_FRAME_EHT_USER_FIELD_ID, + IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID); + } + + iwl_mld_decode_eht_usig(phy_data, skb); + iwl_mld_decode_eht_phy_data(phy_data, rx_status, eht); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1219,34 +1229,30 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, } #endif -/* Note: hdr can be NULL */ -static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, - struct ieee80211_hdr *hdr, - struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) +static void +iwl_mld_set_rx_nonlegacy_rate_info(u32 rate_n_flags, + struct ieee80211_rx_status *rx_status) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; - u32 rate_n_flags = phy_data->rate_n_flags; u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); - bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; - - phy_data->info_type = IWL_RX_PHY_INFO_TYPE_NONE; - if (phy_data->phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - phy_data->info_type = - le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_INFO_TYPE_MASK); - - /* set the preamble flag if appropriate */ - if (format == RATE_MCS_MOD_TYPE_CCK && - phy_data->phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) - rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + /* NSS may be overridden by PHY ntfy with full value */ + rx_status->nss = u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK) + 1; + rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_LDPC_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_LDPC; +} - iwl_mld_fill_signal(mld, link_id, hdr, rx_status, phy_data); +static void iwl_mld_set_rx_rate(struct iwl_mld *mld, + struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status) +{ + u32 rate_n_flags = phy_data->rate_n_flags; + u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); + u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; + bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; - /* This may be overridden by iwl_mld_rx_he() to HE_RU */ + /* bandwidth may be overridden to RU by PHY ntfy */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; @@ -1264,66 +1270,12 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, break; } - /* must be before L-SIG data */ - if (format == RATE_MCS_MOD_TYPE_HE) - iwl_mld_rx_he(mld, skb, phy_data, queue); - - iwl_mld_decode_lsig(skb, phy_data); - - rx_status->device_timestamp = phy_data->gp2_on_air_rise; - - /* using TLV format and must be after all fixed len fields */ - if (format == RATE_MCS_MOD_TYPE_EHT) - iwl_mld_rx_eht(mld, skb, phy_data, queue); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (unlikely(mld->monitor.on)) { - iwl_mld_add_rtap_sniffer_config(mld, skb); - - if (mld->monitor.ptp_time) { - u64 adj_time = - iwl_mld_ptp_get_adj_time(mld, - phy_data->gp2_on_air_rise * - NSEC_PER_USEC); - - rx_status->mactime = div64_u64(adj_time, NSEC_PER_USEC); - rx_status->flag |= RX_FLAG_MACTIME_IS_RTAP_TS64; - rx_status->flag &= ~RX_FLAG_MACTIME; - } - } -#endif - - if (format != RATE_MCS_MOD_TYPE_CCK && is_sgi) - rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - - if (rate_n_flags & RATE_MCS_LDPC_MSK) - rx_status->enc_flags |= RX_ENC_FLAG_LDPC; - switch (format) { - case RATE_MCS_MOD_TYPE_HT: - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags); - rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; - break; - case RATE_MCS_MOD_TYPE_VHT: - case RATE_MCS_MOD_TYPE_HE: - case RATE_MCS_MOD_TYPE_EHT: - if (format == RATE_MCS_MOD_TYPE_VHT) { - rx_status->encoding = RX_ENC_VHT; - } else if (format == RATE_MCS_MOD_TYPE_HE) { - rx_status->encoding = RX_ENC_HE; - rx_status->he_dcm = - !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); - } else if (format == RATE_MCS_MOD_TYPE_EHT) { - rx_status->encoding = RX_ENC_EHT; - } - - rx_status->nss = u32_get_bits(rate_n_flags, - RATE_MCS_NSS_MSK) + 1; - rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; - rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; - break; - default: { + case RATE_MCS_MOD_TYPE_CCK: + if (phy_data->phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) + rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + fallthrough; + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: { int rate = iwl_mld_legacy_hw_idx_to_mac80211_idx(rate_n_flags, rx_status->band); @@ -1337,12 +1289,88 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, /* invalid rate */ rx_status->rate_idx = 0; - if (net_ratelimit()) + /* + * In monitor mode we can see CCK frames on 5 or 6 GHz, usually + * just the (possibly malformed) PHY header by accident, since + * the decoder doesn't seem to turn off CCK. We cannot correctly + * encode the rate to mac80211 (and therefore not in radiotap) + * since we give the per-band index which doesn't cover those + * rates. + */ + if (!mld->monitor.on && net_ratelimit()) IWL_ERR(mld, "invalid rate_n_flags=0x%x, band=%d\n", rate_n_flags, rx_status->band); break; } + case RATE_MCS_MOD_TYPE_HT: + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags); + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + break; + case RATE_MCS_MOD_TYPE_VHT: + rx_status->encoding = RX_ENC_VHT; + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + case RATE_MCS_MOD_TYPE_HE: + rx_status->encoding = RX_ENC_HE; + rx_status->he_dcm = + !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + case RATE_MCS_MOD_TYPE_EHT: + rx_status->encoding = RX_ENC_EHT; + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + default: + WARN_ON_ONCE(1); + } + + if (format != RATE_MCS_MOD_TYPE_CCK && is_sgi) + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; +} + +/* Note: hdr can be NULL */ +static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, + struct ieee80211_hdr *hdr, + struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 rate_n_flags = phy_data->rate_n_flags; + u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; + + iwl_mld_fill_signal(mld, link_id, hdr, rx_status, phy_data); + + rx_status->device_timestamp = phy_data->gp2_on_air_rise; + + iwl_mld_set_rx_rate(mld, phy_data, rx_status); + + /* must be before L-SIG data (radiotap field order) */ + if (format == RATE_MCS_MOD_TYPE_HE) + iwl_mld_rx_he(skb, phy_data); + + iwl_mld_decode_lsig(skb, phy_data); + + /* TLVs - must be after radiotap fixed fields */ + if (format == RATE_MCS_MOD_TYPE_EHT) + iwl_mld_rx_eht(mld, skb, phy_data); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (unlikely(mld->monitor.on)) { + iwl_mld_add_rtap_sniffer_config(mld, skb); + + if (mld->monitor.ptp_time) { + u64 adj_time = + iwl_mld_ptp_get_adj_time(mld, + phy_data->gp2_on_air_rise * + NSEC_PER_USEC); + + rx_status->mactime = div64_u64(adj_time, NSEC_PER_USEC); + rx_status->flag |= RX_FLAG_MACTIME_IS_RTAP_TS64; + rx_status->flag &= ~RX_FLAG_MACTIME; + } } +#endif } /* iwl_mld_create_skb adds the rxb to a new skb */ @@ -1763,13 +1791,36 @@ static int iwl_mld_rx_crypto(struct iwl_mld *mld, return 0; } -static void iwl_mld_rx_update_ampdu_ref(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status) +static void iwl_mld_rx_update_ampdu_data(struct iwl_mld *mld, + struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status) { + u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; bool toggle_bit = phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; + switch (format) { + case RATE_MCS_MOD_TYPE_CCK: + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: + /* no aggregation possible */ + return; + case RATE_MCS_MOD_TYPE_HT: + case RATE_MCS_MOD_TYPE_VHT: + /* single frames are not A-MPDU format */ + if (!(phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU)) + return; + break; + default: + /* HE/EHT/UHR have A-MPDU format for single frames */ + if (!(phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->phy_info & IWL_RX_MPDU_PHY_EOF_INDICATION) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + return; + } + } + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; /* Toggle is switched whenever new aggregation starts. Make * sure ampdu_reference is never 0 so we can later use it to @@ -1781,6 +1832,11 @@ static void iwl_mld_rx_update_ampdu_ref(struct iwl_mld *mld, mld->monitor.ampdu_ref++; mld->monitor.ampdu_toggle = toggle_bit; phy_data->first_subframe = true; + + /* report EOF bit on the first subframe */ + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->phy_info & IWL_RX_MPDU_PHY_EOF_INDICATION) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } rx_status->ampdu_reference = mld->monitor.ampdu_ref; } @@ -1824,6 +1880,8 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, "FW lied about packet len (%d)\n", pkt_len)) return; + iwl_mld_fill_phy_data_from_mpdu(mld, mpdu_desc, &phy_data); + /* Don't use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ @@ -1835,8 +1893,6 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, hdr = (void *)(pkt->data + mpdu_desc_size); - iwl_mld_fill_phy_data(mld, mpdu_desc, &phy_data); - if (mpdu_desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { /* If the device inserted padding it means that (it thought) * the 802.11 header wasn't a multiple of 4 bytes long. In @@ -1861,9 +1917,8 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, if (drop) goto drop; - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_data.phy_info & IWL_RX_MPDU_PHY_AMPDU)) - iwl_mld_rx_update_ampdu_ref(mld, &phy_data, rx_status); + if (unlikely(mld->monitor.on)) + iwl_mld_rx_update_ampdu_data(mld, &phy_data, rx_status); /* Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. @@ -1897,7 +1952,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, link_id = u8_get_bits(mpdu_desc->mac_phy_band, IWL_RX_MPDU_MAC_PHY_BAND_LINK_MASK); - iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data, queue); + iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data); if (iwl_mld_rx_crypto(mld, sta, hdr, rx_status, mpdu_desc, queue, le32_to_cpu(pkt->len_n_flags), &crypto_len)) @@ -2031,87 +2086,64 @@ void iwl_mld_handle_rx_queues_sync_notif(struct iwl_mld *mld, wake_up(&mld->rxq_sync.waitq); } -void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, - struct iwl_rx_packet *pkt, int queue) +static void iwl_mld_no_data_rx(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_phy_air_sniffer_ntfy *ntfy) { - struct iwl_rx_no_data_ver_3 *desc; - struct iwl_mld_rx_phy_data phy_data; struct ieee80211_rx_status *rx_status; + struct iwl_mld_rx_phy_data phy_data = { + .ntfy = ntfy, + .phy_info = 0, /* short preamble set below */ + .rate_n_flags = le32_to_cpu(ntfy->rate), + .gp2_on_air_rise = le32_to_cpu(ntfy->on_air_rise_time), + .energy_a = ntfy->rssi_a, + .energy_b = ntfy->rssi_b, + }; + u32 format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; struct sk_buff *skb; - u32 format, rssi; - u8 channel; - if (unlikely(mld->fw_status.in_hw_restart)) - return; - - if (IWL_FW_CHECK(mld, iwl_rx_packet_payload_len(pkt) < sizeof(*desc), - "Bad RX_NO_DATA_NOTIF size (%d)\n", - iwl_rx_packet_payload_len(pkt))) - return; - - desc = (void *)pkt->data; - - rssi = le32_to_cpu(desc->rssi); - channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); - - phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK); - phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK); - phy_data.data0 = desc->phy_info[0]; - phy_data.data1 = desc->phy_info[1]; - phy_data.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD; - phy_data.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); - phy_data.rate_n_flags = iwl_v3_rate_from_v2_v3(desc->rate, - mld->fw_rates_ver_3); - phy_data.with_data = false; - - BUILD_BUG_ON(sizeof(phy_data.rx_vec) != sizeof(desc->rx_vec)); - memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec)); - - format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; - - /* Don't use dev_alloc_skb(), we'll have enough headroom once - * ieee80211_hdr pulled. - */ skb = alloc_skb(128, GFP_ATOMIC); - if (!skb) { - IWL_ERR(mld, "alloc_skb failed\n"); + if (!skb) return; - } rx_status = IEEE80211_SKB_RXCB(skb); /* 0-length PSDU */ rx_status->flag |= RX_FLAG_NO_PSDU; - /* mark as failed PLCP on any errors to skip checks in mac80211 */ - if (le32_get_bits(desc->info, RX_NO_DATA_INFO_ERR_MSK) != - RX_NO_DATA_INFO_ERR_NONE) - rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; - - switch (le32_get_bits(desc->info, RX_NO_DATA_INFO_TYPE_MSK)) { - case RX_NO_DATA_INFO_TYPE_NDP: + switch (ntfy->status) { + case IWL_SNIF_STAT_PLCP_RX_OK: + /* we only get here with sounding PPDUs */ rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; break; - case RX_NO_DATA_INFO_TYPE_MU_UNMATCHED: - case RX_NO_DATA_INFO_TYPE_TB_UNMATCHED: + case IWL_SNIF_STAT_AID_NOT_FOR_US: rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED; break; + case IWL_SNIF_STAT_PLCP_RX_LSIG_ERR: + case IWL_SNIF_STAT_PLCP_RX_SIGA_ERR: + case IWL_SNIF_STAT_PLCP_RX_SIGB_ERR: + case IWL_SNIF_STAT_UNKNOWN_ERROR: default: + rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; + fallthrough; + case IWL_SNIF_STAT_UNEXPECTED_TB: + case IWL_SNIF_STAT_UNSUPPORTED_RATE: rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR; - break; + /* we could include the real reason in a vendor TLV */ } - rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : - NL80211_BAND_2GHZ; + if (format == RATE_MCS_MOD_TYPE_CCK && + ntfy->legacy_sig.cck & cpu_to_le32(CCK_CRFR_SHORT_PREAMBLE)) + phy_data.phy_info |= IWL_RX_MPDU_PHY_SHORT_PREAMBLE; - rx_status->freq = ieee80211_channel_to_frequency(channel, - rx_status->band); + iwl_mld_fill_rx_status_band_freq(IEEE80211_SKB_RXCB(skb), + ntfy->band, ntfy->channel); /* link ID is ignored for NULL header */ - iwl_mld_rx_fill_status(mld, -1, NULL, skb, &phy_data, queue); + iwl_mld_rx_fill_status(mld, -1, NULL, skb, &phy_data); /* No more radiotap info should be added after this point. * Mark it as mac header for upper layers to know where @@ -2119,29 +2151,72 @@ void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, */ skb_set_mac_header(skb, skb->len); - /* Override the nss from the rx_vec since the rate_n_flags has - * only 1 bit for the nss which gives a max of 2 ss but there - * may be up to 8 spatial streams. - */ - switch (format) { + /* pass the packet to mac80211 */ + rcu_read_lock(); + ieee80211_rx_napi(mld->hw, NULL, skb, napi); + rcu_read_unlock(); +} + +void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_packet *pkt) +{ + struct iwl_rx_phy_air_sniffer_ntfy *ntfy = (void *)pkt->data; + bool is_ndp = false; + u32 he_type; + + if (IWL_FW_CHECK(mld, iwl_rx_packet_payload_len(pkt) < sizeof(*ntfy), + "invalid air sniffer notification size\n")) + return; + + /* check if there's an old one to release as errored */ + if (mld->monitor.phy.valid && !mld->monitor.phy.used) { + /* didn't capture data, so override status */ + mld->monitor.phy.data.status = IWL_SNIF_STAT_AID_NOT_FOR_US; + iwl_mld_no_data_rx(mld, napi, &mld->monitor.phy.data); + } + + /* old data is no longer valid now */ + mld->monitor.phy.valid = false; + + he_type = le32_to_cpu(ntfy->rate) & RATE_MCS_HE_TYPE_MSK; + + switch (le32_to_cpu(ntfy->rate) & RATE_MCS_MOD_TYPE_MSK) { + case RATE_MCS_MOD_TYPE_HT: + is_ndp = !le32_get_bits(ntfy->sigs.ht.a1, + OFDM_RX_FRAME_HT_LENGTH); + break; case RATE_MCS_MOD_TYPE_VHT: - rx_status->nss = - le32_get_bits(desc->rx_vec[0], - RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1; + is_ndp = le32_get_bits(ntfy->sigs.vht.a0, + OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.vht.a0, + OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM); break; case RATE_MCS_MOD_TYPE_HE: - rx_status->nss = - le32_get_bits(desc->rx_vec[0], - RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + break; + is_ndp = le32_get_bits(ntfy->sigs.he.a3, + OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.he.a3, + OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM); break; case RATE_MCS_MOD_TYPE_EHT: - rx_status->nss = - le32_get_bits(desc->rx_vec[2], - RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK) + 1; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + break; + is_ndp = le32_get_bits(ntfy->sigs.eht.sig2, + OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.eht.sig2, + OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM); + break; } - /* pass the packet to mac80211 */ - rcu_read_lock(); - ieee80211_rx_napi(mld->hw, NULL, skb, napi); - rcu_read_unlock(); + if (ntfy->status != IWL_SNIF_STAT_PLCP_RX_OK || is_ndp) { + iwl_mld_no_data_rx(mld, napi, ntfy); + return; + } + + /* hang on to it for the RX_MPDU data packet(s) */ + mld->monitor.phy.data = *ntfy; + mld->monitor.phy.valid = true; + mld->monitor.phy.used = false; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.h b/drivers/net/wireless/intel/iwlwifi/mld/rx.h index 2beabd7e70b1..09dddbd40f55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.h @@ -66,7 +66,8 @@ void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld, struct sk_buff *skb, int queue, struct ieee80211_sta *sta); -void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, - struct iwl_rx_packet *pkt, int queue); +void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_packet *pkt); #endif /* __iwl_mld_agg_h__ */ -- cgit v1.2.3 From 38f79506195c32f4f1d1fe5808e7294cd1f298ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:03 +0300 Subject: wifi: iwlwifi: mld: include raw PHY notification in radiotap This is useful for debugging and can also be used to see anything that isn't encoded in radiotap (yet.) Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.5fe26e9061f2.Iefb45e3a6a2a62ff3247db4de3777059d390af95@changeid --- drivers/net/wireless/intel/iwlwifi/mld/rx.c | 45 +++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 052a19bb85b4..19e78d2fbf9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -1217,8 +1217,9 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, radiotap->oui[0] = 0xf6; radiotap->oui[1] = 0x54; radiotap->oui[2] = 0x25; - /* radiotap sniffer config sub-namespace */ + /* Intel OUI default radiotap subtype */ radiotap->oui_subtype = 1; + /* Sniffer config element type */ radiotap->vendor_type = 0; /* fill the data now */ @@ -1229,6 +1230,34 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, } #endif +static void iwl_mld_add_rtap_sniffer_phy_data(struct iwl_mld *mld, + struct sk_buff *skb, + struct iwl_rx_phy_air_sniffer_ntfy *ntfy) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_radiotap_vendor_content *radiotap; + const u16 vendor_data_len = sizeof(*ntfy); + + radiotap = + iwl_mld_radiotap_put_tlv(skb, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE, + sizeof(*radiotap) + vendor_data_len); + + /* Intel OUI */ + radiotap->oui[0] = 0xf6; + radiotap->oui[1] = 0x54; + radiotap->oui[2] = 0x25; + /* Intel OUI default radiotap subtype */ + radiotap->oui_subtype = 1; + /* PHY data element type */ + radiotap->vendor_type = cpu_to_le16(1); + + /* fill the data now */ + memcpy(radiotap->data, ntfy, vendor_data_len); + + rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; +} + static void iwl_mld_set_rx_nonlegacy_rate_info(u32 rate_n_flags, struct ieee80211_rx_status *rx_status) @@ -1371,6 +1400,9 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, } } #endif + + if (phy_data->ntfy) + iwl_mld_add_rtap_sniffer_phy_data(mld, skb, phy_data->ntfy); } /* iwl_mld_create_skb adds the rxb to a new skb */ @@ -1866,6 +1898,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, u32 mpdu_len; enum iwl_mld_reorder_result reorder_res; struct ieee80211_rx_status *rx_status; + unsigned int alloc_size = 128; if (unlikely(mld->fw_status.in_hw_restart)) return; @@ -1884,8 +1917,13 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, /* Don't use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. + * + * For monitor mode we need more space to include the full PHY + * notification data. */ - skb = alloc_skb(128, GFP_ATOMIC); + if (unlikely(mld->monitor.on) && phy_data.ntfy) + alloc_size += sizeof(struct iwl_rx_phy_air_sniffer_ntfy); + skb = alloc_skb(alloc_size, GFP_ATOMIC); if (!skb) { IWL_ERR(mld, "alloc_skb failed\n"); return; @@ -2102,7 +2140,8 @@ static void iwl_mld_no_data_rx(struct iwl_mld *mld, u32 format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; struct sk_buff *skb; - skb = alloc_skb(128, GFP_ATOMIC); + skb = alloc_skb(128 + sizeof(struct iwl_rx_phy_air_sniffer_ntfy), + GFP_ATOMIC); if (!skb) return; -- cgit v1.2.3 From 7f59fadbcbbc7881e434544531a1d6c04036f034 Mon Sep 17 00:00:00 2001 From: Nidhish A N Date: Sun, 19 Oct 2025 11:45:04 +0300 Subject: wifi: iwlwifi: fw: remove support of several iwl_lari_config_change_cmd versions We only need versions 1, 6, 8 and 12. Remove versions 2, 3, 4, 5, 7, 9, 10, 11. Signed-off-by: Nidhish A N Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.5c3de58594e8.I6e6f8707eb66a2b540fb19303c06393f13e1f68e@changeid --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 134 ++------------------- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 26 +--- 2 files changed, 11 insertions(+), 149 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index e90f3187e55c..4644fc1aa1ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -18,13 +18,8 @@ enum iwl_regulatory_and_nvm_subcmd_ids { /** * @LARI_CONFIG_CHANGE: &struct iwl_lari_config_change_cmd_v1, - * &struct iwl_lari_config_change_cmd_v2, - * &struct iwl_lari_config_change_cmd_v3, - * &struct iwl_lari_config_change_cmd_v4, - * &struct iwl_lari_config_change_cmd_v5, * &struct iwl_lari_config_change_cmd_v6, - * &struct iwl_lari_config_change_cmd_v7, - * &struct iwl_lari_config_change_cmd_v10 or + * &struct iwl_lari_config_change_cmd_v8, * &struct iwl_lari_config_change_cmd */ LARI_CONFIG_CHANGE = 0x1, @@ -564,74 +559,6 @@ struct iwl_lari_config_change_cmd_v1 { __le32 config_bitmap; } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_1 */ -/** - * struct iwl_lari_config_change_cmd_v2 - change LARI configuration - * @config_bitmap: bit map of the config commands. each bit will trigger a - * different predefined FW config operation - * @oem_uhb_allow_bitmap: bitmap of UHB enabled MCC sets - */ -struct iwl_lari_config_change_cmd_v2 { - __le32 config_bitmap; - __le32 oem_uhb_allow_bitmap; -} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_2 */ - -/** - * struct iwl_lari_config_change_cmd_v3 - change LARI configuration - * @config_bitmap: bit map of the config commands. each bit will trigger a - * different predefined FW config operation - * @oem_uhb_allow_bitmap: bitmap of UHB enabled MCC sets - * @oem_11ax_allow_bitmap: bitmap of 11ax allowed MCCs. - * For each supported country, a pair of regulatory override bit and 11ax mode exist - * in the bit field. - */ -struct iwl_lari_config_change_cmd_v3 { - __le32 config_bitmap; - __le32 oem_uhb_allow_bitmap; - __le32 oem_11ax_allow_bitmap; -} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_3 */ - -/** - * struct iwl_lari_config_change_cmd_v4 - change LARI configuration - * @config_bitmap: Bitmap of the config commands. Each bit will trigger a - * different predefined FW config operation. - * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. - * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits - * per country, one to indicate whether to override and the other to - * indicate the value to use. - * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits - * per country, one to indicate whether to override and the other to - * indicate allow/disallow unii4 channels. - */ -struct iwl_lari_config_change_cmd_v4 { - __le32 config_bitmap; - __le32 oem_uhb_allow_bitmap; - __le32 oem_11ax_allow_bitmap; - __le32 oem_unii4_allow_bitmap; -} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_4 */ - -/** - * struct iwl_lari_config_change_cmd_v5 - change LARI configuration - * @config_bitmap: Bitmap of the config commands. Each bit will trigger a - * different predefined FW config operation. - * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. - * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits - * per country, one to indicate whether to override and the other to - * indicate the value to use. - * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits - * per country, one to indicate whether to override and the other to - * indicate allow/disallow unii4 channels. - * @chan_state_active_bitmap: Bitmap for overriding channel state to active. - * Each bit represents a country or region to activate, according to the BIOS - * definitions. - */ -struct iwl_lari_config_change_cmd_v5 { - __le32 config_bitmap; - __le32 oem_uhb_allow_bitmap; - __le32 oem_11ax_allow_bitmap; - __le32 oem_unii4_allow_bitmap; - __le32 chan_state_active_bitmap; -} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_5 */ - /** * struct iwl_lari_config_change_cmd_v6 - change LARI configuration * @config_bitmap: Bitmap of the config commands. Each bit will trigger a @@ -659,8 +586,7 @@ struct iwl_lari_config_change_cmd_v6 { } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_6 */ /** - * struct iwl_lari_config_change_cmd_v7 - change LARI configuration - * This structure is used also for lari cmd version 8 and 9. + * struct iwl_lari_config_change_cmd_v8 - change LARI configuration * @config_bitmap: Bitmap of the config commands. Each bit will trigger a * different predefined FW config operation. * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. @@ -670,21 +596,19 @@ struct iwl_lari_config_change_cmd_v6 { * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits * per country, one to indicate whether to override and the other to * indicate allow/disallow unii4 channels. - * For LARI cmd version 4 to 8 - bits 0:3 are supported. - * For LARI cmd version 9 - bits 0:5 are supported. + * bit 0 - 3: supported. * @chan_state_active_bitmap: Bitmap to enable different bands per country * or region. * Each bit represents a country or region, and a band to activate * according to the BIOS definitions. - * For LARI cmd version 7 - bits 0:3 are supported. - * For LARI cmd version 8 - bits 0:4 are supported. + * bit 0 - 4: supported. * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. * Each bit represents a set of channels in a specific band that should be * disabled * @edt_bitmap: Bitmap of energy detection threshold table. * Disable/enable the EDT optimization method for different band. */ -struct iwl_lari_config_change_cmd_v7 { +struct iwl_lari_config_change_cmd_v8 { __le32 config_bitmap; __le32 oem_uhb_allow_bitmap; __le32 oem_11ax_allow_bitmap; @@ -693,48 +617,8 @@ struct iwl_lari_config_change_cmd_v7 { __le32 force_disable_channels_bitmap; __le32 edt_bitmap; } __packed; -/* LARI_CHANGE_CONF_CMD_S_VER_7 */ /* LARI_CHANGE_CONF_CMD_S_VER_8 */ -/* LARI_CHANGE_CONF_CMD_S_VER_9 */ -/** - * struct iwl_lari_config_change_cmd_v10 - change LARI configuration - * @config_bitmap: Bitmap of the config commands. Each bit will trigger a - * different predefined FW config operation. - * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. - * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits - * per country, one to indicate whether to override and the other to - * indicate the value to use. - * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits - * per country, one to indicate whether to override and the other to - * indicate allow/disallow unii4 channels. - * For LARI cmd version 10 - bits 0:5 are supported. - * @chan_state_active_bitmap: Bitmap to enable different bands per country - * or region. - * Each bit represents a country or region, and a band to activate - * according to the BIOS definitions. - * For LARI cmd version 10 - bits 0:4 are supported. - * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. - * Each bit represents a set of channels in a specific band that should be - * disabled - * @edt_bitmap: Bitmap of energy detection threshold table. - * Disable/enable the EDT optimization method for different band. - * @oem_320mhz_allow_bitmap: 320Mhz bandwidth enablement bitmap per MCC. - * bit0: enable 320Mhz in Japan. - * bit1: enable 320Mhz in South Korea. - * bit 2 - 31: reserved. - */ -struct iwl_lari_config_change_cmd_v10 { - __le32 config_bitmap; - __le32 oem_uhb_allow_bitmap; - __le32 oem_11ax_allow_bitmap; - __le32 oem_unii4_allow_bitmap; - __le32 chan_state_active_bitmap; - __le32 force_disable_channels_bitmap; - __le32 edt_bitmap; - __le32 oem_320mhz_allow_bitmap; -} __packed; -/* LARI_CHANGE_CONF_CMD_S_VER_10 */ /** * struct iwl_lari_config_change_cmd - change LARI configuration @@ -747,14 +631,11 @@ struct iwl_lari_config_change_cmd_v10 { * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits * per country, one to indicate whether to override and the other to * indicate allow/disallow unii4 channels. - * For LARI cmd version 11 - bits 0:5 are supported. * @chan_state_active_bitmap: Bitmap to enable different bands per country * or region. * Each bit represents a country or region, and a band to activate * according to the BIOS definitions. - * For LARI cmd version 11 - bits 0:4 are supported. - * For LARI cmd version 12 - bits 0:6 are supported and bits 7:31 are - * reserved. + * bit 0 - 6: supported. * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. * Each bit represents a set of channels in a specific band that should be * disabled @@ -781,12 +662,11 @@ struct iwl_lari_config_change_cmd { __le32 oem_320mhz_allow_bitmap; __le32 oem_11be_allow_bitmap; } __packed; -/* LARI_CHANGE_CONF_CMD_S_VER_11 */ /* LARI_CHANGE_CONF_CMD_S_VER_12 */ /* Activate UNII-1 (5.2GHz) for World Wide */ #define ACTIVATE_5G2_IN_WW_MASK BIT(4) -#define CHAN_STATE_ACTIVE_BITMAP_CMD_V11 0x1F +#define CHAN_STATE_ACTIVE_BITMAP_CMD_V8 0x1F #define CHAN_STATE_ACTIVE_BITMAP_CMD_V12 0x7F /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index e1f28b053253..d2ad169ae880 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -543,32 +543,14 @@ static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver) switch (cmd_ver) { case 12: - case 11: cmd_size = sizeof(struct iwl_lari_config_change_cmd); break; - case 10: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v10); - break; - case 9: case 8: - case 7: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v7); + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); break; case 6: cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); break; - case 5: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5); - break; - case 4: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); - break; - case 3: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); - break; - case 2: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); - break; default: cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); break; @@ -609,11 +591,11 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, if (!has_raw_dsm_capa) value &= DSM_UNII4_ALLOW_BITMAP; - /* Since version 9, bits 4 and 5 are supported + /* Since version 12, bits 4 and 5 are supported * regardless of this capability, By pass this masking * if firmware has capability of accepting raw DSM table. */ - if (!has_raw_dsm_capa && cmd_ver < 9 && + if (!has_raw_dsm_capa && cmd_ver < 12 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | @@ -637,7 +619,7 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, if (!has_raw_dsm_capa && cmd_ver < 12 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11; + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8; cmd->chan_state_active_bitmap = cpu_to_le32(value); } -- cgit v1.2.3 From 8377e92a3a08304b06e4a5cef89d49ab93728dc1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 19 Oct 2025 11:45:05 +0300 Subject: wifi: iwlwifi: be more chatty when we fail to find a wifi7 device All wifi7 devices need CONFIG_IWLMLD to be enabled. If we can't support the wifi7 device and the module is not enabled, complain to the user. The check in iwl_req_fw_callback is then no longer required. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.071dae9a5de2.I1603085bac5a796442faa75982f8675647becfec@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 9 +-------- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 9 +++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 7d58e294618d..94ef422dc56a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -177,7 +177,7 @@ static inline char iwl_drv_get_step(int step) return 'a' + step; } -static bool iwl_drv_is_wifi7_supported(struct iwl_trans *trans) +bool iwl_drv_is_wifi7_supported(struct iwl_trans *trans) { return trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && CSR_HW_RFID_TYPE(trans->info.hw_rf_id) >= IWL_CFG_RF_TYPE_FM; @@ -1859,13 +1859,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) #if IS_ENABLED(CONFIG_IWLMLD) if (iwl_drv_is_wifi7_supported(drv->trans)) op = &iwlwifi_opmode_table[MLD_OP_MODE]; -#else - if (iwl_drv_is_wifi7_supported(drv->trans)) { - IWL_ERR(drv, - "IWLMLD needs to be compiled to support this firmware\n"); - mutex_unlock(&iwlwifi_opmode_table_mtx); - goto out_unbind; - } #endif IWL_INFO(drv, "loaded firmware version %s op_mode %s\n", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index a0b67e8aba8d..6e60953de2ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -78,6 +78,12 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans); */ void iwl_drv_stop(struct iwl_drv *drv); +/* + * iwl_drv_is_wifi7_supported - returns if wifi7 is supported + * If yes, iwlmld needs to be used to drive the device. + */ +bool iwl_drv_is_wifi7_supported(struct iwl_trans *trans); + /* * exported symbol management * 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 59307b5df441..164d060ec617 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -4218,6 +4218,15 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, pdev->device, pdev->subsystem_device, info.hw_rev, info.hw_rf_id); +#if !IS_ENABLED(CONFIG_IWLMLD) + if (iwl_drv_is_wifi7_supported(iwl_trans)) { + IWL_ERR(iwl_trans, + "IWLMLD needs to be compiled to support this device\n"); + ret = -EOPNOTSUPP; + goto out_free_trans; + } +#endif + dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, CSR_HW_RFID_TYPE(info.hw_rf_id), CSR_HW_RFID_IS_CDB(info.hw_rf_id), -- cgit v1.2.3 From d24076e0758ff8aa788e181c565683abae8bb397 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 19 Oct 2025 11:45:06 +0300 Subject: wifi: iwlwifi: stop checking the firmware's error pointer It is not very clear what values we put in min_umac_error_event_table. For Ma (Meteor Lake), this value is wrong and we get the print: Not valid error log pointer ... Just remove the check. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.a64d0803150f.Ie2db385f68e17fb0adcdcb16e5bf0125289e177d@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 1 - drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 1 - drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 -- drivers/net/wireless/intel/iwlwifi/mld/fw.c | 6 +----- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 13 ++----------- 10 files changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index ca488931a33c..f0453f3f6ba6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -38,7 +38,6 @@ static const struct iwl_family_base_params iwl_22000_base = { .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, .apmg_not_supported = true, .mac_addr_from_csr = 0x380, - .min_umac_error_event_table = 0x400000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 60 * 1024, .mon_smem_regs = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index b56574006ee0..3c844cd419e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -50,7 +50,6 @@ static const struct iwl_family_base_params iwl8000_base = { .smem_offset = IWL8260_SMEM_OFFSET, .smem_len = IWL8260_SMEM_LEN, .apmg_not_supported = true, - .min_umac_error_event_table = 0x800000, }; static const struct iwl_tt_params iwl8000_tt_params = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index ac1fa291cf2f..5872fc9b8caf 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -41,7 +41,6 @@ static const struct iwl_family_base_params iwl9000_base = { .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, .apmg_not_supported = true, .mac_addr_from_csr = 0x380, - .min_umac_error_event_table = 0x800000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 92 * 1024, .nvm_hw_section_num = 10, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index ddf3d313da5a..582f61661062 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -33,7 +33,6 @@ static const struct iwl_family_base_params iwl_ax210_base = { .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, .apmg_not_supported = true, .mac_addr_from_csr = 0x380, - .min_umac_error_event_table = 0x400000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 60 * 1024, .mon_smem_regs = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 18c9244ee8ef..7babb60463be 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -38,7 +38,6 @@ static const struct iwl_family_base_params iwl_bz_base = { .smem_len = IWL_BZ_SMEM_LEN, .apmg_not_supported = true, .mac_addr_from_csr = 0x30, - .min_umac_error_event_table = 0xD0000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 60 * 1024, .mon_smem_regs = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index e53a785686c8..ad65951d5643 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -33,7 +33,6 @@ static const struct iwl_family_base_params iwl_dr_base = { .smem_len = IWL_DR_SMEM_LEN, .apmg_not_supported = true, .mac_addr_from_csr = 0x30, - .min_umac_error_event_table = 0xD0000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 60 * 1024, .mon_smem_regs = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index e9449b59114a..abb6283dfb8f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -41,7 +41,6 @@ static const struct iwl_family_base_params iwl_sc_base = { .smem_len = IWL_SC_SMEM_LEN, .apmg_not_supported = true, .mac_addr_from_csr = 0x30, - .min_umac_error_event_table = 0xD0000, .d3_debug_data_base_addr = 0x401000, .d3_debug_data_length = 60 * 1024, .mon_smem_regs = { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 0b34c9f90b3f..e44936204068 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -170,7 +170,6 @@ struct iwl_fw_mon_regs { * for aggregation * @min_txq_size: minimum number of slots required in a TX queue * @gp2_reg_addr: GP2 (timer) register address - * @min_umac_error_event_table: minimum SMEM location of UMAC error table * @mon_dbgi_regs: monitor DBGI registers * @mon_dram_regs: monitor DRAM registers * @mon_smem_regs: monitor SMEM registers @@ -203,7 +202,6 @@ struct iwl_family_base_params { netdev_features_t features; u32 smem_offset; u32 smem_len; - u32 min_umac_error_event_table; u32 d3_debug_data_base_addr; u32 d3_debug_data_length; u32 min_txq_size; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index b3abfa1ec810..19da521a4bab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -167,11 +167,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, umac_error_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr) & ~FW_ADDR_CACHE_CONTROL; - if (umac_error_table >= trans->mac_cfg->base->min_umac_error_event_table) - iwl_fw_umac_set_alive_err_table(trans, umac_error_table); - else - IWL_ERR(mld, "Not valid error log pointer 0x%08X\n", - umac_error_table); + iwl_fw_umac_set_alive_err_table(trans, umac_error_table); alive_data->valid = status == IWL_ALIVE_STATUS_OK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6b76ce35443d..edae13755ee6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -214,17 +214,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, ~FW_ADDR_CACHE_CONTROL; if (umac_error_table) { - if (umac_error_table >= - mvm->trans->mac_cfg->base->min_umac_error_event_table) { - iwl_fw_umac_set_alive_err_table(mvm->trans, - umac_error_table); - } else { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - umac_error_table, - (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ? - "Init" : "RT"); - } + iwl_fw_umac_set_alive_err_table(mvm->trans, + umac_error_table); } alive_data->valid = status == IWL_ALIVE_STATUS_OK; -- cgit v1.2.3 From 7906c61a8faf6660bc2d5c6e71985be695a71065 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 19 Oct 2025 11:45:07 +0300 Subject: wifi: iwlwifi: mld: check the validity of noa_len Validate iwl_probe_resp_data_notif::noa_attr::len_low since we are using its value to determine the noa_len, which is later used for the NoA attribute. Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.b127a2b57e8c.I7ccaf118d236fb39da5da351b95ad9b37b825bc2@changeid --- drivers/net/wireless/intel/iwlwifi/mld/iface.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index ed379825a923..a5ececfc13e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -528,6 +528,19 @@ void iwl_mld_handle_probe_resp_data_notif(struct iwl_mld *mld, mld_link = &iwl_mld_vif_from_mac80211(vif)->deflink; + /* len_low should be 2 + n*13 (where n is the number of descriptors. + * 13 is the size of a NoA descriptor). We can have either one or two + * descriptors. + */ + if (IWL_FW_CHECK(mld, notif->noa_active && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) * 2, + "Invalid noa_attr.len_low (%d)\n", + notif->noa_attr.len_low)) + return; + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); if (!new_data) return; -- cgit v1.2.3 From f67cf9aaae4681692dce78ce31ba08cdf9cc0705 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:08 +0300 Subject: wifi: iwlwifi: fix build when mvm/mld not configured When neither mvm nor mld are configured, we don't have the iwl_bz_mac_cfg symbol and thus cannot check for it. But in that case the relevant device entries aren't and cannot be present, so just ifdef the test code for that. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202509170625.BAJBe7Bi-lkp@intel.com/ Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.615810979e7b.I9a215f955bb3208d99239be8496d19e0f186b4d0@changeid --- drivers/net/wireless/intel/iwlwifi/tests/devinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index 3054bc0a9c67..6bf2ad18b009 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -274,6 +274,7 @@ static void devinfo_pci_ids_config(struct kunit *test) if (s->device == PCI_ANY_ID || s->subdevice == PCI_ANY_ID) continue; +#if IS_ENABLED(CONFIG_IWLMVM) || IS_ENABLED(CONFIG_IWLMLD) /* * The check below only works for old (pre-CNVI) devices. Most * new have subdevice==ANY, so are already skipped, but for some @@ -281,6 +282,7 @@ static void devinfo_pci_ids_config(struct kunit *test) */ if (s->driver_data == (kernel_ulong_t)&iwl_bz_mac_cfg) continue; +#endif di = iwl_pci_find_dev_info(s->device, s->subdevice, 0, 0, 0, 0, true); -- cgit v1.2.3 From 50d0cafec60ce2c6ece236806df7fbef0cc8a0da Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:09 +0300 Subject: wifi: iwlwifi: bump core version for BZ/SC/DR Start supporting Core 100 FW on those devices. In addition, the move to the new Core scheme (instead of API scheme) will start Core 100 and not 99, as planned. Adjust for that as well. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.00c28b4259da.Idd6281cd647f1b33f2572a8c107c3a3228e03665@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 7babb60463be..28005f25c38b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_BZ_UCODE_CORE_MAX 99 +#define IWL_BZ_UCODE_CORE_MAX 100 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 100 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index ad65951d5643..c1c6174534d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -9,7 +9,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_DR_UCODE_CORE_MAX 99 +#define IWL_DR_UCODE_CORE_MAX 100 /* Lowest firmware API version supported */ #define IWL_DR_UCODE_API_MIN 100 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index abb6283dfb8f..d9943d252ae0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_SC_UCODE_CORE_MAX 99 +#define IWL_SC_UCODE_CORE_MAX 100 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 100 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 94ef422dc56a..3391f07b01de 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -348,8 +348,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) if (first) drv->fw_index = ucode_api_max; - else if (drv->fw_index == ENCODE_CORE_AS_API(99)) - drv->fw_index = 101; /* last API-scheme number below core 99 */ + else if (drv->fw_index == ENCODE_CORE_AS_API(100)) + drv->fw_index = 102; /* last API-scheme number below core 100 */ else drv->fw_index--; -- cgit v1.2.3 From 3e24ba621ba122ff765c8c9790800a05196fbbba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:10 +0300 Subject: wifi: iwlwifi: mvm/mld: report non-HT frames as 20 MHz Non-HT frames can only be encoded in 20 MHz, however, they could be duplicated on all/some of the subchannels (mostly used for RTS/CTS), in which case the firmware will report and estimate of the overall used bandwidth based on energy detected. This could be confusing so don't report it that way, always use 20 MHz for non-HT/legacy frames instead. Note that currently the value doesn't appear to be used by mac80211, it never checks the bandwidth field for legacy encodings. Signed-off-by: Johannes Berg Reviewed-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.23e6695039ca.I3da7c542bde6de4362755f200248dbcc12aa246e@changeid --- drivers/net/wireless/intel/iwlwifi/mld/rx.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 19e78d2fbf9b..6a76e3fcb581 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -1309,6 +1309,9 @@ static void iwl_mld_set_rx_rate(struct iwl_mld *mld, iwl_mld_legacy_hw_idx_to_mac80211_idx(rate_n_flags, rx_status->band); + /* override BW - it could be DUP and indicate the wrong BW */ + rx_status->bw = RATE_INFO_BW_20; + /* valid rate */ if (rate >= 0 && rate <= 0xFF) { rx_status->rate_idx = rate; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 8c1bb3a7ffca..d0c0faae0122 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -519,6 +519,8 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, return; } rx_status->rate_idx = rate; + /* override BW - it could be DUP and indicate the wrong BW */ + rx_status->bw = RATE_INFO_BW_20; } #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v1.2.3 From bd8a6e46e6b89f758669614d2aa1219e8ea048ef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:11 +0300 Subject: wifi: iwlwifi: mld: use FW_CHECK on bad ROC notification If the firmware sends a ROC notification after the driver cancelled it, we can get into this WARN_ON(). Don't do that, use IWL_FW_CHECK() instead. Signed-off-by: Johannes Berg Tested-by: Emmanuel Grumbach Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.48aff2c8922e.Ie27b21eb26b67c8010d13ce9590751cad417d1ad@changeid --- drivers/net/wireless/intel/iwlwifi/mld/roc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/roc.c b/drivers/net/wireless/intel/iwlwifi/mld/roc.c index 4136c98030d0..4e37a288471e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/roc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/roc.c @@ -231,7 +231,9 @@ void iwl_mld_handle_roc_notif(struct iwl_mld *mld, struct ieee80211_vif *vif; vif = iwl_mld_find_roc_vif(mld, activity); - if (WARN_ON(!vif)) + if (IWL_FW_CHECK(mld, !vif, + "unexpected ROC notif from FW for activity %d\n", + activity)) return; mld_vif = iwl_mld_vif_from_mac80211(vif); -- cgit v1.2.3 From 0d0e8149c6d77fe22dfb10b985ebedfbc192a2cd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:12 +0300 Subject: wifi: iwlwifi: bump core version for BZ/SC/DR Start supporting Core 101 FW on these devices. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.23300d52cd8b.I6aad50aed469d7734c165086796dfa9cdf9d81bd@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 28005f25c38b..d25445bd1e5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_BZ_UCODE_CORE_MAX 100 +#define IWL_BZ_UCODE_CORE_MAX 101 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 100 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index c1c6174534d7..a279dcfd3083 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -9,7 +9,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_DR_UCODE_CORE_MAX 100 +#define IWL_DR_UCODE_CORE_MAX 101 /* Lowest firmware API version supported */ #define IWL_DR_UCODE_API_MIN 100 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index d9943d252ae0..ee00b2af7a1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_SC_UCODE_CORE_MAX 100 +#define IWL_SC_UCODE_CORE_MAX 101 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 100 -- cgit v1.2.3 From 7ed47d42943fba8ced505f62d4358f63963bb968 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 19 Oct 2025 11:45:13 +0300 Subject: wifi: iwlwifi: disable EHT if the device doesn't allow it We have a few devices that don't allow EHT. Make sure we reflect this towards mac80211 so that we won't try to enable it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.71121f4e5557.I49e2329d4121f9e52d0889156d0c3e8778e27d88@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c | 1 + drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c | 23 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 6 ++++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c index 456a666c8dfd..fd82050e33a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c @@ -19,6 +19,7 @@ .non_shared_ant = ANT_B, \ .vht_mu_mimo_supported = true, \ .uhb_supported = true, \ + .eht_supported = true, \ .num_rbds = IWL_NUM_RBDS_EHT, \ .nvm_ver = IWL_FM_NVM_VERSION, \ .nvm_type = IWL_NVM_EXT diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c index b8c6b06e7099..b5803ea1eb78 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c @@ -4,8 +4,31 @@ */ #include "iwl-config.h" +/* NVM versions */ +#define IWL_WH_NVM_VERSION 0x0a1d + +#define IWL_DEVICE_WH \ + .ht_params = { \ + .stbc = true, \ + .ldpc = true, \ + .ht40_bands = BIT(NL80211_BAND_2GHZ) | \ + BIT(NL80211_BAND_5GHZ), \ + }, \ + .led_mode = IWL_LED_RF_STATE, \ + .non_shared_ant = ANT_B, \ + .vht_mu_mimo_supported = true, \ + .uhb_supported = true, \ + .num_rbds = IWL_NUM_RBDS_EHT, \ + .nvm_ver = IWL_WH_NVM_VERSION, \ + .nvm_type = IWL_NVM_EXT + /* currently iwl_rf_wh/iwl_rf_wh_160mhz are just defines for the FM ones */ +const struct iwl_rf_cfg iwl_rf_wh_non_eht = { + IWL_DEVICE_WH, + .eht_supported = false, +}; + const char iwl_killer_be1775s_name[] = "Killer(R) Wi-Fi 7 BE1775s 320MHz Wireless Network Adapter (BE211D2W)"; const char iwl_killer_be1775i_name[] = diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index e44936204068..0a5a683325ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -416,6 +416,7 @@ struct iwl_mac_cfg { * @vht_mu_mimo_supported: VHT MU-MIMO support * @nvm_type: see &enum iwl_nvm_type * @uhb_supported: ultra high band channels supported + * @eht_supported: EHT supported * @num_rbds: number of receive buffer descriptors to use * (only used for multi-queue capable devices) * @@ -448,7 +449,8 @@ struct iwl_rf_cfg { host_interrupt_operation_mode:1, lp_xtal_workaround:1, vht_mu_mimo_supported:1, - uhb_supported:1; + uhb_supported:1, + eht_supported:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; @@ -742,6 +744,7 @@ extern const struct iwl_rf_cfg iwl_rf_fm; extern const struct iwl_rf_cfg iwl_rf_fm_160mhz; #define iwl_rf_wh iwl_rf_fm #define iwl_rf_wh_160mhz iwl_rf_fm_160mhz +extern const struct iwl_rf_cfg iwl_rf_wh_non_eht; #define iwl_rf_pe iwl_rf_fm #endif /* CONFIG_IWLMLD */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 23465e4c4b39..e021fc57d85d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -2080,7 +2080,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disabled = !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); - if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) >= IWL_CFG_RF_TYPE_FM) + if (trans->cfg->eht_supported) nvm->sku_cap_11be_enable = true; /* Initialize PHY sku data */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index de04a84def0d..73001cdce13a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1061,8 +1061,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* WH RF */ IWL_DEV_INFO(iwl_rf_wh, iwl_be211_name, RF_TYPE(WH)), - IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x0514)), - IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x4514)), + IWL_DEV_INFO(iwl_rf_wh_non_eht, iwl_ax221_name, RF_TYPE(WH), + SUBDEV(0x0514)), + IWL_DEV_INFO(iwl_rf_wh_non_eht, iwl_ax221_name, RF_TYPE(WH), + SUBDEV(0x4514)), IWL_DEV_INFO(iwl_rf_wh_160mhz, iwl_be213_name, RF_TYPE(WH), BW_LIMITED), /* PE RF */ -- cgit v1.2.3 From 9e69bcb527ea66288d49b97a85e33ce429825079 Mon Sep 17 00:00:00 2001 From: Nidhish A N Date: Sun, 19 Oct 2025 11:45:14 +0300 Subject: wifi: iwlwifi: mld: Move EMLSR prints to IWL_DL_EHT Modify EMLSR debug prints to use IWL_DL_EHT instead of IWL_DL_INFO. This will allow better communication with validation as they might enable only IWL_DL_EHT or IWL_DL_INFO as required. Add prints to log attempt to switch links when missed beacons exceed threshold. Print both link ids and missed beacons when in EMLSR mode. Signed-off-by: Nidhish A N Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.3bfc2bc8f410.I405ab2aa81af1ba0ea5eaff343eae1778f2035d9@changeid --- drivers/net/wireless/intel/iwlwifi/mld/link.c | 9 ++- drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 97 ++++++++++++--------------- drivers/net/wireless/intel/iwlwifi/mld/sta.c | 2 +- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index 738f80fe0c50..deb1e7227dd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -571,8 +571,12 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, /* Not in EMLSR and we can't hear the link. * Try to switch to a better link. EMLSR case is handled below. */ - if (!iwl_mld_emlsr_active(vif)) + if (!iwl_mld_emlsr_active(vif)) { + IWL_DEBUG_EHT(mld, + "missed beacons exceeds threshold. link_id=%u. Try to switch to a better link.\n", + link_id); iwl_mld_int_mlo_scan(mld, vif); + } } /* no more logic if we're not in EMLSR */ @@ -591,7 +595,8 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, return; IWL_DEBUG_EHT(mld, - "missed bcn on the other link (link_id=%u): %u\n", + "missed bcn link_id=%u: %u consecutive=%u, other link_id=%u: %u\n", + link_id, missed_bcon, missed_bcon_since_rx, other_link->link_id, scnd_lnk_bcn_lost); /* Exit EMLSR if we lost more than diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index fa04fbe06656..c6b151f26921 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -31,11 +31,9 @@ static void iwl_mld_print_emlsr_blocked(struct iwl_mld *mld, u32 mask) { #define NAME_FMT(x) "%s" #define NAME_PR(x) (mask & IWL_MLD_EMLSR_BLOCKED_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mld, - "EMLSR blocked = " HANDLE_EMLSR_BLOCKED_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_EMLSR_BLOCKED_REASONS(NAME_PR) - mask); + IWL_DEBUG_EHT(mld, + "EMLSR blocked = " HANDLE_EMLSR_BLOCKED_REASONS(NAME_FMT) + " (0x%x)\n", HANDLE_EMLSR_BLOCKED_REASONS(NAME_PR) mask); #undef NAME_FMT #undef NAME_PR } @@ -72,11 +70,9 @@ static void iwl_mld_print_emlsr_exit(struct iwl_mld *mld, u32 mask) { #define NAME_FMT(x) "%s" #define NAME_PR(x) (mask & IWL_MLD_EMLSR_EXIT_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mld, - "EMLSR exit = " HANDLE_EMLSR_EXIT_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_EMLSR_EXIT_REASONS(NAME_PR) - mask); + IWL_DEBUG_EHT(mld, + "EMLSR exit = " HANDLE_EMLSR_EXIT_REASONS(NAME_FMT) + " (0x%x)\n", HANDLE_EMLSR_EXIT_REASONS(NAME_PR) mask); #undef NAME_FMT #undef NAME_PR } @@ -170,10 +166,10 @@ static void iwl_mld_check_emlsr_prevention(struct iwl_mld *mld, WARN_ON(mld_vif->emlsr.exit_repeat_count > 3); } - IWL_DEBUG_INFO(mld, - "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", - delay / HZ, mld_vif->emlsr.exit_repeat_count, - iwl_mld_get_emlsr_exit_string(reason), reason); + IWL_DEBUG_EHT(mld, + "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", + delay / HZ, mld_vif->emlsr.exit_repeat_count, + iwl_mld_get_emlsr_exit_string(reason), reason); wiphy_delayed_work_queue(mld->wiphy, &mld_vif->emlsr.prevent_done_wk, delay); @@ -217,10 +213,10 @@ static int _iwl_mld_exit_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, link_to_keep = __ffs(vif->active_links); new_active_links = BIT(link_to_keep); - IWL_DEBUG_INFO(mld, - "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", - iwl_mld_get_emlsr_exit_string(exit), exit, - vif->active_links, new_active_links); + IWL_DEBUG_EHT(mld, + "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", + iwl_mld_get_emlsr_exit_string(exit), exit, + vif->active_links, new_active_links); if (sync) ret = ieee80211_set_active_links(vif, new_active_links); @@ -262,9 +258,8 @@ static int _iwl_mld_emlsr_block(struct iwl_mld *mld, struct ieee80211_vif *vif, mld_vif->emlsr.blocked_reasons |= reason; - IWL_DEBUG_INFO(mld, - "Blocking EMLSR mode. reason = %s (0x%x)\n", - iwl_mld_get_emlsr_blocked_string(reason), reason); + IWL_DEBUG_EHT(mld, "Blocking EMLSR mode. reason = %s (0x%x)\n", + iwl_mld_get_emlsr_blocked_string(reason), reason); iwl_mld_print_emlsr_blocked(mld, mld_vif->emlsr.blocked_reasons); if (reason == IWL_MLD_EMLSR_BLOCKED_TPT) @@ -335,9 +330,8 @@ void iwl_mld_unblock_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, mld_vif->emlsr.blocked_reasons &= ~reason; - IWL_DEBUG_INFO(mld, - "Unblocking EMLSR mode. reason = %s (0x%x)\n", - iwl_mld_get_emlsr_blocked_string(reason), reason); + IWL_DEBUG_EHT(mld, "Unblocking EMLSR mode. reason = %s (0x%x)\n", + iwl_mld_get_emlsr_blocked_string(reason), reason); iwl_mld_print_emlsr_blocked(mld, mld_vif->emlsr.blocked_reasons); if (reason == IWL_MLD_EMLSR_BLOCKED_TPT) @@ -348,7 +342,7 @@ void iwl_mld_unblock_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, if (mld_vif->emlsr.blocked_reasons) return; - IWL_DEBUG_INFO(mld, "EMLSR is unblocked\n"); + IWL_DEBUG_EHT(mld, "EMLSR is unblocked\n"); iwl_mld_int_mlo_scan(mld, vif); } @@ -365,18 +359,17 @@ iwl_mld_vif_iter_emlsr_mode_notif(void *data, u8 *mac, switch (action) { case ESR_RECOMMEND_LEAVE: - IWL_DEBUG_INFO(mld_vif->mld, - "FW recommend leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_EHT(mld_vif->mld, + "FW recommend leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); iwl_mld_exit_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_EXIT_FW_REQUEST, iwl_mld_get_primary_link(vif)); break; case ESR_FORCE_LEAVE: - IWL_DEBUG_INFO(mld_vif->mld, - "FW force leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_EHT(mld_vif->mld, "FW force leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); fallthrough; case ESR_RECOMMEND_ENTER: default: @@ -412,11 +405,12 @@ void iwl_mld_handle_emlsr_trans_fail_notif(struct iwl_mld *mld, struct ieee80211_bss_conf *bss_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id); - IWL_DEBUG_INFO(mld, "Failed to %s EMLSR on link %d (FW: %d), reason %d\n", - le32_to_cpu(notif->activation) ? "enter" : "exit", - bss_conf ? bss_conf->link_id : -1, - le32_to_cpu(notif->link_id), - le32_to_cpu(notif->err_code)); + IWL_DEBUG_EHT(mld, + "Failed to %s EMLSR on link %d (FW: %d), reason %d\n", + le32_to_cpu(notif->activation) ? "enter" : "exit", + bss_conf ? bss_conf->link_id : -1, + le32_to_cpu(notif->link_id), + le32_to_cpu(notif->err_code)); if (IWL_FW_CHECK(mld, !bss_conf, "FW reported failure to %sactivate EMLSR on a non-existing link: %d\n", @@ -590,8 +584,8 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) spin_unlock_bh(&queue_counter->lock); } - IWL_DEBUG_INFO(mld, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", - total_tx, total_rx); + IWL_DEBUG_EHT(mld, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", + total_tx, total_rx); /* If we don't have enough MPDUs - exit EMLSR */ if (total_tx < IWL_MLD_ENTER_EMLSR_TPT_THRESH && @@ -605,8 +599,8 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) if (sec_link_id == -1) goto schedule; - IWL_DEBUG_INFO(mld, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", - sec_link_id, sec_link_tx, sec_link_rx); + IWL_DEBUG_EHT(mld, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", + sec_link_id, sec_link_tx, sec_link_rx); /* Calculate the percentage of the secondary link TX/RX */ sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0; @@ -703,10 +697,8 @@ iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld, ret |= IWL_MLD_EMLSR_EXIT_CSA; if (ret) { - IWL_DEBUG_INFO(mld, - "Link %d is not allowed for EMLSR as %s\n", - link->link_id, - primary ? "primary" : "secondary"); + IWL_DEBUG_EHT(mld, "Link %d is not allowed for EMLSR as %s\n", + link->link_id, primary ? "primary" : "secondary"); iwl_mld_print_emlsr_exit(mld, ret); } @@ -870,13 +862,12 @@ iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif, reason_mask |= IWL_MLD_EMLSR_EXIT_CHAN_LOAD; if (reason_mask) { - IWL_DEBUG_INFO(mld, - "Links %d and %d are not a valid pair for EMLSR\n", - a->link_id, b->link_id); - IWL_DEBUG_INFO(mld, - "Links bandwidth are: %d and %d\n", - nl80211_chan_width_to_mhz(a->chandef->width), - nl80211_chan_width_to_mhz(b->chandef->width)); + IWL_DEBUG_EHT(mld, + "Links %d and %d are not a valid pair for EMLSR\n", + a->link_id, b->link_id); + IWL_DEBUG_EHT(mld, "Links bandwidth are: %d and %d\n", + nl80211_chan_width_to_mhz(a->chandef->width), + nl80211_chan_width_to_mhz(b->chandef->width)); iwl_mld_print_emlsr_exit(mld, reason_mask); } @@ -994,8 +985,8 @@ static void _iwl_mld_select_links(struct iwl_mld *mld, } set_active: - IWL_DEBUG_INFO(mld, "Link selection result: 0x%x. Primary = %d\n", - new_active, new_primary); + IWL_DEBUG_EHT(mld, "Link selection result: 0x%x. Primary = %d\n", + new_active, new_primary); mld_vif->emlsr.selected_primary = new_primary; mld_vif->emlsr.selected_links = new_active; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 5cdbfa29a202..61ecc33116cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -890,7 +890,7 @@ static void iwl_mld_count_mpdu(struct ieee80211_link_sta *link_sta, int queue, sizeof(queue_counter->per_link)); queue_counter->window_start_time = jiffies; - IWL_DEBUG_INFO(mld, "MPDU counters are cleared\n"); + IWL_DEBUG_EHT(mld, "MPDU counters are cleared\n"); } link_counter = &queue_counter->per_link[mld_link->fw_id]; -- cgit v1.2.3 From 5ee10092eb77dee1bed468777ff8e16130f21877 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Oct 2025 11:45:15 +0300 Subject: wifi: iwlwifi: cfg: fix a few device names There are going to be some devices called BN203 instead of BN201, adjust the names accordingly. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.2ad0f42ffb57.I2c7864d33f0d7d3dc49381949571c4ce620a9723@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c | 1 + drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 7 ++++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c index 483f21659eff..408b9850bd10 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c @@ -12,5 +12,6 @@ const char iwl_killer_bn1850i_name[] = "Killer(R) Wi-Fi 8 BN1850i 320MHz Wireless Network Adapter (BN201.NGW)"; const char iwl_bn201_name[] = "Intel(R) Wi-Fi 8 BN201"; +const char iwl_bn203_name[] = "Intel(R) Wi-Fi 8 BN203"; const char iwl_be221_name[] = "Intel(R) Wi-Fi 7 BE221"; const char iwl_be223_name[] = "Intel(R) Wi-Fi 7 BE223"; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 0a5a683325ef..076810ee5d34 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -686,6 +686,7 @@ extern const char iwl_be211_name[]; extern const char iwl_killer_bn1850w2_name[]; extern const char iwl_killer_bn1850i_name[]; extern const char iwl_bn201_name[]; +extern const char iwl_bn203_name[]; extern const char iwl_be221_name[]; extern const char iwl_be223_name[]; extern const char iwl_ax221_name[]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 73001cdce13a..dc99e7ac4726 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1069,9 +1069,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* PE RF */ IWL_DEV_INFO(iwl_rf_pe, iwl_bn201_name, RF_TYPE(PE)), - IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x0524)), - IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x4524)), - IWL_DEV_INFO(iwl_rf_pe, iwl_be221_name, RF_TYPE(PE), SUBDEV(0x0324)), + IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), + SUBDEV_MASKED(0x0524, 0xFFF)), + IWL_DEV_INFO(iwl_rf_pe, iwl_bn203_name, RF_TYPE(PE), + SUBDEV_MASKED(0x0324, 0xFFF)), /* Killer */ IWL_DEV_INFO(iwl_rf_wh, iwl_killer_be1775s_name, SUBDEV(0x1776)), -- cgit v1.2.3 From 75dd87e3f181bbf7d333c69fa45ef49eb75e4acd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 19 Oct 2025 11:45:16 +0300 Subject: wifi: iwlwifi: mld: check for NULL pointer after kmalloc Coverity complained that we didn't add a NULL check for the link we allocate. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251019114304.d1f958160c5a.Icc891c14c633c3b8625372680fdc67ca33c83cc7@changeid --- drivers/net/wireless/intel/iwlwifi/mld/link.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index deb1e7227dd8..27ae8bd6f407 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -465,10 +465,13 @@ int iwl_mld_add_link(struct iwl_mld *mld, int ret; if (!link) { - if (is_deflink) + if (is_deflink) { link = &mld_vif->deflink; - else + } else { link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + } } else { WARN_ON(!mld->fw_status.in_hw_restart); } -- cgit v1.2.3 From 3df28496673bd8009f1cd3a85a63650c96e369f4 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Fri, 17 Oct 2025 12:11:28 +0800 Subject: wifi: iwlwifi: mld: add null check for kzalloc() in iwl_mld_send_proto_offload() Add a missing NULL pointer check after kzalloc() in iwl_mld_send_proto_offload(). Without this check, a failed allocation could lead to a NULL dereference. Fixes: d1e879ec600f9 ("wifi: iwlwifi: add iwlmld sub-driver") Signed-off-by: Li Qiang Link: https://patch.msgid.link/20251017041128.1379715-1-liqiang01@kylinos.cn Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 1d4282a21f09..dd85be94433c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -1794,6 +1794,10 @@ iwl_mld_send_proto_offload(struct iwl_mld *mld, u32 enabled = 0; cmd = kzalloc(hcmd.len[0], GFP_KERNEL); + if (!cmd) { + IWL_DEBUG_WOWLAN(mld, "Failed to allocate proto offload cmd\n"); + return -ENOMEM; + } #if IS_ENABLED(CONFIG_IPV6) struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); -- cgit v1.2.3