diff options
Diffstat (limited to 'drivers/net/wireless/intel')
82 files changed, 1517 insertions, 3647 deletions
diff --git a/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h index 1e8ab704dbfb..f00eb878b94b 100644 --- a/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h +++ b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h @@ -50,28 +50,4 @@ struct ieee80211_measurement_params { __le16 duration; } __packed; -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - #endif diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 9f543946b285..3e6206e739f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -9,11 +9,11 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 102 +/* Highest firmware core release supported */ +#define IWL_BZ_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 98 +#define IWL_BZ_UCODE_API_MIN 100 /* Memory offsets and lengths */ #define IWL_BZ_SMEM_OFFSET 0x400000 @@ -75,7 +75,7 @@ static const struct iwl_family_base_params iwl_bz_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_BZ_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_BZ_UCODE_CORE_MAX), .ucode_api_min = IWL_BZ_UCODE_API_MIN, }; @@ -101,8 +101,8 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = { .low_latency_xtal = true, }; -IWL_FW_AND_PNVM(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_API_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index 807f4e29d55a..e53a785686c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -8,11 +8,11 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_DR_UCODE_API_MAX 102 +/* Highest firmware core release supported */ +#define IWL_DR_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_DR_UCODE_API_MIN 98 +#define IWL_DR_UCODE_API_MIN 100 /* Memory offsets and lengths */ #define IWL_DR_SMEM_OFFSET 0x400000 @@ -20,9 +20,6 @@ #define IWL_DR_A_PE_A_FW_PRE "iwlwifi-dr-a0-pe-a0" -#define IWL_DR_A_PE_A_FW_MODULE_FIRMWARE(api) \ - IWL_DR_A_PE_A_FW_PRE "-" __stringify(api) ".ucode" - static const struct iwl_family_base_params iwl_dr_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -73,7 +70,7 @@ static const struct iwl_family_base_params iwl_dr_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_DR_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_DR_UCODE_CORE_MAX), .ucode_api_min = IWL_DR_UCODE_API_MIN, }; @@ -89,5 +86,5 @@ const struct iwl_mac_cfg iwl_dr_mac_cfg = { .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; -MODULE_FIRMWARE(IWL_DR_A_PE_A_FW_MODULE_FIRMWARE(IWL_DR_UCODE_API_MAX)); +IWL_CORE_FW(IWL_DR_A_PE_A_FW_PRE, IWL_DR_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c index 7ff5170faaa9..c16cda087a7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c @@ -9,7 +9,7 @@ #define IWL_GF_UCODE_API_MAX 100 /* Lowest firmware API version supported */ -#define IWL_GF_UCODE_API_MIN 98 +#define IWL_GF_UCODE_API_MIN 100 #define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0" #define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0" @@ -23,6 +23,18 @@ #define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" #define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" +#define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_SC_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_SC_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" + /* NVM versions */ #define IWL_GF_NVM_VERSION 0x0a1d @@ -67,7 +79,7 @@ IWL_FW_AND_PNVM(IWL_MA_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_MA_B_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_MA_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_MA_B_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_BZ_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_BZ_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); +MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF4_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c index 9f408d276ce9..6cf187d92dbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c @@ -9,7 +9,7 @@ #define IWL_HR_UCODE_API_MAX 100 /* Lowest firmware API version supported */ -#define IWL_HR_UCODE_API_MIN 98 +#define IWL_HR_UCODE_API_MIN 100 #define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0" #define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0" diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 6d4a3bce49b9..e9449b59114a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -9,11 +9,11 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 102 +/* Highest firmware core release supported */ +#define IWL_SC_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 98 +#define IWL_SC_UCODE_API_MIN 100 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d @@ -78,7 +78,7 @@ static const struct iwl_family_base_params iwl_sc_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_SC_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_SC_UCODE_CORE_MAX), .ucode_api_min = IWL_SC_UCODE_API_MIN, }; @@ -94,8 +94,8 @@ const struct iwl_mac_cfg iwl_sc_mac_cfg = { .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; -IWL_FW_AND_PNVM(IWL_SC_A_FM_B_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); +IWL_CORE_FW(IWL_SC_A_FM_B_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC_A_FM_C_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC_A_WH_A_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC2_A_FM_C_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC2_A_WH_A_FW_PRE, IWL_SC_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c index 9f8cdb027839..d337ab543eb0 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c @@ -766,7 +766,7 @@ static int iwl_init_otp_access(struct iwl_trans *trans) { int ret; - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 0771a46bd552..a0a26ef482a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -378,7 +378,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - iwl_trans_d3_suspend(priv->trans, false, true); + iwl_trans_d3_suspend(priv->trans, true); goto out; @@ -422,7 +422,6 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) struct ieee80211_vif *vif; u32 base; int ret; - enum iwl_d3_status d3_status; struct error_table_start { /* cf. struct iwl_error_event_table */ u32 valid; @@ -451,15 +450,10 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) /* we'll clear ctx->vif during iwlagn_prepare_restart() */ vif = ctx->vif; - ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true); + ret = iwl_trans_d3_resume(priv->trans, true); if (ret) goto out_unlock; - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(priv, "Device was reset during suspend\n"); - goto out_unlock; - } - /* uCode is no longer operating by itself */ iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.c b/drivers/net/wireless/intel/iwlwifi/dvm/power.c index 6b42d6e5f30f..e7dbba7134f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.c @@ -368,7 +368,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - priv->power_data.bus_pm = priv->trans->pm_support; + priv->power_data.bus_pm = iwl_trans_is_pm_supported(priv->trans); priv->power_data.debug_sleep_level_override = -1; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index bee7d92293b8..52edc19d8cdd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -9,9 +9,9 @@ #include "acpi.h" #include "fw/runtime.h" -const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, - 0xA5, 0xB3, 0x1F, 0x73, - 0x8E, 0x28, 0x5A, 0xDE); +static const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, + 0xA5, 0xB3, 0x1F, 0x73, + 0x8E, 0x28, 0x5A, 0xDE); static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { [DSM_FUNC_QUERY] = sizeof(u32), @@ -169,7 +169,7 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func)) return -EINVAL; expected_size = acpi_dsm_size[func]; @@ -178,6 +178,29 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) return -EOPNOTSUPP; + if (!fwrt->acpi_dsm_funcs_valid) { + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, + DSM_FUNC_QUERY, + &iwl_guid, &tmp, + acpi_dsm_size[DSM_FUNC_QUERY]); + if (ret) { + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = BIT(0); + return ret; + } + + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)tmp); + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = tmp | BIT(0); + } + + if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n", + func); + return -ENODATA; + } + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, &iwl_guid, &tmp, expected_size); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 68d8fb5f6357..20bc6671f4eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -140,8 +140,6 @@ struct iwl_dsm_internal_product_reset_cmd { struct iwl_fw_runtime; -extern const guid_t iwl_guid; - union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, union acpi_object *args, const guid_t *guid); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 53445087e9cb..d3bed0216df4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -367,6 +367,7 @@ enum iwl_wowlan_flags { ENABLE_NBNS_FILTERING = BIT(2), ENABLE_DHCP_FILTERING = BIT(3), ENABLE_STORE_BEACON = BIT(4), + HAS_BEACON_PROTECTION = BIT(5), }; /** @@ -631,10 +632,65 @@ struct iwl_wowlan_gtk_status_v3 { struct iwl_wowlan_all_rsc_tsc_v5 sc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */ +/** + * enum iwl_wowlan_key_status - Status of security keys in WoWLAN notifications + * @IWL_WOWLAN_NOTIF_NO_KEY: No key is present; this entry should be ignored. + * @IWL_WOWLAN_STATUS_OLD_KEY: old key exists; no rekey occurred, and only + * metadata is available. + * @IWL_WOWLAN_STATUS_NEW_KEY: A new key was created after a rekey; new key + * material is available. + */ +enum iwl_wowlan_key_status { + IWL_WOWLAN_NOTIF_NO_KEY = 0, + IWL_WOWLAN_STATUS_OLD_KEY = 1, + IWL_WOWLAN_STATUS_NEW_KEY = 2 +}; + +/** + * struct iwl_wowlan_gtk_status - GTK status + * @key: GTK material + * @key_len: GTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0:1]: key index assigned by the AP + * bits[2:6]: GTK index of the key in the internal DB + * bit[7]: Set iff this is the currently used GTK + * @key_status: key status, see &enum iwl_wowlan_key_status + * @reserved: padding + * @tkip_mic_key: TKIP RX MIC key + * @sc: RSC/TSC counters + */ +struct iwl_wowlan_gtk_status { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 key_len; + u8 key_flags; + u8 key_status; + u8 reserved; + u8 tkip_mic_key[IWL_MIC_KEY_SIZE]; + struct iwl_wowlan_all_rsc_tsc_v5 sc; +} __packed; /* WOWLAN_GTK_MATERIAL_VER_4 */ + #define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) #define IWL_WOWLAN_IGTK_BIGTK_IDX_MASK (BIT(0)) /** + * struct iwl_wowlan_igtk_status_v1 - IGTK status + * @key: IGTK material + * @ipn: the IGTK packet number (replay counter) + * @key_len: IGTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0]: key index assigned by the AP (0: index 4, 1: index 5) + * (0: index 6, 1: index 7 with bigtk) + * bits[1:5]: IGTK index of the key in the internal DB + * bit[6]: Set iff this is the currently used IGTK + */ +struct iwl_wowlan_igtk_status_v1 { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 ipn[6]; + u8 key_len; + u8 key_flags; +} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */ + +/** * struct iwl_wowlan_igtk_status - IGTK status * @key: IGTK material * @ipn: the IGTK packet number (replay counter) @@ -644,13 +700,17 @@ struct iwl_wowlan_gtk_status_v3 { * (0: index 6, 1: index 7 with bigtk) * bits[1:5]: IGTK index of the key in the internal DB * bit[6]: Set iff this is the currently used IGTK + * @key_status: key status, see &enum iwl_wowlan_key_status + * @reserved: padding */ struct iwl_wowlan_igtk_status { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 ipn[6]; u8 key_len; u8 key_flags; -} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */ + u8 key_status; + u8 reserved[3]; +} __packed; /* WOWLAN_IGTK_MATERIAL_VER_2 */ /** * struct iwl_wowlan_status_v6 - WoWLAN status @@ -700,7 +760,7 @@ struct iwl_wowlan_status_v6 { */ struct iwl_wowlan_status_v7 { struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 non_qos_seq_ctr; @@ -735,7 +795,7 @@ struct iwl_wowlan_status_v7 { */ struct iwl_wowlan_info_notif_v1 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 reserved1; @@ -817,8 +877,8 @@ struct iwl_wowlan_mlo_gtk { */ struct iwl_wowlan_info_notif_v3 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 reserved1; @@ -833,6 +893,45 @@ struct iwl_wowlan_info_notif_v3 { } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */ /** + * struct iwl_wowlan_info_notif_v5 - WoWLAN information notification + * @gtk: GTK data + * @igtk: IGTK data + * @bigtk: BIGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched patterns + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @station_id: station id + * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs + * following this notif + * @tid_offloaded_tx: tid used by the firmware to transmit data packets + * while in wowlan + * @mlo_gtks: array of GTKs of size num_mlo_link_keys + */ +struct iwl_wowlan_info_notif_v5 { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 qos_seq_ctr; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + u8 tid_tear_down; + u8 station_id; + u8 num_mlo_link_keys; + u8 tid_offloaded_tx; + struct iwl_wowlan_mlo_gtk mlo_gtks[]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ + +/** * struct iwl_wowlan_info_notif - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data @@ -854,7 +953,7 @@ struct iwl_wowlan_info_notif_v3 { * @mlo_gtks: array of GTKs of size num_mlo_link_keys */ struct iwl_wowlan_info_notif { - struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; __le64 replay_ctr; @@ -869,7 +968,7 @@ struct iwl_wowlan_info_notif { u8 num_mlo_link_keys; u8 tid_offloaded_tx; struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_6 */ /** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index b9f559dac39f..f76cea6e9ec8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -420,6 +420,8 @@ struct iwl_mac_config_cmd { * eht_support set to true. No longer used since _VER_3 of this command. * @LINK_CONTEXT_MODIFY_BANDWIDTH: Covers iwl_link_ctx_cfg_cmd::modify_bandwidth. * Request RX OMI to the AP to modify bandwidth of this link. + * @LINK_CONTEXT_MODIFY_UHR_PARAMS: covers iwl_link_ctx_cfg_cmd::npca_params and + * iwl_link_ctx_cfg_cmd::prio_edca_params. Since _VER_7. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -432,6 +434,7 @@ enum iwl_link_ctx_modify_flags { LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6), LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7), LINK_CONTEXT_MODIFY_BANDWIDTH = BIT(8), + LINK_CONTEXT_MODIFY_UHR_PARAMS = BIT(9), LINK_CONTEXT_MODIFY_ALL = 0xff, }; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index 2a1c2b0f19e4..bb801650a565 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -20,7 +20,7 @@ enum iwl_prot_offload_subcmd_ids { /** * @WOWLAN_INFO_NOTIFICATION: Notification in * &struct iwl_wowlan_info_notif_v1, iwl_wowlan_info_notif_v3, - * or &struct iwl_wowlan_info_notif + * &struct iwl_wowlan_info_notif_v5 or &struct iwl_wowlan_info_notif */ WOWLAN_INFO_NOTIFICATION = 0xFD, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 786b3bf4b448..5eb8d10678fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -571,17 +571,16 @@ enum iwl_ppag_flags { /** * union iwl_ppag_table_cmd - union for all versions of PPAG command * @v1: command version 1 structure. - * @v2: command version from 2 to 6 are same structure as v2. - * but has a different format of the flags bitmap - * @v3: command version 7 structure. + * @v5: command version 5 structure. + * @v7: command version 7 structure. * @v1.flags: values from &enum iwl_ppag_flags * @v1.gain: table of antenna gain values per chain and sub-band * @v1.reserved: reserved - * @v2.flags: values from &enum iwl_ppag_flags - * @v2.gain: table of antenna gain values per chain and sub-band - * @v3.ppag_config_info: see @struct bios_value_u32 - * @v3.gain: table of antenna gain values per chain and sub-band - * @v3.reserved: reserved + * @v5.flags: values from &enum iwl_ppag_flags + * @v5.gain: table of antenna gain values per chain and sub-band + * @v7.ppag_config_info: see @struct bios_value_u32 + * @v7.gain: table of antenna gain values per chain and sub-band + * @v7.reserved: reserved */ union iwl_ppag_table_cmd { struct { @@ -593,30 +592,19 @@ union iwl_ppag_table_cmd { __le32 flags; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 reserved[2]; - } __packed v2; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_2, VER3, VER4, - * VER5, VER6 - */ + } __packed v5; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_5 */ struct { struct bios_value_u32 ppag_config_info; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 reserved[2]; - } __packed v3; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ + } __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ } __packed; -#define IWL_PPAG_CMD_V4_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) -#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V4_MASK | \ +#define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) +#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V1_MASK | \ IWL_PPAG_ETSI_LPI_UHB_MASK | \ IWL_PPAG_USA_LPI_UHB_MASK) -#define IWL_PPAG_CMD_V6_MASK (IWL_PPAG_CMD_V5_MASK | \ - IWL_PPAG_ETSI_VLP_UHB_MASK | \ - IWL_PPAG_ETSI_SP_UHB_MASK | \ - IWL_PPAG_USA_VLP_UHB_MASK | \ - IWL_PPAG_USA_SP_UHB_MASK | \ - IWL_PPAG_CANADA_LPI_UHB_MASK | \ - IWL_PPAG_CANADA_VLP_UHB_MASK | \ - IWL_PPAG_CANADA_SP_UHB_MASK) - #define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 #define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 3222cbcbe1ab..9c464e7aba10 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -24,6 +24,8 @@ * for BPSK (MCS 0) with 2 spatial * streams * @IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK: enable support for EHT extra LTF + * @IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK: support ELR 1.5 Mbps + * @IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK: support ELR 3 Mbps */ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), @@ -32,6 +34,8 @@ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK = BIT(3), IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK = BIT(4), IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK = BIT(6), + IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK = BIT(7), + IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK = BIT(8), }; /** @@ -201,6 +205,37 @@ struct iwl_tlc_config_cmd_v4 { } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */ /** + * struct iwl_tlc_config_cmd - TLC configuration + * @sta_id: station id + * @reserved1: reserved + * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw + * @mode: &enum iwl_tlc_mng_cfg_mode + * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains + * @sgi_ch_width_supp: bitmap of SGI support per channel width + * use BIT(&enum iwl_tlc_mng_cfg_cw) + * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags + * @non_ht_rates: bitmap of supported legacy rates + * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per <nss, channel-width> + * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz). + * @max_mpdu_len: max MPDU length, in bytes + * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), + * set zero for no limit. + */ +struct iwl_tlc_config_cmd { + u8 sta_id; + u8 reserved1[3]; + u8 max_ch_width; + u8 mode; + u8 chains; + u8 sgi_ch_width_supp; + __le16 flags; + __le16 non_ht_rates; + __le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4]; + __le16 max_mpdu_len; + __le16 max_tx_op; +} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */ + +/** * enum iwl_tlc_update_flags - updated fields * @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update * @IWL_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 2879be4b8fcb..2ce55859641c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -830,7 +830,7 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, } /* reading RXF/TXF sizes */ - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { + if (iwl_trans_is_fw_error(fwrt->trans)) { fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg); fifo_len += iwl_fw_txf_len(fwrt, mem_cfg); @@ -2393,7 +2393,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_dump_cfg_name *cfg_name; u32 size = sizeof(*tlv) + sizeof(*dump); u32 num_of_cfg_names = 0; - u32 hw_type, is_cdb, is_jacket; + u32 hw_type, is_cdb; list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { size += sizeof(*cfg_name); @@ -2426,11 +2426,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, hw_type = CSR_HW_REV_TYPE(fwrt->trans->info.hw_rev); is_cdb = CSR_HW_RFID_IS_CDB(fwrt->trans->info.hw_rf_id); - is_jacket = !!(iwl_read_umac_prph(fwrt->trans, WFPM_OTP_CFG1_ADDR) & - WFPM_OTP_CFG1_IS_JACKET_BIT); - - /* Use bits 12 and 13 to indicate jacket/CDB, respectively */ - hw_type |= (is_jacket | (is_cdb << 1)) << IWL_JACKET_CDB_SHIFT; + hw_type |= IWL_CDB_MASK(is_cdb); dump->hw_type = cpu_to_le32(hw_type); @@ -2478,36 +2474,6 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, return entry->size; } -static u32 iwl_dump_ini_file_name_info(struct iwl_fw_runtime *fwrt, - struct list_head *list) -{ - struct iwl_fw_ini_dump_entry *entry; - struct iwl_dump_file_name_info *tlv; - u32 len = strnlen(fwrt->trans->dbg.dump_file_name_ext, - IWL_FW_INI_MAX_NAME); - - if (!fwrt->trans->dbg.dump_file_name_ext_valid) - return 0; - - entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + len); - if (!entry) - return 0; - - entry->size = sizeof(*tlv) + len; - - tlv = (void *)entry->data; - tlv->type = cpu_to_le32(IWL_INI_DUMP_NAME_TYPE); - tlv->len = cpu_to_le32(len); - memcpy(tlv->data, fwrt->trans->dbg.dump_file_name_ext, len); - - /* add the dump file name extension tlv to the list */ - list_add_tail(&entry->list, list); - - fwrt->trans->dbg.dump_file_name_ext_valid = false; - - return entry->size; -} - static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { [IWL_FW_INI_REGION_INVALID] = {}, [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { @@ -2764,7 +2730,6 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, &iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]); if (size) { - size += iwl_dump_ini_file_name_info(fwrt, list); size += iwl_dump_ini_info(fwrt, trigger, list); } @@ -3151,7 +3116,7 @@ static void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, .len[0] = sizeof(hcmd_data), }; - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) + if (iwl_trans_is_fw_error(fwrt->trans)) return; if (fw_has_capa(&fwrt->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index f633124979ab..ddd714cff2f4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -14,13 +14,6 @@ #include "iwl-csr.h" #include "pnvm.h" -#define FW_ASSERT_LMAC_FATAL 0x70 -#define FW_ASSERT_LMAC2_FATAL 0x72 -#define FW_ASSERT_UMAC_FATAL 0x71 -#define UMAC_RT_NMI_LMAC2_FATAL 0x72 -#define RT_NMI_INTERRUPT_OTHER_LMAC_FATAL 0x73 -#define FW_ASSERT_NMI_UNKNOWN 0x84 - /* * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is @@ -103,17 +96,6 @@ struct iwl_umac_error_event_table { #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) -static bool iwl_fwrt_if_errorid_other_cpu(u32 err_id) -{ - err_id &= 0xFF; - - if ((err_id >= FW_ASSERT_LMAC_FATAL && - err_id <= RT_NMI_INTERRUPT_OTHER_LMAC_FATAL) || - err_id == FW_ASSERT_NMI_UNKNOWN) - return true; - return false; -} - static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) { struct iwl_trans *trans = fwrt->trans; @@ -131,13 +113,6 @@ static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) if (table.valid) fwrt->dump.umac_err_id = table.error_id; - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.umac_err_id) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.umac_err_id); - } - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", @@ -203,7 +178,7 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu if (err) return; - err = iwl_finish_nic_init(trans); + err = iwl_trans_activate_nic(trans); if (err) return; } @@ -213,13 +188,6 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu if (table.valid) fwrt->dump.lmac_err_id[lmac_num] = table.error_id; - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.lmac_err_id[lmac_num]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.lmac_err_id[lmac_num]); - } - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", @@ -305,16 +273,6 @@ static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx) iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - if (table.valid) - fwrt->dump.tcm_err_id[idx] = table.error_id; - - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.tcm_err_id[idx]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.tcm_err_id[idx]); - } - IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2); @@ -378,16 +336,6 @@ static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx) iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - if (table.valid) - fwrt->dump.rcm_err_id[idx] = table.error_id; - - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.rcm_err_id[idx]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.rcm_err_id[idx]); - } - IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); IWL_ERR(fwrt, "0x%08X | rcm branchlink2\n", table.blink2); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index cf41021d59ad..c2a73cc85eff 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -372,7 +372,8 @@ struct iwl_fw_ini_dump_cfg_name { u8 cfg_name[IWL_FW_INI_MAX_CFG_NAME]; } __packed; -#define IWL_JACKET_CDB_SHIFT 12 +#define IWL_CDB_MASK(val) val << 13 + /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 4d91ae065c8d..f297e82d63d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -237,11 +237,12 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, return -ENOENT; } -static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) +static u8 *iwl_pnvm_get_from_fs(struct iwl_trans *trans, size_t *len) { const struct firmware *pnvm; char pnvm_name[MAX_PNVM_NAME]; size_t new_len; + u8 *data; int ret; iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); @@ -250,29 +251,73 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) if (ret) { IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n", pnvm_name, ret); - return ret; + return NULL; } new_len = pnvm->size; - *data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); + data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); release_firmware(pnvm); - if (!*data) - return -ENOMEM; + if (!data) + return NULL; *len = new_len; - return 0; + return data; +} + +/** + * enum iwl_pnvm_source - different PNVM possible sources + * + * @IWL_PNVM_SOURCE_NONE: No PNVM. + * @IWL_PNVM_SOURCE_BIOS: PNVM should be read from BIOS. + * @IWL_PNVM_SOURCE_EXTERNAL: read .pnvm external file + * @IWL_PNVM_SOURCE_EMBEDDED: PNVM is embedded in the .ucode file. + */ +enum iwl_pnvm_source { + IWL_PNVM_SOURCE_NONE, + IWL_PNVM_SOURCE_BIOS, + IWL_PNVM_SOURCE_EXTERNAL, + IWL_PNVM_SOURCE_EMBEDDED +}; + +static enum iwl_pnvm_source iwl_select_pnvm_source(struct iwl_trans *trans, + bool intel_sku) +{ + + /* Get PNVM from BIOS for non-Intel SKU */ + if (!intel_sku) + return IWL_PNVM_SOURCE_BIOS; + + /* Before those devices, PNVM didn't exist at all */ + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return IWL_PNVM_SOURCE_NONE; + + /* After those devices, we moved to embedded PNVM */ + if (trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_AX210) + return IWL_PNVM_SOURCE_EMBEDDED; + + /* For IWL_DEVICE_FAMILY_AX210, depends on the CRF */ + if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_GF) + return IWL_PNVM_SOURCE_EXTERNAL; + + return IWL_PNVM_SOURCE_NONE; } static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, __le32 sku_id[3], const struct iwl_fw *fw) { struct pnvm_sku_package *package; + enum iwl_pnvm_source pnvm_src = + iwl_select_pnvm_source(trans_p, sku_id[2] == 0); u8 *image = NULL; - /* Get PNVM from BIOS for non-Intel SKU */ - if (sku_id[2]) { + IWL_DEBUG_FW(trans_p, "PNVM source %d\n", pnvm_src); + + if (pnvm_src == IWL_PNVM_SOURCE_NONE) + return NULL; + + if (pnvm_src == IWL_PNVM_SOURCE_BIOS) { package = iwl_uefi_get_pnvm(trans_p, len); if (!IS_ERR_OR_NULL(package)) { if (*len >= sizeof(*package)) { @@ -289,18 +334,26 @@ static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, if (image) return image; } + + /* PNVM doesn't exist in BIOS. Find the fallback source */ + pnvm_src = iwl_select_pnvm_source(trans_p, true); + IWL_DEBUG_FW(trans_p, "PNVM in BIOS doesn't exist, try %d\n", + pnvm_src); } - if (fw->pnvm_data) { - *len = fw->pnvm_size; + if (pnvm_src == IWL_PNVM_SOURCE_EXTERNAL) { + image = iwl_pnvm_get_from_fs(trans_p, len); + if (image) + return image; + } + if (pnvm_src == IWL_PNVM_SOURCE_EMBEDDED && fw->pnvm_data) { + *len = fw->pnvm_size; return fw->pnvm_data; } - /* If it's not available, or for Intel SKU, try from the filesystem */ - if (iwl_pnvm_get_from_fs(trans_p, &image, len)) - return NULL; - return image; + IWL_ERR(trans_p, "Couldn't get PNVM from required source: %d\n", pnvm_src); + return NULL; } static void diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 3d6d1a85bb51..e1f28b053253 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -59,11 +59,16 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), }, }, - { .ident = "ASUS", + { .ident = "ASUSTEK", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + }, + }, { .ident = "GOOGLE-HP", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), @@ -141,11 +146,16 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, }, - { .ident = "ASUS", + { .ident = "ASUSTEK", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + }, + }, { .ident = "GOOGLE-HP", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), @@ -305,6 +315,7 @@ static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, return true; } +/* Utility function for iwlmvm and iwlxvt */ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, int *cmd_size) { @@ -344,18 +355,18 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V1; gain = cmd->v1.gain[0]; *cmd_size = sizeof(cmd->v1); - cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); + cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK); if (fwrt->ppag_bios_rev >= 1) { /* in this case FW supports revision 0 */ IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d, send truncated table\n", fwrt->ppag_bios_rev); } - } else if (cmd_ver >= 2 && cmd_ver <= 6) { + } else if (cmd_ver == 5) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v2.gain[0]; - *cmd_size = sizeof(cmd->v2); - cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags); + gain = cmd->v5.gain[0]; + *cmd_size = sizeof(cmd->v5); + cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK); if (fwrt->ppag_bios_rev == 0) { /* in this case FW supports revisions 1,2 or 3 */ IWL_DEBUG_RADIO(fwrt, @@ -363,11 +374,11 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, } } else if (cmd_ver == 7) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v3.gain[0]; - *cmd_size = sizeof(cmd->v3); - cmd->v3.ppag_config_info.table_source = fwrt->ppag_bios_source; - cmd->v3.ppag_config_info.table_revision = fwrt->ppag_bios_rev; - cmd->v3.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); + gain = cmd->v7.gain[0]; + *cmd_size = sizeof(cmd->v7); + cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source; + cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev; + cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); } else { IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); return -EINVAL; @@ -378,30 +389,22 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, "PPAG MODE bits were read from bios: %d\n", fwrt->ppag_flags); - if (cmd_ver == 6) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK); - else if (cmd_ver == 5) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK); - else if (cmd_ver < 5) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); - - if ((cmd_ver == 1 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || - (cmd_ver == 2 && fwrt->ppag_bios_rev >= 2)) { + if (cmd_ver == 1 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); } else { IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); } - /* The 'flags' field is the same in v1 and v2 so we can just + /* The 'flags' field is the same in v1 and v5 so we can just * use v1 to access it. */ IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits going to be sent: %d\n", (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) : - le32_to_cpu(cmd->v3.ppag_config_info.value)); + le32_to_cpu(cmd->v7.ppag_config_info.value)); for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index a07c512b6ed4..735482e7adf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -12,7 +12,6 @@ #include "fw/api/phy.h" #include "fw/api/config.h" #include "fw/api/nvm-reg.h" -#include "fw/img.h" #include "iwl-trans.h" #define BIOS_SAR_MAX_PROFILE_NUM 4 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 0444a736c2b2..806f9bcdf4f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -113,6 +113,10 @@ struct iwl_txf_iter_data { * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source + * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid, + * 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 */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -146,8 +150,6 @@ struct iwl_fw_runtime { unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM]; u32 *d3_debug_data; u32 lmac_err_id[MAX_NUM_LMAC]; - u32 tcm_err_id[MAX_NUM_TCM]; - u32 rcm_err_id[MAX_NUM_RCM]; u32 umac_err_id; struct iwl_txf_iter_data txf_iter_data; @@ -189,6 +191,10 @@ struct iwl_fw_runtime { bool uats_valid; u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; + +#ifdef CONFIG_ACPI + u32 acpi_dsm_funcs_valid; +#endif }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 48126ec6b94b..4ae4d215e633 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -727,6 +727,8 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, struct uefi_cnv_var_general_cfg *data; int ret = -EINVAL; + BUILD_BUG_ON(ARRAY_SIZE(data->functions) < DSM_FUNC_NUM_FUNCS); + /* Not supported function index */ if (func >= DSM_FUNC_NUM_FUNCS || func == 5) return -EOPNOTSUPP; @@ -742,8 +744,9 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, goto out; } - if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { - IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); + if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, data->functions[DSM_FUNC_QUERY]); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 30e5f5a5cd89..a607e7ab914b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -11,6 +11,7 @@ #include <linux/netdevice.h> #include <linux/ieee80211.h> #include <linux/nl80211.h> +#include <linux/module.h> #include <linux/mod_devicetable.h> #include "iwl-csr.h" #include "iwl-drv.h" @@ -107,6 +108,9 @@ enum iwl_nvm_type { MODULE_FIRMWARE(pfx "-" __stringify(api) ".ucode"); \ MODULE_FIRMWARE(pfx ".pnvm") +#define IWL_CORE_FW(pfx, core) \ + MODULE_FIRMWARE(pfx "-c" __stringify(core) ".ucode") + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + @@ -192,8 +196,8 @@ struct iwl_family_base_params { u8 max_ll_items; u8 led_compensation; - u8 ucode_api_max; - u8 ucode_api_min; + u16 ucode_api_max; + u16 ucode_api_min; u32 mac_addr_from_csr:10; u8 nvm_hw_section_num; netdev_features_t features; @@ -211,6 +215,34 @@ struct iwl_family_base_params { }; /* + * FW is released as "core N release", and we used to have a + * gap of 3 between the API version and core number. Now the + * reported API version will be 1000 + core and we encode it + * in the filename as "c<core>". + */ +#define API_IS_CORE_START 1000 +#define API_TO_CORE_OFFS 3 +#define ENCODE_CORE_AS_API(core) (API_IS_CORE_START + (core)) + +static inline bool iwl_api_is_core_number(int api) +{ + return api >= API_IS_CORE_START; +} + +static inline int iwl_api_to_core(int api) +{ + if (iwl_api_is_core_number(api)) + return api - API_IS_CORE_START; + + return api - API_TO_CORE_OFFS; +} + +#define FW_API_FMT "%s%d" +#define FW_API_ARG(n) \ + iwl_api_is_core_number(n) ? "c" : "", \ + iwl_api_is_core_number(n) ? (n) - API_IS_CORE_START : (n) + +/* * @stbc: support Tx STBC and 1*SS Rx STBC * @ldpc: support Tx/Rx with LDPC * @use_rts_for_aggregation: use rts/cts protection for HT traffic @@ -422,8 +454,8 @@ struct iwl_rf_cfg { u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; - u8 ucode_api_max; - u8 ucode_api_min; + u16 ucode_api_max; + u16 ucode_api_min; u16 num_rbds; }; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 28aad975434b..607fcea6f4ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -337,10 +337,18 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -EINVAL; } + if (CSR_HW_RFID_TYPE(drv->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_WH && + CSR_HW_RFID_STEP(drv->trans->info.hw_rf_id) == SILICON_A_STEP) { + IWL_ERR(drv, "WH A step is not supported\n"); + return -EINVAL; + } + fw_name_pre = iwl_drv_get_fwname_pre(drv->trans, _fw_name_pre); 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 drv->fw_index--; @@ -348,13 +356,15 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (ucode_api_min == ucode_api_max) { - IWL_ERR(drv, "%s-%d is required\n", fw_name_pre, - ucode_api_max); + IWL_ERR(drv, "%s-" FW_API_FMT " is required\n", + fw_name_pre, FW_API_ARG(ucode_api_max)); } else { - IWL_ERR(drv, "minimum version required: %s-%d\n", - fw_name_pre, ucode_api_min); - IWL_ERR(drv, "maximum version supported: %s-%d\n", - fw_name_pre, ucode_api_max); + IWL_ERR(drv, + "minimum version required: %s-" FW_API_FMT "\n", + fw_name_pre, FW_API_ARG(ucode_api_min)); + IWL_ERR(drv, + "maximum version supported: %s-" FW_API_FMT "\n", + fw_name_pre, FW_API_ARG(ucode_api_max)); } IWL_ERR(drv, @@ -362,8 +372,9 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -ENOENT; } - snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s-%d.ucode", - fw_name_pre, drv->fw_index); + snprintf(drv->firmware_name, sizeof(drv->firmware_name), + "%s-" FW_API_FMT ".ucode", + fw_name_pre, FW_API_ARG(drv->fw_index)); IWL_DEBUG_FW_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); @@ -1588,6 +1599,7 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) */ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) { + unsigned int min_core, max_core, loaded_core; struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; const struct iwl_ucode_header *ucode; @@ -1650,11 +1662,24 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) * firmware filename ... but we don't check for that and only rely * on the API version read from firmware header from here on forward */ - if (api_ver < api_min || api_ver > api_max) { + + /* + * if -cN.ucode file was loaded, core version == file version, + * otherwise core version == file version (API version) - 3 + */ + if (iwl_api_is_core_number(drv->fw_index)) + loaded_core = api_ver; + else + loaded_core = api_ver - API_TO_CORE_OFFS; + + min_core = iwl_api_to_core(api_min); + max_core = iwl_api_to_core(api_max); + + if (loaded_core < min_core || loaded_core > max_core) { IWL_ERR(drv, "Driver unable to support your firmware API. " - "Driver supports v%u, firmware is v%u.\n", - api_max, api_ver); + "Driver supports FW core %u..%u, firmware is %u.\n", + min_core, max_core, loaded_core); goto try_again; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 5e483a55a4ba..b1944584c693 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -3,7 +3,6 @@ * Copyright (C) 2003-2014, 2018-2022, 2024-2025 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/export.h> @@ -13,6 +12,7 @@ #include "iwl-debug.h" #include "iwl-prph.h" #include "iwl-fh.h" +#include "pcie/gen1_2/internal.h" void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) { @@ -160,7 +160,7 @@ int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, do { if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) - return t; + return 0; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; } while (t < timeout); @@ -396,96 +396,11 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) return 0; } -#define IWL_HOST_MON_BLOCK_PEMON 0x00 -#define IWL_HOST_MON_BLOCK_HIPM 0x22 - -#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00 -#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01 -#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06 - -static void iwl_dump_host_monitor_block(struct iwl_trans *trans, - u32 block, u32 vec, u32 iter) -{ - int i; - - IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); - iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); - for (i = 0; i < iter; i++) - IWL_ERR(trans, " value [iter %d]: 0x%08x\n", - i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); -} - -static void iwl_dump_host_monitor(struct iwl_trans *trans) -{ - switch (trans->mac_cfg->device_family) { - case IWL_DEVICE_FAMILY_22000: - case IWL_DEVICE_FAMILY_AX210: - IWL_ERR(trans, "CSR_RESET = 0x%x\n", - iwl_read32(trans, CSR_RESET)); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_VEC1, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_WFPM, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM, - IWL_HOST_MON_BLOCK_PEMON_VEC0, 1); - break; - default: - /* not supported yet */ - return; - } -} - -int iwl_finish_nic_init(struct iwl_trans *trans) +int iwl_trans_activate_nic(struct iwl_trans *trans) { - const struct iwl_mac_cfg *mac_cfg = trans->mac_cfg; - u32 poll_ready; - int err; - - if (mac_cfg->bisr_workaround) { - /* ensure the TOP FSM isn't still in previous reset */ - mdelay(2); - } - - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - if (mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | - CSR_GP_CNTRL_REG_FLAG_MAC_INIT); - poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; - } else { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; - } - - if (mac_cfg->device_family == IWL_DEVICE_FAMILY_8000) - udelay(2); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); - if (err < 0) { - IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); - - iwl_dump_host_monitor(trans); - } - - if (mac_cfg->bisr_workaround) { - /* ensure BISR shift has finished */ - udelay(200); - } - - return err < 0 ? err : 0; + return iwl_pcie_gen1_2_activate_nic(trans); } -IWL_EXPORT_SYMBOL(iwl_finish_nic_init); +IWL_EXPORT_SYMBOL(iwl_trans_activate_nic); void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, u32 sw_err_bit) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index 731cda1a4e66..5bcec239ffc4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -57,7 +57,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); void iwl_force_nmi(struct iwl_trans *trans); -int iwl_finish_nic_init(struct iwl_trans *trans); +int iwl_trans_activate_nic(struct iwl_trans *trans); /* Error handling */ int iwl_dump_fh(struct iwl_trans *trans, char **buf); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index a67b9572aac3..23465e4c4b39 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -140,50 +140,6 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { #define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) /** - * enum iwl_nvm_channel_flags - channel flags in NVM - * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo - * @NVM_CHANNEL_IBSS: usable as an IBSS channel and deprecated - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY: active scanning allowed and - * AP allowed only in 20 MHz. Valid only - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_ACTIVE: active scanning allowed and allows IBSS - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_RADAR: radar detection required - * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed - * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS - * on same channel on 2.4 or same UNII band on 5.2 - * @NVM_CHANNEL_UNIFORM: uniform spreading required - * @NVM_CHANNEL_20MHZ: 20 MHz channel okay - * @NVM_CHANNEL_40MHZ: 40 MHz channel okay - * @NVM_CHANNEL_80MHZ: 80 MHz channel okay - * @NVM_CHANNEL_160MHZ: 160 MHz channel okay - * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) - * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP - * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP - * @NVM_CHANNEL_VLP_AP_NOT_ALLOWED: UHB VLP AP not allowed, - * Valid only when %NVM_CHANNEL_VLP is enabled. - */ -enum iwl_nvm_channel_flags { - NVM_CHANNEL_VALID = BIT(0), - NVM_CHANNEL_IBSS = BIT(1), - NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2), - NVM_CHANNEL_ACTIVE = BIT(3), - NVM_CHANNEL_RADAR = BIT(4), - NVM_CHANNEL_INDOOR_ONLY = BIT(5), - NVM_CHANNEL_GO_CONCURRENT = BIT(6), - NVM_CHANNEL_UNIFORM = BIT(7), - NVM_CHANNEL_20MHZ = BIT(8), - NVM_CHANNEL_40MHZ = BIT(9), - NVM_CHANNEL_80MHZ = BIT(10), - NVM_CHANNEL_160MHZ = BIT(11), - NVM_CHANNEL_DC_HIGH = BIT(12), - NVM_CHANNEL_VLP = BIT(13), - NVM_CHANNEL_AFC = BIT(14), - NVM_CHANNEL_VLP_AP_NOT_ALLOWED = BIT(15), -}; - -/** * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory * domain. * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the @@ -282,30 +238,6 @@ enum iwl_reg_capa_flags_v4 { */ #define REG_CAPA_V4_RESP_VER 8 -/** - * struct iwl_reg_capa - struct for global regulatory capabilities, Used for - * handling the different APIs of reg_capa_flags. - * - * @allow_40mhz: 11n channel with a width of 40Mhz is allowed - * for this regulatory domain. - * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). - * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). - * @allow_320mhz: 11be channel with a width of 320Mhz is allowed - * for this regulatory domain (valid only in 6 Ghz). - * @disable_11ax: 11ax is forbidden for this regulatory domain. - * @disable_11be: 11be is forbidden for this regulatory domain. - */ -struct iwl_reg_capa { - bool allow_40mhz; - bool allow_80mhz; - bool allow_160mhz; - bool allow_320mhz; - bool disable_11ax; - bool disable_11be; -}; - static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, int chan, u32 flags) { @@ -1042,10 +974,6 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; - if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) - iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |= - IEEE80211_HE_MAC_CAP2_BCAST_TWT; - if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_22000 && !is_ap) { iftype_data->vendor_elems.data = iwl_vendor_caps; @@ -1600,9 +1528,10 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, } IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); -static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, - int ch_idx, u16 nvm_flags, - struct iwl_reg_capa reg_capa) +VISIBLE_IF_IWLWIFI_KUNIT +u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, + int ch_idx, u16 nvm_flags, + struct iwl_reg_capa reg_capa) { u32 flags = NL80211_RRF_NO_HT40; @@ -1692,6 +1621,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, return flags; } +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_nvm_get_regdom_bw_flags); static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 9ce9fa4e78fd..cbc92abf9f87 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -21,6 +21,80 @@ enum iwl_nvm_sbands_flags { IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ = BIT(1), }; +/** + * struct iwl_reg_capa - struct for global regulatory capabilities, Used for + * handling the different APIs of reg_capa_flags. + * + * @allow_40mhz: 11n channel with a width of 40Mhz is allowed + * for this regulatory domain. + * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_320mhz: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 6 Ghz). + * @disable_11ax: 11ax is forbidden for this regulatory domain. + * @disable_11be: 11be is forbidden for this regulatory domain. + */ +struct iwl_reg_capa { + bool allow_40mhz; + bool allow_80mhz; + bool allow_160mhz; + bool allow_320mhz; + bool disable_11ax; + bool disable_11be; +}; + +/** + * enum iwl_nvm_channel_flags - channel flags in NVM + * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo + * @NVM_CHANNEL_IBSS: usable as an IBSS channel and deprecated + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY: active scanning allowed and + * AP allowed only in 20 MHz. Valid only + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_ACTIVE: active scanning allowed and allows IBSS + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_RADAR: radar detection required + * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed + * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS + * on same channel on 2.4 or same UNII band on 5.2 + * @NVM_CHANNEL_UNIFORM: uniform spreading required + * @NVM_CHANNEL_20MHZ: 20 MHz channel okay + * @NVM_CHANNEL_40MHZ: 40 MHz channel okay + * @NVM_CHANNEL_80MHZ: 80 MHz channel okay + * @NVM_CHANNEL_160MHZ: 160 MHz channel okay + * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) + * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP + * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP + * @NVM_CHANNEL_VLP_AP_NOT_ALLOWED: UHB VLP AP not allowed, + * Valid only when %NVM_CHANNEL_VLP is enabled. + */ +enum iwl_nvm_channel_flags { + NVM_CHANNEL_VALID = BIT(0), + NVM_CHANNEL_IBSS = BIT(1), + NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2), + NVM_CHANNEL_ACTIVE = BIT(3), + NVM_CHANNEL_RADAR = BIT(4), + NVM_CHANNEL_INDOOR_ONLY = BIT(5), + NVM_CHANNEL_GO_CONCURRENT = BIT(6), + NVM_CHANNEL_UNIFORM = BIT(7), + NVM_CHANNEL_20MHZ = BIT(8), + NVM_CHANNEL_40MHZ = BIT(9), + NVM_CHANNEL_80MHZ = BIT(10), + NVM_CHANNEL_160MHZ = BIT(11), + NVM_CHANNEL_DC_HIGH = BIT(12), + NVM_CHANNEL_VLP = BIT(13), + NVM_CHANNEL_AFC = BIT(14), + NVM_CHANNEL_VLP_AP_NOT_ALLOWED = BIT(15), +}; + +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, + int ch_idx, u16 nvm_flags, + struct iwl_reg_capa reg_capa); +#endif + /* * iwl_parse_nvm_data - parse NVM data and return values * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 3694b41d6621..5232f66c2d52 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -268,9 +268,7 @@ static void iwl_trans_restart_wk(struct work_struct *wk) struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_mac_cfg *mac_cfg, - unsigned int txcmd_size, - unsigned int txcmd_align) + const struct iwl_mac_cfg *mac_cfg) { struct iwl_trans *trans; #ifdef CONFIG_LOCKDEP @@ -292,22 +290,12 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, INIT_DELAYED_WORK(&trans->restart.wk, iwl_trans_restart_wk); - snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), - "iwl_cmd_pool:%s", dev_name(trans->dev)); - trans->dev_cmd_pool = - kmem_cache_create(trans->dev_cmd_pool_name, - txcmd_size, txcmd_align, - SLAB_HWCACHE_ALIGN, NULL); - if (!trans->dev_cmd_pool) - return NULL; - return trans; } void iwl_trans_free(struct iwl_trans *trans) { cancel_delayed_work_sync(&trans->restart.wk); - kmem_cache_destroy(trans->dev_cmd_pool); } int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) @@ -318,9 +306,6 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) test_bit(STATUS_RFKILL_OPMODE, &trans->status))) return -ERFKILL; - if (unlikely(test_bit(STATUS_SUSPENDED, &trans->status))) - return -EHOSTDOWN; - if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) return -EIO; @@ -348,6 +333,19 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) } IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); +struct iwl_device_tx_cmd *iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) +{ + return iwl_pcie_gen1_2_alloc_tx_cmd(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_alloc_tx_cmd); + +void iwl_trans_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd) +{ + iwl_pcie_gen1_2_free_tx_cmd(trans, dev_cmd); +} +IWL_EXPORT_SYMBOL(iwl_trans_free_tx_cmd); + /* Comparator for struct iwl_hcmd_names. * Used in the binary search over a list of host commands. * @@ -399,7 +397,7 @@ void iwl_trans_op_mode_enter(struct iwl_trans *trans, WARN_ON_ONCE(!trans->conf.rx_mpdu_cmd); - iwl_trans_pcie_op_mode_enter(trans); + iwl_pcie_gen1_2_op_mode_enter(trans); } IWL_EXPORT_SYMBOL(iwl_trans_op_mode_enter); @@ -408,8 +406,6 @@ int iwl_trans_start_hw(struct iwl_trans *trans) might_sleep(); clear_bit(STATUS_TRANS_RESET_IN_PROGRESS, &trans->status); - /* opmode may not resume if it detects errors */ - clear_bit(STATUS_SUSPENDED, &trans->status); return iwl_trans_pcie_start_hw(trans); } @@ -507,33 +503,19 @@ iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, sanitize_ops, sanitize_ctx); } -int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset) +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool reset) { - int err; - might_sleep(); - err = iwl_trans_pcie_d3_suspend(trans, test, reset); - - if (!err) - set_bit(STATUS_SUSPENDED, &trans->status); - - return err; + return iwl_trans_pcie_d3_suspend(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_suspend); -int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test, bool reset) +int iwl_trans_d3_resume(struct iwl_trans *trans, bool reset) { - int err; - might_sleep(); - err = iwl_trans_pcie_d3_resume(trans, status, test, reset); - - clear_bit(STATUS_SUSPENDED, &trans->status); - - return err; + return iwl_trans_pcie_d3_resume(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_resume); @@ -825,3 +807,18 @@ void iwl_trans_set_reduce_power(struct iwl_trans *trans, { iwl_trans_pcie_ctx_info_v2_set_reduce_power(trans, capa); } + +bool iwl_trans_is_pm_supported(struct iwl_trans *trans) +{ + if (WARN_ON(trans->mac_cfg->gen2)) + return false; + + return iwl_pcie_gen1_is_pm_supported(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_is_pm_supported); + +bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans) +{ + return iwl_pcie_gen1_2_is_ltr_enabled(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_is_ltr_enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index d0e658801c2e..a0cc5d7745e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -275,16 +275,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) #define IWL_9000_MAX_RX_HW_QUEUES 1 /** - * enum iwl_d3_status - WoWLAN image/device status - * @IWL_D3_STATUS_ALIVE: firmware is still running after resume - * @IWL_D3_STATUS_RESET: device was reset while suspended - */ -enum iwl_d3_status { - IWL_D3_STATUS_ALIVE, - IWL_D3_STATUS_RESET, -}; - -/** * enum iwl_trans_status: transport status flags * @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed * @STATUS_DEVICE_ENABLED: APM is enabled @@ -294,16 +284,12 @@ enum iwl_d3_status { * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode * @STATUS_FW_ERROR: the fw is in error state * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation - * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once, - * e.g. for testing * @STATUS_IN_SW_RESET: device is undergoing reset, cleared by opmode * via iwl_trans_finish_sw_reset() * @STATUS_RESET_PENDING: reset worker was scheduled, but didn't dump * the firmware state yet * @STATUS_TRANS_RESET_IN_PROGRESS: reset is still in progress, don't * attempt another reset yet - * @STATUS_SUSPENDED: device is suspended, don't send commands that - * aren't marked accordingly */ enum iwl_trans_status { STATUS_SYNC_HCMD_ACTIVE, @@ -314,11 +300,9 @@ enum iwl_trans_status { STATUS_RFKILL_OPMODE, STATUS_FW_ERROR, STATUS_TRANS_DEAD, - STATUS_SUPPRESS_CMD_ERROR_ONCE, STATUS_IN_SW_RESET, STATUS_RESET_PENDING, STATUS_TRANS_RESET_IN_PROGRESS, - STATUS_SUSPENDED, }; static inline int @@ -658,8 +642,6 @@ struct iwl_pc_data { * @restart_required: indicates debug restart is required * @last_tp_resetfw: last handling of reset during debug timepoint * @imr_data: IMR debug data allocation - * @dump_file_name_ext: dump file name extension - * @dump_file_name_ext_valid: dump file name extension if valid or not * @num_pc: number of program counter for cpu * @pc_data: details of the program counter * @yoyo_bin_loaded: tells if a yoyo debug file has been loaded @@ -698,8 +680,6 @@ struct iwl_trans_debug { bool restart_required; u32 last_tp_resetfw; struct iwl_imr_data imr_data; - u8 dump_file_name_ext[IWL_FW_INI_MAX_NAME]; - bool dump_file_name_ext_valid; u32 num_pc; struct iwl_pc_data *pc_data; bool yoyo_bin_loaded; @@ -830,7 +810,6 @@ struct iwl_txq { * @hw_rf_id: the device RF ID * @hw_cnv_id: the device CNV ID * @hw_crf_id: the device CRF ID - * @hw_wfpm_id: the device wfpm ID * @hw_id: the ID of the device / sub-device * Bits 0:15 represent the sub-device ID * Bits 16:31 represent the device ID. @@ -846,7 +825,6 @@ struct iwl_trans_info { u32 hw_rf_id; u32 hw_crf_id; u32 hw_cnv_id; - u32 hw_wfpm_id; u32 hw_id; u8 pcie_link_speed; u8 num_rxqs; @@ -866,14 +844,11 @@ struct iwl_trans_info { * @dev: pointer to struct device * that represents the device * @info: device information for use by other layers * @pnvm_loaded: indicates PNVM was loaded - * @pm_support: set to true in start_hw if link pm is supported - * @ltr_enabled: set to true if the LTR is enabled + * @suppress_cmd_error_once: suppress "FW error in SYNC CMD" once, + * e.g. for testing * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed * @reduce_power_loaded: indicates reduced power section was loaded * @failed_to_load_reduce_power_image: set to true if pnvm loading failed - * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. - * The user should use iwl_trans_{alloc,free}_tx_cmd. - * @dev_cmd_pool_name: name for the TX command allocation pool * @dbgfs_dir: iwlwifi debugfs base dir for this device * @sync_cmd_lockdep_map: lockdep map for checking sync commands * @dbg: additional debug data, see &struct iwl_trans_debug @@ -905,18 +880,13 @@ struct iwl_trans { const struct iwl_trans_info info; bool reduced_cap_sku; bool step_urm; + bool suppress_cmd_error_once; - bool pm_support; - bool ltr_enabled; u8 pnvm_loaded:1; u8 fail_to_parse_pnvm_image:1; u8 reduce_power_loaded:1; u8 failed_to_load_reduce_power_image:1; - /* The following fields are internal only */ - struct kmem_cache *dev_cmd_pool; - char dev_cmd_pool_name[50]; - struct dentry *dbgfs_dir; #ifdef CONFIG_LOCKDEP @@ -956,29 +926,21 @@ int iwl_trans_start_fw(struct iwl_trans *trans, const struct iwl_fw *fw, void iwl_trans_stop_device(struct iwl_trans *trans); -int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset); +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool reset); -int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test, bool reset); +int iwl_trans_d3_resume(struct iwl_trans *trans, bool reset); struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, void *sanitize_ctx); -static inline struct iwl_device_tx_cmd * -iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) -{ - return kmem_cache_zalloc(trans->dev_cmd_pool, GFP_ATOMIC); -} +struct iwl_device_tx_cmd *iwl_trans_alloc_tx_cmd(struct iwl_trans *trans); int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); -static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, - struct iwl_device_tx_cmd *dev_cmd) -{ - kmem_cache_free(trans->dev_cmd_pool, dev_cmd); -} +void iwl_trans_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd); int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_tx_cmd *dev_cmd, int queue); @@ -1205,9 +1167,7 @@ static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) *****************************************************/ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_mac_cfg *mac_cfg, - unsigned int txcmd_size, - unsigned int txcmd_align); + const struct iwl_mac_cfg *mac_cfg); void iwl_trans_free(struct iwl_trans *trans); static inline bool iwl_trans_is_hw_error_value(u32 val) @@ -1230,11 +1190,6 @@ static inline u16 iwl_trans_get_num_rbds(struct iwl_trans *trans) return result; } -static inline void iwl_trans_suppress_cmd_error_once(struct iwl_trans *trans) -{ - set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &trans->status); -} - static inline bool iwl_trans_device_enabled(struct iwl_trans *trans) { return test_bit(STATUS_DEVICE_ENABLED, &trans->status); @@ -1245,6 +1200,20 @@ static inline bool iwl_trans_is_dead(struct iwl_trans *trans) return test_bit(STATUS_TRANS_DEAD, &trans->status); } +static inline bool iwl_trans_is_fw_error(struct iwl_trans *trans) +{ + return test_bit(STATUS_FW_ERROR, &trans->status); +} + +/* + * This function notifies the transport layer of firmware error, the recovery + * will be handled by the op mode + */ +static inline void iwl_trans_notify_fw_error(struct iwl_trans *trans) +{ + trans->state = IWL_TRANS_NO_FW; + set_bit(STATUS_FW_ERROR, &trans->status); +} /***************************************************** * PCIe handling *****************************************************/ @@ -1289,4 +1258,8 @@ static inline u16 iwl_trans_get_device_id(struct iwl_trans *trans) return u32_get_bits(trans->info.hw_id, GENMASK(31, 16)); } +bool iwl_trans_is_pm_supported(struct iwl_trans *trans); + +bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); + #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h index ba1f75f739c2..f985ab90d41c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/sap.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h @@ -300,13 +300,11 @@ enum iwl_sap_msg { * @type: See &enum iwl_sap_msg. * @len: The length of the message (header not included). * @seq_num: For debug. - * @payload: The payload of the message. */ struct iwl_sap_hdr { __le16 type; __le16 len; __le32 seq_num; - u8 payload[]; }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index ed0a0f76f1c5..1d4282a21f09 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -11,6 +11,7 @@ #include "mcc.h" #include "sta.h" #include "mlo.h" +#include "key.h" #include "fw/api/d3.h" #include "fw/api/offload.h" @@ -40,8 +41,6 @@ enum iwl_mld_d3_notif { struct iwl_mld_resume_key_iter_data { struct iwl_mld *mld; struct iwl_mld_wowlan_status *wowlan_status; - u32 num_keys, gtk_cipher, igtk_cipher, bigtk_cipher; - bool unhandled_cipher; }; struct iwl_mld_suspend_key_iter_data { @@ -71,6 +70,12 @@ struct iwl_mld_mcast_key_data { }; +struct iwl_mld_wowlan_mlo_key { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 idx, type, link_id; + u8 pn[6]; +}; + /** * struct iwl_mld_wowlan_status - contains wowlan status data from * all wowlan notifications @@ -89,6 +94,8 @@ struct iwl_mld_mcast_key_data { * @bigtk: data of the last two used gtk's by the FW upon resume * @ptk: last seq numbers per tid passed by the FW, * holds both in tkip and aes formats + * @num_mlo_keys: number of &struct iwl_mld_wowlan_mlo_key structs + * @mlo_keys: array of MLO keys */ struct iwl_mld_wowlan_status { u32 wakeup_reasons; @@ -108,6 +115,9 @@ struct iwl_mld_wowlan_status { struct ieee80211_key_seq tkip_seq[IWL_MAX_TID_COUNT]; } ptk; + + int num_mlo_keys; + struct iwl_mld_wowlan_mlo_key mlo_keys[WOWLAN_MAX_MLO_KEYS]; }; #define NETDETECT_QUERY_BUF_LEN \ @@ -271,7 +281,7 @@ iwl_mld_convert_gtk_resume_seq(struct iwl_mld_mcast_key_data *gtk_data, static void iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, - const struct iwl_wowlan_gtk_status_v3 *gtk_data, + const struct iwl_wowlan_gtk_status *gtk_data, const struct iwl_wowlan_all_rsc_tsc_v5 *sc) { int status_idx = 0; @@ -283,8 +293,9 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, for (int notif_idx = 0; notif_idx < ARRAY_SIZE(wowlan_status->gtk); notif_idx++) { int rsc_idx; + u8 key_status = gtk_data[notif_idx].key_status; - if (!(gtk_data[notif_idx].key_len)) + if (!key_status) continue; wowlan_status->gtk[status_idx].len = @@ -294,10 +305,6 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, wowlan_status->gtk[status_idx].id = wowlan_status->gtk[status_idx].flags & IWL_WOWLAN_GTK_IDX_MASK; - memcpy(wowlan_status->gtk[status_idx].key, - gtk_data[notif_idx].key, - sizeof(gtk_data[notif_idx].key)); - /* The rsc for both gtk keys are stored in gtk[0]->sc->mcast_rsc * The gtk ids can be any two numbers between 0 and 3, * the id_map maps between the key id and the index in sc->mcast @@ -307,13 +314,27 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx], sc, rsc_idx); - /* if it's as long as the TKIP encryption key, copy MIC key */ - if (wowlan_status->gtk[status_idx].len == - NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) - memcpy(wowlan_status->gtk[status_idx].key + - NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, - gtk_data[notif_idx].tkip_mic_key, - sizeof(gtk_data[notif_idx].tkip_mic_key)); + if (key_status == IWL_WOWLAN_STATUS_NEW_KEY) { + memcpy(wowlan_status->gtk[status_idx].key, + gtk_data[notif_idx].key, + sizeof(gtk_data[notif_idx].key)); + + /* if it's as long as the TKIP encryption key, + * copy MIC key + */ + if (wowlan_status->gtk[status_idx].len == + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(wowlan_status->gtk[status_idx].key + + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + gtk_data[notif_idx].tkip_mic_key, + sizeof(gtk_data[notif_idx].tkip_mic_key)); + } else { + /* If the key status is WOWLAN_STATUS_OLD_KEY, it + * indicates that no key material is present, Set the + * key length to 0 as an indication + */ + wowlan_status->gtk[status_idx].len = 0; + } status_idx++; } } @@ -360,11 +381,11 @@ static void iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, const struct iwl_wowlan_igtk_status *igtk) { - BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key)); - - if (!igtk->key_len) + if (!igtk->key_status) return; + BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key)); + wowlan_status->igtk.len = igtk->key_len; wowlan_status->igtk.flags = igtk->key_flags; wowlan_status->igtk.id = @@ -372,7 +393,15 @@ iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) + WOWLAN_IGTK_MIN_INDEX; - memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key)); + if (igtk->key_status == IWL_WOWLAN_STATUS_NEW_KEY) + memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key)); + else + /* If the key status is WOWLAN_STATUS_OLD_KEY, it indicates + * that no key material is present. Set the key length to 0 + * as an indication. + */ + wowlan_status->igtk.len = 0; + iwl_mld_convert_mcast_ipn(&wowlan_status->igtk, igtk); } @@ -386,7 +415,7 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, for (int notif_idx = 0; notif_idx < WOWLAN_BIGTK_KEYS_NUM; notif_idx++) { - if (!bigtk[notif_idx].key_len) + if (!bigtk[notif_idx].key_status) continue; wowlan_status->bigtk[status_idx].len = bigtk[notif_idx].key_len; @@ -399,32 +428,218 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, BUILD_BUG_ON(sizeof(wowlan_status->bigtk[status_idx].key) < sizeof(bigtk[notif_idx].key)); - memcpy(wowlan_status->bigtk[status_idx].key, - bigtk[notif_idx].key, sizeof(bigtk[notif_idx].key)); + if (bigtk[notif_idx].key_status == IWL_WOWLAN_STATUS_NEW_KEY) + memcpy(wowlan_status->bigtk[status_idx].key, + bigtk[notif_idx].key, + sizeof(bigtk[notif_idx].key)); + else + /* If the key status is WOWLAN_STATUS_OLD_KEY, it + * indicates that no key material is present. Set the + * key length to 0 as an indication. + */ + wowlan_status->bigtk[status_idx].len = 0; + iwl_mld_convert_mcast_ipn(&wowlan_status->bigtk[status_idx], &bigtk[notif_idx]); status_idx++; } } +static void +iwl_mld_convert_mlo_keys(struct iwl_mld *mld, + const struct iwl_wowlan_info_notif *notif, + struct iwl_mld_wowlan_status *wowlan_status) +{ + if (!notif->num_mlo_link_keys) + return; + + wowlan_status->num_mlo_keys = notif->num_mlo_link_keys; + + if (IWL_FW_CHECK(mld, wowlan_status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, + "Too many MLO keys: %d, max %d\n", + wowlan_status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) + wowlan_status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; + + for (int i = 0; i < wowlan_status->num_mlo_keys; i++) { + const struct iwl_wowlan_mlo_gtk *fw_mlo_key = ¬if->mlo_gtks[i]; + struct iwl_mld_wowlan_mlo_key *driver_mlo_key = + &wowlan_status->mlo_keys[i]; + u16 flags = le16_to_cpu(fw_mlo_key->flags); + + driver_mlo_key->link_id = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); + driver_mlo_key->type = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); + driver_mlo_key->idx = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); + + BUILD_BUG_ON(sizeof(driver_mlo_key->key) != sizeof(fw_mlo_key->key)); + BUILD_BUG_ON(sizeof(driver_mlo_key->pn) != sizeof(fw_mlo_key->pn)); + + memcpy(driver_mlo_key->key, fw_mlo_key->key, sizeof(fw_mlo_key->key)); + memcpy(driver_mlo_key->pn, fw_mlo_key->pn, sizeof(fw_mlo_key->pn)); + } +} + +static void +iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5, + struct iwl_wowlan_info_notif *notif) +{ + /* Convert GTK from v3 to the new format */ + BUILD_BUG_ON(ARRAY_SIZE(notif->gtk) != ARRAY_SIZE(notif_v5->gtk)); + + for (int i = 0; i < ARRAY_SIZE(notif_v5->gtk); i++) { + const struct iwl_wowlan_gtk_status_v3 *gtk_v3 = ¬if_v5->gtk[i]; + struct iwl_wowlan_gtk_status *gtk = ¬if->gtk[i]; + + /* Copy key material and metadata */ + BUILD_BUG_ON(sizeof(gtk->key) != sizeof(gtk_v3->key)); + BUILD_BUG_ON(sizeof(gtk->tkip_mic_key) != sizeof(gtk_v3->tkip_mic_key)); + + memcpy(gtk->key, gtk_v3->key, sizeof(gtk_v3->key)); + + gtk->key_len = gtk_v3->key_len; + gtk->key_flags = gtk_v3->key_flags; + + memcpy(gtk->tkip_mic_key, gtk_v3->tkip_mic_key, + sizeof(gtk_v3->tkip_mic_key)); + gtk->sc = gtk_v3->sc; + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (gtk_v3->key_len) + gtk->key_status = IWL_WOWLAN_STATUS_NEW_KEY; + } + + /* Convert IGTK from v1 to the new format, only one IGTK is passed by FW */ + BUILD_BUG_ON(offsetof(struct iwl_wowlan_igtk_status, key_status) != + sizeof(struct iwl_wowlan_igtk_status_v1)); + + memcpy(¬if->igtk[0], ¬if_v5->igtk[0], + offsetof(struct iwl_wowlan_igtk_status, key_status)); + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (notif_v5->igtk[0].key_len) + notif->igtk[0].key_status = IWL_WOWLAN_STATUS_NEW_KEY; + + /* Convert BIGTK from v1 to the new format */ + BUILD_BUG_ON(ARRAY_SIZE(notif->bigtk) != ARRAY_SIZE(notif_v5->bigtk)); + + for (int i = 0; i < ARRAY_SIZE(notif_v5->bigtk); i++) { + /* Copy everything until key_status */ + memcpy(¬if->bigtk[i], ¬if_v5->bigtk[i], + offsetof(struct iwl_wowlan_igtk_status, key_status)); + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (notif_v5->bigtk[i].key_len) + notif->bigtk[i].key_status = IWL_WOWLAN_STATUS_NEW_KEY; + } + + notif->replay_ctr = notif_v5->replay_ctr; + notif->pattern_number = notif_v5->pattern_number; + notif->qos_seq_ctr = notif_v5->qos_seq_ctr; + notif->wakeup_reasons = notif_v5->wakeup_reasons; + notif->num_of_gtk_rekeys = notif_v5->num_of_gtk_rekeys; + notif->transmitted_ndps = notif_v5->transmitted_ndps; + notif->received_beacons = notif_v5->received_beacons; + notif->tid_tear_down = notif_v5->tid_tear_down; + notif->station_id = notif_v5->station_id; + notif->num_mlo_link_keys = notif_v5->num_mlo_link_keys; + notif->tid_offloaded_tx = notif_v5->tid_offloaded_tx; + + /* Copy MLO GTK keys */ + if (notif_v5->num_mlo_link_keys) { + memcpy(notif->mlo_gtks, notif_v5->mlo_gtks, + notif_v5->num_mlo_link_keys * sizeof(struct iwl_wowlan_mlo_gtk)); + } +} + +static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, + u32 len, + u32 expected_len, + u8 num_mlo_keys, + int version) +{ + u32 len_with_mlo_keys; + + if (IWL_FW_CHECK(mld, len < expected_len, + "Invalid wowlan_info_notif v%d (expected=%u got=%u)\n", + version, expected_len, len)) + return false; + + len_with_mlo_keys = expected_len + + (num_mlo_keys * sizeof(struct iwl_wowlan_mlo_gtk)); + + if (IWL_FW_CHECK(mld, len < len_with_mlo_keys, + "Invalid wowlan_info_notif v%d with MLO keys (expected=%u got=%u)\n", + version, len_with_mlo_keys, len)) + return false; + + return true; +} + static bool iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, struct iwl_rx_packet *pkt) { - const struct iwl_wowlan_info_notif *notif = (void *)pkt->data; - u32 expected_len, len = iwl_rx_packet_payload_len(pkt); - - expected_len = sizeof(*notif); + const struct iwl_wowlan_info_notif *notif; + struct iwl_wowlan_info_notif *converted_notif __free(kfree) = NULL; + u32 len = iwl_rx_packet_payload_len(pkt); + int wowlan_info_ver = iwl_fw_lookup_notif_ver(mld->fw, + PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + IWL_FW_CMD_VER_UNKNOWN); + + if (wowlan_info_ver == 5) { + /* v5 format - validate before conversion */ + const struct iwl_wowlan_info_notif_v5 *notif_v5 = (void *)pkt->data; + + if (!iwl_mld_validate_wowlan_notif_size(mld, len, + sizeof(*notif_v5), + notif_v5->num_mlo_link_keys, + 5)) + return true; + + converted_notif = kzalloc(struct_size(converted_notif, + mlo_gtks, + notif_v5->num_mlo_link_keys), + GFP_ATOMIC); + if (!converted_notif) { + IWL_ERR(mld, + "Failed to allocate memory for converted wowlan_info_notif\n"); + return true; + } - if (IWL_FW_CHECK(mld, len < expected_len, - "Invalid wowlan_info_notif (expected=%ud got=%ud)\n", - expected_len, len)) + iwl_mld_convert_wowlan_notif_v5(notif_v5, + converted_notif); + notif = converted_notif; + } else if (wowlan_info_ver == 6) { + notif = (void *)pkt->data; + if (!iwl_mld_validate_wowlan_notif_size(mld, len, + sizeof(*notif), + notif->num_mlo_link_keys, + 6)) + return true; + } else { + /* smaller versions are not supported */ + IWL_WARN(mld, + "Unsupported wowlan_info_notif version %d\n", + wowlan_info_ver); return true; + } if (IWL_FW_CHECK(mld, notif->tid_offloaded_tx != IWL_WOWLAN_OFFLOAD_TID, "Invalid tid_offloaded_tx %d\n", - wowlan_status->tid_offloaded_tx)) + notif->tid_offloaded_tx)) return true; iwl_mld_convert_gtk_resume_data(mld, wowlan_status, notif->gtk, @@ -442,8 +657,10 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld, wowlan_status->num_of_gtk_rekeys = le32_to_cpu(notif->num_of_gtk_rekeys); wowlan_status->wakeup_reasons = le32_to_cpu(notif->wakeup_reasons); + + iwl_mld_convert_mlo_keys(mld, notif, wowlan_status); + return false; - /* TODO: mlo_links (task=MLO)*/ } static bool @@ -619,8 +836,8 @@ iwl_mld_set_key_rx_seq_tids(struct ieee80211_key_conf *key, } static void -iwl_mld_set_key_rx_seq(struct ieee80211_key_conf *key, - struct iwl_mld_mcast_key_data *key_data) +iwl_mld_update_mcast_rx_seq(struct ieee80211_key_conf *key, + struct iwl_mld_mcast_key_data *key_data) { switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: @@ -687,132 +904,53 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, struct iwl_mld_wowlan_status *wowlan_status = data->wowlan_status; u8 status_idx; - /* TODO: check key link id (task=MLO) */ - if (data->unhandled_cipher) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - /* ignore WEP completely, nothing to do */ - return; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - case WLAN_CIPHER_SUITE_TKIP: + if (key->keyidx >= 0 && key->keyidx <= 3) { + /* PTK */ if (sta) { iwl_mld_update_ptk_rx_seq(data->mld, wowlan_status, sta, key, key->cipher == WLAN_CIPHER_SUITE_TKIP); - return; + /* GTK */ + } else { + status_idx = key->keyidx == wowlan_status->gtk[1].id; + iwl_mld_update_mcast_rx_seq(key, + &wowlan_status->gtk[status_idx]); } + } - if (WARN_ON(data->gtk_cipher && - data->gtk_cipher != key->cipher)) - return; + /* IGTK */ + if (key->keyidx == 4 || key->keyidx == 5) { + if (key->keyidx == wowlan_status->igtk.id) + iwl_mld_update_mcast_rx_seq(key, &wowlan_status->igtk); + } - data->gtk_cipher = key->cipher; - status_idx = key->keyidx == wowlan_status->gtk[1].id; - iwl_mld_set_key_rx_seq(key, &wowlan_status->gtk[status_idx]); - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - if (key->keyidx == 4 || key->keyidx == 5) { - if (WARN_ON(data->igtk_cipher && - data->igtk_cipher != key->cipher)) - return; - - data->igtk_cipher = key->cipher; - if (key->keyidx == wowlan_status->igtk.id) - iwl_mld_set_key_rx_seq(key, &wowlan_status->igtk); - } - if (key->keyidx == 6 || key->keyidx == 7) { - if (WARN_ON(data->bigtk_cipher && - data->bigtk_cipher != key->cipher)) - return; - - data->bigtk_cipher = key->cipher; - status_idx = key->keyidx == wowlan_status->bigtk[1].id; - iwl_mld_set_key_rx_seq(key, &wowlan_status->bigtk[status_idx]); - } - break; - default: - data->unhandled_cipher = true; - return; + /* BIGTK */ + if (key->keyidx == 6 || key->keyidx == 7) { + status_idx = key->keyidx == wowlan_status->bigtk[1].id; + iwl_mld_update_mcast_rx_seq(key, + &wowlan_status->bigtk[status_idx]); } - data->num_keys++; } static void iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, struct iwl_mld *mld, struct iwl_mld_mcast_key_data *key_data, - struct ieee80211_bss_conf *link_conf, - u32 cipher) + struct ieee80211_bss_conf *link_conf) { struct ieee80211_key_conf *key_config; - struct { - struct ieee80211_key_conf conf; - u8 key[WOWLAN_KEY_MAX_SIZE]; - } conf = { - .conf.cipher = cipher, - .conf.keyidx = key_data->id, - }; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - u8 key[WOWLAN_KEY_MAX_SIZE]; - - BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_BIP_GMAC_128); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_BIP_GMAC_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_AES_CMAC); - BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); if (!key_data->len) return; - switch (cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf.conf.keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; - break; - default: - WARN_ON(1); - } - - memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - - memcpy(key, key_data->key, sizeof(key_data->key)); - - key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key, - sizeof(key), link_id); + key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key_data->key, + sizeof(key_data->key), link_id); if (IS_ERR(key_config)) return; - iwl_mld_set_key_rx_seq(key_config, key_data); + iwl_mld_update_mcast_rx_seq(key_config, key_data); /* The FW holds only one igtk so we keep track of the valid one */ if (key_config->keyidx == 4 || key_config->keyidx == 5) { @@ -831,37 +969,78 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, } /* Also keep track of the new BIGTK */ - if ((key_config->keyidx == 6 || key_config->keyidx == 7) && - vif->type == NL80211_IFTYPE_STATION) { - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - - rcu_assign_pointer(mld_vif->bigtks[key_config->keyidx - 6], key_config); - } + if (key_config->keyidx == 6 || key_config->keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key_config, true); } static void -iwl_mld_add_all_rekeys(struct ieee80211_vif *vif, +iwl_mld_add_all_rekeys(struct iwl_mld *mld, + struct ieee80211_vif *vif, struct iwl_mld_wowlan_status *wowlan_status, - struct iwl_mld_resume_key_iter_data *key_iter_data, struct ieee80211_bss_conf *link_conf) { int i; for (i = 0; i < ARRAY_SIZE(wowlan_status->gtk); i++) - iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->gtk[i], - link_conf, - key_iter_data->gtk_cipher); + iwl_mld_add_mcast_rekey(vif, mld, &wowlan_status->gtk[i], + link_conf); - iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->igtk, - link_conf, key_iter_data->igtk_cipher); + iwl_mld_add_mcast_rekey(vif, mld, &wowlan_status->igtk, link_conf); for (i = 0; i < ARRAY_SIZE(wowlan_status->bigtk); i++) - iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->bigtk[i], - link_conf, - key_iter_data->bigtk_cipher); + iwl_mld_add_mcast_rekey(vif, mld, &wowlan_status->bigtk[i], + link_conf); +} + +static void iwl_mld_mlo_rekey(struct iwl_mld *mld, + struct iwl_mld_wowlan_status *wowlan_status, + struct ieee80211_vif *vif) +{ + struct iwl_mld_old_mlo_keys *old_keys __free(kfree) = NULL; + + IWL_DEBUG_WOWLAN(mld, "Num of MLO Keys: %d\n", wowlan_status->num_mlo_keys); + + if (!wowlan_status->num_mlo_keys) + return; + + for (int i = 0; i < wowlan_status->num_mlo_keys; i++) { + struct iwl_mld_wowlan_mlo_key *mlo_key = &wowlan_status->mlo_keys[i]; + struct ieee80211_key_conf *key; + struct ieee80211_key_seq seq; + u8 link_id = mlo_key->link_id; + + if (IWL_FW_CHECK(mld, mlo_key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + mlo_key->idx >= 8 || + mlo_key->type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES, + "Invalid MLO key link_id %d, idx %d, type %d\n", + mlo_key->link_id, mlo_key->idx, mlo_key->type)) + continue; + + if (!(vif->valid_links & BIT(link_id)) || + (vif->active_links & BIT(link_id))) + continue; + + IWL_DEBUG_WOWLAN(mld, "Add MLO key id %d, link id %d\n", + mlo_key->idx, link_id); + + key = ieee80211_gtk_rekey_add(vif, mlo_key->idx, mlo_key->key, + sizeof(mlo_key->key), link_id); + + if (IS_ERR(key)) + continue; + + /* + * mac80211 expects the PN in big-endian + * also note that seq is a union of all cipher types + * (ccmp, gcmp, cmac, gmac), and they all have the same + * pn field (of length 6) so just copy it to ccmp.pn. + */ + for (int j = 5; j >= 0; j--) + seq.ccmp.pn[5 - j] = mlo_key->pn[j]; + + /* group keys are non-QoS and use TID 0 */ + ieee80211_set_key_rx_seq(key, 0, &seq); + } } static bool @@ -884,23 +1063,19 @@ iwl_mld_update_sec_keys(struct iwl_mld *mld, ieee80211_iter_keys(mld->hw, vif, iwl_mld_resume_keys_iter, &key_iter_data); - if (key_iter_data.unhandled_cipher) - return false; - - IWL_DEBUG_WOWLAN(mld, - "Number of installed keys: %d, Number of rekeys: %d\n", - key_iter_data.num_keys, + IWL_DEBUG_WOWLAN(mld, "Number of rekeys: %d\n", wowlan_status->num_of_gtk_rekeys); - if (!key_iter_data.num_keys || !wowlan_status->num_of_gtk_rekeys) + if (!wowlan_status->num_of_gtk_rekeys) return true; - iwl_mld_add_all_rekeys(vif, wowlan_status, &key_iter_data, + iwl_mld_add_all_rekeys(mld, vif, wowlan_status, link_conf); + iwl_mld_mlo_rekey(mld, wowlan_status, vif); + ieee80211_gtk_rekey_notify(vif, link_conf->bssid, (void *)&replay_ctr, GFP_KERNEL); - /* TODO: MLO rekey (task=MLO) */ return true; } @@ -1179,7 +1354,6 @@ static int iwl_mld_wait_d3_notif(struct iwl_mld *mld, WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION) }; struct iwl_notification_wait wait_d3_notif; - enum iwl_d3_status d3_status; int ret; if (with_wowlan) @@ -1195,14 +1369,10 @@ static int iwl_mld_wait_d3_notif(struct iwl_mld *mld, iwl_mld_handle_d3_notif, resume_data); - ret = iwl_trans_d3_resume(mld->trans, &d3_status, false, false); - if (ret || d3_status != IWL_D3_STATUS_ALIVE) { - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(mld, "Device was reset during suspend\n"); - ret = -ENOENT; - } else { - IWL_ERR(mld, "Transport resume failed\n"); - } + ret = iwl_trans_d3_resume(mld->trans, false); + if (ret) { + /* Avoid sending commands if the FW is dead */ + iwl_trans_notify_fw_error(mld->trans); iwl_remove_notification(&mld->notif_wait, &wait_d3_notif); return ret; } @@ -1236,16 +1406,11 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld) iwl_mld_low_latency_stop(mld); - /* This will happen if iwl_mld_supsend failed with FW error */ - if (mld->trans->state == IWL_TRANS_NO_FW && - test_bit(STATUS_FW_ERROR, &mld->trans->status)) - return -ENODEV; - ret = iwl_mld_update_device_power(mld, true); if (ret) { IWL_ERR(mld, "d3 suspend: couldn't send power_device %d\n", ret); - goto out; + return ret; } ret = iwl_mld_send_cmd_pdu(mld, D3_CONFIG_CMD, @@ -1253,24 +1418,20 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld) if (ret) { IWL_ERR(mld, "d3 suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - goto out; + return ret; } - ret = iwl_trans_d3_suspend(mld->trans, false, false); + ret = iwl_trans_d3_suspend(mld->trans, false); if (ret) { IWL_ERR(mld, "d3 suspend: trans_d3_suspend failed %d\n", ret); + /* We are going to stop the FW. Avoid sending commands in that flow */ + iwl_trans_notify_fw_error(mld->trans); } else { /* Async notification might send hcmds, which is not allowed in suspend */ iwl_mld_cancel_async_notifications(mld); mld->fw_status.in_d3 = true; } - out: - if (ret) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } - return ret; } @@ -1290,15 +1451,12 @@ int iwl_mld_no_wowlan_resume(struct iwl_mld *mld) iwl_fw_dbg_read_d3_debug_data(&mld->fwrt); ret = iwl_mld_wait_d3_notif(mld, &resume_data, false); + if (ret) + return ret; if (!ret && (resume_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) return -ENODEV; - if (ret) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - return ret; - } iwl_mld_low_latency_restart(mld); return iwl_mld_update_device_power(mld, false); @@ -1530,7 +1688,8 @@ static void iwl_mld_set_wowlan_config_cmd(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan, struct iwl_wowlan_config_cmd *wowlan_config_cmd, - struct ieee80211_sta *ap_sta) + struct ieee80211_sta *ap_sta, + struct ieee80211_bss_conf *link) { wowlan_config_cmd->is_11n_connection = ap_sta->deflink.ht_cap.ht_supported; @@ -1540,6 +1699,9 @@ iwl_mld_set_wowlan_config_cmd(struct iwl_mld *mld, if (ap_sta->mfp) wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (iwl_mld_beacon_protection_enabled(mld, link)) + wowlan_config_cmd->flags |= HAS_BEACON_PROTECTION; + if (wowlan->disconnect) wowlan_config_cmd->wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | @@ -1737,7 +1899,7 @@ iwl_mld_wowlan_config(struct iwl_mld *mld, struct ieee80211_vif *bss_vif, return ret; iwl_mld_set_wowlan_config_cmd(mld, wowlan, - &wowlan_config_cmd, ap_sta); + &wowlan_config_cmd, ap_sta, link_conf); ret = iwl_mld_send_cmd_pdu(mld, WOWLAN_CONFIGURATION, &wowlan_config_cmd); if (ret) @@ -1807,7 +1969,6 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) }; int link_id; int ret; - bool fw_err = false; lockdep_assert_wiphy(mld->wiphy); @@ -1850,7 +2011,6 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) ret = iwl_mld_wait_d3_notif(mld, &resume_data, true); if (ret) { IWL_ERR(mld, "Couldn't get the d3 notifs %d\n", ret); - fw_err = true; goto err; } @@ -1887,11 +2047,6 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) goto out; err: - if (fw_err) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } - mld->fw_status.in_hw_restart = true; ret = 1; out: diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c index cc052b0aa53f..b9c9cd3f44e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c @@ -86,7 +86,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mld *mld, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) { mld->fw_status.do_not_dump_once = true; - iwl_trans_suppress_cmd_error_once(mld->trans); + mld->trans->suppress_cmd_error_once = true; } /* take the return value to make compiler happy - it will @@ -1001,8 +1001,12 @@ void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw, * If not, this is a per-link dir of a MLO vif, add in it the iwlmld * dir. */ - if (!mld_link_dir) + if (!mld_link_dir) { mld_link_dir = debugfs_create_dir("iwlmld", dir); + } else { + /* Release the reference from debugfs_lookup */ + dput(mld_link_dir); + } } static ssize_t _iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index 38993d65c052..ed379825a923 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -115,20 +115,12 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld, static void iwl_mld_set_he_support(struct iwl_mld *mld, struct ieee80211_vif *vif, - struct iwl_mac_config_cmd *cmd, - int cmd_ver) + struct iwl_mac_config_cmd *cmd) { - if (vif->type == NL80211_IFTYPE_AP) { - if (cmd_ver == 2) - cmd->wifi_gen_v2.he_ap_support = cpu_to_le16(1); - else - cmd->wifi_gen.he_ap_support = 1; - } else { - if (cmd_ver == 2) - cmd->wifi_gen_v2.he_support = cpu_to_le16(1); - else - cmd->wifi_gen.he_support = 1; - } + if (vif->type == NL80211_IFTYPE_AP) + cmd->wifi_gen.he_ap_support = 1; + else + cmd->wifi_gen.he_support = 1; } /* fill the common part for all interface types */ @@ -140,9 +132,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); struct ieee80211_bss_conf *link_conf; unsigned int link_id; - int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, - MAC_CONFIG_CMD), 0); lockdep_assert_wiphy(mld->wiphy); @@ -169,11 +158,8 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, * and enable both when we have MLO. */ if (ieee80211_vif_is_mld(vif)) { - iwl_mld_set_he_support(mld, vif, cmd, cmd_ver); - if (cmd_ver == 2) - cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); - else - cmd->wifi_gen.eht_support = 1; + iwl_mld_set_he_support(mld, vif, cmd); + cmd->wifi_gen.eht_support = 1; return; } @@ -181,7 +167,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, if (!link_conf->he_support) continue; - iwl_mld_set_he_support(mld, vif, cmd, cmd_ver); + iwl_mld_set_he_support(mld, vif, cmd); /* EHT, if supported, was already set above */ break; @@ -451,24 +437,21 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) return ret; } -int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) +void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - int ret; lockdep_assert_wiphy(mld->wiphy); - ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) - return -EINVAL; + return; RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL); iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_VIF, mld_vif->fw_id); - - return ret; } void iwl_mld_set_vif_associated(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index 05dcb63701b1..a3573d20f214 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -125,8 +125,6 @@ struct iwl_mld_emlsr { * @ap_sta: pointer to AP sta, for easier access to it. * Relevant only for STA vifs. * @authorized: indicates the AP station was set to authorized - * @bigtks: BIGTKs of the AP, for beacon protection. - * Only valid for STA. (FIXME: needs to be per link) * @num_associated_stas: number of associated STAs. Relevant only for AP mode. * @ap_ibss_active: whether the AP/IBSS was started * @cca_40mhz_workaround: When we are connected in 2.4 GHz and 40 MHz, and the @@ -158,7 +156,6 @@ struct iwl_mld_vif { struct iwl_mld_session_protect session_protect; struct ieee80211_sta *ap_sta; bool authorized; - struct ieee80211_key_conf __rcu *bigtks[2]; u8 num_associated_stas; bool ap_ibss_active; enum iwl_mld_cca_40mhz_wa_status cca_40mhz_workaround; @@ -227,7 +224,7 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, u32 action); int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); -int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); +void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); void iwl_mld_set_vif_associated(struct iwl_mld *mld, struct ieee80211_vif *vif); u8 iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld *mld); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c index 13462a5ad79a..04192c5f07ff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c @@ -368,3 +368,41 @@ int iwl_mld_update_sta_keys(struct iwl_mld *mld, &data); return data.err; } + +void iwl_mld_track_bigtk(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *key, bool add) +{ + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_mld_link *link; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (WARN_ON(key->keyidx < 6 || key->keyidx > 7)) + return; + + if (WARN_ON(key->link_id < 0)) + return; + + link = iwl_mld_link_dereference_check(mld_vif, key->link_id); + if (WARN_ON(!link)) + return; + + if (add) + rcu_assign_pointer(link->bigtks[key->keyidx - 6], key); + else + RCU_INIT_POINTER(link->bigtks[key->keyidx - 6], NULL); +} + +bool iwl_mld_beacon_protection_enabled(struct iwl_mld *mld, + struct ieee80211_bss_conf *link) +{ + struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); + + if (WARN_ON(!mld_link)) + return false; + + return rcu_access_pointer(mld_link->bigtks[0]) || + rcu_access_pointer(mld_link->bigtks[1]); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.h b/drivers/net/wireless/intel/iwlwifi/mld/key.h index a68ea48913be..5a9efdaa3b03 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.h @@ -36,4 +36,11 @@ iwl_mld_cleanup_keys_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, key->hw_key_idx = STA_KEY_IDX_INVALID; } +void iwl_mld_track_bigtk(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *key, bool add); + +bool iwl_mld_beacon_protection_enabled(struct iwl_mld *mld, + struct ieee80211_bss_conf *link); + #endif /* __iwl_mld_key_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index 782fc41aa1c3..738f80fe0c50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -532,7 +532,8 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, le32_to_cpu(notif->consec_missed_beacons_other_link); struct ieee80211_bss_conf *link_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id); - u32 bss_param_ch_cnt_link_id; + struct ieee80211_bss_conf *other_link; + u32 bss_param_ch_cnt_link_id, other_link_fw_id; struct ieee80211_vif *vif; u8 link_id; @@ -550,11 +551,6 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (WARN_ON(!vif)) return; - mld->trans->dbg.dump_file_name_ext_valid = true; - snprintf(mld->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "LinkId_%d_MacType_%d", fw_link_id, - iwl_mld_mac80211_iftype_to_fw(vif)); - iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); @@ -572,8 +568,11 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (missed_bcon_since_rx > IWL_MLD_MISSED_BEACONS_THRESHOLD) { ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); - /* try to switch links, no-op if we don't have MLO */ - iwl_mld_int_mlo_scan(mld, vif); + /* 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)) + iwl_mld_int_mlo_scan(mld, vif); } /* no more logic if we're not in EMLSR */ @@ -584,6 +583,17 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (le32_to_cpu(notif->other_link_id) == FW_CTXT_ID_INVALID) return; + other_link_fw_id = le32_to_cpu(notif->other_link_id); + other_link = iwl_mld_fw_id_to_link_conf(mld, other_link_fw_id); + + if (IWL_FW_CHECK(mld, !other_link, "link doesn't exist for: %d\n", + other_link_fw_id)) + return; + + IWL_DEBUG_EHT(mld, + "missed bcn on the other link (link_id=%u): %u\n", + other_link->link_id, scnd_lnk_bcn_lost); + /* Exit EMLSR if we lost more than * IWL_MLD_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH on current link. diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h index cad2c9426349..9e4da8e4de93 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h @@ -36,6 +36,7 @@ struct iwl_probe_resp_data { * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked. * @igtk: fw can only have one IGTK at a time, whereas mac80211 can have two. * This tracks the one IGTK that currently exists in FW. + * @bigtks: BIGTKs of the AP. Only valid for STA mode. * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. * @mon_sta: station used for TX injection in monitor interface. @@ -59,6 +60,7 @@ struct iwl_mld_link { struct ieee80211_chanctx_conf __rcu *chan_ctx; bool he_ru_2mhz_block; struct ieee80211_key_conf *igtk; + struct ieee80211_key_conf __rcu *bigtks[2]; ); /* And here fields that survive a fw restart */ struct iwl_mld_int_sta bcast_sta; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index b0bd01914a91..5725104a53bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -626,7 +626,7 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } - if (vif->p2p || iwl_fw_lookup_cmd_ver(mld->fw, PHY_CONTEXT_CMD, 0) < 5) + if (vif->p2p) vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW; /* @@ -1966,13 +1966,8 @@ iwl_mld_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) iwl_fw_runtime_suspend(&mld->fwrt); ret = iwl_mld_wowlan_suspend(mld, wowlan); - if (ret) { - if (ret < 0) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } + if (ret) return 1; - } if (iwl_mld_no_wowlan_suspend(mld)) return 1; @@ -2065,9 +2060,8 @@ static int iwl_mld_set_key_add(struct iwl_mld *mld, return -EOPNOTSUPP; } - if (vif->type == NL80211_IFTYPE_STATION && - (keyidx == 6 || keyidx == 7)) - rcu_assign_pointer(mld_vif->bigtks[keyidx - 6], key); + if (keyidx == 6 || keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key, true); /* After exiting from RFKILL, hostapd configures GTK/ITGK before the * AP is started, but those keys can't be sent to the FW before the @@ -2116,9 +2110,8 @@ static void iwl_mld_set_key_remove(struct iwl_mld *mld, sta ? iwl_mld_sta_from_mac80211(sta) : NULL; int keyidx = key->keyidx; - if (vif->type == NL80211_IFTYPE_STATION && - (keyidx == 6 || keyidx == 7)) - RCU_INIT_POINTER(mld_vif->bigtks[keyidx - 6], NULL); + if (keyidx == 6 || keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key, false); if (mld_sta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 7b46ccc306ab..a6962256bdd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -147,6 +147,7 @@ iwl_mld_construct_fw_runtime(struct iwl_mld *mld, struct iwl_trans *trans, */ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = { HCMD_NAME(UCODE_ALIVE_NTFY), + HCMD_NAME(REPLY_ERROR), HCMD_NAME(INIT_COMPLETE_NOTIF), HCMD_NAME(PHY_CONTEXT_CMD), HCMD_NAME(SCAN_CFG_CMD), @@ -158,12 +159,14 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = { HCMD_NAME(LEDS_CMD), HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION), HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION), + HCMD_NAME(PHY_CONFIGURATION_CMD), HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), HCMD_NAME(POWER_TABLE_CMD), HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), HCMD_NAME(BEACON_NOTIFICATION), HCMD_NAME(BEACON_TEMPLATE_CMD), HCMD_NAME(TX_ANT_CONFIGURATION_CMD), + HCMD_NAME(BT_CONFIG), HCMD_NAME(REDUCE_TX_POWER_CMD), HCMD_NAME(MISSED_BEACONS_NOTIFICATION), HCMD_NAME(MAC_PM_POWER_TABLE), @@ -251,6 +254,7 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(RX_BAID_ALLOCATION_CONFIG_CMD), HCMD_NAME(SCD_QUEUE_CONFIG_CMD), + HCMD_NAME(SEC_KEY_CMD), HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(TLC_MNG_UPDATE_NOTIF), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index e57f5388fe77..241a6271d13d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -357,38 +357,26 @@ iwl_mld_vif_iter_emlsr_mode_notif(void *data, u8 *mac, struct ieee80211_vif *vif) { const struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - enum iwl_mvm_fw_esr_recommendation action; - const struct iwl_esr_mode_notif *notif = NULL; - - if (iwl_fw_lookup_notif_ver(mld_vif->mld->fw, DATA_PATH_GROUP, - ESR_MODE_NOTIF, 0) > 1) { - notif = (void *)data; - action = le32_to_cpu(notif->action); - } else { - const struct iwl_esr_mode_notif_v1 *notif_v1 = (void *)data; - - action = le32_to_cpu(notif_v1->action); - } + const struct iwl_esr_mode_notif *notif = (void *)data; + enum iwl_mvm_fw_esr_recommendation action = le32_to_cpu(notif->action); if (!iwl_mld_vif_has_emlsr_cap(vif)) return; switch (action) { case ESR_RECOMMEND_LEAVE: - if (notif) - IWL_DEBUG_INFO(mld_vif->mld, - "FW recommend leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_INFO(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: - if (notif) - IWL_DEBUG_INFO(mld_vif->mld, - "FW force leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_INFO(mld_vif->mld, + "FW force leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); fallthrough; case ESR_RECOMMEND_ENTER: default: @@ -735,12 +723,6 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld, u16 max_grade = 0; unsigned long link_id; - /* - * TODO: don't select links that weren't discovered in the last scan - * This requires mac80211 (or cfg80211) changes to forward/track when - * a BSS was last updated. cfg80211 already tracks this information but - * it is not exposed within the kernel. - */ for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf = link_conf_dereference_protected(vif, link_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index f17aeca4fae6..884973d0b344 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -333,7 +333,6 @@ CMD_VERSIONS(bt_coex_notif, CMD_VERSIONS(beacon_notification, CMD_VER_ENTRY(6, iwl_extended_beacon_notif)) CMD_VERSIONS(emlsr_mode_notif, - CMD_VER_ENTRY(1, iwl_esr_mode_notif_v1) CMD_VER_ENTRY(2, iwl_esr_mode_notif)) CMD_VERSIONS(emlsr_trans_fail_notif, CMD_VER_ENTRY(1, iwl_esr_trans_fail_notif)) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 75d2f5cb23a7..40571125b3ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -163,18 +163,32 @@ int iwl_mld_init_sgom(struct iwl_mld *mld) static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld) { - union iwl_ppag_table_cmd cmd = {}; - int ret, len; + struct iwl_fw_runtime *fwrt = &mld->fwrt; + union iwl_ppag_table_cmd cmd = { + .v7.ppag_config_info.table_source = fwrt->ppag_bios_source, + .v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev, + .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), + }; + int ret; - ret = iwl_fill_ppag_table(&mld->fwrt, &cmd, &len); - /* Not supporting PPAG table is a valid scenario */ - if (ret < 0) - return 0; + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits going to be sent: %d\n", + fwrt->ppag_flags); + + for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) { + for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) { + cmd.v7.gain[chain][subband] = + fwrt->ppag_chains[chain].subbands[subband]; + IWL_DEBUG_RADIO(fwrt, + "PPAG table: chain[%d] band[%d]: gain = %d\n", + chain, subband, cmd.v7.gain[chain][subband]); + } + } IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), - &cmd, len); + &cmd, sizeof(cmd.v7)); if (ret < 0) IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", ret); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/roc.c b/drivers/net/wireless/intel/iwlwifi/mld/roc.c index e85f45bce79a..4136c98030d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/roc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/roc.c @@ -82,9 +82,6 @@ int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct iwl_roc_req cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), }; - u8 ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); - u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd); enum iwl_roc_activity activity; int ret = 0; @@ -140,7 +137,7 @@ int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, memcpy(cmd.node_addr, vif->addr, ETH_ALEN); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - &cmd, cmd_len); + &cmd); if (ret) { IWL_ERR(mld, "Couldn't send the ROC_CMD\n"); return ret; @@ -190,9 +187,6 @@ int iwl_mld_cancel_roc(struct ieee80211_hw *hw, struct iwl_roc_req cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), }; - u8 ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); - u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd); int ret; lockdep_assert_wiphy(mld->wiphy); @@ -208,7 +202,7 @@ int iwl_mld_cancel_roc(struct ieee80211_hw *hw, cmd.activity = cpu_to_le32(mld_vif->roc_activity); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - &cmd, cmd_len); + &cmd); if (ret) IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index b6dedd1ecd4d..20d866dd92c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -1611,20 +1611,21 @@ iwl_mld_rx_with_sta(struct iwl_mld *mld, struct ieee80211_hdr *hdr, return sta; } -#define KEY_IDX_LEN 2 - static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rx_status, u32 mpdu_status, u32 mpdu_len) { + struct iwl_mld_link *link; struct wireless_dev *wdev; struct iwl_mld_sta *mld_sta; struct iwl_mld_vif *mld_vif; u8 keyidx; struct ieee80211_key_conf *key; const u8 *frame = (void *)hdr; + const u8 *mmie; + u8 link_id; if ((mpdu_status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) @@ -1657,21 +1658,30 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, return 0; } + link_id = rx_status->link_valid ? rx_status->link_id : 0; + link = rcu_dereference(mld_vif->link[link_id]); + if (WARN_ON_ONCE(!link)) + return -1; + /* both keys will have the same cipher and MIC length, use * whichever one is available */ - key = rcu_dereference(mld_vif->bigtks[0]); + key = rcu_dereference(link->bigtks[0]); if (!key) { - key = rcu_dereference(mld_vif->bigtks[1]); + key = rcu_dereference(link->bigtks[1]); if (!key) goto report; } - if (mpdu_len < key->icv_len + IEEE80211_GMAC_PN_LEN + KEY_IDX_LEN) + /* get the real key ID */ + if (mpdu_len < key->icv_len) goto report; - /* get the real key ID */ - keyidx = frame[mpdu_len - key->icv_len - IEEE80211_GMAC_PN_LEN - KEY_IDX_LEN]; + mmie = frame + (mpdu_len - key->icv_len); + + /* the position of the key_id in ieee80211_mmie_16 is the same */ + keyidx = le16_to_cpu(((const struct ieee80211_mmie *) mmie)->key_id); + /* and if that's the other key, look it up */ if (keyidx != key->keyidx) { /* shouldn't happen since firmware checked, but be safe @@ -1680,7 +1690,7 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, if (keyidx != 6 && keyidx != 7) return -1; - key = rcu_dereference(mld_vif->bigtks[keyidx - 6]); + key = rcu_dereference(link->bigtks[keyidx - 6]); if (!key) goto report; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index 62f97a18a16c..fd1022ddc912 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -504,9 +504,7 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, */ if (scan_status == IWL_MLD_SCAN_REGULAR && ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP && - gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE && - iwl_fw_lookup_notif_ver(mld->fw, SCAN_GROUP, - CHANNEL_SURVEY_NOTIF, 0) >= 1) + gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE) flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS; return flags; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 8fb51209b4a6..5cdbfa29a202 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -401,11 +401,9 @@ static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta) static int iwl_mld_send_sta_cmd(struct iwl_mld *mld, const struct iwl_sta_cfg_cmd *cmd) { - u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); - int cmd_len = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0) > 1 ? - sizeof(*cmd) : - sizeof(struct iwl_sta_cfg_cmd_v1); - int ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, cmd_len); + int ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), + cmd); if (ret) IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c index cbc64db5eab6..7b8709716324 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c @@ -379,11 +379,14 @@ static void iwl_mld_update_link_sig(struct ieee80211_vif *vif, int sig, /* TODO: task=statistics handle CQM notifications */ - if (sig < IWL_MLD_LOW_RSSI_MLO_SCAN_THRESH) - iwl_mld_int_mlo_scan(mld, vif); - - if (!iwl_mld_emlsr_active(vif)) + if (!iwl_mld_emlsr_active(vif)) { + /* We're not in EMLSR and our signal is bad, + * try to switch link maybe. EMLSR will be handled below. + */ + if (sig < IWL_MLD_LOW_RSSI_MLO_SCAN_THRESH) + iwl_mld_int_mlo_scan(mld, vif); return; + } /* We are in EMLSR, check if we need to exit */ exit_emlsr_thresh = diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index a9ca92c0455e..0e172281b0c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -157,9 +157,9 @@ iwl_mld_get_highest_fw_mcs(const struct ieee80211_sta_vht_cap *vht_cap, static void iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_vht_cap *vht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { - u16 supp; + u32 supp; int i, highest_mcs; u8 max_nss = link_sta->rx_nss; struct ieee80211_vht_cap ieee_vht_cap = { @@ -182,7 +182,7 @@ iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9); - cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp); + cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le32(supp); /* Check if VHT extended NSS indicates that the bandwidth/NSS * configuration is supported - only for MCS 0 since we already * decoded the MCS bits anyway ourselves. @@ -196,7 +196,7 @@ iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, } } -static u16 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) +static u32 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) { switch (mcs) { case IEEE80211_HE_MCS_SUPPORT_0_7: @@ -216,7 +216,7 @@ static u16 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) static void iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_he_cap *own_he_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); @@ -245,7 +245,7 @@ iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, if (_mcs_80 > _tx_mcs_80) _mcs_80 = _tx_mcs_80; cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80)); + cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80)); /* If one side doesn't support - mark both as not supporting */ if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED || @@ -256,19 +256,19 @@ iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, if (_mcs_160 > _tx_mcs_160) _mcs_160 = _tx_mcs_160; cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] = - cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160)); + cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160)); } } -static void iwl_mld_set_eht_mcs(__le16 ht_rates[][3], +static void iwl_mld_set_eht_mcs(__le32 ht_rates[][3], enum IWL_TLC_MCS_PER_BW bw, - u8 max_nss, u16 mcs_msk) + u8 max_nss, u32 mcs_msk) { if (max_nss >= 2) - ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le16(mcs_msk); + ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le32(mcs_msk); if (max_nss >= 1) - ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le16(mcs_msk); + ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le32(mcs_msk); } static const @@ -307,7 +307,7 @@ iwl_mld_fill_eht_rates(struct ieee80211_vif *vif, const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_he_cap *own_he_cap, const struct ieee80211_sta_eht_cap *own_eht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { /* peer RX mcs capa */ const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs = @@ -405,7 +405,7 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_supported_band *sband, const struct ieee80211_sta_he_cap *own_he_cap, const struct ieee80211_sta_eht_cap *own_eht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { int i; u16 non_ht_rates = 0; @@ -435,7 +435,7 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, } else if (ht_cap->ht_supported) { cmd->mode = IWL_TLC_MNG_MODE_HT; cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(ht_cap->mcs.rx_mask[0]); + cpu_to_le32(ht_cap->mcs.rx_mask[0]); /* the station support only a single receive chain */ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC) @@ -443,10 +443,30 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, 0; else cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(ht_cap->mcs.rx_mask[1]); + cpu_to_le32(ht_cap->mcs.rx_mask[1]); } } +static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v4 *cmd_v4) +{ + /* Copy everything until ht_rates */ + memcpy(cmd_v4, cmd, offsetof(struct iwl_tlc_config_cmd, ht_rates)); + + /* Convert ht_rates from __le32 to __le16 */ + BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates)); + BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates[0]) != ARRAY_SIZE(cmd->ht_rates[0])); + + for (int nss = 0; nss < ARRAY_SIZE(cmd->ht_rates); nss++) + for (int bw = 0; bw < ARRAY_SIZE(cmd->ht_rates[nss]); bw++) + cmd_v4->ht_rates[nss][bw] = + cpu_to_le16(le32_to_cpu(cmd->ht_rates[nss][bw])); + + /* Copy the rest */ + cmd_v4->max_mpdu_len = cmd->max_mpdu_len; + cmd_v4->max_tx_op = cmd->max_tx_op; +} + static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, @@ -458,7 +478,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, ieee80211_get_he_iftype_cap_vif(sband, vif); const struct ieee80211_sta_eht_cap *own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif); - struct iwl_tlc_config_cmd_v4 cmd = { + struct iwl_tlc_config_cmd cmd = { /* For AP mode, use 20 MHz until the STA is authorized */ .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? iwl_mld_fw_bw_from_sta_bw(link_sta) : @@ -470,6 +490,11 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, .max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len), }; int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); + u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); + struct iwl_tlc_config_cmd_v4 cmd_v4; + void *cmd_ptr; + u8 cmd_size; int ret; if (fw_sta_id < 0) @@ -481,14 +506,26 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, own_he_cap, own_eht_cap, &cmd); + if (cmd_ver == 5) { + cmd_ptr = &cmd; + cmd_size = sizeof(cmd); + } else if (cmd_ver == 4) { + iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + cmd_ptr = &cmd_v4; + cmd_size = sizeof(cmd_v4); + } else { + IWL_ERR(mld, "Unsupported TLC config cmd version %d\n", + cmd_ver); + return; + } + IWL_DEBUG_RATE(mld, "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n", cmd.sta_id, cmd.max_ch_width, cmd.mode); /* Send async since this can be called within a RCU-read section */ - ret = iwl_mld_send_cmd_with_flags_pdu(mld, WIDE_ID(DATA_PATH_GROUP, - TLC_MNG_CONFIG_CMD), - CMD_ASYNC, &cmd); + ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr, + cmd_size); if (ret) IWL_ERR(mld, "Failed to send TLC cmd (%d)\n", ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 13cdc077d8d3..ca63f780140f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -253,93 +253,6 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, swap(data->primary, data->secondary); } -/* - * This function receives the LB link id and checks if eSR should be - * enabled or disabled (due to BT coex) - */ -bool -iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s32 link_rssi, - bool primary) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool have_wifi_loss_rate = - iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - BT_PROFILE_NOTIFICATION, 0) > 4 || - iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, - PROFILE_NOTIF, 0) >= 1; - u8 wifi_loss_mid_high_rssi; - u8 wifi_loss_low_rssi; - u8 wifi_loss_rate; - - if (iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, - PROFILE_NOTIF, 0) >= 1) { - /* For now, we consider 2.4 GHz band / ANT_A only */ - wifi_loss_mid_high_rssi = - mvm->last_bt_wifi_loss.wifi_loss_mid_high_rssi[PHY_BAND_24][0]; - wifi_loss_low_rssi = - mvm->last_bt_wifi_loss.wifi_loss_low_rssi[PHY_BAND_24][0]; - } else { - wifi_loss_mid_high_rssi = mvm->last_bt_notif.wifi_loss_mid_high_rssi; - wifi_loss_low_rssi = mvm->last_bt_notif.wifi_loss_low_rssi; - } - - if (wifi_loss_low_rssi == BT_OFF) - return true; - - if (primary) - return false; - - /* The feature is not supported */ - if (!have_wifi_loss_rate) - return true; - - - /* - * In case we don't know the RSSI - take the lower wifi loss, - * so we will more likely enter eSR, and if RSSI is low - - * we will get an update on this and exit eSR. - */ - if (!link_rssi) - wifi_loss_rate = wifi_loss_mid_high_rssi; - - else if (mvmvif->esr_active) - /* RSSI needs to get really low to disable eSR... */ - wifi_loss_rate = - link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ? - wifi_loss_low_rssi : - wifi_loss_mid_high_rssi; - else - /* ...And really high before we enable it back */ - wifi_loss_rate = - link_rssi <= -IWL_MVM_BT_COEX_ENABLE_ESR_THRESH ? - wifi_loss_low_rssi : - wifi_loss_mid_high_rssi; - - return wifi_loss_rate <= IWL_MVM_BT_COEX_WIFI_LOSS_THRESH; -} - -void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - int link_id) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; - - if (!ieee80211_vif_is_mld(vif) || - !iwl_mvm_vif_from_mac80211(vif)->authorized || - WARN_ON(!link)) - return; - - if (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, - (s8)link->beacon_stats.avg_signal, - link_id == iwl_mvm_get_primary_link(vif))) - /* In case we decided to exit eSR - stay with the primary */ - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_COEX, - iwl_mvm_get_primary_link(vif)); -} - static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_bt_iterator_data *data, @@ -385,8 +298,6 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, return; } - iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; else @@ -525,32 +436,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id); } -/* must be called under rcu_read_lock */ -static void iwl_mvm_bt_coex_notif_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = _data; - struct ieee80211_bss_conf *link_conf; - unsigned int link_id; - - lockdep_assert_held(&mvm->mutex); - - if (vif->type != NL80211_IFTYPE_STATION) - return; - - for_each_vif_active_link(vif, link_conf, link_id) { - struct ieee80211_chanctx_conf *chanctx_conf = - rcu_dereference_check(link_conf->chanctx_conf, - lockdep_is_held(&mvm->mutex)); - - if ((!chanctx_conf || - chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) - continue; - - iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); - } -} - static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) { struct iwl_bt_iterator_data data = { @@ -654,22 +539,6 @@ void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, iwl_mvm_bt_coex_notif_handle(mvm); } -void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - const struct iwl_rx_packet *pkt = rxb_addr(rxb); - const struct iwl_bt_coex_profile_notif *notif = (const void *)pkt->data; - - lockdep_assert_held(&mvm->mutex); - - mvm->last_bt_wifi_loss = *notif; - - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_bt_coex_notif_iterator, - mvm); -} - void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data rssi_event) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 776600ddaea6..17f94663c941 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2024 Intel Corporation + * Copyright (C) 2013-2014, 2018-2025 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -11,15 +11,7 @@ #include "fw-api.h" #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 -#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69 -#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63 -#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0 #define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30 -#define IWL_MVM_TPT_COUNT_WINDOW_SEC 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 15 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11 -#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH -72 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) @@ -129,14 +121,4 @@ #define IWL_MVM_MIN_BEACON_INTERVAL_TU 16 #define IWL_MVM_AUTO_EML_ENABLE true -#define IWL_MVM_HIGH_RSSI_THRESH_20MHZ -67 -#define IWL_MVM_LOW_RSSI_THRESH_20MHZ -71 -#define IWL_MVM_HIGH_RSSI_THRESH_40MHZ -64 -#define IWL_MVM_LOW_RSSI_THRESH_40MHZ -67 -#define IWL_MVM_HIGH_RSSI_THRESH_80MHZ -61 -#define IWL_MVM_LOW_RSSI_THRESH_80MHZ -74 -#define IWL_MVM_HIGH_RSSI_THRESH_160MHZ -58 -#define IWL_MVM_LOW_RSSI_THRESH_160MHZ -61 - -#define IWL_MVM_ENTER_ESR_TPT_THRESH 400 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 029c846a236f..07f1a84c274e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -928,6 +928,10 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, if (ap_sta->mfp) wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (rcu_access_pointer(mvmvif->bcn_prot.keys[0]) || + rcu_access_pointer(mvmvif->bcn_prot.keys[1])) + wowlan_config_cmd->flags |= HAS_BEACON_PROTECTION; + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) { /* Query the last used seqno and set it */ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); @@ -1238,15 +1242,14 @@ static void iwl_mvm_free_nd(struct iwl_mvm *mvm) } static int __iwl_mvm_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan, - bool test) + struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; struct iwl_mvm_vif_link_info *mvm_link; - struct iwl_d3_manager_config d3_cfg_cmd_data = { + struct iwl_d3_manager_config d3_cfg_cmd = { /* * Program the minimum sleep time to 10 seconds, as many * platforms have issues processing a wakeup signal while @@ -1254,23 +1257,14 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, */ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), }; - struct iwl_host_cmd d3_cfg_cmd = { - .id = D3_CONFIG_CMD, - .flags = CMD_WANT_SKB, - .data[0] = &d3_cfg_cmd_data, - .len[0] = sizeof(d3_cfg_cmd_data), - }; int ret; int len __maybe_unused; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); if (!wowlan) { - /* - * mac80211 shouldn't get here, but for D3 test - * it doesn't warrant a warning - */ - WARN_ON(!test); + /* mac80211 shouldn't get here */ + WARN_ON(1); return -EINVAL; } @@ -1278,10 +1272,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (IS_ERR_OR_NULL(vif)) return 1; - ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); - if (ret) - return ret; - mutex_lock(&mvm->mutex); set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); @@ -1351,7 +1341,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvm->d3_wake_sysassert) - d3_cfg_cmd_data.wakeup_flags |= + d3_cfg_cmd.wakeup_flags |= cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR); #endif @@ -1364,21 +1354,14 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_fw_dbg_stop_restart_recording(&mvm->fwrt, NULL, true); /* must be last -- this switches firmware state */ - ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, 0, sizeof(d3_cfg_cmd), + &d3_cfg_cmd); if (ret) goto out; -#ifdef CONFIG_IWLWIFI_DEBUGFS - len = iwl_rx_packet_payload_len(d3_cfg_cmd.resp_pkt); - if (len >= sizeof(u32)) { - mvm->d3_test_pme_ptr = - le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); - } -#endif - iwl_free_resp(&d3_cfg_cmd); clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - ret = iwl_trans_d3_suspend(mvm->trans, test, !unified_image); + ret = iwl_trans_d3_suspend(mvm->trans, !unified_image); out: if (ret < 0) { iwl_mvm_free_nd(mvm); @@ -1401,7 +1384,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) iwl_fw_runtime_suspend(&mvm->fwrt); mutex_unlock(&mvm->mutex); - return __iwl_mvm_suspend(hw, wowlan, false); + return __iwl_mvm_suspend(hw, wowlan); } struct iwl_multicast_key_data { @@ -1794,63 +1777,8 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - u32 gtk_cipher, igtk_cipher, bigtk_cipher; - bool unhandled_cipher, igtk_support, bigtk_support; - int num_keys; }; -static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) -{ - struct iwl_mvm_d3_gtk_iter_data *data = _data; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - - if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) - return; - - if (data->unhandled_cipher) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - /* ignore WEP completely, nothing to do */ - return; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - case WLAN_CIPHER_SUITE_TKIP: - /* we support these */ - data->gtk_cipher = key->cipher; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - /* we support these */ - if (data->igtk_support && - (key->keyidx == 4 || key->keyidx == 5)) { - data->igtk_cipher = key->cipher; - } else if (data->bigtk_support && - (key->keyidx == 6 || key->keyidx == 7)) { - data->bigtk_cipher = key->cipher; - } else { - data->unhandled_cipher = true; - return; - } - break; - default: - /* everything else - disconnect from AP */ - data->unhandled_cipher = true; - return; - } - - data->num_keys++; -} - static void iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, struct ieee80211_key_seq *seq, u32 cipher) @@ -1896,9 +1824,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) return; - if (data->unhandled_cipher) - return; - switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -1947,52 +1872,24 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, - struct iwl_mvm *mvm, u32 gtk_cipher) + struct iwl_mvm *mvm) { int i, j; struct ieee80211_key_conf *key; - DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, - WOWLAN_KEY_MAX_SIZE); int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - u8 key_data[WOWLAN_KEY_MAX_SIZE]; - - conf->cipher = gtk_cipher; - - BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); - BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_CCMP); - BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_GCMP_256); - BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_TKIP); - BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(status->gtk[0].key)); - - switch (gtk_cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf->keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf->keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_TKIP: - conf->keylen = WLAN_KEY_LEN_TKIP; - break; - default: - WARN_ON(1); - } for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { if (!status->gtk[i].len) continue; - conf->keyidx = status->gtk[i].id; IWL_DEBUG_WOWLAN(mvm, - "Received from FW GTK cipher %d, key index %d\n", - conf->cipher, conf->keyidx); - memcpy(conf->key, status->gtk[i].key, - sizeof(status->gtk[i].key)); - memcpy(key_data, status->gtk[i].key, sizeof(status->gtk[i].key)); - - key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data, - sizeof(key_data), link_id); + "Received from FW GTK: key index %d\n", + status->gtk[i].id); + + key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, + status->gtk[i].key, + sizeof(status->gtk[i].key), + link_id); if (IS_ERR(key)) { /* FW may send also the old keys */ if (PTR_ERR(key) == -EALREADY) @@ -2015,53 +1912,26 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, static bool iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, - struct ieee80211_vif *vif, u32 cipher, + struct ieee80211_vif *vif, struct iwl_multicast_key_data *key_data) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, - WOWLAN_KEY_MAX_SIZE); struct ieee80211_key_conf *key_config; struct ieee80211_key_seq seq; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - u8 key[WOWLAN_KEY_MAX_SIZE]; s8 keyidx = key_data->id; - conf->cipher = cipher; - conf->keyidx = keyidx; - if (!key_data->len) return true; - iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf->cipher); - - switch (cipher) { - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - conf->keylen = WLAN_KEY_LEN_AES_CMAC; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256; - break; - default: - WARN_ON(1); - } - BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key)); - memcpy(conf->key, key_data->key, conf->keylen); - - memcpy(key, key_data->key, sizeof(key_data->key)); - - key_config = ieee80211_gtk_rekey_add(vif, keyidx, key, sizeof(key), - link_id); + key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key, + sizeof(key_data->key), link_id); if (IS_ERR(key_config)) { /* FW may send also the old keys */ return PTR_ERR(key_config) == -EALREADY; } + + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, key_config->cipher); ieee80211_set_key_rx_seq(key_config, 0, &seq); if (keyidx == 4 || keyidx == 5) { @@ -2115,27 +1985,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (!status || !vif->bss_conf.bssid) return false; - - if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || - iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, - WOWLAN_INFO_NOTIFICATION, - 0)) - gtkdata.igtk_support = true; - - if (iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, - WOWLAN_INFO_NOTIFICATION, - 0) >= 3) - gtkdata.bigtk_support = true; - - /* find last GTK that we used initially, if any */ - ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_d3_find_last_keys, >kdata); - /* not trying to keep connections with MFP/unhandled ciphers */ - if (gtkdata.unhandled_cipher) - return false; - if (!gtkdata.num_keys) - goto out; - /* * invalidate all other GTKs that might still exist and update * the one that we used @@ -2149,17 +1998,15 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", status->num_of_gtk_rekeys); - if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) + if (!iwl_mvm_gtk_rekey(status, vif, mvm)) return false; if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, - gtkdata.igtk_cipher, &status->igtk)) return false; for (i = 0; i < ARRAY_SIZE(status->bigtk); i++) { if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, - gtkdata.bigtk_cipher, &status->bigtk[i])) return false; } @@ -2168,7 +2015,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, (void *)&replay_ctr, GFP_KERNEL); } -out: if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, WOWLAN_GET_STATUSES, IWL_FW_CMD_VER_UNKNOWN) < 10) { @@ -2236,7 +2082,7 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, } static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, - struct iwl_wowlan_igtk_status *data) + struct iwl_wowlan_igtk_status_v1 *data) { int i; @@ -2260,7 +2106,7 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, } static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, - const struct iwl_wowlan_igtk_status *data) + const struct iwl_wowlan_igtk_status_v1 *data) { int data_idx, status_idx = 0; @@ -2291,7 +2137,7 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, } static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, - struct iwl_wowlan_info_notif *data, + struct iwl_wowlan_info_notif_v5 *data, struct iwl_wowlan_status_data *status, u32 len) { @@ -2727,7 +2573,6 @@ enum iwl_d3_notif { /* manage d3 resume data */ struct iwl_d3_data { struct iwl_wowlan_status_data *status; - bool test; u32 d3_end_flags; u32 notif_expected; /* bitmap - see &enum iwl_d3_notif */ u32 notif_received; /* bitmap - see &enum iwl_d3_notif */ @@ -2919,18 +2764,11 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, if (mvm->net_detect) { iwl_mvm_query_netdetect_reasons(mvm, vif, d3_data); - } else { - bool keep = iwl_mvm_query_wakeup_reasons(mvm, vif, - d3_data->status); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (keep) - mvm->keep_vif = vif; -#endif - - return keep; + return false; } - return false; + + return iwl_mvm_query_wakeup_reasons(mvm, vif, + d3_data->status); } #define IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT (IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET | \ @@ -3069,7 +2907,7 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif, d3_data->status, len); } else if (wowlan_info_ver == 5) { - struct iwl_wowlan_info_notif *notif = + struct iwl_wowlan_info_notif_v5 *notif = (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif(mvm, notif, @@ -3143,10 +2981,9 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, return d3_data->notif_received == d3_data->notif_expected; } -static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test) +static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm) { int ret; - enum iwl_d3_status d3_status; struct iwl_host_cmd cmd = { .id = D0I3_END_CMD, .flags = CMD_WANT_SKB, @@ -3154,15 +2991,10 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test) bool reset = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !reset); + ret = iwl_trans_d3_resume(mvm->trans, !reset); if (ret) return ret; - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(mvm, "Device was reset during suspend\n"); - return -ENOENT; - } - /* * We should trigger resume flow using command only for 22000 family * AX210 and above don't need the command since they have @@ -3207,7 +3039,7 @@ static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm, ARRAY_SIZE(d3_resume_notif), iwl_mvm_wait_d3_notif, d3_data); - ret = iwl_mvm_resume_firmware(mvm, d3_data->test); + ret = iwl_mvm_resume_firmware(mvm); if (ret) { iwl_remove_notification(&mvm->notif_wait, &wait_d3_notif); return ret; @@ -3227,13 +3059,12 @@ static inline bool iwl_mvm_d3_resume_notif_based(struct iwl_mvm *mvm) D3_END_NOTIFICATION, 0); } -static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) +static int __iwl_mvm_resume(struct iwl_mvm *mvm) { struct ieee80211_vif *vif = NULL; int ret = 1; struct iwl_mvm_nd_results results = {}; struct iwl_d3_data d3_data = { - .test = test, .notif_expected = IWL_D3_NOTIF_WOWLAN_INFO | IWL_D3_NOTIF_D3_END_NOTIF, @@ -3271,7 +3102,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) rt_status = iwl_mvm_check_rt_status(mvm, vif); if (rt_status != FW_ALIVE) { - set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_trans_notify_fw_error(mvm->trans); if (rt_status == FW_ERROR) { IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n"); iwl_mvm_dump_nic_error_log(mvm); @@ -3298,13 +3129,11 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) if (ret) goto err; } else { - ret = iwl_mvm_resume_firmware(mvm, test); + ret = iwl_mvm_resume_firmware(mvm); if (ret < 0) goto err; } - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); - /* when reset is required we can't send these following commands */ if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE) goto query_wakeup_reasons; @@ -3346,7 +3175,7 @@ out: kfree(d3_data.status); iwl_mvm_free_nd(mvm); - if (!d3_data.test && !mvm->net_detect) + if (!mvm->net_detect) ieee80211_iterate_active_interfaces_mtx(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_d3_disconnect_iter, @@ -3385,7 +3214,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - ret = __iwl_mvm_resume(mvm, false); + ret = __iwl_mvm_resume(mvm); iwl_mvm_resume_tcm(mvm); @@ -3420,7 +3249,7 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm) IWL_ERR(mvm, "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - ret = iwl_trans_d3_suspend(mvm->trans, false, false); + ret = iwl_trans_d3_suspend(mvm->trans, false); if (ret) IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); } @@ -3443,7 +3272,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) rt_status = iwl_mvm_check_rt_status(mvm, NULL); if (rt_status != FW_ALIVE) { - set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_trans_notify_fw_error(mvm->trans); if (rt_status == FW_ERROR) { IWL_ERR(mvm, "iwl_mvm_check_rt_status failed, device is gone during suspend\n"); @@ -3455,7 +3284,6 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) &iwl_dump_desc_assert, false, 0); } - mvm->trans->state = IWL_TRANS_NO_FW; ret = -ENODEV; goto out; @@ -3473,125 +3301,3 @@ out: return ret; } - -#ifdef CONFIG_IWLWIFI_DEBUGFS -static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) -{ - struct iwl_mvm *mvm = inode->i_private; - int err; - - if (mvm->d3_test_active) - return -EBUSY; - - file->private_data = inode->i_private; - - iwl_mvm_pause_tcm(mvm, true); - - iwl_fw_runtime_suspend(&mvm->fwrt); - - /* start pseudo D3 */ - rtnl_lock(); - wiphy_lock(mvm->hw->wiphy); - err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); - wiphy_unlock(mvm->hw->wiphy); - rtnl_unlock(); - if (err > 0) - err = -EINVAL; - if (err) - return err; - - mvm->d3_test_active = true; - mvm->keep_vif = NULL; - return 0; -} - -static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - unsigned long end = jiffies + 60 * HZ; - u32 pme_asserted; - - while (true) { - /* read pme_ptr if available */ - if (mvm->d3_test_pme_ptr) { - pme_asserted = iwl_trans_read_mem32(mvm->trans, - mvm->d3_test_pme_ptr); - if (pme_asserted) - break; - } - - if (msleep_interruptible(100)) - break; - - if (time_is_before_jiffies(end)) { - IWL_ERR(mvm, - "ending pseudo-D3 with timeout after ~60 seconds\n"); - return -ETIMEDOUT; - } - } - - return 0; -} - -static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - /* skip the one we keep connection on */ - if (_data == vif) - return; - - if (vif->type == NL80211_IFTYPE_STATION) - ieee80211_connection_loss(vif); -} - -static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) -{ - struct iwl_mvm *mvm = inode->i_private; - bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - - mvm->d3_test_active = false; - - iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); - - rtnl_lock(); - wiphy_lock(mvm->hw->wiphy); - __iwl_mvm_resume(mvm, true); - wiphy_unlock(mvm->hw->wiphy); - rtnl_unlock(); - - iwl_mvm_resume_tcm(mvm); - - iwl_fw_runtime_resume(&mvm->fwrt); - - iwl_abort_notification_waits(&mvm->notif_wait); - if (!unified_image) { - int remaining_time = 10; - - ieee80211_restart_hw(mvm->hw); - - /* wait for restart and disconnect all interfaces */ - while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - remaining_time > 0) { - remaining_time--; - msleep(1000); - } - - if (remaining_time == 0) - IWL_ERR(mvm, "Timed out waiting for HW restart!\n"); - } - - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); - - return 0; -} - -const struct file_operations iwl_dbgfs_d3_test_ops = { - .open = iwl_mvm_d3_test_open, - .read = iwl_mvm_d3_test_read, - .release = iwl_mvm_d3_test_release, -}; -#endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index fbe4e4a50852..a56c352a459a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -762,96 +762,6 @@ static ssize_t iwl_dbgfs_max_tx_op_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 action; - int ret; - - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) - return -EINVAL; - - if (kstrtou32(buf, 0, &action)) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - if (!action) { - ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false); - } else if (action == 1) { - ret = iwl_mvm_int_mlo_scan(mvm, vif); - } else { - ret = -EINVAL; - } - - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_esr_disable_reason_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - unsigned long esr_mask; - char *buf; - int bufsz, pos, i; - ssize_t rv; - - mutex_lock(&mvm->mutex); - esr_mask = mvmvif->esr_disable_reason; - mutex_unlock(&mvm->mutex); - - bufsz = hweight32(esr_mask) * 32 + 40; - buf = kmalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos = scnprintf(buf, bufsz, "EMLSR state: '0x%lx'\nreasons:\n", - esr_mask); - for_each_set_bit(i, &esr_mask, BITS_PER_LONG) - pos += scnprintf(buf + pos, bufsz - pos, " - %s\n", - iwl_get_esr_state_string(BIT(i))); - - rv = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return rv; -} - -static ssize_t iwl_dbgfs_esr_disable_reason_write(struct ieee80211_vif *vif, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 reason; - u8 block; - int ret; - - ret = sscanf(buf, "%u %hhu", &reason, &block); - if (ret < 0) - return ret; - - if (hweight16(reason) != 1 || !(reason & IWL_MVM_BLOCK_ESR_REASONS)) - return -EINVAL; - - mutex_lock(&mvm->mutex); - if (block) - iwl_mvm_block_esr(mvm, vif, reason, - iwl_mvm_get_primary_link(vif)); - else - iwl_mvm_unblock_esr(mvm, vif, reason); - mutex_unlock(&mvm->mutex); - - return count; -} - #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -884,8 +794,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); MVM_DEBUGFS_READ_WRITE_FILE_OPS(max_tx_op, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(int_mlo_scan, 32); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(esr_disable_reason, 32); void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -916,8 +824,6 @@ void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(max_tx_op, mvmvif->dbgfs_dir, 0600); debugfs_create_bool("ftm_unprotected", 0200, mvmvif->dbgfs_dir, &mvmvif->ftm_unprotected); - MVM_DEBUGFS_ADD_FILE_VIF(int_mlo_scan, mvmvif->dbgfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE_VIF(esr_disable_reason, mvmvif->dbgfs_dir, 0600); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index f0e184c8a81a..683c0ba5fb39 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1134,7 +1134,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) { set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); - iwl_trans_suppress_cmd_error_once(mvm->trans); + mvm->trans->suppress_cmd_error_once = true; } /* take the return value to make compiler happy - it will fail anyway */ @@ -2159,7 +2159,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR); #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400); debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, &mvm->d3_wake_sysassert); debugfs_create_u32("last_netdetect_scans", 0400, mvm->debugfs_dir, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d931c6eaf12f..865f973f677d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -837,7 +837,7 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), }; - if (!mvm->trans->ltr_enabled) + if (!iwl_trans_is_ltr_enabled(mvm->trans)) return 0; return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 2269acc55c0e..738facceb240 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -5,50 +5,6 @@ #include "mvm.h" #include "time-event.h" -#define HANDLE_ESR_REASONS(HOW) \ - HOW(BLOCKED_PREVENTION) \ - HOW(BLOCKED_WOWLAN) \ - HOW(BLOCKED_TPT) \ - HOW(BLOCKED_FW) \ - HOW(BLOCKED_NON_BSS) \ - HOW(BLOCKED_ROC) \ - HOW(BLOCKED_TMP_NON_BSS) \ - HOW(EXIT_MISSED_BEACON) \ - HOW(EXIT_LOW_RSSI) \ - HOW(EXIT_COEX) \ - HOW(EXIT_BANDWIDTH) \ - HOW(EXIT_CSA) \ - HOW(EXIT_LINK_USAGE) - -static const char *const iwl_mvm_esr_states_names[] = { -#define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x, - HANDLE_ESR_REASONS(NAME_ENTRY) -}; - -const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state) -{ - int offs = ilog2(state); - - if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) || - !iwl_mvm_esr_states_names[offs]) - return "UNKNOWN"; - - return iwl_mvm_esr_states_names[offs]; -} - -static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask) -{ -#define NAME_FMT(x) "%s" -#define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mvm, - "EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_ESR_REASONS(NAME_PR) - mask); -#undef NAME_FMT -#undef NAME_PR -} - static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, struct iwl_link_config_cmd *cmd, enum iwl_ctxt_action action) @@ -114,65 +70,6 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } -struct iwl_mvm_esr_iter_data { - struct ieee80211_vif *vif; - unsigned int link_id; - bool lift_block; -}; - -static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_esr_iter_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int link_id; - - if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION) - return; - - for_each_mvm_vif_valid_link(mvmvif, link_id) { - struct iwl_mvm_vif_link_info *link_info = - mvmvif->link[link_id]; - if (vif == data->vif && link_id == data->link_id) - continue; - if (link_info->active) - data->lift_block = false; - } -} - -int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - unsigned int link_id, bool active) -{ - /* An active link of a non-station vif blocks EMLSR. Upon activation - * block EMLSR on the bss vif. Upon deactivation, check if this link - * was the last non-station link active, and if so unblock the bss vif - */ - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_esr_iter_data data = { - .vif = vif, - .link_id = link_id, - .lift_block = true, - }; - - if (IS_ERR_OR_NULL(bss_vif)) - return 0; - - if (active) - return iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_NON_BSS); - - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_esr_vif_iterator, &data); - if (data.lift_block) { - mutex_lock(&mvm->mutex); - iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS); - mutex_unlock(&mvm->mutex); - } - - return 0; -} - int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, u32 changes, bool active) @@ -388,452 +285,6 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; } -struct iwl_mvm_rssi_to_grade { - s8 rssi[2]; - u16 grade; -}; - -#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \ - { \ - .rssi = {_lb, _hb_uhb}, \ - .grade = _grade \ - } - -/* - * This array must be sorted by increasing RSSI for proper functionality. - * The grades are actually estimated throughput, represented as fixed-point - * with a scale factor of 1/10. - */ -static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = { - RSSI_TO_GRADE_LINE(-85, -89, 177), - RSSI_TO_GRADE_LINE(-83, -86, 344), - RSSI_TO_GRADE_LINE(-82, -85, 516), - RSSI_TO_GRADE_LINE(-80, -83, 688), - RSSI_TO_GRADE_LINE(-77, -79, 1032), - RSSI_TO_GRADE_LINE(-73, -76, 1376), - RSSI_TO_GRADE_LINE(-70, -74, 1548), - RSSI_TO_GRADE_LINE(-69, -72, 1750), - RSSI_TO_GRADE_LINE(-65, -68, 2064), - RSSI_TO_GRADE_LINE(-61, -66, 2294), - RSSI_TO_GRADE_LINE(-58, -61, 2580), - RSSI_TO_GRADE_LINE(-55, -58, 2868), - RSSI_TO_GRADE_LINE(-46, -55, 3098), - RSSI_TO_GRADE_LINE(-43, -54, 3442) -}; - -#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade) - -#define DEFAULT_CHAN_LOAD_LB 30 -#define DEFAULT_CHAN_LOAD_HB 15 -#define DEFAULT_CHAN_LOAD_UHB 0 - -/* Factors calculation is done with fixed-point with a scaling factor of 1/256 */ -#define SCALE_FACTOR 256 - -/* Convert a percentage from [0,100] to [0,255] */ -#define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100) - -static unsigned int -iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf) -{ - enum nl80211_chan_width chan_width = - link_conf->chanreq.oper.width; - int mhz = nl80211_chan_width_to_mhz(chan_width); - unsigned int n_subchannels, n_punctured, puncturing_penalty; - - if (WARN_ONCE(mhz < 20 || mhz > 320, - "Invalid channel width : (%d)\n", mhz)) - return SCALE_FACTOR; - - /* No puncturing, no penalty */ - if (mhz < 80) - return SCALE_FACTOR; - - /* total number of subchannels */ - n_subchannels = mhz / 20; - /* how many of these are punctured */ - n_punctured = hweight16(link_conf->chanreq.oper.punctured); - - puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels; - return SCALE_FACTOR - puncturing_penalty; -} - -static unsigned int -iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf) -{ - struct ieee80211_vif *vif = link_conf->vif; - struct iwl_mvm_vif_link_info *mvm_link = - iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id]; - const struct element *bss_load_elem; - const struct ieee80211_bss_load_elem *bss_load; - enum nl80211_band band = link_conf->chanreq.oper.chan->band; - const struct cfg80211_bss_ies *ies; - unsigned int chan_load; - u32 chan_load_by_us; - - rcu_read_lock(); - if (ieee80211_vif_link_active(vif, link_conf->link_id)) - ies = rcu_dereference(link_conf->bss->beacon_ies); - else - ies = rcu_dereference(link_conf->bss->ies); - - if (ies) - bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD, - ies->data, ies->len); - else - bss_load_elem = NULL; - - /* If there isn't BSS Load element, take the defaults */ - if (!bss_load_elem || - bss_load_elem->datalen != sizeof(*bss_load)) { - rcu_read_unlock(); - switch (band) { - case NL80211_BAND_2GHZ: - chan_load = DEFAULT_CHAN_LOAD_LB; - break; - case NL80211_BAND_5GHZ: - chan_load = DEFAULT_CHAN_LOAD_HB; - break; - case NL80211_BAND_6GHZ: - chan_load = DEFAULT_CHAN_LOAD_UHB; - break; - default: - chan_load = 0; - break; - } - /* The defaults are given in percentage */ - return NORMALIZE_PERCENT_TO_255(chan_load); - } - - bss_load = (const void *)bss_load_elem->data; - /* Channel util is in range 0-255 */ - chan_load = bss_load->channel_util; - rcu_read_unlock(); - - if (!mvm_link || !mvm_link->active) - return chan_load; - - if (WARN_ONCE(!mvm_link->phy_ctxt, - "Active link (%u) without phy ctxt assigned!\n", - link_conf->link_id)) - return chan_load; - - /* channel load by us is given in percentage */ - chan_load_by_us = - NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us); - - /* Use only values that firmware sends that can possibly be valid */ - if (chan_load_by_us <= chan_load) - chan_load -= chan_load_by_us; - - return chan_load; -} - -static unsigned int -iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf) -{ - return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf); -} - -/* This function calculates the grade of a link. Returns 0 in error case */ -VISIBLE_IF_IWLWIFI_KUNIT -unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf) -{ - enum nl80211_band band; - int i, rssi_idx; - s32 link_rssi; - unsigned int grade = MAX_GRADE; - - if (WARN_ON_ONCE(!link_conf)) - return 0; - - band = link_conf->chanreq.oper.chan->band; - if (WARN_ONCE(band != NL80211_BAND_2GHZ && - band != NL80211_BAND_5GHZ && - band != NL80211_BAND_6GHZ, - "Invalid band (%u)\n", band)) - return 0; - - link_rssi = MBM_TO_DBM(link_conf->bss->signal); - /* - * For 6 GHz the RSSI of the beacons is lower than - * the RSSI of the data. - */ - if (band == NL80211_BAND_6GHZ) - link_rssi += 4; - - rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1; - - /* No valid RSSI - take the lowest grade */ - if (!link_rssi) - link_rssi = rssi_to_grade_map[0].rssi[rssi_idx]; - - /* Get grade based on RSSI */ - for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) { - const struct iwl_mvm_rssi_to_grade *line = - &rssi_to_grade_map[i]; - - if (link_rssi > line->rssi[rssi_idx]) - continue; - grade = line->grade; - break; - } - - /* apply the channel load and puncturing factors */ - grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR; - grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR; - return grade; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade); - -static -u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif, - struct iwl_mvm_link_sel_data *data, - unsigned long usable_links, - u8 *best_link_idx) -{ - u8 n_data = 0; - u16 max_grade = 0; - unsigned long link_id; - - /* TODO: don't select links that weren't discovered in the last scan */ - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, link_id); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - data[n_data].link_id = link_id; - data[n_data].chandef = &link_conf->chanreq.oper; - data[n_data].signal = link_conf->bss->signal / 100; - data[n_data].grade = iwl_mvm_get_link_grade(link_conf); - - if (data[n_data].grade > max_grade) { - max_grade = data[n_data].grade; - *best_link_idx = n_data; - } - n_data++; - } - - return n_data; -} - -struct iwl_mvm_bw_to_rssi_threshs { - s8 low; - s8 high; -}; - -#define BW_TO_RSSI_THRESHOLDS(_bw) \ - [IWL_PHY_CHANNEL_MODE ## _bw] = { \ - .low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \ - .high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \ - } - -s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm, - const struct cfg80211_chan_def *chandef, - bool low) -{ - const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = { - BW_TO_RSSI_THRESHOLDS(20), - BW_TO_RSSI_THRESHOLDS(40), - BW_TO_RSSI_THRESHOLDS(80), - BW_TO_RSSI_THRESHOLDS(160) - /* 320 MHz has the same thresholds as 20 MHz */ - }; - const struct iwl_mvm_bw_to_rssi_threshs *threshs; - u8 chan_width = iwl_mvm_get_channel_width(chandef); - - if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ && - chandef->chan->band != NL80211_BAND_5GHZ && - chandef->chan->band != NL80211_BAND_6GHZ)) - return S8_MAX; - - /* 6 GHz will always use 20 MHz thresholds, regardless of the BW */ - if (chan_width == IWL_PHY_CHANNEL_MODE320) - chan_width = IWL_PHY_CHANNEL_MODE20; - - threshs = &bw_to_rssi_threshs_map[chan_width]; - - return low ? threshs->low : threshs->high; -} - -static u32 -iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *link, - bool primary) -{ - struct wiphy *wiphy = mvm->hw->wiphy; - struct ieee80211_bss_conf *conf; - enum iwl_mvm_esr_state ret = 0; - s8 thresh; - - conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]); - if (WARN_ON_ONCE(!conf)) - return false; - - /* BT Coex effects eSR mode only if one of the links is on LB */ - if (link->chandef->chan->band == NL80211_BAND_2GHZ && - (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal, - primary))) - ret |= IWL_MVM_ESR_EXIT_COEX; - - thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef, - false); - - if (link->signal < thresh) - ret |= IWL_MVM_ESR_EXIT_LOW_RSSI; - - if (conf->csa_active) - ret |= IWL_MVM_ESR_EXIT_CSA; - - if (ret) { - IWL_DEBUG_INFO(mvm, - "Link %d is not allowed for esr\n", - link->link_id); - iwl_mvm_print_esr_state(mvm, ret); - } - return ret; -} - -VISIBLE_IF_IWLWIFI_KUNIT -bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - enum iwl_mvm_esr_state ret = 0; - - /* Per-link considerations */ - if (iwl_mvm_esr_disallowed_with_link(mvm, vif, a, true) || - iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false)) - return false; - - if (a->chandef->chan->band == b->chandef->chan->band || - a->chandef->width != b->chandef->width) - ret |= IWL_MVM_ESR_EXIT_BANDWIDTH; - - if (ret) { - IWL_DEBUG_INFO(mvm, - "Links %d and %d are not a valid pair for EMLSR\n", - a->link_id, b->link_id); - iwl_mvm_print_esr_state(mvm, ret); - return false; - } - - return true; - -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair); - -/* - * Returns the combined eSR grade of two given links. - * Returns 0 if eSR is not allowed with these 2 links. - */ -static -unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b, - u8 *primary_id) -{ - struct ieee80211_bss_conf *primary_conf; - struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy; - unsigned int primary_load; - - lockdep_assert_wiphy(wiphy); - - /* a is always primary, b is always secondary */ - if (b->grade > a->grade) - swap(a, b); - - *primary_id = a->link_id; - - if (!iwl_mvm_mld_valid_link_pair(vif, a, b)) - return 0; - - primary_conf = wiphy_dereference(wiphy, vif->link_conf[*primary_id]); - - if (WARN_ON_ONCE(!primary_conf)) - return 0; - - primary_load = iwl_mvm_get_chan_load(primary_conf); - - return a->grade + - ((b->grade * primary_load) / SCALE_FACTOR); -} - -void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS]; - struct iwl_mvm_link_sel_data *best_link; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 max_active_links = iwl_mvm_max_active_links(mvm, vif); - u16 usable_links = ieee80211_vif_usable_links(vif); - u8 best, primary_link, best_in_pair, n_data; - u16 max_esr_grade = 0, new_active_links; - - lockdep_assert_wiphy(mvm->hw->wiphy); - - if (!mvmvif->authorized || !ieee80211_vif_is_mld(vif)) - return; - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* The logic below is a simple version that doesn't suit more than 2 - * links - */ - WARN_ON_ONCE(max_active_links > 2); - - n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links, - &best); - - if (WARN(!n_data, "Couldn't find a valid grade for any link!\n")) - return; - - best_link = &data[best]; - primary_link = best_link->link_id; - new_active_links = BIT(best_link->link_id); - - /* eSR is not supported/blocked, or only one usable link */ - if (max_active_links == 1 || !iwl_mvm_vif_has_esr_cap(mvm, vif) || - mvmvif->esr_disable_reason || n_data == 1) - goto set_active; - - for (u8 a = 0; a < n_data; a++) - for (u8 b = a + 1; b < n_data; b++) { - u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a], - &data[b], - &best_in_pair); - - if (esr_grade <= max_esr_grade) - continue; - - max_esr_grade = esr_grade; - primary_link = best_in_pair; - new_active_links = BIT(data[a].link_id) | - BIT(data[b].link_id); - } - - /* No valid pair was found, go with the best link */ - if (hweight16(new_active_links) <= 1) - goto set_active; - - /* For equal grade - prefer EMLSR */ - if (best_link->grade > max_esr_grade) { - primary_link = best_link->link_id; - new_active_links = BIT(best_link->link_id); - } -set_active: - IWL_DEBUG_INFO(mvm, "Link selection result: 0x%x. Primary = %d\n", - new_active_links, primary_link); - ieee80211_set_active_links_async(vif, new_active_links); - mvmvif->link_selection_res = new_active_links; - mvmvif->link_selection_primary = primary_link; -} - u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -856,266 +307,6 @@ u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) return __ffs(vif->active_links); } -/* - * For non-MLO/single link, this will return the deflink/single active link, - * respectively - */ -u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id) -{ - switch (hweight16(vif->active_links)) { - case 0: - return 0; - default: - WARN_ON(1); - fallthrough; - case 1: - return __ffs(vif->active_links); - case 2: - return __ffs(vif->active_links & ~BIT(link_id)); - } -} - -/* Reasons that can cause esr prevention */ -#define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON -#define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400) -#define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300) -#define IWL_MVM_ESR_PREVENT_LONG (HZ * 600) - -static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, - enum iwl_mvm_esr_state reason) -{ - bool timeout_expired = time_after(jiffies, - mvmvif->last_esr_exit.ts + - IWL_MVM_PREVENT_ESR_TIMEOUT); - unsigned long delay; - - lockdep_assert_held(&mvm->mutex); - - /* Only handle reasons that can cause prevention */ - if (!(reason & IWL_MVM_ESR_PREVENT_REASONS)) - return false; - - /* - * Reset the counter if more than 400 seconds have passed between one - * exit and the other, or if we exited due to a different reason. - * Will also reset the counter after the long prevention is done. - */ - if (timeout_expired || mvmvif->last_esr_exit.reason != reason) { - mvmvif->exit_same_reason_count = 1; - return false; - } - - mvmvif->exit_same_reason_count++; - if (WARN_ON(mvmvif->exit_same_reason_count < 2 || - mvmvif->exit_same_reason_count > 3)) - return false; - - mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION; - - /* - * For the second exit, use a short prevention, and for the third one, - * use a long prevention. - */ - delay = mvmvif->exit_same_reason_count == 2 ? - IWL_MVM_ESR_PREVENT_SHORT : - IWL_MVM_ESR_PREVENT_LONG; - - IWL_DEBUG_INFO(mvm, - "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", - delay / HZ, mvmvif->exit_same_reason_count, - iwl_get_esr_state_string(reason), reason); - - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk, delay); - return true; -} - -#define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ) - -/* API to exit eSR mode */ -void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u16 new_active_links; - bool prevented; - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* Nothing to do */ - if (!mvmvif->esr_active) - return; - - if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized)) - return; - - if (WARN_ON(!(vif->active_links & BIT(link_to_keep)))) - link_to_keep = __ffs(vif->active_links); - - new_active_links = BIT(link_to_keep); - IWL_DEBUG_INFO(mvm, - "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", - iwl_get_esr_state_string(reason), reason, - vif->active_links, new_active_links); - - ieee80211_set_active_links_async(vif, new_active_links); - - /* Prevent EMLSR if needed */ - prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason); - - /* Remember why and when we exited EMLSR */ - mvmvif->last_esr_exit.ts = jiffies; - mvmvif->last_esr_exit.reason = reason; - - /* - * If EMLSR is prevented now - don't try to get back to EMLSR. - * If we exited due to a blocking event, we will try to get back to - * EMLSR when the corresponding unblocking event will happen. - */ - if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS) - return; - - /* If EMLSR is not blocked - try enabling it again in 30 seconds */ - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, - round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME)); -} - -void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* This should be called only with disable reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return; - - if (mvmvif->esr_disable_reason & reason) - return; - - IWL_DEBUG_INFO(mvm, - "Blocking EMLSR mode. reason = %s (0x%x)\n", - iwl_get_esr_state_string(reason), reason); - - mvmvif->esr_disable_reason |= reason; - - iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); - - iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep); -} - -int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason) -{ - int primary_link = iwl_mvm_get_primary_link(vif); - int ret; - - if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif)) - return 0; - - /* This should be called only with blocking reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return 0; - - /* leave ESR immediately, not only async with iwl_mvm_block_esr() */ - ret = ieee80211_set_active_links(vif, BIT(primary_link)); - if (ret) - return ret; - - mutex_lock(&mvm->mutex); - /* only additionally block for consistency and to avoid concurrency */ - iwl_mvm_block_esr(mvm, vif, reason, primary_link); - mutex_unlock(&mvm->mutex); - - return 0; -} - -static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts + - IWL_MVM_TRIGGER_LINK_SEL_TIME); - - lockdep_assert_held(&mvm->mutex); - - if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized || - mvmvif->esr_active) - return; - - IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n"); - - /* If we exited due to an EXIT reason, and the exit was in less than - * 30 seconds, then a MLO scan was scheduled already. - */ - if (!need_new_sel && - !(mvmvif->last_esr_exit.reason & IWL_MVM_BLOCK_ESR_REASONS)) { - IWL_DEBUG_INFO(mvm, "Wait for MLO scan\n"); - return; - } - - /* - * If EMLSR was blocked for more than 30 seconds, or the last link - * selection decided to not enter EMLSR, trigger a new scan. - */ - if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) { - IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n"); - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, 0); - /* - * If EMLSR was blocked for less than 30 seconds, and the last link - * selection decided to use EMLSR, activate EMLSR using the previous - * link selection result. - */ - } else { - IWL_DEBUG_INFO(mvm, - "Use the latest link selection result: 0x%x\n", - mvmvif->link_selection_res); - ieee80211_set_active_links_async(vif, - mvmvif->link_selection_res); - } -} - -void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* This should be called only with disable reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return; - - /* No Change */ - if (!(mvmvif->esr_disable_reason & reason)) - return; - - mvmvif->esr_disable_reason &= ~reason; - - IWL_DEBUG_INFO(mvm, - "Unblocking EMLSR mode. reason = %s (0x%x)\n", - iwl_get_esr_state_string(reason), reason); - iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); - - if (!mvmvif->esr_disable_reason) - iwl_mvm_esr_unblocked(mvm, vif); -} - void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) { link->bcast_sta.sta_id = IWL_INVALID_STA; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 8805ab344895..9c9e0e1c6e1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1586,13 +1586,11 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, u32 id = le32_to_cpu(mb->link_id); union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; u32 mac_type; - int link_id; u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, MISSED_BEACONS_NOTIFICATION, 0); u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, 0); - struct ieee80211_bss_conf *bss_conf; /* If the firmware uses the new notification (from MAC_CONF_GROUP), * refer to that notification's version. @@ -1617,16 +1615,10 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, if (!vif) return; - bss_conf = &vif->bss_conf; - link_id = bss_conf->link_id; mac_type = iwl_mvm_get_mac_type(vif); IWL_DEBUG_INFO(mvm, "missed beacon mac_type=%u,\n", mac_type); - mvm->trans->dbg.dump_file_name_ext_valid = true; - snprintf(mvm->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "MacId_%d_MacType_%d", id, mac_type); - rx_missed_bcon = le32_to_cpu(mb->consec_missed_beacons); rx_missed_bcon_since_rx = le32_to_cpu(mb->consec_missed_beacons_since_last_rx); @@ -1644,41 +1636,11 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, "missed_beacons:%d, missed_beacons_since_rx:%d\n", rx_missed_bcon, rx_missed_bcon_since_rx); } - } else if (link_id >= 0 && hweight16(vif->active_links) > 1) { - u32 bss_param_ch_cnt_link_id = - bss_conf->bss_param_ch_cnt_link_id; - u32 scnd_lnk_bcn_lost = 0; - - if (notif_ver >= 5 && - !IWL_FW_CHECK(mvm, - le32_to_cpu(mb->other_link_id) == IWL_MVM_FW_LINK_ID_INVALID, - "No data for other link id but we are in EMLSR active_links: 0x%x\n", - vif->active_links)) - scnd_lnk_bcn_lost = - le32_to_cpu(mb->consec_missed_beacons_other_link); - - /* Exit EMLSR if we lost more than - * IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links - * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link. - * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED - * and the link's bss_param_ch_count has changed. - */ - if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS && - scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) || - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH || - (bss_param_ch_cnt_link_id != link_id && - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) - iwl_mvm_exit_esr(mvm, vif, - IWL_MVM_ESR_EXIT_MISSED_BEACON, - iwl_mvm_get_primary_link(vif)); } else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) { if (!iwl_mvm_has_new_tx_api(mvm)) ieee80211_beacon_loss(vif); else ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); - - /* try to switch links, no-op if we don't have MLO */ - iwl_mvm_int_mlo_scan(mvm, vif); } iwl_dbg_tlv_time_point(&mvm->fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4ad3d32683d8..44029ceb8f77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1425,12 +1425,6 @@ void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* Stop internal MLO scan, if running */ - mutex_lock(&mvm->mutex); - iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false); - mutex_unlock(&mvm->mutex); - - wiphy_work_cancel(mvm->hw->wiphy, &mvm->trig_link_selection_wk); wiphy_work_flush(mvm->hw->wiphy, &mvm->async_handlers_wiphy_wk); flush_work(&mvm->async_handlers_wk); flush_work(&mvm->add_stream_wk); @@ -1715,57 +1709,6 @@ static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, IWL_STA_MULTICAST); } -static void iwl_mvm_prevent_esr_done_wk(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, prevent_esr_done_wk.work); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvm); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_PREVENTION); -} - -static void iwl_mvm_mlo_int_scan_wk(struct wiphy *wiphy, struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = container_of(wk, struct iwl_mvm_vif, - mlo_int_scan_wk.work); - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvmvif->mvm); - iwl_mvm_int_mlo_scan(mvmvif->mvm, vif); -} - -static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, unblock_esr_tpt_wk); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvm); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT); -} - -static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, - unblock_esr_tmp_non_bss_wk.work); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - mutex_lock(&mvm->mutex); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); - mutex_unlock(&mvm->mutex); -} - void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) { lockdep_assert_held(&mvm->mutex); @@ -1777,18 +1720,6 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) INIT_DELAYED_WORK(&mvmvif->csa_work, iwl_mvm_channel_switch_disconnect_wk); - - wiphy_delayed_work_init(&mvmvif->prevent_esr_done_wk, - iwl_mvm_prevent_esr_done_wk); - - wiphy_delayed_work_init(&mvmvif->mlo_int_scan_wk, - iwl_mvm_mlo_int_scan_wk); - - wiphy_work_init(&mvmvif->unblock_esr_tpt_wk, - iwl_mvm_unblock_esr_tpt); - - wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk, - iwl_mvm_unblock_esr_tmp_non_bss); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1926,16 +1857,6 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, flush_work(&mvm->roc_done_wk); } - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk); - - wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk); - cancel_delayed_work_sync(&mvmvif->csa_work); } @@ -4008,21 +3929,6 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, callbacks->mac_ctxt_changed(mvm, vif, false); iwl_mvm_mei_host_associated(mvm, vif, mvm_sta); - - memset(&mvmvif->last_esr_exit, 0, - sizeof(mvmvif->last_esr_exit)); - - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT, 0); - - /* Block until FW notif will arrive */ - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW, 0); - - /* when client is authorized (AP station marked as such), - * try to enable the best link(s). - */ - if (vif->type == NL80211_IFTYPE_STATION && - !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - iwl_mvm_select_links(mvm, vif); } mvm_sta->authorized = true; @@ -4070,16 +3976,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, /* disable beacon filtering */ iwl_mvm_disable_beacon_filter(mvm, vif); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk); - - wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk); } return 0; @@ -4920,7 +4816,6 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct iwl_mvm_roc_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); u32 lmac_id; int ret; @@ -4933,13 +4828,6 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ flush_work(&mvm->roc_done_wk); - if (!IS_ERR_OR_NULL(bss_vif)) { - ret = iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_ROC); - if (ret) - return ret; - } - guard(mvm)(mvm); switch (vif->type) { @@ -5604,9 +5492,9 @@ static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta) } #define IWL_MAX_CSA_BLOCK_TX 1500 -int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +static int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { struct ieee80211_vif *csa_vif; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5724,9 +5612,9 @@ int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index bf24f8cb673e..b1dca76b7141 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -340,20 +340,6 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* update EMLSR mode */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { - int ret; - - ret = iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, - true); - /* - * Don't activate this link if failed to exit EMLSR in - * the BSS interface - */ - if (ret) - return ret; - } - guard(mvm)(mvm); return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false); } @@ -472,10 +458,6 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_add_link(mvm, vif, link_conf); } mutex_unlock(&mvm->mutex); - - /* update EMLSR mode */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) - iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, false); } static void @@ -684,25 +666,6 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, &callbacks); } -static bool iwl_mvm_esr_bw_criteria(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) -{ - struct ieee80211_bss_conf *other_link; - int link_id; - - /* Exit EMLSR if links don't have equal bandwidths */ - for_each_vif_active_link(vif, other_link, link_id) { - if (link_id == link_conf->link_id) - continue; - if (link_conf->chanreq.oper.width == - other_link->chanreq.oper.width) - return true; - } - - return false; -} - static void iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -737,14 +700,6 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; } - if ((changes & BSS_CHANGED_BANDWIDTH) && - ieee80211_vif_link_active(vif, link_conf->link_id) && - mvmvif->esr_active && - !iwl_mvm_esr_bw_criteria(mvm, vif, link_conf)) - iwl_mvm_exit_esr(mvm, vif, - IWL_MVM_ESR_EXIT_BANDWIDTH, - iwl_mvm_get_primary_link(vif)); - /* if associated, maybe puncturing changed - we'll check later */ if (vif->cfg.assoc) link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS; @@ -879,11 +834,6 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } - - if (changes & (BSS_CHANGED_MLD_VALID_LINKS | BSS_CHANGED_MLD_TTLM) && - ieee80211_vif_is_mld(vif) && mvmvif->authorized) - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, 0); } static void @@ -1239,91 +1189,6 @@ iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return NEG_TTLM_RES_ACCEPT; } -static int -iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - mutex_lock(&mvm->mutex); - if (mvmvif->esr_active) { - u8 primary = iwl_mvm_get_primary_link(vif); - int selected; - - /* prefer primary unless quiet CSA on it */ - if (chsw->link_id == primary && chsw->block_tx) - selected = iwl_mvm_get_other_link(vif, primary); - else - selected = primary; - - /* - * remembers to tell the firmware that this link can't tx - * Note that this logic seems to be unrelated to esr, but it - * really is needed only when esr is active. When we have a - * single link, the firmware will handle all this on its own. - * In multi-link scenarios, we can learn about the CSA from - * another link and this logic is too complex for the firmware - * to track. - * Since we want to de-activate the link that got a CSA, we - * need to tell the firmware not to send any frame on that link - * as the firmware may not be aware that link is under a CSA - * with mode=1 (no Tx allowed). - */ - if (chsw->block_tx && mvmvif->link[chsw->link_id]) - mvmvif->link[chsw->link_id]->csa_block_tx = true; - - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected); - mutex_unlock(&mvm->mutex); - - /* - * If we've not kept the link active that's doing the CSA - * then we don't need to do anything else, just return. - */ - if (selected != chsw->link_id) - return 0; - - mutex_lock(&mvm->mutex); - } - - ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw); - mutex_unlock(&mvm->mutex); - - return ret; -} - -#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ) - -static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw, - enum nl80211_iftype type) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_vif *mvmvif; - int ret; - - IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n", - type); - - if (IS_ERR_OR_NULL(bss_vif) || - !(type == NL80211_IFTYPE_AP || - type == NL80211_IFTYPE_P2P_GO || - type == NL80211_IFTYPE_P2P_CLIENT)) - return; - - mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); - ret = iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); - if (ret) - return; - - wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk, - IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT); -} - const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1377,7 +1242,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx_last_beacon = iwl_mvm_tx_last_beacon, .channel_switch = iwl_mvm_channel_switch, - .pre_channel_switch = iwl_mvm_mld_mac_pre_channel_switch, + .pre_channel_switch = iwl_mvm_mac_pre_channel_switch, .post_channel_switch = iwl_mvm_post_channel_switch, .abort_channel_switch = iwl_mvm_abort_channel_switch, .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon, @@ -1418,5 +1283,4 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_sta_links = iwl_mvm_mld_change_sta_links, .can_activate_links = iwl_mvm_mld_can_activate_links, .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, - .prep_add_interface = iwl_mvm_mld_prep_add_interface, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index e1010521c3ea..d9a2801636cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -852,8 +852,6 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, link_id); } - kfree(mvm_sta->mpdu_counters); - mvm_sta->mpdu_counters = NULL; return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index fdaeefa305e1..b515028adc8f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -348,68 +348,6 @@ struct iwl_mvm_vif_link_info { }; /** - * enum iwl_mvm_esr_state - defines reasons for which the EMLSR is exited or - * blocked. - * The low 16 bits are used for blocking reasons, and the 16 higher bits - * are used for exit reasons. - * For the blocking reasons - use iwl_mvm_(un)block_esr(), and for the exit - * reasons - use iwl_mvm_exit_esr(). - * - * Note: new reasons shall be added to HANDLE_ESR_REASONS as well (for logs) - * - * @IWL_MVM_ESR_BLOCKED_PREVENTION: Prevent EMLSR to avoid entering and exiting - * in a loop. - * @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR - * @IWL_MVM_ESR_BLOCKED_TPT: block EMLSR when there is not enough traffic - * @IWL_MVM_ESR_BLOCKED_FW: FW didn't recommended/forced exit from EMLSR - * @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is - * preventing EMLSR - * @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR - * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link - * is preventing EMLSR. This is a temporary blocking that is set when there - * is an indication that a non-BSS interface is to be added. - * @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons - * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR - * due to low RSSI. - * @IWL_MVM_ESR_EXIT_COEX: link is deactivated/not allowed for EMLSR - * due to BT Coex. - * @IWL_MVM_ESR_EXIT_BANDWIDTH: Bandwidths of primary and secondry links - * preventing the enablement of EMLSR - * @IWL_MVM_ESR_EXIT_CSA: CSA happened, so exit EMLSR - * @IWL_MVM_ESR_EXIT_LINK_USAGE: Exit EMLSR due to low tpt on secondary link - */ -enum iwl_mvm_esr_state { - IWL_MVM_ESR_BLOCKED_PREVENTION = 0x1, - IWL_MVM_ESR_BLOCKED_WOWLAN = 0x2, - IWL_MVM_ESR_BLOCKED_TPT = 0x4, - IWL_MVM_ESR_BLOCKED_FW = 0x8, - IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10, - IWL_MVM_ESR_BLOCKED_ROC = 0x20, - IWL_MVM_ESR_BLOCKED_TMP_NON_BSS = 0x40, - IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000, - IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000, - IWL_MVM_ESR_EXIT_COEX = 0x40000, - IWL_MVM_ESR_EXIT_BANDWIDTH = 0x80000, - IWL_MVM_ESR_EXIT_CSA = 0x100000, - IWL_MVM_ESR_EXIT_LINK_USAGE = 0x200000, -}; - -#define IWL_MVM_BLOCK_ESR_REASONS 0xffff - -const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state); - -/** - * struct iwl_mvm_esr_exit - details of the last exit from EMLSR mode. - * @reason: The reason for the last exit from EMLSR. - * &iwl_mvm_prevent_esr_reasons. Will be 0 before exiting EMLSR. - * @ts: the time stamp of the last time we existed EMLSR. - */ -struct iwl_mvm_esr_exit { - unsigned long ts; - enum iwl_mvm_esr_state reason; -}; - -/** * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context * @mvm: pointer back to the mvm struct * @id: between 0 and 3 @@ -443,7 +381,6 @@ struct iwl_mvm_esr_exit { * @deflink: default link data for use in non-MLO * @link: link data for each link in MLO * @esr_active: indicates eSR mode is active - * @esr_disable_reason: a bitmap of &enum iwl_mvm_esr_state * @pm_enabled: indicates powersave is enabled * @link_selection_res: bitmap of active links as it was decided in the last * link selection. Valid only for a MLO vif after assoc. 0 if there wasn't @@ -451,15 +388,6 @@ struct iwl_mvm_esr_exit { * @link_selection_primary: primary link selected by link selection * @primary_link: primary link in eSR. Valid only for an associated MLD vif, * and in eSR mode. Valid only for a STA. - * @last_esr_exit: Details of the last exit from EMLSR. - * @exit_same_reason_count: The number of times we exited due to the specified - * @last_esr_exit::reason, only counting exits due to - * &IWL_MVM_ESR_PREVENT_REASONS. - * @prevent_esr_done_wk: work that should be done when esr prevention ends. - * @mlo_int_scan_wk: work for the internal MLO scan. - * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. - * @unblock_esr_tmp_non_bss_wk: work for removing the - * IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). * @session_prot_connection_loss: the connection was lost due to session @@ -515,7 +443,6 @@ struct iwl_mvm_vif { u8 authorized:1; bool ps_disabled; - u32 esr_disable_reason; u32 ap_beacon_time; bool bf_enabled; bool ba_enabled; @@ -591,12 +518,6 @@ struct iwl_mvm_vif { u16 link_selection_res; u8 link_selection_primary; u8 primary_link; - struct iwl_mvm_esr_exit last_esr_exit; - u8 exit_same_reason_count; - struct wiphy_delayed_work prevent_esr_done_wk; - struct wiphy_delayed_work mlo_int_scan_wk; - struct wiphy_work unblock_esr_tpt_wk; - struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk; struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -622,7 +543,6 @@ enum iwl_scan_status { IWL_MVM_SCAN_REGULAR = BIT(0), IWL_MVM_SCAN_SCHED = BIT(1), IWL_MVM_SCAN_NETDETECT = BIT(2), - IWL_MVM_SCAN_INT_MLO = BIT(3), IWL_MVM_SCAN_STOPPING_REGULAR = BIT(8), IWL_MVM_SCAN_STOPPING_SCHED = BIT(9), @@ -635,8 +555,6 @@ enum iwl_scan_status { IWL_MVM_SCAN_STOPPING_SCHED, IWL_MVM_SCAN_NETDETECT_MASK = IWL_MVM_SCAN_NETDETECT | IWL_MVM_SCAN_STOPPING_NETDETECT, - IWL_MVM_SCAN_INT_MLO_MASK = IWL_MVM_SCAN_INT_MLO | - IWL_MVM_SCAN_STOPPING_INT_MLO, IWL_MVM_SCAN_STOPPING_MASK = 0xff << IWL_MVM_SCAN_STOPPING_SHIFT, IWL_MVM_SCAN_MASK = 0xff, @@ -1017,8 +935,6 @@ struct iwl_mvm { /* For async rx handlers that require the wiphy lock */ struct wiphy_work async_handlers_wiphy_wk; - struct wiphy_work trig_link_selection_wk; - struct work_struct roc_done_wk; unsigned long init_status; @@ -1203,20 +1119,13 @@ struct iwl_mvm { u8 offload_tid; #ifdef CONFIG_IWLWIFI_DEBUGFS bool d3_wake_sysassert; - bool d3_test_active; - u32 d3_test_pme_ptr; - struct ieee80211_vif *keep_vif; u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */ #endif #endif wait_queue_head_t rx_sync_waitq; - /* BT-Coex - only one of those will be used */ - union { - struct iwl_bt_coex_prof_old_notif last_bt_notif; - struct iwl_bt_coex_profile_notif last_bt_wifi_loss; - }; + struct iwl_bt_coex_prof_old_notif last_bt_notif; struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; u8 bt_tx_prio; @@ -2099,9 +2008,7 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); -void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif); -u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id); struct iwl_mvm_link_sel_data { u8 link_id; @@ -2111,13 +2018,6 @@ struct iwl_mvm_link_sel_data { }; #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) -unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf); -bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b); - -s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif); - extern const struct iwl_hcmd_arr iwl_mvm_groups[]; extern const unsigned int iwl_mvm_groups_size; #endif @@ -2201,7 +2101,6 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify); int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm); void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); void iwl_mvm_scan_timeout_wk(struct work_struct *work); -int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); @@ -2327,8 +2226,6 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); @@ -2929,9 +2826,10 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw); void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw); -int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw); +int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw); + void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); @@ -2988,30 +2886,6 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, /* EMLSR */ bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep); -int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason); -void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason); -void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep); -s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm, - const struct cfg80211_chan_def *chandef, - bool low); -void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - int link_id); -bool -iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s32 link_rssi, - bool primary); -int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - unsigned int link_id, bool active); - void iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c7f08cde1f72..5ebd046371f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -143,24 +143,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } -static void iwl_mvm_rx_esr_mode_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_esr_mode_notif *notif = (void *)pkt->data; - struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm); - - /* FW recommendations is only for entering EMLSR */ - if (IS_ERR_OR_NULL(vif) || iwl_mvm_vif_from_mac80211(vif)->esr_active) - return; - - if (le32_to_cpu(notif->action) == ESR_RECOMMEND_ENTER) - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW); - else - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW, - iwl_mvm_get_primary_link(vif)); -} - static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -345,9 +327,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_old_notif, RX_HANDLER_ASYNC_LOCKED_WIPHY, struct iwl_bt_coex_prof_old_notif), - RX_HANDLER_GRP(BT_COEX_GROUP, PROFILE_NOTIF, iwl_mvm_rx_bt_coex_notif, - RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_bt_coex_profile_notif), RX_HANDLER_NO_SIZE(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_NO_SIZE(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, @@ -457,11 +436,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_ASYNC_UNLOCKED, struct iwl_channel_switch_error_notif), - RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF, - iwl_mvm_rx_esr_mode_notif, - RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_esr_mode_notif), - RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_datapath_monitor_notif), @@ -661,7 +635,6 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(SCD_QUEUE_CONFIG_CMD), HCMD_NAME(SEC_KEY_CMD), - HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), HCMD_NAME(BEACON_FILTER_IN_NOTIF), @@ -1220,29 +1193,6 @@ static const struct iwl_mei_ops mei_ops = { .nic_stolen = iwl_mvm_mei_nic_stolen, }; -static void iwl_mvm_find_link_selection_vif(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (ieee80211_vif_is_mld(vif) && mvmvif->authorized) - iwl_mvm_select_links(mvmvif->mvm, vif); -} - -static void iwl_mvm_trig_link_selection(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm *mvm = - container_of(wk, struct iwl_mvm, trig_link_selection_wk); - - mutex_lock(&mvm->mutex); - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_find_link_selection_vif, - NULL); - mutex_unlock(&mvm->mutex); -} - static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -1411,9 +1361,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, wiphy_work_init(&mvm->async_handlers_wiphy_wk, iwl_mvm_async_handlers_wiphy_wk); - wiphy_work_init(&mvm->trig_link_selection_wk, - iwl_mvm_trig_link_selection); - init_waitqueue_head(&mvm->rx_sync_waitq); mvm->queue_sync_state = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 8fae0d41b119..8c1bb3a7ffca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -563,7 +563,6 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, int thold = bss_conf->cqm_rssi_thold; int hyst = bss_conf->cqm_rssi_hyst; int last_event; - s8 exit_esr_thresh; if (sig == 0) { IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); @@ -619,27 +618,6 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, sig, GFP_KERNEL); } - - /* ESR recalculation */ - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) - return; - - /* We're not in EMLSR and our signal is bad, try to switch link maybe */ - if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) { - iwl_mvm_int_mlo_scan(mvm, vif); - return; - } - - /* We are in EMLSR, check if we need to exit */ - exit_esr_thresh = - iwl_mvm_get_esr_rssi_thresh(mvm, - &bss_conf->chanreq.oper, - true); - - if (sig < exit_esr_thresh) - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_LOW_RSSI, - iwl_mvm_get_other_link(vif, - bss_conf->link_id)); } static void iwl_mvm_stat_iterator(void *_data, u8 *mac, @@ -914,10 +892,6 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, link_info->beacon_stats.avg_signal = -le32_to_cpu(link_stats->beacon_average_energy); - if (link_info->phy_ctxt && - link_info->phy_ctxt->channel->band == NL80211_BAND_2GHZ) - iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); - /* make sure that beacon statistics don't go backwards with TCM * request to clear statistics */ @@ -956,111 +930,6 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, } } -#define SEC_LINK_MIN_PERC 10 -#define SEC_LINK_MIN_TX 3000 -#define SEC_LINK_MIN_RX 400 - -/* Accept a ~20% short window to avoid issues due to jitter */ -#define IWL_MVM_TPT_MIN_COUNT_WINDOW (IWL_MVM_TPT_COUNT_WINDOW_SEC * HZ * 4 / 5) - -static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) -{ - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_vif *mvmvif; - struct iwl_mvm_sta *mvmsta; - unsigned long total_tx = 0, total_rx = 0; - unsigned long sec_link_tx = 0, sec_link_rx = 0; - u8 sec_link_tx_perc, sec_link_rx_perc; - u8 sec_link; - bool skip = false; - - lockdep_assert_held(&mvm->mutex); - - if (IS_ERR_OR_NULL(bss_vif)) - return; - - mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); - - if (!mvmvif->esr_active || !mvmvif->ap_sta) - return; - - mvmsta = iwl_mvm_sta_from_mac80211(mvmvif->ap_sta); - /* We only count for the AP sta in a MLO connection */ - if (!mvmsta->mpdu_counters) - return; - - /* Get the FW ID of the secondary link */ - sec_link = iwl_mvm_get_other_link(bss_vif, - iwl_mvm_get_primary_link(bss_vif)); - if (WARN_ON(!mvmvif->link[sec_link])) - return; - sec_link = mvmvif->link[sec_link]->fw_link_id; - - /* Sum up RX and TX MPDUs from the different queues/links */ - for (int q = 0; q < mvm->trans->info.num_rxqs; q++) { - spin_lock_bh(&mvmsta->mpdu_counters[q].lock); - - /* The link IDs that doesn't exist will contain 0 */ - for (int link = 0; link < IWL_FW_MAX_LINK_ID; link++) { - total_tx += mvmsta->mpdu_counters[q].per_link[link].tx; - total_rx += mvmsta->mpdu_counters[q].per_link[link].rx; - } - - sec_link_tx += mvmsta->mpdu_counters[q].per_link[sec_link].tx; - sec_link_rx += mvmsta->mpdu_counters[q].per_link[sec_link].rx; - - /* - * In EMLSR we have statistics every 5 seconds, so we can reset - * the counters upon every statistics notification. - * The FW sends the notification regularly, but it will be - * misaligned at the start. Skipping the measurement if it is - * short will synchronize us. - */ - if (jiffies - mvmsta->mpdu_counters[q].window_start < - IWL_MVM_TPT_MIN_COUNT_WINDOW) - skip = true; - mvmsta->mpdu_counters[q].window_start = jiffies; - memset(mvmsta->mpdu_counters[q].per_link, 0, - sizeof(mvmsta->mpdu_counters[q].per_link)); - - spin_unlock_bh(&mvmsta->mpdu_counters[q].lock); - } - - if (skip) { - IWL_DEBUG_INFO(mvm, "MPDU statistics window was short\n"); - return; - } - - IWL_DEBUG_INFO(mvm, "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_MVM_ENTER_ESR_TPT_THRESH && - total_rx < IWL_MVM_ENTER_ESR_TPT_THRESH) { - iwl_mvm_block_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_TPT, - iwl_mvm_get_primary_link(bss_vif)); - return; - } - - IWL_DEBUG_INFO(mvm, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", - sec_link, 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; - sec_link_rx_perc = total_rx ? sec_link_rx * 100 / total_rx : 0; - - /* - * The TX/RX percentage is checked only if it exceeds the required - * minimum. In addition, RX is checked only if the TX check failed. - */ - if ((total_tx > SEC_LINK_MIN_TX && - sec_link_tx_perc < SEC_LINK_MIN_PERC) || - (total_rx > SEC_LINK_MIN_RX && - sec_link_rx_perc < SEC_LINK_MIN_PERC)) - iwl_mvm_exit_esr(mvm, bss_vif, IWL_MVM_ESR_EXIT_LINK_USAGE, - iwl_mvm_get_primary_link(bss_vif)); -} - void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -1088,8 +957,6 @@ void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); - - iwl_mvm_update_esr_mode_tpt(mvm); } void iwl_mvm_handle_rx_system_oper_part1_stats(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 62e76a79f621..d35c63a673b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -332,6 +332,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_key_conf *key; u32 len = le16_to_cpu(desc->mpdu_len); const u8 *frame = (void *)hdr; + const u8 *mmie; if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) return 0; @@ -375,11 +376,15 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, goto report; } - if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) + if (len < key->icv_len) goto report; /* get the real key ID */ - keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; + mmie = frame + (len - key->icv_len); + + /* the position of the key_id in ieee80211_mmie_16 is the same */ + keyid = le16_to_cpu(((const struct ieee80211_mmie *) mmie)->key_id); + /* and if that's the other key, look it up */ if (keyid != key->keyidx) { /* @@ -2099,7 +2104,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0; - u8 sta_id = le32_get_bits(desc->status, IWL_RX_MPDU_STATUS_STA_ID); size_t desc_size; struct iwl_mvm_rx_phy_data phy_data = {}; u32 format; @@ -2246,6 +2250,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rcu_read_lock(); if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { + u8 sta_id = le32_get_bits(desc->status, + IWL_RX_MPDU_STATUS_STA_ID); + if (!WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations)) { struct ieee80211_link_sta *link_sta; @@ -2373,16 +2380,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_agg_rx_received(mvm, reorder_data, baid); } - - if (ieee80211_is_data(hdr->frame_control)) { - u8 sub_frame_idx = desc->amsdu_info & - IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; - - /* 0 means not an A-MSDU, and 1 means a new A-MSDU */ - if (!sub_frame_idx || sub_frame_idx == 1) - iwl_mvm_count_mpdu(mvmsta, sta_id, 1, false, - queue); - } } /* management stuff on default queue */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 9ce1ce0dab34..b588f1dcf20d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1392,8 +1392,6 @@ static u32 iwl_mvm_scan_umac_ooc_priority(int type) { if (type == IWL_MVM_SCAN_REGULAR) return IWL_SCAN_PRIORITY_EXT_6; - if (type == IWL_MVM_SCAN_INT_MLO) - return IWL_SCAN_PRIORITY_EXT_4; return IWL_SCAN_PRIORITY_EXT_2; } @@ -3220,7 +3218,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, struct iwl_umac_scan_complete *notif = (void *)pkt->data; u32 uid = __le32_to_cpu(notif->uid); bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); - bool select_links = false; mvm->mei_scan_filter.is_mei_limited_scan = false; @@ -3267,13 +3264,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; - } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_INT_MLO) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan completed\n"); - /* - * Other scan types won't necessarily scan for the MLD links channels. - * Therefore, only select links after successful internal scan. - */ - select_links = notif->status == IWL_SCAN_OFFLOAD_COMPLETED; } mvm->scan_status &= ~mvm->scan_uid_status[uid]; @@ -3286,9 +3276,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = false; mvm->scan_uid_status[uid] = 0; - - if (select_links) - wiphy_work_queue(mvm->hw->wiphy, &mvm->trig_link_selection_wk); } void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, @@ -3483,11 +3470,6 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; } - uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_INT_MLO); - if (uid >= 0) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan aborted\n"); - mvm->scan_uid_status[uid] = 0; - } uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_STOPPING_REGULAR); @@ -3583,89 +3565,6 @@ out: return ret; } -static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel **channels, - size_t n_channels) -{ - struct cfg80211_scan_request *req = NULL; - struct ieee80211_scan_ies ies = {}; - size_t size, i; - int ret; - - lockdep_assert_held(&mvm->mutex); - - IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n", - n_channels); - - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || - hweight16(vif->valid_links) == 1) - return -EINVAL; - - size = struct_size(req, channels, n_channels); - req = kzalloc(size, GFP_KERNEL); - if (!req) - return -ENOMEM; - - /* set the requested channels */ - for (i = 0; i < n_channels; i++) - req->channels[i] = channels[i]; - - req->n_channels = n_channels; - - /* set the rates */ - for (i = 0; i < NUM_NL80211_BANDS; i++) - if (mvm->hw->wiphy->bands[i]) - req->rates[i] = - (1 << mvm->hw->wiphy->bands[i]->n_bitrates) - 1; - - req->wdev = ieee80211_vif_to_wdev(vif); - req->wiphy = mvm->hw->wiphy; - req->scan_start = jiffies; - req->tsf_report_link_id = -1; - - ret = _iwl_mvm_single_scan_start(mvm, vif, req, &ies, - IWL_MVM_SCAN_INT_MLO); - kfree(req); - - IWL_DEBUG_SCAN(mvm, "Internal MLO scan: ret=%d\n", ret); - return ret; -} - -int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS]; - unsigned long usable_links = ieee80211_vif_usable_links(vif); - size_t n_channels = 0; - u8 link_id; - - lockdep_assert_held(&mvm->mutex); - - if (mvm->scan_status & IWL_MVM_SCAN_INT_MLO) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan is already running\n"); - return -EBUSY; - } - - rcu_read_lock(); - - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - rcu_dereference(vif->link_conf[link_id]); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - channels[n_channels++] = link_conf->chanreq.oper.chan; - } - - rcu_read_unlock(); - - if (!n_channels) - return -EINVAL; - - return iwl_mvm_int_mlo_scan_start(mvm, vif, channels, n_channels); -} - static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm, enum nl80211_band band, u16 phy_chan_num) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 11c6b86db4ec..363232bb74fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1835,18 +1835,6 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); - /* MPDUs are counted only when EMLSR is possible */ - if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && - !sta->tdls && ieee80211_vif_is_mld(vif)) { - mvm_sta->mpdu_counters = - kcalloc(mvm->trans->info.num_rxqs, - sizeof(*mvm_sta->mpdu_counters), - GFP_KERNEL); - if (mvm_sta->mpdu_counters) - for (int q = 0; q < mvm->trans->info.num_rxqs; q++) - spin_lock_init(&mvm_sta->mpdu_counters[q].lock); - } - return 0; } @@ -4328,80 +4316,3 @@ void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "Failed to cancel the channel switch\n"); } - -static int iwl_mvm_fw_sta_id_to_fw_link_id(struct iwl_mvm_vif *mvmvif, - u8 fw_sta_id) -{ - struct ieee80211_link_sta *link_sta = - rcu_dereference(mvmvif->mvm->fw_id_to_link_sta[fw_sta_id]); - struct iwl_mvm_vif_link_info *link; - - if (WARN_ON_ONCE(!link_sta)) - return -EINVAL; - - link = mvmvif->link[link_sta->link_id]; - - if (WARN_ON_ONCE(!link)) - return -EINVAL; - - return link->fw_link_id; -} - -#define IWL_MVM_TPT_COUNT_WINDOW (IWL_MVM_TPT_COUNT_WINDOW_SEC * HZ) - -void iwl_mvm_count_mpdu(struct iwl_mvm_sta *mvm_sta, u8 fw_sta_id, u32 count, - bool tx, int queue) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvm_sta->vif); - struct iwl_mvm *mvm = mvmvif->mvm; - struct iwl_mvm_tpt_counter *queue_counter; - struct iwl_mvm_mpdu_counter *link_counter; - u32 total_mpdus = 0; - int fw_link_id; - - /* Count only for a BSS sta, and only when EMLSR is possible */ - if (!mvm_sta->mpdu_counters) - return; - - /* Map sta id to link id */ - fw_link_id = iwl_mvm_fw_sta_id_to_fw_link_id(mvmvif, fw_sta_id); - if (fw_link_id < 0) - return; - - queue_counter = &mvm_sta->mpdu_counters[queue]; - link_counter = &queue_counter->per_link[fw_link_id]; - - spin_lock_bh(&queue_counter->lock); - - if (tx) - link_counter->tx += count; - else - link_counter->rx += count; - - /* - * When not in EMLSR, the window and the decision to enter EMLSR are - * handled during counting, when in EMLSR - in the statistics flow - */ - if (mvmvif->esr_active) - goto out; - - if (time_is_before_jiffies(queue_counter->window_start + - IWL_MVM_TPT_COUNT_WINDOW)) { - memset(queue_counter->per_link, 0, - sizeof(queue_counter->per_link)); - queue_counter->window_start = jiffies; - - IWL_DEBUG_INFO(mvm, "MPDU counters are cleared\n"); - } - - for (int i = 0; i < IWL_FW_MAX_LINK_ID; i++) - total_mpdus += tx ? queue_counter->per_link[i].tx : - queue_counter->per_link[i].rx; - - if (total_mpdus > IWL_MVM_ENTER_ESR_TPT_THRESH) - wiphy_work_queue(mvmvif->mvm->hw->wiphy, - &mvmvif->unblock_esr_tpt_wk); - -out: - spin_unlock_bh(&queue_counter->lock); -} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index f6906061510b..c25edc7c1813 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -344,24 +344,6 @@ struct iwl_mvm_link_sta { u8 avg_energy; }; -struct iwl_mvm_mpdu_counter { - u32 tx; - u32 rx; -}; - -/** - * struct iwl_mvm_tpt_counter - per-queue MPDU counter - * - * @lock: Needed to protect the counters when modified from statistics. - * @per_link: per-link counters. - * @window_start: timestamp of the counting-window start - */ -struct iwl_mvm_tpt_counter { - spinlock_t lock; - struct iwl_mvm_mpdu_counter per_link[IWL_FW_MAX_LINK_ID]; - unsigned long window_start; -} ____cacheline_aligned_in_smp; - /** * struct iwl_mvm_sta - representation of a station in the driver * @vif: the interface the station belongs to @@ -409,7 +391,6 @@ struct iwl_mvm_tpt_counter { * @link: per link sta entries. For non-MLO only link[0] holds data. For MLO, * link[0] points to deflink and link[link_id] is allocated when new link * sta is added. - * @mpdu_counters: RX/TX MPDUs counters for each queue. * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -449,8 +430,6 @@ struct iwl_mvm_sta { struct iwl_mvm_link_sta deflink; struct iwl_mvm_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; - - struct iwl_mvm_tpt_counter *mpdu_counters; }; u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); @@ -533,9 +512,6 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_count_mpdu(struct iwl_mvm_sta *mvm_sta, u8 fw_sta_id, u32 count, - bool tx, int queue); - /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start, u16 buf_size, u16 timeout); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile index bb33f4a06f1c..2267be4cfb44 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile @@ -1,3 +1,3 @@ -iwlmvm-tests-y += module.o links.o hcmd.o +iwlmvm-tests-y += module.o hcmd.o obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmvm-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c deleted file mode 100644 index d692f1813d44..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c +++ /dev/null @@ -1,433 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * KUnit tests for channel helper functions - * - * Copyright (C) 2024 Intel Corporation - */ -#include <net/mac80211.h> -#include "../mvm.h" -#include <kunit/test.h> - -MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); - -static struct wiphy wiphy = { - .mtx = __MUTEX_INITIALIZER(wiphy.mtx), -}; - -static struct ieee80211_hw hw = { - .wiphy = &wiphy, -}; - -static struct ieee80211_channel chan_5ghz = { - .band = NL80211_BAND_5GHZ, -}; - -static struct ieee80211_channel chan_6ghz = { - .band = NL80211_BAND_6GHZ, -}; - -static struct ieee80211_channel chan_2ghz = { - .band = NL80211_BAND_2GHZ, -}; - -static struct cfg80211_chan_def chandef_a = {}; - -static struct cfg80211_chan_def chandef_b = {}; - -static struct iwl_mvm_phy_ctxt ctx = {}; - -static struct iwl_mvm_vif_link_info mvm_link = { - .phy_ctxt = &ctx, - .active = true -}; - -static struct cfg80211_bss bss = {}; - -static struct ieee80211_bss_conf link_conf = {.bss = &bss}; - -static const struct iwl_fw_cmd_version entry = { - .group = LEGACY_GROUP, - .cmd = BT_PROFILE_NOTIFICATION, - .notif_ver = 4 -}; - -static struct iwl_fw fw = { - .ucode_capa = { - .n_cmd_versions = 1, - .cmd_versions = &entry, - }, -}; - -static struct iwl_mvm mvm = { - .hw = &hw, - .fw = &fw, -}; - -static const struct link_grading_case { - const char *desc; - const struct cfg80211_chan_def chandef; - s32 signal; - s16 channel_util; - int chan_load_by_us; - unsigned int grade; -} link_grading_cases[] = { - { - .desc = "UHB, RSSI below range, no factors", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -100, - .grade = 177, - }, - { - .desc = "LB, RSSI in range, no factors", - .chandef = { - .chan = &chan_2ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -84, - .grade = 344, - }, - { - .desc = "HB, RSSI above range, no factors", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -50, - .grade = 3442, - }, - { - .desc = "HB, BSS Load IE (20 percent), inactive link, no puncturing factor", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -66, - .channel_util = 51, - .grade = 1836, - }, - { - .desc = "LB, BSS Load IE (20 percent), active link, chan_load_by_us=10 percent. No puncturing factor", - .chandef = { - .chan = &chan_2ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -61, - .channel_util = 51, - .chan_load_by_us = 10, - .grade = 2061, - }, - { - .desc = "UHB, BSS Load IE (40 percent), active link, chan_load_by_us=50 (invalid) percent. No puncturing factor", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -66, - .channel_util = 102, - .chan_load_by_us = 50, - .grade = 1552, - }, - { .desc = "HB, 80 MHz, no channel load factor, punctured percentage 0", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_80, - .punctured = 0x0000 - }, - .signal = -72, - .grade = 1750, - }, - { .desc = "HB, 160 MHz, no channel load factor, punctured percentage 25", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_160, - .punctured = 0x3 - }, - .signal = -72, - .grade = 1312, - }, - { .desc = "UHB, 320 MHz, no channel load factor, punctured percentage 12.5 (2/16)", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_320, - .punctured = 0x3 - }, - .signal = -72, - .grade = 1806, - }, - { .desc = "HB, 160 MHz, channel load 20, channel load by us 10, punctured percentage 25", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_160, - .punctured = 0x3 - }, - .channel_util = 51, - .chan_load_by_us = 10, - .signal = -72, - .grade = 1179, - }, -}; - -KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc) - -static void setup_link_conf(struct kunit *test) -{ - const struct link_grading_case *params = test->param_value; - size_t vif_size = sizeof(struct ieee80211_vif) + - sizeof(struct iwl_mvm_vif); - struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); - struct ieee80211_bss_load_elem *bss_load; - struct element *element; - size_t ies_size = sizeof(struct cfg80211_bss_ies) + sizeof(*bss_load) + sizeof(element); - struct cfg80211_bss_ies *ies; - struct iwl_mvm_vif *mvmvif; - - KUNIT_ASSERT_NOT_NULL(test, vif); - - mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (params->chan_load_by_us > 0) { - ctx.channel_load_by_us = params->chan_load_by_us; - mvmvif->link[0] = &mvm_link; - } - - link_conf.vif = vif; - link_conf.chanreq.oper = params->chandef; - bss.signal = DBM_TO_MBM(params->signal); - - ies = kunit_kzalloc(test, ies_size, GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, ies); - ies->len = sizeof(*bss_load) + sizeof(struct element); - - element = (void *)ies->data; - element->datalen = sizeof(*bss_load); - element->id = 11; - - bss_load = (void *)element->data; - bss_load->channel_util = params->channel_util; - - rcu_assign_pointer(bss.ies, ies); - rcu_assign_pointer(bss.beacon_ies, ies); -} - -static void test_link_grading(struct kunit *test) -{ - const struct link_grading_case *params = test->param_value; - unsigned int ret; - - setup_link_conf(test); - - rcu_read_lock(); - ret = iwl_mvm_get_link_grade(&link_conf); - rcu_read_unlock(); - - KUNIT_EXPECT_EQ(test, ret, params->grade); - - kunit_kfree(test, link_conf.vif); - RCU_INIT_POINTER(bss.ies, NULL); -} - -static struct kunit_case link_grading_test_cases[] = { - KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params), - {} -}; - -static struct kunit_suite link_grading = { - .name = "iwlmvm-link-grading", - .test_cases = link_grading_test_cases, -}; - -kunit_test_suite(link_grading); - -static const struct valid_link_pair_case { - const char *desc; - bool bt; - struct ieee80211_channel *chan_a; - struct ieee80211_channel *chan_b; - enum nl80211_chan_width cw_a; - enum nl80211_chan_width cw_b; - s32 sig_a; - s32 sig_b; - bool csa_a; - bool valid; -} valid_link_pair_cases[] = { - { - .desc = "HB + UHB, valid.", - .chan_a = &chan_6ghz, - .chan_b = &chan_5ghz, - .valid = true, - }, - { - .desc = "LB + HB, no BT.", - .chan_a = &chan_2ghz, - .chan_b = &chan_5ghz, - .valid = true, - }, - { - .desc = "LB + HB, with BT.", - .bt = true, - .chan_a = &chan_2ghz, - .chan_b = &chan_5ghz, - .valid = false, - }, - { - .desc = "Same band", - .chan_a = &chan_2ghz, - .chan_b = &chan_2ghz, - .valid = false, - }, - { - .desc = "RSSI: LB, 20 MHz, low", - .chan_a = &chan_2ghz, - .cw_a = NL80211_CHAN_WIDTH_20, - .sig_a = -68, - .chan_b = &chan_5ghz, - .valid = false, - }, - { - .desc = "RSSI: UHB, 20 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_20, - .sig_a = -66, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_20, - .valid = true, - }, - { - .desc = "RSSI: UHB, 40 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_40, - .sig_a = -65, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_40, - .valid = false, - }, - { - .desc = "RSSI: UHB, 40 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_40, - .sig_a = -63, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_40, - .valid = true, - }, - { - .desc = "RSSI: UHB, 80 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_80, - .sig_a = -62, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_80, - .valid = false, - }, - { - .desc = "RSSI: UHB, 80 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_80, - .sig_a = -60, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_80, - .valid = true, - }, - { - .desc = "RSSI: UHB, 160 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -59, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = false, - }, - { - .desc = "RSSI: HB, 160 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -5, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = true, - }, - { - .desc = "CSA active", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -5, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = false, - /* same as previous entry with valid=true except for CSA */ - .csa_a = true, - }, -}; - -KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc) - -static void test_valid_link_pair(struct kunit *test) -{ - const struct valid_link_pair_case *params = test->param_value; - size_t vif_size = sizeof(struct ieee80211_vif) + - sizeof(struct iwl_mvm_vif); - struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); - struct iwl_trans *trans = kunit_kzalloc(test, sizeof(struct iwl_trans), - GFP_KERNEL); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_link_sel_data link_a = { - .chandef = &chandef_a, - .link_id = 1, - .signal = params->sig_a, - }; - struct iwl_mvm_link_sel_data link_b = { - .chandef = &chandef_b, - .link_id = 5, - .signal = params->sig_b, - }; - struct ieee80211_bss_conf *conf; - bool result; - - KUNIT_ASSERT_NOT_NULL(test, vif); - KUNIT_ASSERT_NOT_NULL(test, trans); - - chandef_a.chan = params->chan_a; - chandef_b.chan = params->chan_b; - - chandef_a.width = params->cw_a ?: NL80211_CHAN_WIDTH_20; - chandef_b.width = params->cw_b ?: NL80211_CHAN_WIDTH_20; - - mvm.trans = trans; - - mvm.last_bt_notif.wifi_loss_low_rssi = params->bt; - mvmvif->mvm = &mvm; - - conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, conf); - conf->chanreq.oper = chandef_a; - conf->csa_active = params->csa_a; - vif->link_conf[link_a.link_id] = (void __rcu *)conf; - - conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, conf); - conf->chanreq.oper = chandef_b; - vif->link_conf[link_b.link_id] = (void __rcu *)conf; - - wiphy_lock(&wiphy); - result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b); - wiphy_unlock(&wiphy); - - KUNIT_EXPECT_EQ(test, result, params->valid); - - kunit_kfree(test, vif); - kunit_kfree(test, trans); -} - -static struct kunit_case valid_link_pair_test_cases[] = { - KUNIT_CASE_PARAM(test_valid_link_pair, valid_link_pair_gen_params), - {}, -}; - -static struct kunit_suite valid_link_pair = { - .name = "iwlmvm-valid-link-pair", - .test_cases = valid_link_pair_test_cases, -}; - -kunit_test_suite(valid_link_pair); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index aa653782d6d7..0c9c2492d8a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -47,7 +47,6 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) { - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); struct ieee80211_vif *vif = mvm->p2p_device_vif; lockdep_assert_held(&mvm->mutex); @@ -125,8 +124,6 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) iwl_mvm_rm_aux_sta(mvm); } - if (!IS_ERR_OR_NULL(bss_vif)) - iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_ROC); mutex_unlock(&mvm->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 25d1a882a6a0..bb97837baeda 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1769,9 +1769,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", next_reclaimed); - if (tid < IWL_MAX_TID_COUNT) - iwl_mvm_count_mpdu(mvmsta, sta_id, 1, - true, 0); } else { IWL_DEBUG_TX_REPLY(mvm, "NDP - don't update next_reclaimed\n"); @@ -2150,13 +2147,10 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ba_res->tx_rate, false); } - if (mvmsta) { + if (mvmsta) iwl_mvm_tx_airtime(mvm, mvmsta, le32_to_cpu(ba_res->wireless_time)); - iwl_mvm_count_mpdu(mvmsta, sta_id, - le16_to_cpu(ba_res->txed), true, 0); - } rcu_read_unlock(); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 62da0132f383..22602c32faa5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -22,11 +22,6 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) { int ret; -#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) - if (WARN_ON(mvm->d3_test_active)) - return -EIO; -#endif - /* * Synchronous commands from this op-mode must hold * the mutex, this ensures we don't try to send two @@ -79,11 +74,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, lockdep_assert_held(&mvm->mutex); -#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) - if (WARN_ON(mvm->d3_test_active)) - return -EIO; -#endif - /* * Only synchronous commands can wait for status, * we use WANT_SKB so the caller can't. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index b7add05f7a85..b21a4d8eb105 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -124,13 +124,13 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_mac_cfg)},/* low 5GHz active */ {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_mac_cfg)},/* high 5GHz active */ -/* 6x30 Series */ - {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1000_mac_cfg)}, +/* 1030/6x30 Series */ + {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5327, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008B, 0x5317, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_mac_cfg)}, @@ -181,12 +181,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl1000_mac_cfg)}, /* 130 Series WiFi */ - {IWL_PCI_DEVICE(0x0896, 0x5005, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5007, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0897, 0x5015, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0897, 0x5017, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5025, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5027, iwl1000_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5005, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5007, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5015, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5017, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5025, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5027, iwl6030_mac_cfg)}, /* 2x00 Series */ {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_mac_cfg)}, @@ -673,6 +673,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, DEVICE(0x0082), SUBDEV_MASKED(0xC000, 0xF000)), + IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, + DEVICE(0x0085), SUBDEV_MASKED(0xC000, 0xF000)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_d_name, DEVICE(0x0082), SUBDEV(0x4820)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_mow1_name, @@ -729,10 +731,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x0083), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, DEVICE(0x0083), SUBDEV_MASKED(0x6, 0xF)), + IWL_DEV_INFO(iwl1000_bgn_cfg, iwl1000_bgn_name, + DEVICE(0x0084), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1216)), - IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1316)), + DEVICE(0x0084), SUBDEV_MASKED(0x6, 0xF)), /* 100 Series WiFi */ IWL_DEV_INFO(iwl100_bgn_cfg, iwl100_bgn_name, @@ -964,6 +966,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x24F3), SUBDEV(0x0004)), IWL_DEV_INFO(iwl8260_cfg, iwl8260_2n_name, DEVICE(0x24F3), SUBDEV(0x0044)), + IWL_DEV_INFO(iwl8260_cfg, iwl8260_2ac_name, + DEVICE(0x24F4)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F5)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F6)), IWL_DEV_INFO(iwl8265_cfg, iwl8265_2ac_name, DEVICE(0x24FD)), IWL_DEV_INFO(iwl8265_cfg, iwl8275_2ac_name, @@ -1171,16 +1179,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void iwl_pci_remove(struct pci_dev *pdev) { struct iwl_trans *trans = pci_get_drvdata(pdev); - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); if (!trans) return; - cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); - - iwl_drv_stop(trans->drv); - - iwl_trans_pcie_free(trans); + iwl_pcie_gen1_2_remove(trans); } #ifdef CONFIG_PM_SLEEP @@ -1222,11 +1225,15 @@ static int _iwl_pci_resume(struct device *device, bool restore) * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan, * but not bits [15:8]. So if we have bits set in lower word, assume * the device is alive. + * Alternatively, if the scratch value is 0xFFFFFFFF, then we no longer + * have access to the device and consider it powered off. * For older devices, just try silently to grab the NIC. */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - if (!(iwl_read32(trans, CSR_FUNC_SCRATCH) & - CSR_FUNC_SCRATCH_POWER_OFF_MASK)) + u32 scratch = iwl_read32(trans, CSR_FUNC_SCRATCH); + + if (!(scratch & CSR_FUNC_SCRATCH_POWER_OFF_MASK) || + scratch == ~0U) device_was_powered_off = true; } else { /* @@ -1248,7 +1255,7 @@ static int _iwl_pci_resume(struct device *device, bool restore) * won't really know how to recover. */ iwl_pcie_prepare_card_hw(trans); - iwl_finish_nic_init(trans); + iwl_trans_activate_nic(trans); iwl_op_mode_device_powered_off(trans->op_mode); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index f48aeebb151c..207c56e338dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -400,6 +400,11 @@ struct iwl_pcie_txqs { * @me_recheck_wk: worker to recheck WiAMT/CSME presence * @invalid_tx_cmd: invalid TX command buffer * @wait_command_queue: wait queue for sync commands + * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. + * The user should use iwl_trans_{alloc,free}_tx_cmd. + * @dev_cmd_pool_name: name for the TX command allocation pool + * @pm_support: set to true in start_hw if link pm is supported + * @ltr_enabled: set to true if the LTR is enabled */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -506,6 +511,12 @@ struct iwl_trans_pcie { struct iwl_dma_ptr invalid_tx_cmd; wait_queue_head_t wait_command_queue; + + struct kmem_cache *dev_cmd_pool; + char dev_cmd_pool_name[50]; + + bool pm_support; + bool ltr_enabled; }; static inline struct iwl_trans_pcie * @@ -783,6 +794,23 @@ static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans, return le16_to_cpu(tb->hi_n_len) >> 4; } +static inline struct iwl_device_tx_cmd * +iwl_pcie_gen1_2_alloc_tx_cmd(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return kmem_cache_zalloc(trans_pcie->dev_cmd_pool, GFP_ATOMIC); +} + +static inline void +iwl_pcie_gen1_2_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + kmem_cache_free(trans_pcie->dev_cmd_pool, dev_cmd); +} + void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs, bool is_flush); void iwl_pcie_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr); @@ -818,6 +846,8 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans) trans_pcie->fh_init_mask); iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, trans_pcie->hw_init_mask); + trans_pcie->fh_mask = 0; + trans_pcie->hw_mask = 0; } IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } @@ -1000,6 +1030,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) } else { iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, trans_pcie->fh_init_mask); + trans_pcie->fh_mask = 0; iwl_enable_hw_int_msk_msix(trans, MSIX_HW_INT_CAUSES_REG_RF_KILL); } @@ -1047,7 +1078,7 @@ static inline void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { } void iwl_pcie_rx_allocator_work(struct work_struct *data); /* common trans ops for all generations transports */ -void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans); +void iwl_pcie_gen1_2_op_mode_enter(struct iwl_trans *trans); int _iwl_trans_pcie_start_hw(struct iwl_trans *trans); int iwl_trans_pcie_start_hw(struct iwl_trans *trans); void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans); @@ -1064,9 +1095,8 @@ iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, void *sanitize_ctx); int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status, - bool test, bool reset); -int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset); + bool reset); +int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool reset); void iwl_trans_pci_interrupts(struct iwl_trans *trans, bool enable); void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans); void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, @@ -1081,6 +1111,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, const struct pci_device_id *ent, const struct iwl_mac_cfg *mac_cfg, u8 __iomem *hw_base, u32 hw_rev); +void iwl_pcie_gen1_2_remove(struct iwl_trans *trans); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); @@ -1105,6 +1136,7 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); +int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -1124,4 +1156,17 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, int iwl_trans_pcie_rxq_dma_data(struct iwl_trans *trans, int queue, struct iwl_trans_rxq_dma_data *data); +static inline bool iwl_pcie_gen1_is_pm_supported(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return trans_pcie->pm_support; +} + +static inline bool iwl_pcie_gen1_2_is_ltr_enabled(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return trans_pcie->ltr_enabled; +} #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c index 1951be3a30b7..b15c5d486527 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c @@ -47,7 +47,7 @@ int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) iwl_pcie_apm_config(trans); - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; 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 327366bf87de..59307b5df441 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -25,13 +25,52 @@ #include "fw/dbg.h" #include "fw/api/tx.h" #include "fw/acpi.h" -#include "fw/api/tx.h" #include "mei/iwl-mei.h" #include "internal.h" #include "iwl-fh.h" #include "pcie/iwl-context-info-v2.h" #include "pcie/utils.h" +#define IWL_HOST_MON_BLOCK_PEMON 0x00 +#define IWL_HOST_MON_BLOCK_HIPM 0x22 + +#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00 +#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01 +#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06 + +static void iwl_dump_host_monitor_block(struct iwl_trans *trans, + u32 block, u32 vec, u32 iter) +{ + int i; + + IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); + iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); + for (i = 0; i < iter; i++) + IWL_ERR(trans, " value [iter %d]: 0x%08x\n", + i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); +} + +static void iwl_pcie_dump_host_monitor(struct iwl_trans *trans) +{ + switch (trans->mac_cfg->device_family) { + case IWL_DEVICE_FAMILY_22000: + case IWL_DEVICE_FAMILY_AX210: + IWL_ERR(trans, "CSR_RESET = 0x%x\n", + iwl_read32(trans, CSR_RESET)); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_VEC1, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_WFPM, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM, + IWL_HOST_MON_BLOCK_PEMON_VEC0, 1); + break; + default: + return; + } +} + /* extended range in FW SRAM */ #define IWL_FW_MEM_EXTENDED_START 0x40000 #define IWL_FW_MEM_EXTENDED_END 0x57FFF @@ -175,13 +214,13 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_DISABLED); pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); - trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); + trans_pcie->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); - trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; + trans_pcie->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; IWL_DEBUG_POWER(trans, "L1 %sabled - LTR %sabled\n", (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", - trans->ltr_enabled ? "En" : "Dis"); + trans_pcie->ltr_enabled ? "En" : "Dis"); } /* @@ -228,7 +267,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) if (trans->mac_cfg->base->pll_cfg) iwl_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; @@ -301,7 +340,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) ret = iwl_trans_pcie_sw_reset(trans, true); if (!ret) - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (WARN_ON(ret)) { /* Release XTAL ON request */ @@ -1397,17 +1436,10 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq) } static void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, - bool test, bool reset) + bool reset) { iwl_disable_interrupts(trans); - /* - * in testing mode, the host stays awake and the - * hardware won't be reset (not even partially) - */ - if (test) - return; - iwl_pcie_disable_ict(trans); iwl_pcie_synchronize_irqs(trans); @@ -1478,7 +1510,7 @@ static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend) return ret; } -int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) +int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool reset) { int ret; @@ -1491,26 +1523,18 @@ int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) if (ret) return ret; - iwl_pcie_d3_complete_suspend(trans, test, reset); + iwl_pcie_d3_complete_suspend(trans, reset); return 0; } int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status, - bool test, bool reset) + bool reset) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 val; int ret; - if (test) { - iwl_enable_interrupts(trans); - *status = IWL_D3_STATUS_ALIVE; - ret = 0; - goto out; - } - if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); @@ -1518,9 +1542,12 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - ret = iwl_finish_nic_init(trans); - if (ret) + ret = iwl_trans_activate_nic(trans); + if (ret) { + IWL_ERR(trans, "Failed to init nic upon resume. err = %d\n", + ret); return ret; + } /* * Reconfigure IVAR table in case of MSIX or reset ict table in @@ -1554,18 +1581,13 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_read_umac_prph(trans, WFPM_GP2)); val = iwl_read32(trans, CSR_RESET); - if (val & CSR_RESET_REG_FLAG_NEVO_RESET) - *status = IWL_D3_STATUS_RESET; - else - *status = IWL_D3_STATUS_ALIVE; - -out: - if (*status == IWL_D3_STATUS_ALIVE) - ret = iwl_pcie_d3_handshake(trans, false); - else + if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { + IWL_INFO(trans, "Device was reset during suspend\n"); trans->state = IWL_TRANS_NO_FW; + return -ENOENT; + } - return ret; + return iwl_pcie_d3_handshake(trans, false); } static void @@ -1744,7 +1766,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) { int ret; - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret < 0) return ret; @@ -1882,7 +1904,7 @@ void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val) iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans) +void iwl_pcie_gen1_2_op_mode_enter(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2000,6 +2022,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) free_percpu(trans_pcie->txqs.tso_hdr_page); } + kmem_cache_destroy(trans_pcie->dev_cmd_pool); iwl_trans_free(trans); } @@ -3516,7 +3539,7 @@ iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, struct iwl_trans_dump_data *dump_data; u32 len, num_rbs = 0, monitor_len = 0; int i, ptr; - bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && + bool dump_rbs = iwl_trans_is_fw_error(trans) && !trans->mac_cfg->mq_rx_supported && dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); @@ -3684,28 +3707,40 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit); } -static int iwl_trans_pcie_set_txcmd_info(const struct iwl_mac_cfg *mac_cfg, - unsigned int *txcmd_size, - unsigned int *txcmd_align) +static int iwl_trans_pcie_alloc_txcmd_pool(struct iwl_trans *trans) { - if (!mac_cfg->gen2) { - *txcmd_size = sizeof(struct iwl_tx_cmd_v6); - *txcmd_align = sizeof(void *); - } else if (mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { - *txcmd_size = sizeof(struct iwl_tx_cmd_v9); - *txcmd_align = 64; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned int txcmd_size, txcmd_align; + + if (!trans->mac_cfg->gen2) { + txcmd_size = sizeof(struct iwl_tx_cmd_v6); + txcmd_align = sizeof(void *); + } else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { + txcmd_size = sizeof(struct iwl_tx_cmd_v9); + txcmd_align = 64; } else { - *txcmd_size = sizeof(struct iwl_tx_cmd); - *txcmd_align = 128; + txcmd_size = sizeof(struct iwl_tx_cmd); + txcmd_align = 128; } - *txcmd_size += sizeof(struct iwl_cmd_header); - *txcmd_size += 36; /* biggest possible 802.11 header */ + txcmd_size += sizeof(struct iwl_cmd_header); + txcmd_size += 36; /* biggest possible 802.11 header */ /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ - if (WARN_ON((mac_cfg->gen2 && *txcmd_size >= *txcmd_align))) + if (WARN_ON((trans->mac_cfg->gen2 && txcmd_size >= txcmd_align))) return -EINVAL; + snprintf(trans_pcie->dev_cmd_pool_name, + sizeof(trans_pcie->dev_cmd_pool_name), + "iwl_cmd_pool:%s", dev_name(trans->dev)); + + trans_pcie->dev_cmd_pool = + kmem_cache_create(trans_pcie->dev_cmd_pool_name, + txcmd_size, txcmd_align, + SLAB_HWCACHE_ALIGN, NULL); + if (!trans_pcie->dev_cmd_pool) + return -ENOMEM; + return 0; } @@ -3715,18 +3750,12 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans_info *info, u8 __iomem *hw_base) { struct iwl_trans_pcie *trans_pcie, **priv; - unsigned int txcmd_size, txcmd_align; struct iwl_trans *trans; unsigned int bc_tbl_n_entries; int ret, addr_size; - ret = iwl_trans_pcie_set_txcmd_info(mac_cfg, &txcmd_size, - &txcmd_align); - if (ret) - return ERR_PTR(ret); - trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, - mac_cfg, txcmd_size, txcmd_align); + mac_cfg); if (!trans) return ERR_PTR(-ENOMEM); @@ -3737,6 +3766,10 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); + ret = iwl_trans_pcie_alloc_txcmd_pool(trans); + if (ret) + goto out_free_trans; + if (trans->mac_cfg->gen2) { trans_pcie->txqs.tfd.addr_size = 64; trans_pcie->txqs.tfd.max_tbs = IWL_TFH_NUM_TBS; @@ -3756,7 +3789,7 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->txqs.tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); if (!trans_pcie->txqs.tso_hdr_page) { ret = -ENOMEM; - goto out_free_trans; + goto out_free_txcmd_pool; } if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) @@ -3906,6 +3939,8 @@ out_free_ndev: free_netdev(trans_pcie->napi_dev); out_free_tso: free_percpu(trans_pcie->txqs.tso_hdr_page); +out_free_txcmd_pool: + kmem_cache_destroy(trans_pcie->dev_cmd_pool); out_free_trans: iwl_trans_free(trans); return ERR_PTR(ret); @@ -3999,6 +4034,7 @@ static void get_crf_id(struct iwl_trans *iwl_trans, /* Read cdb info (also contains the jacket info if needed in the future */ hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); + IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n", info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id); } @@ -4014,10 +4050,8 @@ static int map_crf_id(struct iwl_trans *iwl_trans, u32 val = info->hw_crf_id; u32 step_id = REG_CRF_ID_STEP(val); u32 slave_id = REG_CRF_ID_SLAVE(val); - u32 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id); u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); - u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id); u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); /* Map between crf id to rf id */ @@ -4066,21 +4100,12 @@ static int map_crf_id(struct iwl_trans *iwl_trans, IWL_INFO(iwl_trans, "Adding cdb to rf id\n"); } - /* Set Jacket capabilities */ - if (jacket_id_wfpm || jacket_id_cnv) { - info->hw_rf_id += BIT(29); - IWL_INFO(iwl_trans, "Adding jacket to rf id\n"); - } - IWL_INFO(iwl_trans, "Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n", REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id); IWL_INFO(iwl_trans, - "Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n", - cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id); - IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n", - jacket_id_cnv, info->hw_cnv_id); - + "Detected cdb-id 0x%x from wfpm id 0x%x\n", + cdb_id_wfpm, hw_wfpm_id); out: return ret; } @@ -4163,7 +4188,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, */ ret = iwl_pcie_prepare_card_hw(iwl_trans); if (!ret) { - ret = iwl_finish_nic_init(iwl_trans); + ret = iwl_trans_activate_nic(iwl_trans); if (ret) goto out_free_trans; if (iwl_trans_grab_nic_access(iwl_trans)) { @@ -4271,3 +4296,63 @@ out_free_trans: iwl_trans_pcie_free(iwl_trans); return ret; } + +void iwl_pcie_gen1_2_remove(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); + + iwl_drv_stop(trans->drv); + + iwl_trans_pcie_free(trans); +} + +int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans) +{ + const struct iwl_mac_cfg *mac_cfg = trans->mac_cfg; + u32 poll_ready; + int err; + + if (mac_cfg->bisr_workaround) { + /* ensure the TOP FSM isn't still in previous reset */ + mdelay(2); + } + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + if (mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } else { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; + } + + if (mac_cfg->device_family == IWL_DEVICE_FAMILY_8000) + udelay(2); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); + if (err < 0) { + IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); + + iwl_pcie_dump_host_monitor(trans); + } + + if (mac_cfg->bisr_workaround) { + /* ensure BISR shift has finished */ + udelay(200); + } + + return err; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c index 84a05cc1c27a..6e85aa519e1b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c @@ -2092,7 +2092,8 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, break; } - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_7000 && + trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) len = DIV_ROUND_UP(len, 4); if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) @@ -2601,8 +2602,9 @@ static int iwl_trans_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (test_bit(STATUS_FW_ERROR, &trans->status)) { - if (!test_and_clear_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, - &trans->status)) { + if (trans->suppress_cmd_error_once) { + trans->suppress_cmd_error_once = false; + } else { IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); dump_stack(); } diff --git a/drivers/net/wireless/intel/iwlwifi/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/tests/Makefile index 1b49241c578f..b996c45d43e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/tests/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -iwlwifi-tests-y += module.o devinfo.o utils.o +iwlwifi-tests-y += module.o devinfo.o utils.o nvm_parse.o ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/tests/nvm_parse.c b/drivers/net/wireless/intel/iwlwifi/tests/nvm_parse.c new file mode 100644 index 000000000000..853911900bfd --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/tests/nvm_parse.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for NVM parse + * + * Copyright (C) 2025 Intel Corporation + */ +#include <kunit/static_stub.h> +#include <kunit/test.h> +#include <iwl-nvm-parse.h> + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +static const struct nvm_flag_case { + const char *desc; + u16 nvm_flags; + u32 reg_rule_flags; + u32 set_reg_rule_flags; + u32 clear_reg_rule_flags; +} nvm_flag_cases[] = { + { + .desc = "Restricting VLP client and AP access", + .nvm_flags = 0, + .set_reg_rule_flags = NL80211_RRF_NO_6GHZ_VLP_CLIENT, + .clear_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP, + }, + { + .desc = "Allow VLP client and AP access", + .nvm_flags = NVM_CHANNEL_VLP, + .set_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP, + .clear_reg_rule_flags = NL80211_RRF_NO_6GHZ_VLP_CLIENT, + }, + { + .desc = "Allow VLP client access, while restricting AP access", + .nvm_flags = NVM_CHANNEL_VLP | NVM_CHANNEL_VLP_AP_NOT_ALLOWED, + .set_reg_rule_flags = 0, + .clear_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP | + NL80211_RRF_NO_6GHZ_VLP_CLIENT, + }, +}; + +KUNIT_ARRAY_PARAM_DESC(nvm_flag, nvm_flag_cases, desc) + +static void test_nvm_flags(struct kunit *test) +{ + const struct nvm_flag_case *params = test->param_value; + struct iwl_reg_capa reg_capa = {}; + u32 flags = 0; + + flags = iwl_nvm_get_regdom_bw_flags(NULL, 0, params->nvm_flags, + reg_capa); + + if ((params->set_reg_rule_flags & flags) != params->set_reg_rule_flags) + KUNIT_FAIL(test, "Expected set bits:0x%08x flags:0x%08x\n", + params->set_reg_rule_flags, flags); + + if (params->clear_reg_rule_flags & flags) + KUNIT_FAIL(test, "Expected clear bits:0x%08x flags:0x%08x\n", + params->clear_reg_rule_flags, flags); +} + +static struct kunit_case nvm_flags_test_cases[] = { + KUNIT_CASE_PARAM(test_nvm_flags, + nvm_flag_gen_params), + {}, +}; + +static struct kunit_suite nvm_flags_suite = { + .name = "iwlwifi-nvm_flags", + .test_cases = nvm_flags_test_cases, +}; + +kunit_test_suite(nvm_flags_suite); |