From 9be162a7b670b7e8dbada3c139d77961f457a34d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 14 Mar 2023 19:49:18 +0200 Subject: wifi: iwlwifi: mvm: add support for the new MAC CTXT command As a part of the new MLD FW API changes, we have a new MAC CTXT command. Add structures and enum definitions, along with the functions that sends this command (i.e. add, remove and change mac ctxt). This functions will be in used in the next patches. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230314194113.99a41a5bc55f.I310312c829f5f2f69b64fcddce487b1eab80165b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index f4e9446d9dc2..69c390ff2745 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -521,6 +521,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), HCMD_NAME(SESSION_PROTECTION_CMD), + HCMD_NAME(MAC_CONFIG_CMD), HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_START_NOTIF), }; -- cgit v1.2.3 From 55eb1c5fa4b260491d8be3299d4546d0b34465f4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 14 Mar 2023 19:49:19 +0200 Subject: wifi: iwlwifi: mvm: add support for the new LINK command As a part of the new MLD FW API changes, we have a new LINK command to add/remove/configure a link. Add structures and enum definitions, along with the functions that sends this command (i.e. add, remove and change mac ctxt). These functions will be in used in the next patches. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230314194113.d7808329effb.I13bea2db206b78540bc866bc3ab755ad5be78c53@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 179 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 175 ++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 26 ++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 20 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 7 files changed, 390 insertions(+), 20 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/link.c (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') 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 f12b2a25cd3d..301f34f13523 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -37,6 +37,10 @@ enum iwl_mac_conf_subcmd_ids { * @MAC_CONFIG_CMD: &struct iwl_mac_config_cmd */ MAC_CONFIG_CMD = 0x8, + /** + * @LINK_CONFIG_CMD: &struct iwl_link_config_cmd + */ + LINK_CONFIG_CMD = 0x9, /** * @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif */ @@ -287,4 +291,179 @@ struct iwl_mac_config_cmd { }; } __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_1 */ +/** + * enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being + * modified in &iwl_link_ctx_cfg_cmd + * + * @LINK_CONTEXT_MODIFY_ACTIVE: covers iwl_link_ctx_cfg_cmd::active + * @LINK_CONTEXT_MODIFY_RATES_INFO: covers iwl_link_ctx_cfg_cmd::cck_rates, + * iwl_link_ctx_cfg_cmd::ofdm_rates, + * iwl_link_ctx_cfg_cmd::cck_short_preamble, + * iwl_link_ctx_cfg_cmd::short_slot + * @LINK_CONTEXT_MODIFY_PROTECT_FLAGS: covers + * iwl_link_ctx_cfg_cmd::protection_flags + * @LINK_CONTEXT_MODIFY_QOS_PARAMS: covers iwl_link_ctx_cfg_cmd::qos_flags, + * iwl_link_ctx_cfg_cmd::ac, + * @LINK_CONTEXT_MODIFY_BEACON_TIMING: covers iwl_link_ctx_cfg_cmd::bi, + * iwl_link_ctx_cfg_cmd::dtim_interval, + * iwl_link_ctx_cfg_cmd::dtim_time, + * iwl_link_ctx_cfg_cmd::dtim_tsf, + * iwl_link_ctx_cfg_cmd::assoc_beacon_arrive_time. + * This flag can be set only once after assoc. + * @LINK_CONTEXT_MODIFY_HE_PARAMS: covers + * iwl_link_ctx_cfg_cmd::htc_trig_based_pkt_ext + * iwl_link_ctx_cfg_cmd::rand_alloc_ecwmin, + * iwl_link_ctx_cfg_cmd::rand_alloc_ecwmax, + * iwl_link_ctx_cfg_cmd::trig_based_txf, + * iwl_link_ctx_cfg_cmd::bss_color, + * iwl_link_ctx_cfg_cmd::ndp_fdbk_buff_th_exp, + * iwl_link_ctx_cfg_cmd::ref_bssid_addr + * iwl_link_ctx_cfg_cmd::bssid_index, + * iwl_link_ctx_cfg_cmd::frame_time_rts_th. + * This flag can be set any time. + * @LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE: covers + * iwl_link_ctx_cfg_cmd::bss_color_disable + * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. + * This flag can be set only if the MAC that this link relates to has + * eht_support set to true. + * @LINK_CONTEXT_MODIFY_ALL: set all above flags + */ +enum iwl_link_ctx_modify_flags { + LINK_CONTEXT_MODIFY_ACTIVE = BIT(0), + LINK_CONTEXT_MODIFY_RATES_INFO = BIT(1), + LINK_CONTEXT_MODIFY_PROTECT_FLAGS = BIT(2), + LINK_CONTEXT_MODIFY_QOS_PARAMS = BIT(3), + LINK_CONTEXT_MODIFY_BEACON_TIMING = BIT(4), + LINK_CONTEXT_MODIFY_HE_PARAMS = BIT(5), + LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6), + LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7), + LINK_CONTEXT_MODIFY_ALL = 0xff, +}; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */ + +/** + * enum iwl_link_ctx_protection_flags - link protection flags + * @LINK_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, + * this will require CCK RTS/CTS2self. + * RTS/CTS will protect full burst time. + * @LINK_PROT_FLG_HT_PROT: enable HT protection + * @LINK_PROT_FLG_FAT_PROT: protect 40 MHz transmissions + * @LINK_PROT_FLG_SELF_CTS_EN: allow CTS2self + */ +enum iwl_link_ctx_protection_flags { + LINK_PROT_FLG_TGG_PROTECT = BIT(0), + LINK_PROT_FLG_HT_PROT = BIT(1), + LINK_PROT_FLG_FAT_PROT = BIT(2), + LINK_PROT_FLG_SELF_CTS_EN = BIT(3), +}; /* LINK_PROTECT_FLAGS_E_VER_1 */ + +/** + * enum iwl_link_ctx_flags - link context flags + * + * @LINK_FLG_BSS_COLOR_DIS: BSS color disable, don't use the BSS + * color for RX filter but use MAC header + * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG + * @LINK_FLG_MU_EDCA_CW: indicates that there is an element of MU EDCA + * parameter set, i.e. the backoff counters for trig-based ACs + * @LINK_FLG_RU_2MHZ_BLOCK: indicates that 26-tone RU OFDMA transmission are + * not allowed (as there are OBSS that might classify such transmissions as + * radar pulses). + */ +enum iwl_link_ctx_flags { + LINK_FLG_BSS_COLOR_DIS = BIT(0), + LINK_FLG_MU_EDCA_CW = BIT(1), + LINK_FLG_RU_2MHZ_BLOCK = BIT(2), +}; /* LINK_CONTEXT_FLAG_E_VER_1 */ + +/** + * struct iwl_link_config_cmd - command structure to configure the LINK context + * in MLD API + * ( LINK_CONFIG_CMD =0x9 ) + * + * @action: action to perform, one of FW_CTXT_ACTION_* + * @link_id: the id of the link that this cmd configures + * @mac_id: interface ID. Relevant only if action is FW_CTXT_ACTION_ADD + * @phy_id: PHY index. Can be changed only if the link was inactive + * (and stays inactive). If the link is active (or becomes active), + * this field is ignored. + * @local_link_addr: the links MAC address. Can be changed only if the link was + * inactive (and stays inactive). If the link is active + * (or becomes active), this field is ignored. + * @reserved_for_local_link_addr: reserved + * @modify_mask: from &enum iwl_link_ctx_modify_flags, selects what to change. + * Relevant only if action is FW_CTXT_ACTION_MODIFY + * @active: indicates whether the link is active or not + * @listen_lmac: indicates whether the link should be allocated on the Listen + * Lmac or on the Main Lmac. Cannot be changed on an active Link. + * Relevant only for eSR. + * @cck_rates: basic rates available for CCK + * @ofdm_rates: basic rates available for OFDM + * @cck_short_preamble: 1 for enabling short preamble, 0 otherwise + * @short_slot: 1 for enabling short slots, 0 otherwise + * @protection_flags: combination of &enum iwl_link_ctx_protection_flags + * @qos_flags: from &enum iwl_mac_qos_flags + * @ac: one iwl_mac_qos configuration for each AC + * @htc_trig_based_pkt_ext: default PE in 4us units + * @rand_alloc_ecwmin: random CWmin = 2**ECWmin-1 + * @rand_alloc_ecwmax: random CWmax = 2**ECWmax-1 + * @ndp_fdbk_buff_th_exp: set exponent for the NDP feedback buffered threshold + * @trig_based_txf: MU EDCA Parameter set for the trigger based traffic queues + * @dtim_time: DTIM arrival time in system time + * @dtim_tsf: DTIM arrival time in TSF + * @assoc_beacon_arrive_time: TSF of first beacon after association + * @bi: beacon interval in TU, applicable only when associated + * @dtim_interval: DTIM interval in TU. + * Relevant only for GO, otherwise this is offloaded. + * @beacon_template: beacon template ID. For GO only + * @puncture_mask: puncture mask for EHT + * @frame_time_rts_th: HE duration RTS threshold, in units of 32us + * @flags: a combination from &enum iwl_link_ctx_flags + * @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags + * Below fields are for multi-bssid: + * @ref_bssid_addr: reference BSSID used by the AP + * @reserved_for_ref_bssid_addr: reserved + * @bssid_index: index of the associated VAP + * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame + * @reserved: alignment + */ +struct iwl_link_config_cmd { + __le32 action; + __le32 link_id; + __le32 mac_id; + __le32 phy_id; + u8 local_link_addr[6]; + __le16 reserved_for_local_link_addr; + __le32 modify_mask; + __le32 active; + __le32 listen_lmac; + __le32 cck_rates; + __le32 ofdm_rates; + __le32 cck_short_preamble; + __le32 short_slot; + __le32 protection_flags; + /* MAC_QOS_PARAM_API_S_VER_1 */ + __le32 qos_flags; + struct iwl_ac_qos ac[AC_NUM + 1]; + u8 htc_trig_based_pkt_ext; + u8 rand_alloc_ecwmin; + u8 rand_alloc_ecwmax; + u8 ndp_fdbk_buff_th_exp; + struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; + __le32 dtim_time; + __le64 dtim_tsf; + __le32 assoc_beacon_arrive_time; + __le32 bi; + __le32 dtim_interval; + __le32 beacon_template; + __le16 puncture_mask; + __le16 frame_time_rts_th; + __le32 flags; + __le32 flags_mask; + /* The below fields are for multi-bssid */ + u8 ref_bssid_addr[6]; + __le16 reserved_for_ref_bssid_addr; + u8 bssid_index; + u8 bss_color; + u8 reserved[2]; +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index d71f0a99b7c4..ec6346c6c8e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -7,7 +7,7 @@ iwlmvm-y += power.o coex.o iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-y += ftm-responder.o ftm-initiator.o iwlmvm-y += rfi.o -iwlmvm-y += mld-key.o mld-mac.o +iwlmvm-y += mld-key.o mld-mac.o link.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c new file mode 100644 index 000000000000..2688cb49c951 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2022 Intel Corporation + */ +#include "mvm.h" + +static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, + struct iwl_link_config_cmd *cmd, + enum iwl_ctxt_action action) +{ + int ret; + + cmd->action = cpu_to_le32(action); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), 0, + sizeof(*cmd), cmd); + if (ret) + IWL_ERR(mvm, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n", + action, ret); + return ret; +} + +int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_link_config_cmd cmd = {}; + + if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) + return -EINVAL; + + /* Update SF - Disable if needed. if this fails, SF might still be on + * while many macs are bound, which is forbidden - so fail the binding. + */ + if (iwl_mvm_sf_update(mvm, vif, false)) + return -EINVAL; + + cmd.link_id = cpu_to_le32(mvmvif->phy_ctxt->id); + cmd.mac_id = cpu_to_le32(mvmvif->id); + cmd.phy_id = cpu_to_le32(mvmvif->phy_ctxt->id); + + memcpy(cmd.local_link_addr, vif->addr, ETH_ALEN); + + return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); +} + +int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + u32 changes, bool active) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_phy_ctxt *phyctxt = mvmvif->phy_ctxt; + struct iwl_link_config_cmd cmd = {}; + u32 ht_flag, flags = 0, flags_mask = 0; + + if (!phyctxt) + return -EINVAL; + + cmd.link_id = cpu_to_le32(phyctxt->id); + + /* The phy_id, link address and listen_lmac can be modified only until + * the link becomes active, otherwise they will be ignored. + */ + cmd.phy_id = cpu_to_le32(phyctxt->id); + cmd.mac_id = cpu_to_le32(mvmvif->id); + + memcpy(cmd.local_link_addr, vif->addr, ETH_ALEN); + + cmd.active = cpu_to_le32(active); + + /* TODO: set a value to cmd.listen_lmac when system requiremens + * will define it + */ + + iwl_mvm_set_fw_basic_rates(mvm, vif, &cmd.cck_rates, &cmd.ofdm_rates); + + cmd.cck_short_preamble = cpu_to_le32(vif->bss_conf.use_short_preamble); + cmd.short_slot = cpu_to_le32(vif->bss_conf.use_short_slot); + + /* The fw does not distinguish between ht and fat */ + ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT; + iwl_mvm_set_fw_protection_flags(mvm, vif, &cmd.protection_flags, + ht_flag, LINK_PROT_FLG_TGG_PROTECT); + + iwl_mvm_set_fw_qos_params(mvm, vif, &cmd.ac[0], &cmd.qos_flags); + + /* We need the dtim_period to set the MAC as associated */ + if (vif->cfg.assoc && vif->bss_conf.dtim_period) + iwl_mvm_set_fw_dtim_tbtt(mvm, vif, &cmd.dtim_tsf, + &cmd.dtim_time, + &cmd.assoc_beacon_arrive_time); + else + changes &= ~LINK_CONTEXT_MODIFY_BEACON_TIMING; + + cmd.bi = cpu_to_le32(vif->bss_conf.beacon_int); + cmd.dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * + vif->bss_conf.dtim_period); + + /* TODO: Assumes that the beacon id == mac context id */ + cmd.beacon_template = cpu_to_le32(mvmvif->id); + + if (!vif->bss_conf.he_support || iwlwifi_mod_params.disable_11ax || + !vif->cfg.assoc) { + changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS; + goto send_cmd; + } + + cmd.htc_trig_based_pkt_ext = vif->bss_conf.htc_trig_based_pkt_ext; + + if (vif->bss_conf.uora_exists) { + cmd.rand_alloc_ecwmin = + vif->bss_conf.uora_ocw_range & 0x7; + cmd.rand_alloc_ecwmax = + (vif->bss_conf.uora_ocw_range >> 3) & 0x7; + } + + /* TODO how to set ndp_fdbk_buff_th_exp? */ + + if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif, + &cmd.trig_based_txf[0])) { + flags |= LINK_FLG_MU_EDCA_CW; + flags_mask |= LINK_FLG_MU_EDCA_CW; + } + + if (vif->bss_conf.eht_puncturing && !iwlwifi_mod_params.disable_11be) + cmd.puncture_mask = cpu_to_le16(vif->bss_conf.eht_puncturing); + else + /* This flag can be set only if the MAC has eht support */ + changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; + + cmd.bss_color = vif->bss_conf.he_bss_color.color; + + if (!vif->bss_conf.he_bss_color.enabled) { + flags |= LINK_FLG_BSS_COLOR_DIS; + flags_mask |= LINK_FLG_BSS_COLOR_DIS; + } + + cmd.frame_time_rts_th = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + + /* Block 26-tone RU OFDMA transmissions */ + if (mvmvif->he_ru_2mhz_block) { + flags |= LINK_FLG_RU_2MHZ_BLOCK; + flags_mask |= LINK_FLG_RU_2MHZ_BLOCK; + } + + if (vif->bss_conf.nontransmitted) { + ether_addr_copy(cmd.ref_bssid_addr, + vif->bss_conf.transmitter_bssid); + cmd.bssid_index = vif->bss_conf.bssid_index; + } + +send_cmd: + cmd.modify_mask = cpu_to_le32(changes); + cmd.flags = cpu_to_le32(flags); + cmd.flags_mask = cpu_to_le32(flags_mask); + + return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); +} + +int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_link_config_cmd cmd = {}; + int ret; + + if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) + return -EINVAL; + + cmd.link_id = cpu_to_le32(mvmvif->phy_ctxt->id); + ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE); + + if (!ret) + if (iwl_mvm_sf_update(mvm, vif, true)) + IWL_ERR(mvm, "Failed to update SF state\n"); + + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index b21327ec4401..4d7ad91c53d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -396,9 +396,8 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, *ofdm_rates = ofdm; } -static void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - __le32 *cck_rates, __le32 *ofdm_rates) +void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + __le32 *cck_rates, __le32 *ofdm_rates) { struct ieee80211_chanctx_conf *chanctx; u8 cck_ack_rates, ofdm_ack_rates; @@ -414,11 +413,10 @@ static void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, *ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates); } -static void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - __le32 *protection_flags, - u32 ht_flag, - u32 tgg_flag) +void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + __le32 *protection_flags, u32 ht_flag, + u32 tgg_flag) { /* for both sta and ap, ht_operation_mode hold the protection_mode */ u8 protection_mode = vif->bss_conf.ht_operation_mode & @@ -460,9 +458,8 @@ static void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm, } } -static void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_ac_qos *ac, __le32 *qos_flags) +void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_ac_qos *ac, __le32 *qos_flags) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; @@ -572,10 +569,9 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, return ret; } -static void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - __le64 *dtim_tsf, __le32 *dtim_time, - __le32 *assoc_beacon_arrive_time) +void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + __le64 *dtim_tsf, __le32 *dtim_time, + __le32 *assoc_beacon_arrive_time) { u32 dtim_offs; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 210b134c735f..cf08cb834cc4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2000,10 +2000,9 @@ static void iwl_mvm_get_optimal_ppe_info(struct iwl_he_pkt_ext_v2 *pkt_ext, * This function sets the MU EDCA parameters ans returns whether MU EDCA * is enabled or not */ -static bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, - struct iwl_he_backoff_conf - *trig_based_txf) +bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif, + struct iwl_he_backoff_conf *trig_based_txf) { int i; /* Mark MU EDCA as enabled, unless none detected on some AC */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 1287207a34b3..4663cb7a0b10 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1640,6 +1640,20 @@ u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); /* MAC (virtual interface) programming */ +void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + __le32 *cck_rates, __le32 *ofdm_rates); +void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + __le32 *protection_flags, u32 ht_flag, + u32 tgg_flag); +void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_ac_qos *ac, __le32 *qos_flags); +bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif, + struct iwl_he_backoff_conf *trig_based_txf); +void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + __le64 *dtim_tsf, __le32 *dtim_time, + __le32 *assoc_beacon_arrive_time); __le32 iwl_mac_ctxt_p2p_dev_has_extended_disc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm, @@ -1702,6 +1716,12 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +/* Links */ +int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + u32 changes, bool active); +int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif); + /* Quota management */ static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 69c390ff2745..c3767f62026a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -522,6 +522,7 @@ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), HCMD_NAME(SESSION_PROTECTION_CMD), HCMD_NAME(MAC_CONFIG_CMD), + HCMD_NAME(LINK_CONFIG_CMD), HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_START_NOTIF), }; -- cgit v1.2.3 From 006c152ac9e56ac7871efa995854c3ff8cf6915a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 14 Mar 2023 19:49:20 +0200 Subject: wifi: iwlwifi: mvm: add support for the new STA related commands As a part of the new MLD FW API changes, we have new commands for STA related operations (add/remove/aux/disable tx). Add structures and enum definitions, along with part of the functions that sends this commands. This functions will be in used and more will be added in the next patches. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230314194113.132873ce015c.I7b12a77e5be066730762e6ceeeaa7190293c3df1@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 128 ++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 281 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 + drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 16 +- 6 files changed, 431 insertions(+), 8 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') 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 301f34f13523..a111e7366d49 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -41,6 +41,22 @@ enum iwl_mac_conf_subcmd_ids { * @LINK_CONFIG_CMD: &struct iwl_link_config_cmd */ LINK_CONFIG_CMD = 0x9, + /** + * @STA_CONFIG_CMD: &struct iwl_mvm_sta_cfg_cmd + */ + STA_CONFIG_CMD = 0xA, + /** + * @AUX_STA_CMD: &struct iwl_mvm_aux_sta_cmd + */ + AUX_STA_CMD = 0xB, + /** + * @STA_REMOVE_CMD: &struct iwl_mvm_remove_sta_cmd + */ + STA_REMOVE_CMD = 0xC, + /** + * @STA_DISABLE_TX_CMD: &struct iwl_mvm_sta_disable_tx_cmd + */ + STA_DISABLE_TX_CMD = 0xD, /** * @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif */ @@ -466,4 +482,116 @@ struct iwl_link_config_cmd { u8 reserved[2]; } __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */ +/** + * enum iwl_fw_sta_type - FW station types + * @STATION_TYPE_PEER: represents a peer - AP in BSS, a TDLS sta, a client in + * P2P. + * @STATION_TYPE_BCAST_MGMT: The station used to send beacons and + * probe responses. Also used for traffic injection in sniffer mode + * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be + * suspended / resumed at the right timing depending on the clients' + * power save state and the DTIM timing + */ +enum iwl_fw_sta_type { + STATION_TYPE_PEER, + STATION_TYPE_BCAST_MGMT, + STATION_TYPE_MCAST, +}; /* STATION_TYPE_E_VER_1 */ + +/** + * struct iwl_mvm_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's + * station table + * ( STA_CONFIG_CMD = 0xA ) + * + * @sta_id: index of station in uCode's station table + * @link_id: the id of the link that is used to communicate with this sta + * @peer_mld_address: the peers mld address + * @reserved_for_peer_mld_address: reserved + * @peer_link_address: the address of the link that is used to communicate + * with this sta + * @reserved_for_peer_link_address: reserved + * @station_type: type of this station. See &enum iwl_fw_sta_type + * @assoc_id: for GO only + * @beamform_flags: beam forming controls + * @mfp: indicates whether the STA uses management frame protection or not. + * @mimo: indicates whether the sta uses mimo or not + * @mimo_protection: indicates whether the sta uses mimo protection or not + * @ack_enabled: indicates that the AP supports receiving ACK- + * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG + * @trig_rnd_alloc: indicates that trigger based random allocation + * is enabled according to UORA element existence + * @tx_ampdu_spacing: minimum A-MPDU spacing: + * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density + * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K, + * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K. + * @sp_length: the size of the SP in actual number of frames + * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver + * enabled ACs. + * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY + * capa + * @htc_flags: which features are supported in HTC + */ +struct iwl_mvm_sta_cfg_cmd { + __le32 sta_id; + __le32 link_id; + u8 peer_mld_address[ETH_ALEN]; + __le16 reserved_for_peer_mld_address; + u8 peer_link_address[ETH_ALEN]; + __le16 reserved_for_peer_link_address; + __le32 station_type; + __le32 assoc_id; + __le32 beamform_flags; + __le32 mfp; + __le32 mimo; + __le32 mimo_protection; + __le32 ack_enabled; + __le32 trig_rnd_alloc; + __le32 tx_ampdu_spacing; + __le32 tx_ampdu_max_size; + __le32 sp_length; + __le32 uapsd_acs; + struct iwl_he_pkt_ext_v2 pkt_ext; + __le32 htc_flags; +} __packed; /* STA_CMD_API_S_VER_1 */ + +/** + * struct iwl_mvm_aux_sta_cmd - command for AUX STA configuration + * ( AUX_STA_CMD = 0xB ) + * + * @sta_id: index of aux sta to configure + * @lmac_id: ? + * @mac_addr: mac addr of the auxilary sta + * @reserved_for_mac_addr: reserved + */ +struct iwl_mvm_aux_sta_cmd { + __le32 sta_id; + __le32 lmac_id; + u8 mac_addr[ETH_ALEN]; + __le16 reserved_for_mac_addr; + +} __packed; /* AUX_STA_CMD_API_S_VER_1 */ + +/** + * struct iwl_mvm_remove_sta_cmd - a cmd structure to remove a sta added by + * STA_CONFIG_CMD or AUX_STA_CONFIG_CMD + * ( STA_REMOVE_CMD = 0xC ) + * + * @sta_id: index of station to remove + */ +struct iwl_mvm_remove_sta_cmd { + __le32 sta_id; +} __packed; /* REMOVE_STA_API_S_VER_1 */ + +/** + * struct iwl_mvm_sta_disable_tx_cmd - disable / re-enable tx to a sta + * ( STA_DISABLE_TX_CMD = 0xD ) + * + * @sta_id: index of the station to disable tx to + * @disable: indicates if to disable or re-enable tx + */ +struct iwl_mvm_sta_disable_tx_cmd { + __le32 sta_id; + __le32 disable; +} __packed; /* STA_DISABLE_TX_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index ec6346c6c8e4..0e9b5381e265 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -7,7 +7,7 @@ iwlmvm-y += power.o coex.o iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-y += ftm-responder.o ftm-initiator.o iwlmvm-y += rfi.o -iwlmvm-y += mld-key.o mld-mac.o link.o +iwlmvm-y += mld-key.o mld-mac.o link.o mld-sta.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c new file mode 100644 index 000000000000..cef4fc441afe --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2022 Intel Corporation + */ +#include "mvm.h" + +static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, + struct iwl_mvm_sta_cfg_cmd *cmd) +{ + int ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), + 0, sizeof(*cmd), cmd); + if (ret) + IWL_ERR(mvm, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); + return ret; +} + +/* + * Add an internal station to the FW table + */ +static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, + u16 phy_id) +{ + struct iwl_mvm_sta_cfg_cmd cmd; + + lockdep_assert_held(&mvm->mutex); + + memset(&cmd, 0, sizeof(cmd)); + cmd.sta_id = cpu_to_le32((u8)sta->sta_id); + + cmd.link_id = cpu_to_le32(phy_id); + + cmd.station_type = cpu_to_le32(sta->type); + + if (addr) { + memcpy(cmd.peer_mld_address, addr, ETH_ALEN); + memcpy(cmd.peer_link_address, addr, ETH_ALEN); + } + + return iwl_mvm_mld_send_sta_cmd(mvm, &cmd); +} + +/* + * Remove a station from the FW table. Before sending the command to remove + * the station validate that the station is indeed known to the driver (sanity + * only). + */ +static int iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm *mvm, u32 sta_id) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_remove_sta_cmd rm_sta_cmd = { + .sta_id = cpu_to_le32(sta_id), + }; + int ret; + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + + /* Note: internal stations are marked as error values */ + if (!sta) { + IWL_ERR(mvm, "Invalid station id\n"); + return -EINVAL; + } + + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, STA_REMOVE_CMD), + 0, sizeof(rm_sta_cmd), &rm_sta_cmd); + if (ret) { + IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id); + return ret; + } + + return 0; +} + +/* + * Adds an internal sta to the FW table with its queues + */ +static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, int phy_id, + u16 *queue, u8 tid, + unsigned int *_wdg_timeout) +{ + int ret, txq; + unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : + mvm->trans->trans_cfg->base_params->wd_timeout; + + if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) + return -ENOSPC; + + ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, phy_id); + if (ret) + return ret; + + /* + * For 22000 firmware and on we cannot add queue to a station unknown + * to firmware so enable queue here - after the station was added + */ + txq = iwl_mvm_tvqm_enable_txq(mvm, NULL, sta->sta_id, tid, + wdg_timeout); + if (txq < 0) { + iwl_mvm_mld_rm_sta_from_fw(mvm, sta->sta_id); + return txq; + } + *queue = txq; + + return 0; +} + +/* + * Adds a new int sta: allocate it in the driver, add it to the FW table, + * and add its queues. + */ +static int iwl_mvm_mld_add_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *int_sta, u16 *queue, + enum nl80211_iftype iftype, + enum iwl_fw_sta_type sta_type, + int phy_id, const u8 *addr, u8 tid, + unsigned int *wdg_timeout) +{ + int ret; + + lockdep_assert_held(&mvm->mutex); + + /* qmask argument is not used in the new tx api, send a don't care */ + ret = iwl_mvm_allocate_int_sta(mvm, int_sta, 0, iftype, + sta_type); + if (ret) + return ret; + + ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, int_sta, addr, phy_id, + queue, tid, wdg_timeout); + if (ret) { + iwl_mvm_dealloc_int_sta(mvm, int_sta); + return ret; + } + + return 0; +} + +/* Allocate a new station entry for the broadcast station to the given vif, + * and send it to the FW. + * Note that each P2P mac should have its own broadcast station. + */ +int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; + static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + const u8 *baddr = _baddr; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + u16 *queue; + + lockdep_assert_held(&mvm->mutex); + + if (vif->type == NL80211_IFTYPE_ADHOC) + baddr = vif->bss_conf.bssid; + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) { + queue = &mvm->probe_queue; + } else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + queue = &mvm->p2p_dev_queue; + } else { + WARN(1, "Missing required TXQ for adding bcast STA\n"); + return -EINVAL; + } + + return iwl_mvm_mld_add_int_sta(mvm, bsta, queue, + ieee80211_vif_type_p2p(vif), + STATION_TYPE_BCAST_MGMT, + mvmvif->phy_ctxt->id, baddr, + IWL_MAX_TID_COUNT, &wdg_timeout); +} + +/* Allocate a new station entry for the sniffer station to the given vif, + * and send it to the FW. + */ +int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); + + return iwl_mvm_mld_add_int_sta(mvm, &mvm->snif_sta, &mvm->snif_queue, + vif->type, STATION_TYPE_BCAST_MGMT, + mvmvif->phy_ctxt->id, NULL, + IWL_MAX_TID_COUNT, NULL); +} + +static int iwl_mvm_mld_disable_txq(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + u16 *queueptr, u8 tid) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + int queue = *queueptr; + int ret = 0; + + if (mvm->sta_remove_requires_queue_remove) { + u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, + SCD_QUEUE_CONFIG_CMD); + struct iwl_scd_queue_cfg_cmd remove_cmd = { + .operation = cpu_to_le32(IWL_SCD_QUEUE_REMOVE), + .u.remove.tid = cpu_to_le32(tid), + .u.remove.sta_mask = + cpu_to_le32(BIT(mvmsta->sta_id)), + }; + + ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, + sizeof(remove_cmd), + &remove_cmd); + } + + iwl_trans_txq_free(mvm->trans, queue); + *queueptr = IWL_MVM_INVALID_QUEUE; + + return ret; +} + +/* Removes a sta from the FW table, disable its queues, and dealloc it + */ +static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *int_sta, + bool flush, u8 tid, u16 *queuptr) +{ + int ret; + + lockdep_assert_held(&mvm->mutex); + + if (WARN_ON_ONCE(int_sta->sta_id == IWL_MVM_INVALID_STA)) + return -EINVAL; + + if (flush) + iwl_mvm_flush_sta(mvm, int_sta, true); + + iwl_mvm_mld_disable_txq(mvm, NULL, queuptr, tid); + + ret = iwl_mvm_mld_rm_sta_from_fw(mvm, int_sta->sta_id); + if (ret) + IWL_WARN(mvm, "Failed sending remove station\n"); + + iwl_mvm_dealloc_int_sta(mvm, int_sta); + + return ret; +} + +int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 *queueptr; + + lockdep_assert_held(&mvm->mutex); + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + queueptr = &mvm->probe_queue; + break; + case NL80211_IFTYPE_P2P_DEVICE: + queueptr = &mvm->p2p_dev_queue; + break; + default: + WARN(1, "Can't free bcast queue on vif type %d\n", + vif->type); + return -EINVAL; + } + + return iwl_mvm_mld_rm_int_sta(mvm, &mvmvif->bcast_sta, true, + IWL_MAX_TID_COUNT, queueptr); +} + +int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + lockdep_assert_held(&mvm->mutex); + + return iwl_mvm_mld_rm_int_sta(mvm, &mvm->snif_sta, false, + IWL_MAX_TID_COUNT, &mvm->snif_queue); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c3767f62026a..03da4e53de67 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -523,6 +523,10 @@ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(SESSION_PROTECTION_CMD), HCMD_NAME(MAC_CONFIG_CMD), HCMD_NAME(LINK_CONFIG_CMD), + HCMD_NAME(STA_CONFIG_CMD), + HCMD_NAME(AUX_STA_CMD), + HCMD_NAME(STA_REMOVE_CMD), + HCMD_NAME(STA_DISABLE_TX_CMD), HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_START_NOTIF), }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 46af2b422849..313c5416ae5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -783,9 +783,9 @@ static int iwl_mvm_get_queue_size(struct ieee80211_sta *sta) return IWL_DEFAULT_QUEUE_SIZE; } -static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - u8 sta_id, u8 tid, unsigned int timeout) +int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + u8 sta_id, u8 tid, unsigned int timeout) { int queue, size; @@ -2005,7 +2005,7 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, u32 qmask, enum nl80211_iftype iftype, - enum iwl_sta_type type) + u8 type) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || sta->sta_id == IWL_MVM_INVALID_STA) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index f1a4fc3e4038..d11851b47684 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2016 Intel Deutschland GmbH */ @@ -436,7 +436,7 @@ iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta) */ struct iwl_mvm_int_sta { u32 sta_id; - enum iwl_sta_type type; + u8 type; u32 tfd_queue_msk; }; @@ -519,7 +519,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, u32 qmask, enum nl80211_iftype iftype, - enum iwl_sta_type type); + u8 type); void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta); int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -551,4 +551,14 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 mac_id); +/* Queues */ +int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + u8 sta_id, u8 tid, unsigned int timeout); + +/* New MLD STA related APIs */ +int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); #endif /* __sta_h__ */ -- cgit v1.2.3 From 1595ecce1cf32688760281f40b58b7a1d4a69aa9 Mon Sep 17 00:00:00 2001 From: Krishnanand Prabhu Date: Mon, 20 Mar 2023 12:33:02 +0200 Subject: wifi: iwlwifi: mvm: add support for PTP HW clock (PHC) Add support to enable/disable PHC clock. The PHC clock includes support for fetching the cross timestamp i.e. a non-atomic snapshot of the current time from the hardware (WiFi device) clock and system clock (wall-clock) simultaneously. Signed-off-by: Krishnanand Prabhu Signed-off-by: Luca Coelho Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.ae1d64f513b9.Ib3b6ad61c9fa2fc5908f1e0d6f59f4af6eec1a77@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 15 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 + drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 131 ++++++++++++++++++++++++ 5 files changed, 152 insertions(+) create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/ptp.c (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index b82f79ac5378..943e8de9bc98 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -8,6 +8,7 @@ iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-y += ftm-responder.o ftm-initiator.o iwlmvm-y += rfi.o iwlmvm-y += mld-key.o mld-mac.o link.o mld-sta.o mld-mac80211.o +iwlmvm-y += ptp.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index fe7dfdcd531b..4079c0d939c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1669,6 +1669,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); + if (!mvm->ptp_data.ptp_clock) + iwl_mvm_ptp_init(mvm); + if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7cc3526e78ce..4d99e76811a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -16,6 +16,8 @@ #include #endif +#include + #include #include "iwl-op-mode.h" @@ -770,6 +772,15 @@ struct iwl_mvm_dqa_txq_info { enum iwl_mvm_queue_status status; }; +struct ptp_data { + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_clock_info; + /* keeps track of GP2 wrap-around */ + u32 last_gp2; + u32 wrap_counter; + struct delayed_work dwork; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -1080,6 +1091,8 @@ struct iwl_mvm { struct list_head resp_pasn_list; + struct ptp_data ptp_data; + struct { u8 range_resp; } cmd_ver; @@ -2121,6 +2134,8 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, const struct ieee80211_sta *sta, u16 tid); +void iwl_mvm_ptp_init(struct iwl_mvm *mvm); +void iwl_mvm_ptp_remove(struct iwl_mvm *mvm); int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 03da4e53de67..e7def1a0f767 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1435,6 +1435,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->error_recovery_buf); mvm->error_recovery_buf = NULL; + iwl_mvm_ptp_remove(mvm); + iwl_trans_op_mode_leave(mvm->trans); iwl_phy_db_free(mvm->phy_db); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c new file mode 100644 index 000000000000..f786f5efb497 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2021 - 2023 Intel Corporation + */ + +#include "mvm.h" +#include "iwl-debug.h" +#include + +#define IWL_PTP_GP2_WRAP 0x100000000ULL +#define IWL_PTP_WRAP_TIME (3600 * HZ) + +static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) +{ + if (gp2 < mvm->ptp_data.last_gp2) { + mvm->ptp_data.wrap_counter++; + IWL_DEBUG_INFO(mvm, + "PTP: wraparound detected (new counter=%u)\n", + mvm->ptp_data.wrap_counter); + } + + mvm->ptp_data.last_gp2 = gp2; + schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME); +} + +static int +iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, + ptp_data.ptp_clock_info); + /* Raw value read from GP2 register in usec */ + u32 gp2; + /* GP2 value in ns*/ + s64 gp2_ns; + /* System (wall) time */ + ktime_t sys_time; + + memset(xtstamp, 0, sizeof(struct system_device_crosststamp)); + + if (!mvm->ptp_data.ptp_clock) { + IWL_ERR(mvm, "No PHC clock registered\n"); + return -ENODEV; + } + + iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &gp2, NULL, &sys_time); + + iwl_mvm_ptp_update_new_read(mvm, gp2); + + gp2_ns = (gp2 + (mvm->ptp_data.wrap_counter * IWL_PTP_GP2_WRAP)) * + NSEC_PER_USEC; + + IWL_INFO(mvm, "Got Sync Time: GP2:%u, last_GP2: %u, GP2_ns: %lld, sys_time: %lld\n", + gp2, mvm->ptp_data.last_gp2, gp2_ns, (s64)sys_time); + + /* System monotonic raw time is not used */ + xtstamp->device = (ktime_t)gp2_ns; + xtstamp->sys_realtime = sys_time; + + return 0; +} + +static void iwl_mvm_ptp_work(struct work_struct *wk) +{ + struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, + ptp_data.dwork.work); + u32 gp2; + + mutex_lock(&mvm->mutex); + gp2 = iwl_mvm_get_systime(mvm); + iwl_mvm_ptp_update_new_read(mvm, gp2); + mutex_unlock(&mvm->mutex); +} + +/* iwl_mvm_ptp_init - initialize PTP for devices which support it. + * @mvm: internal mvm structure, see &struct iwl_mvm. + * + * Performs the required steps for enabling PTP support. + */ +void iwl_mvm_ptp_init(struct iwl_mvm *mvm) +{ + /* Warn if the interface already has a ptp_clock defined */ + if (WARN_ON(mvm->ptp_data.ptp_clock)) + return; + + mvm->ptp_data.ptp_clock_info.owner = THIS_MODULE; + mvm->ptp_data.ptp_clock_info.max_adj = 0x7fffffff; + mvm->ptp_data.ptp_clock_info.getcrosststamp = + iwl_mvm_phc_get_crosstimestamp; + + /* Give a short 'friendly name' to identify the PHC clock */ + snprintf(mvm->ptp_data.ptp_clock_info.name, + sizeof(mvm->ptp_data.ptp_clock_info.name), + "%s", "iwlwifi-PTP"); + + INIT_DELAYED_WORK(&mvm->ptp_data.dwork, iwl_mvm_ptp_work); + + mvm->ptp_data.ptp_clock = + ptp_clock_register(&mvm->ptp_data.ptp_clock_info, mvm->dev); + + if (IS_ERR(mvm->ptp_data.ptp_clock)) { + IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n", + PTR_ERR(mvm->ptp_data.ptp_clock)); + mvm->ptp_data.ptp_clock = NULL; + } else if (mvm->ptp_data.ptp_clock) { + IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); + } +} + +/* iwl_mvm_ptp_remove - disable PTP device. + * @mvm: internal mvm structure, see &struct iwl_mvm. + * + * Disable PTP support. + */ +void iwl_mvm_ptp_remove(struct iwl_mvm *mvm) +{ + if (mvm->ptp_data.ptp_clock) { + IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); + + ptp_clock_unregister(mvm->ptp_data.ptp_clock); + mvm->ptp_data.ptp_clock = NULL; + memset(&mvm->ptp_data.ptp_clock_info, 0, + sizeof(mvm->ptp_data.ptp_clock_info)); + mvm->ptp_data.last_gp2 = 0; + cancel_delayed_work_sync(&mvm->ptp_data.dwork); + } +} -- cgit v1.2.3 From c7eca79def44f1faf024d8442044287bef749818 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 20 Mar 2023 12:33:04 +0200 Subject: wifi: iwlwifi: mvm: report hardware timestamps in RX/TX status For TM/FTM frames, report the hardware timestamps reported by the fw as part of the RX/TX status. Since the fw reports the timestamps in a dedicated notification (and not as part of the RX/TX status), hold the frame until the fw timestamps notification is received. Timestamping is enabled when a station is connected and disabled when disconnected. For AP interface, only the first station will have timestamping enabled since the fw only supports timestamping for one peer. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.e0392d498101.I9bf12c8ecfb3f17253a13dc48a48647ddd6e7855@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/commands.h | 18 +++ .../net/wireless/intel/iwlwifi/fw/api/datapath.h | 135 ++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 14 ++ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 7 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 8 + drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c | 174 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h | 30 ++++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 +- 11 files changed, 396 insertions(+), 4 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 28c87a480246..111d96cbde6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -265,6 +265,24 @@ enum iwl_legacy_cmds { */ HOT_SPOT_CMD = 0x53, + /** + * @WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION: Time Sync + * measurement notification for TM/FTM. Sent on receipt of + * respective WNM action frame for TM protocol or public action + * frame for FTM protocol from peer device along with additional + * meta data specified in &struct iwl_time_msmt_notify + */ + WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION = 0x67, + + /** + * @WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION: Time Sync + * measurement confirmation notification for TM/FTM. Sent on + * receipt of Ack from peer for previously Tx'ed TM/FTM + * action frame along with additional meta data specified in + * &struct iwl_time_msmt_cfm_notify + */ + WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION = 0x68, + /** * @SCAN_OFFLOAD_COMPLETE: * notification, &struct iwl_periodic_scan_complete diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 59db52f32e43..6f59381b9f9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -31,6 +31,12 @@ enum iwl_data_path_subcmd_ids { */ WNM_PLATFORM_PTM_REQUEST_CMD = 0x3, + /** + * @WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD: + * &struct iwl_time_sync_cfg_cmd + */ + WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD = 0x4, + /** * @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd */ @@ -151,6 +157,25 @@ enum iwl_channel_estimation_flags { IWL_CHANNEL_ESTIMATION_COUNTER = BIT(2), }; +enum iwl_time_sync_protocol_type { + IWL_TIME_SYNC_PROTOCOL_TM = BIT(0), + IWL_TIME_SYNC_PROTOCOL_FTM = BIT(1), +}; /* WNM_TIMING_ENABLED_PROTOCOL_API_E_VER_1 */ + +/** + * struct iwl_time_sync_cfg_cmd - TM/FTM time sync measurement configuration + * + * @protocols: The type of frames to raise notifications for. A bitmap + * of @iwl_time_sync_protocol_type + * @peer_addr: peer address with which TM/FTM measurements are required + * @reserved: for alignment + */ +struct iwl_time_sync_cfg_cmd { + __le32 protocols; + u8 peer_addr[ETH_ALEN]; + u8 reserved[2]; +} __packed; /* WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD_API_S_VER_1 */ + /** * enum iwl_synced_time_operation - PTM request options * @@ -193,6 +218,116 @@ struct iwl_synced_time_rsp { __le32 gp2_timestamp_lo; } __packed; /* WNM_80211V_TIMING_RSP_API_S_VER_1 */ +/* PTP_CTX_MAX_DATA_SIZE_IN_API_D_VER_1 */ +#define PTP_CTX_MAX_DATA_SIZE 128 + +/** + * struct iwl_time_msmt_ptp_ctx - Vendor specific information element + * to allow a space for flexibility for the userspace App + * + * @element_id: element id of vendor specific ie + * @length: length of vendor specific ie + * @reserved: for alignment + * @data: vendor specific data blob + */ +struct iwl_time_msmt_ptp_ctx { + /* Differentiate between FTM and TM specific Vendor IEs */ + union { + struct { + u8 element_id; + u8 length; + __le16 reserved; + u8 data[PTP_CTX_MAX_DATA_SIZE]; + } ftm; /* FTM specific vendor IE */ + struct { + u8 element_id; + u8 length; + u8 data[PTP_CTX_MAX_DATA_SIZE]; + } tm; /* TM specific vendor IE */ + }; +} __packed /* PTP_CTX_VER_1 */; + +/** + * struct iwl_time_msmt_notify - Time Sync measurement notification + * for TM/FTM, along with additional meta data. + * + * @peer_addr: peer address + * @reserved: for alignment + * @dialog_token: measurement flow dialog token number + * @followup_dialog_token: Measurement flow previous dialog token number + * @t1_hi: high dword of t1-time of the Tx'ed action frame departure on + * sender side in units of 10 nano seconds + * @t1_lo: low dword of t1-time of the Tx'ed action frame departure on + * sender side in units of 10 nano seconds + * @t1_max_err: maximum t1-time error in units of 10 nano seconds + * @t4_hi: high dword of t4-time of the Rx'ed action frame's Ack arrival on + * sender side in units of 10 nano seconds + * @t4_lo: low dword of t4-time of the Rx'ed action frame's Ack arrival on + * sender side in units of 10 nano seconds + * @t4_max_err: maximum t4-time error in units of 10 nano seconds + * @t2_hi: high dword of t2-time of the Rx'ed action frame arrival on + * receiver side in units of 10 nano seconds + * @t2_lo: low dword of t2-time of the Rx'ed action frame arrival on + * receiver side in units of 10 nano seconds + * @t2_max_err: maximum t2-time error in units of 10 nano seconds + * @t3_hi: high dword of t3-time of the Tx'ed action frame's Ack departure on + * receiver side in units of 10 nano seconds + * @t3_lo: low dword of t3-time of the Tx'ed action frame's Ack departure on + * receiver side in units of 10 nano seconds + * @t3_max_err: maximum t3-time error in units of 10 nano seconds + * @ptp: vendor specific information element + */ +struct iwl_time_msmt_notify { + u8 peer_addr[ETH_ALEN]; + u8 reserved[2]; + __le32 dialog_token; + __le32 followup_dialog_token; + __le32 t1_hi; + __le32 t1_lo; + __le32 t1_max_err; + __le32 t4_hi; + __le32 t4_lo; + __le32 t4_max_err; + __le32 t2_hi; + __le32 t2_lo; + __le32 t2_max_err; + __le32 t3_hi; + __le32 t3_lo; + __le32 t3_max_err; + struct iwl_time_msmt_ptp_ctx ptp; +} __packed; /* WNM_80211V_TIMING_MEASUREMENT_NTFY_API_S_VER_1 */ + +/** + * struct iwl_time_msmt_cfm_notify - Time Sync measurement confirmation + * notification for TM/FTM. Sent on receipt of 802.11 Ack from peer for the + * Tx'ed TM/FTM measurement action frame. + * + * @peer_addr: peer address + * @reserved: for alignment + * @dialog_token: measurement flow dialog token number + * @t1_hi: high dword of t1-time of the Tx'ed action frame departure on + * sender side in units of 10 nano seconds + * @t1_lo: low dword of t1-time of the Tx'ed action frame departure on + * sender side in units of 10 nano seconds + * @t1_max_err: maximum t1-time error in units of 10 nano seconds + * @t4_hi: high dword of t4-time of the Rx'ed action frame's Ack arrival on + * sender side in units of 10 nano seconds + * @t4_lo: low dword of t4-time of the Rx'ed action frame's Ack arrival on + * sender side in units of 10 nano seconds + * @t4_max_err: maximum t4-time error in units of 10 nano seconds + */ +struct iwl_time_msmt_cfm_notify { + u8 peer_addr[ETH_ALEN]; + u8 reserved[2]; + __le32 dialog_token; + __le32 t1_hi; + __le32 t1_lo; + __le32 t1_max_err; + __le32 t4_hi; + __le32 t4_lo; + __le32 t4_max_err; +} __packed; /* WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NTFY_API_S_VER_1 */ + /** * struct iwl_channel_estimation_cfg - channel estimation reporting config */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index e4b2f1a87575..1c47046e8f69 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -456,6 +456,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104, IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT = (__force iwl_ucode_tlv_capa_t)105, IWL_UCODE_TLV_CAPA_SYNCED_TIME = (__force iwl_ucode_tlv_capa_t)106, + IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM = (__force iwl_ucode_tlv_capa_t)108, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 943e8de9bc98..593fe28d89cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -9,6 +9,7 @@ iwlmvm-y += ftm-responder.o ftm-initiator.o iwlmvm-y += rfi.o iwlmvm-y += mld-key.o mld-mac.o link.o mld-sta.o mld-mac80211.o iwlmvm-y += ptp.o +iwlmvm-y += time-sync.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 4d99e76811a3..b6b73164357d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -781,6 +781,12 @@ struct ptp_data { struct delayed_work dwork; }; +struct iwl_time_sync_data { + struct sk_buff_head frame_list; + u8 peer_addr[ETH_ALEN]; + bool active; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -1126,6 +1132,8 @@ struct iwl_mvm { bool sta_remove_requires_queue_remove; bool pldr_sync; + + struct iwl_time_sync_data time_sync; }; /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index e7def1a0f767..70926bb1df6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -29,6 +29,7 @@ #include "fw-api.h" #include "fw/acpi.h" #include "fw/uefi.h" +#include "time-sync.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -404,6 +405,15 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(SYSTEM_GROUP, RFI_DEACTIVATE_NOTIF, iwl_rfi_deactivate_notif_handler, RX_HANDLER_ASYNC_UNLOCKED, struct iwl_rfi_deactivate_notif), + + RX_HANDLER_GRP(LEGACY_GROUP, + WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION, + iwl_mvm_time_sync_msmt_event, RX_HANDLER_SYNC, + struct iwl_time_msmt_notify), + RX_HANDLER_GRP(LEGACY_GROUP, + WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION, + iwl_mvm_time_sync_msmt_confirm_event, RX_HANDLER_SYNC, + struct iwl_time_msmt_cfm_notify), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -449,6 +459,8 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP), HCMD_NAME(BT_COEX_CI), + HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION), + HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION), HCMD_NAME(PHY_CONFIGURATION_CMD), HCMD_NAME(CALIB_RES_NOTIF_PHY_DB), HCMD_NAME(PHY_DB_CMD), @@ -1338,6 +1350,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, else memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); + iwl_mvm_init_time_sync(&mvm->time_sync); + mvm->debugfs_dir = dbgfs_dir; mvm->mei_registered = !iwl_mei_register(mvm, &mei_ops); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 91556d43735a..6286132f165a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -9,6 +9,7 @@ #include "iwl-trans.h" #include "mvm.h" #include "fw-api.h" +#include "time-sync.h" static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, int queue, struct ieee80211_sta *sta) @@ -2585,9 +2586,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, goto out; } - if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) - iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, - sta); + if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) && + (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2)))) + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta); out: rcu_read_unlock(); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bbcc7459f3a0..1594221abdba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -9,6 +9,7 @@ #include "mvm.h" #include "sta.h" #include "rs.h" +#include "time-sync.h" /* * New version of ADD_STA_sta command added new fields at the end of the @@ -1770,6 +1771,11 @@ update_fw: } } + if (!sta->tdls) + iwl_mvm_time_sync_config(mvm, sta->addr, + IWL_TIME_SYNC_PROTOCOL_TM | + IWL_TIME_SYNC_PROTOCOL_FTM); + rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); return 0; @@ -1984,6 +1990,8 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, spin_lock_bh(&mvm_sta->lock); spin_unlock_bh(&mvm_sta->lock); + iwl_mvm_time_sync_sta_rm(mvm, sta); + ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c new file mode 100644 index 000000000000..b42e58e5ff24 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2022 Intel Corporation + */ + +#include "mvm.h" +#include "time-sync.h" +#include + +void iwl_mvm_init_time_sync(struct iwl_time_sync_data *data) +{ + skb_queue_head_init(&data->frame_list); +} + +static bool iwl_mvm_is_skb_match(struct sk_buff *skb, u8 *addr, u8 dialog_token) +{ + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 skb_dialog_token; + + if (ieee80211_is_timing_measurement(skb)) + skb_dialog_token = mgmt->u.action.u.wnm_timing_msr.dialog_token; + else + skb_dialog_token = mgmt->u.action.u.ftm.dialog_token; + + if ((ether_addr_equal(mgmt->sa, addr) || + ether_addr_equal(mgmt->da, addr)) && + skb_dialog_token == dialog_token) + return true; + + return false; +} + +static struct sk_buff *iwl_mvm_time_sync_find_skb(struct iwl_mvm *mvm, u8 *addr, + u8 dialog_token) +{ + struct sk_buff *skb; + + /* The queue is expected to have only one SKB. If there are other SKBs + * in the queue, they did not get a time sync notification and are + * probably obsolete by now, so drop them. + */ + while ((skb = skb_dequeue(&mvm->time_sync.frame_list))) { + if (iwl_mvm_is_skb_match(skb, addr, dialog_token)) + break; + + kfree_skb(skb); + skb = NULL; + } + + return skb; +} + +static u64 iwl_mvm_get_64_bit(__le32 high, __le32 low) +{ + return ((u64)le32_to_cpu(high) << 32) | le32_to_cpu(low); +} + +void iwl_mvm_time_sync_msmt_event(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_time_msmt_notify *notif = (void *)pkt->data; + struct ieee80211_rx_status *rx_status; + struct skb_shared_hwtstamps *shwt; + u64 ts_10ns; + struct sk_buff *skb = + iwl_mvm_time_sync_find_skb(mvm, notif->peer_addr, + le32_to_cpu(notif->dialog_token)); + + if (!skb) { + IWL_DEBUG_INFO(mvm, "Time sync event but no pending skb\n"); + return; + } + + ts_10ns = iwl_mvm_get_64_bit(notif->t3_hi, notif->t3_lo); + rx_status = IEEE80211_SKB_RXCB(skb); + rx_status->ack_tx_hwtstamp = ktime_set(0, ts_10ns * 10); + + ts_10ns = iwl_mvm_get_64_bit(notif->t2_hi, notif->t2_lo); + shwt = skb_hwtstamps(skb); + shwt->hwtstamp = ktime_set(0, ts_10ns * 10); + + IWL_DEBUG_INFO(mvm, + "Time sync: RX event - report frame t2=%llu t3=%llu\n", + ktime_to_ns(shwt->hwtstamp), + ktime_to_ns(rx_status->ack_tx_hwtstamp)); + ieee80211_rx_napi(mvm->hw, NULL, skb, NULL); +} + +void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_time_msmt_cfm_notify *notif = (void *)pkt->data; + struct ieee80211_tx_status status = {}; + struct skb_shared_hwtstamps *shwt; + u64 ts_10ns; + + status.skb = + iwl_mvm_time_sync_find_skb(mvm, notif->peer_addr, + le32_to_cpu(notif->dialog_token)); + + if (!status.skb) { + IWL_DEBUG_INFO(mvm, "Time sync confirm but no pending skb\n"); + return; + } + + status.info = IEEE80211_SKB_CB(status.skb); + + ts_10ns = iwl_mvm_get_64_bit(notif->t4_hi, notif->t4_lo); + status.ack_hwtstamp = ktime_set(0, ts_10ns * 10); + + ts_10ns = iwl_mvm_get_64_bit(notif->t1_hi, notif->t1_lo); + shwt = skb_hwtstamps(status.skb); + shwt->hwtstamp = ktime_set(0, ts_10ns * 10); + + IWL_DEBUG_INFO(mvm, + "Time sync: TX event - report frame t1=%llu t4=%llu\n", + ktime_to_ns(shwt->hwtstamp), + ktime_to_ns(status.ack_hwtstamp)); + ieee80211_tx_status_ext(mvm->hw, &status); +} + +int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, u8 *addr, u32 protocols) +{ + struct iwl_time_sync_cfg_cmd cmd = {}; + int err; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM)) + return -EINVAL; + + /* The fw only supports one peer. We do allow reconfiguration of the + * same peer for cases of fw reset etc. + */ + if (mvm->time_sync.active && + !ether_addr_equal(addr, mvm->time_sync.peer_addr)) { + IWL_DEBUG_INFO(mvm, "Time sync: reject config for peer: %pM\n", + addr); + return -ENOBUFS; + } + + if (protocols & ~(IWL_TIME_SYNC_PROTOCOL_TM | + IWL_TIME_SYNC_PROTOCOL_FTM)) + return -EINVAL; + + cmd.protocols = cpu_to_le32(protocols); + + ether_addr_copy(cmd.peer_addr, addr); + + err = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(DATA_PATH_GROUP, + WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD), + 0, sizeof(cmd), &cmd); + if (err) { + IWL_ERR(mvm, "Failed to send time sync cfg cmd: %d\n", err); + } else { + mvm->time_sync.active = protocols != 0; + ether_addr_copy(mvm->time_sync.peer_addr, addr); + IWL_DEBUG_INFO(mvm, "Time sync: set peer addr=%pM\n", addr); + } + + return err; +} + +void iwl_mvm_time_sync_sta_rm(struct iwl_mvm *mvm, struct ieee80211_sta *sta) +{ + /* Disable time sync with this station */ + iwl_mvm_time_sync_config(mvm, sta->addr, 0); + + skb_queue_purge(&mvm->time_sync.frame_list); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h new file mode 100644 index 000000000000..c43d1d0b25cb --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2022 Intel Corporation + */ +#ifndef __TIME_SYNC_H__ +#define __TIME_SYNC_H__ + +#include "mvm.h" +#include + +void iwl_mvm_init_time_sync(struct iwl_time_sync_data *data); +void iwl_mvm_time_sync_msmt_event(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, u8 *addr, u32 protocols); +void iwl_mvm_time_sync_sta_rm(struct iwl_mvm *mvm, struct ieee80211_sta *sta); + +static inline +bool iwl_mvm_time_sync_frame(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *addr) +{ + if (ether_addr_equal(mvm->time_sync.peer_addr, addr) && + (ieee80211_is_timing_measurement(skb) || ieee80211_is_ftm(skb))) { + skb_queue_tail(&mvm->time_sync.frame_list, skb); + return true; + } + + return false; +} +#endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a6d69885cd3f..6e2e0791d848 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -14,6 +14,7 @@ #include "iwl-eeprom-parse.h" #include "mvm.h" #include "sta.h" +#include "time-sync.h" static void iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, @@ -1643,7 +1644,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, info->status.status_driver_data[0] = RS_DRV_DATA_PACK(lq_color, tx_resp->reduced_tpc); - ieee80211_tx_status(mvm->hw, skb); + if (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr1))) + ieee80211_tx_status(mvm->hw, skb); } /* This is an aggregation queue or might become one, so we use -- cgit v1.2.3 From 9e2de88d28b235a65db6209e331496f8f2fd203a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 28 Mar 2023 10:58:43 +0300 Subject: wifi: iwlwifi: mvm: add an indication that the new MLD API is used WE can't mix between the new MLD API and the old API. I.e. - we can't send one of the new cmds and then one of the old ones. This will cause a FW assert. So we need an indication what API should be used. We use the new API if: 1. FW supports it 2. We are registered to mac80211 with the new MLD ops Add an indication which will only be true if both conditions are true. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230328104948.5756b0907403.I0adce36d1783cce23d0e080e3c4a8953db33b515@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 72056cccc77e..443f0b80b63e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1155,6 +1155,7 @@ struct iwl_mvm { unsigned long last_reset_or_resume_time_jiffies; bool sta_remove_requires_queue_remove; + bool mld_api_is_used; bool pldr_sync; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 70926bb1df6c..5c8784ddfa66 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1295,6 +1295,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->sta_remove_requires_queue_remove = trans_cfg.queue_alloc_cmd_ver > 0; + /* Until we register with the MLD ops - we don't use the MLD API */ + mvm->mld_api_is_used = false; + /* Configure transport layer */ iwl_trans_configure(mvm->trans, &trans_cfg); -- cgit v1.2.3 From cbce62a315f67e3badfd3f4a7b33e21c90ddc415 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 28 Mar 2023 10:58:50 +0300 Subject: wifi: iwlwifi: mvm: add all missing ops to iwl_mvm_mld_ops Add all the callbacks that are not changing with the new MLD API and register to mac80211 with the new ops. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230328104948.a2f724342522.I5d1d6a8f5f14e6275da56ea704c3c0063fee5226@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 200 ++++++++++----------- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 114 +++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 135 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 +- 4 files changed, 334 insertions(+), 119 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 631d1becc6ab..e922cc45c390 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -258,8 +258,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { }, }; -static int -iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); *tx_ant = iwl_mvm_get_valid_tx_ant(mvm); @@ -703,9 +702,8 @@ static void iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, ieee80211_free_txskb(mvm->hw, skb); } -static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, - struct sk_buff *skb) +void iwl_mvm_mac_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, struct sk_buff *skb) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct ieee80211_sta *sta = control->sta; @@ -801,8 +799,8 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq) rcu_read_unlock(); } -static void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) +void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq); @@ -897,9 +895,9 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } } -static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) +int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -1095,7 +1093,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) return ret; } -static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +int iwl_mvm_mac_start(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -1164,9 +1162,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) mutex_unlock(&mvm->mutex); } -static void -iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, - enum ieee80211_reconfig_type reconfig_type) +void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -1228,7 +1225,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) } } -static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +void iwl_mvm_mac_stop(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -1366,8 +1363,8 @@ out_unlock: return ret; } -static void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -1731,11 +1728,6 @@ out: mutex_unlock(&mvm->mutex); } -static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - return 0; -} - struct iwl_mvm_mc_iter_data { struct iwl_mvm *mvm; int port_id; @@ -1807,8 +1799,8 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) IWL_ERR(mvm, "Failed to synchronize multicast groups update\n"); } -static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) +u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mcast_filter_cmd *cmd; @@ -1844,10 +1836,9 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, return (u64)(unsigned long)cmd; } -static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +void iwl_mvm_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast; @@ -3038,9 +3029,8 @@ iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req) +int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -3056,8 +3046,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, return ret; } -static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3076,7 +3066,7 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static void +void iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int num_frames, @@ -3091,7 +3081,7 @@ iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, tids, more_data, false); } -static void +void iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int num_frames, @@ -3165,10 +3155,8 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, spin_unlock_bh(&mvmsta->lock); } -static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) +void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { __iwl_mvm_mac_sta_notify(hw, cmd, sta); } @@ -3226,9 +3214,9 @@ void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) rcu_read_unlock(); } -static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -3710,7 +3698,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, return ret; } -static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3719,9 +3707,8 @@ static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } -static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) +void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u32 changed) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -3763,9 +3750,9 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, return 0; } -static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_prep_tx_info *info) +void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3774,9 +3761,9 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_prep_tx_info *info) +void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3789,10 +3776,10 @@ static void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_scan_ies *ies) +int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3812,8 +3799,8 @@ out: return ret; } -static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -4069,11 +4056,9 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, return ret; } -static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -4085,11 +4070,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, return ret; } -static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4519,8 +4504,8 @@ out: return ret; } -static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) +int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -4543,8 +4528,8 @@ static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm, iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); } -static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) +void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4553,9 +4538,8 @@ static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - u32 changed) +void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, u32 changed) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; @@ -4963,16 +4947,15 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops); } -static int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw) +int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); return mvm->ibss_manager; } -static int iwl_mvm_set_tim(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - bool set) +int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -5038,9 +5021,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, return -EOPNOTSUPP; } -static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - void *data, int len) +int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void *data, int len) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int err; @@ -5053,9 +5036,8 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, } #endif -static void iwl_mvm_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { /* By implementing this operation, we prevent mac80211 from * starting its own channel switch timer, so that we can call @@ -5130,9 +5112,9 @@ static int iwl_mvm_old_pre_chan_sw_sta(struct iwl_mvm *mvm, } #define IWL_MAX_CSA_BLOCK_TX 1500 -static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +int iwl_mvm_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); struct ieee80211_vif *csa_vif; @@ -5245,9 +5227,9 @@ out_unlock: return ret; } -static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5332,8 +5314,8 @@ static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) mutex_unlock(&mvm->mutex); } -static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u32 queues, bool drop) +void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif; @@ -5390,8 +5372,8 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, iwl_trans_wait_tx_queues_empty(mvm->trans, msk); } -static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) +int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -5575,10 +5557,10 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo) } } -static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct station_info *sinfo) +void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5719,9 +5701,9 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm, event->u.ba.ssn); } -static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const struct ieee80211_event *event) +void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct ieee80211_event *event) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -5803,7 +5785,7 @@ out: } } -static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) +void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -5812,7 +5794,7 @@ static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) mutex_unlock(&mvm->mutex); } -static int +int iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_ftm_responder_stats *stats) @@ -5841,9 +5823,8 @@ iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw, return 0; } -static int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *request) +int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -5855,9 +5836,8 @@ static int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, return ret; } -static void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *request) +void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request) { 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 818aed050b73..5f54e57de8e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -244,7 +244,8 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, } static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -319,8 +320,22 @@ out_unlock: return ret; } +static int iwl_mvm_mld_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + return iwl_mvm_mld_start_ap_ibss(hw, vif, link_conf); +} + +static int iwl_mvm_mld_start_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return iwl_mvm_mld_start_ap_ibss(hw, vif, &vif->bss_conf); +} + static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -348,6 +363,19 @@ static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_mld_stop_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + iwl_mvm_mld_stop_ap_ibss(hw, vif, link_conf); +} + +static void iwl_mvm_mld_stop_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + iwl_mvm_mld_stop_ap_ibss(hw, vif, &vif->bss_conf); +} + static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -630,18 +658,90 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops); } const struct ieee80211_ops iwl_mvm_mld_hw_ops = { + .tx = iwl_mvm_mac_tx, + .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, + .ampdu_action = iwl_mvm_mac_ampdu_action, + .get_antenna = iwl_mvm_op_get_antenna, + .start = iwl_mvm_mac_start, + .reconfig_complete = iwl_mvm_mac_reconfig_complete, + .stop = iwl_mvm_mac_stop, .add_interface = iwl_mvm_mld_mac_add_interface, .remove_interface = iwl_mvm_mld_mac_remove_interface, + .config = iwl_mvm_mac_config, + .prepare_multicast = iwl_mvm_prepare_multicast, + .configure_filter = iwl_mvm_configure_filter, .config_iface_filter = iwl_mvm_mld_config_iface_filter, + .bss_info_changed = iwl_mvm_mld_bss_info_changed, + .hw_scan = iwl_mvm_mac_hw_scan, + .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, + .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove, + .sta_state = iwl_mvm_mld_mac_sta_state, + .sta_notify = iwl_mvm_mac_sta_notify, + .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, + .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, + .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, + .sta_rc_update = iwl_mvm_sta_rc_update, + .conf_tx = iwl_mvm_mld_mac_conf_tx, + .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, + .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, + .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, + .flush = iwl_mvm_mac_flush, + .sched_scan_start = iwl_mvm_mac_sched_scan_start, + .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, + .set_key = iwl_mvm_mac_set_key, + .update_tkip_key = iwl_mvm_mac_update_tkip_key, .remain_on_channel = iwl_mvm_mld_roc, .cancel_remain_on_channel = iwl_mvm_cancel_roc, + .add_chanctx = iwl_mvm_add_chanctx, + .remove_chanctx = iwl_mvm_remove_chanctx, + .change_chanctx = iwl_mvm_change_chanctx, .assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx, .unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx, .switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx, - .join_ibss = iwl_mvm_mld_start_ap_ibss, - .leave_ibss = iwl_mvm_mld_stop_ap_ibss, + + .start_ap = iwl_mvm_mld_start_ap, + .stop_ap = iwl_mvm_mld_stop_ap, + .join_ibss = iwl_mvm_mld_start_ibss, + .leave_ibss = iwl_mvm_mld_stop_ibss, + + .tx_last_beacon = iwl_mvm_tx_last_beacon, + + .set_tim = iwl_mvm_set_tim, + + .channel_switch = iwl_mvm_channel_switch, + .pre_channel_switch = iwl_mvm_pre_channel_switch, .post_channel_switch = iwl_mvm_post_channel_switch, - .sta_state = iwl_mvm_mld_mac_sta_state, - .conf_tx = iwl_mvm_mld_mac_conf_tx, - .bss_info_changed = iwl_mvm_mld_bss_info_changed, + .abort_channel_switch = iwl_mvm_abort_channel_switch, + .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon, + + .tdls_channel_switch = iwl_mvm_tdls_channel_switch, + .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, + .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch, + + .event_callback = iwl_mvm_mac_event_callback, + + .sync_rx_queues = iwl_mvm_sync_rx_queues, + + CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) + +#ifdef CONFIG_PM_SLEEP + /* look at d3.c */ + .suspend = iwl_mvm_suspend, + .resume = iwl_mvm_resume, + .set_wakeup = iwl_mvm_set_wakeup, + .set_rekey_data = iwl_mvm_set_rekey_data, +#if IS_ENABLED(CONFIG_IPV6) + .ipv6_addr_change = iwl_mvm_ipv6_addr_change, +#endif + .set_default_unicast_key = iwl_mvm_set_default_unicast_key, +#endif + .get_survey = iwl_mvm_mac_get_survey, + .sta_statistics = iwl_mvm_mac_sta_statistics, + .get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats, + .start_pmsr = iwl_mvm_start_pmsr, + .abort_pmsr = iwl_mvm_abort_pmsr, + +#ifdef CONFIG_IWLWIFI_DEBUGFS + .sta_add_debugfs = iwl_mvm_sta_add_debugfs, +#endif }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bf1de6405cd6..6f4ed5d1efb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1384,6 +1384,28 @@ static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT); } +static inline bool iwl_mvm_has_mld_api(const struct iwl_fw *fw) +{ + return (iwl_fw_lookup_cmd_ver(fw, LINK_CONFIG_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN) && + (iwl_fw_lookup_cmd_ver(fw, MAC_CONFIG_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN) && + (iwl_fw_lookup_cmd_ver(fw, STA_CONFIG_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN) && + (iwl_fw_lookup_cmd_ver(fw, AUX_STA_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN) && + (iwl_fw_lookup_cmd_ver(fw, STA_REMOVE_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN) && + (iwl_fw_lookup_cmd_ver(fw, STA_DISABLE_TX_CMD, + IWL_FW_CMD_VER_UNKNOWN) != + IWL_FW_CMD_VER_UNKNOWN); +} + static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm) { /* TODO - replace with TLV once defined */ @@ -2462,4 +2484,117 @@ void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool forbidden); bool iwl_mvm_is_vendor_in_approved_list(void); + +/* Callbacks for ieee80211_ops */ +void iwl_mvm_mac_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, struct sk_buff *skb); +void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq); + +int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params); +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); +int iwl_mvm_mac_start(struct ieee80211_hw *hw); +void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type); +void iwl_mvm_mac_stop(struct ieee80211_hw *hw); +static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) +{ + return 0; +} + +u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list); + +void iwl_mvm_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast); +int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req); +void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta); +void +iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tids, + int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data); +void +iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tids, + int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data); +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u32 changed); +void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info); +void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info); +void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); +int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies); +int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); +int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); +void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); +void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, u32 changed); +int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw); +int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set); +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 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); +void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw); +void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct ieee80211_event *event); +void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw); +int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void *data, int len); +int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); +void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo); +int +iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_ftm_responder_stats *stats); +int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request); +void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request); #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 5c8784ddfa66..b355b9ebad0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1116,6 +1116,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ********************************/ hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) + sizeof(struct iwl_mvm), + iwl_mvm_has_mld_api(fw) ? &iwl_mvm_mld_hw_ops : &iwl_mvm_hw_ops); if (!hw) return NULL; @@ -1295,8 +1296,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->sta_remove_requires_queue_remove = trans_cfg.queue_alloc_cmd_ver > 0; - /* Until we register with the MLD ops - we don't use the MLD API */ - mvm->mld_api_is_used = false; + mvm->mld_api_is_used = iwl_mvm_has_mld_api(mvm->fw); /* Configure transport layer */ iwl_trans_configure(mvm->trans, &trans_cfg); -- cgit v1.2.3 From 1a3e70391e55d12010073935e383629ab856528a Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 28 Mar 2023 10:59:01 +0300 Subject: wifi: iwlwifi: mvm: adjust SMPS for MLO Configure SMPS per-link. Add link_id parameter to iwl_mvm_update_smps() and refactor iwl_mvm_intf_dual_chain_req() since it has to handle all active links. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230328104949.da6a19db562c.Ic88b02338c8973f2934439ac3ee77c7451bc0054@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 19 ++++++++------ .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 19 ++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 23 +++++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 29 ++++++++++++++++++---- 7 files changed, 73 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ops.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 21ba3c7dd9b4..daaa173aaed6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -291,7 +291,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) { /* ... relax constraints and disable rssi events */ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); + smps_mode, 0); iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id, false); @@ -325,7 +325,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); + smps_mode, 0); /* low latency is always primary */ if (iwl_mvm_vif_low_latency(mvmvif)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4dbc9a57746b..ef3eb57b806a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2481,17 +2481,19 @@ void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm, mvmvif->bf_data.ave_beacon_signal = 0; iwl_mvm_bt_coex_vif_change(mvm); - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, - IEEE80211_SMPS_AUTOMATIC); + iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_TT, + IEEE80211_SMPS_AUTOMATIC); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) iwl_mvm_config_scan(mvm); } /* Execute the common part for MLD and non-MLD modes */ -void iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u64 changes) +void +iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + u64 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -2529,7 +2531,7 @@ void iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, } if (changes & BSS_CHANGED_BANDWIDTH) - iwl_mvm_apply_fw_smps_request(vif); + iwl_mvm_update_link_smps(vif, link_conf); } static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, @@ -2641,7 +2643,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (vif->p2p) { iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_PROT, - IEEE80211_SMPS_DYNAMIC); + IEEE80211_SMPS_DYNAMIC, 0); } } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { iwl_mvm_mei_host_disassociated(mvm); @@ -2697,7 +2699,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes); } - iwl_mvm_bss_info_changed_station_common(mvm, vif, changes); + iwl_mvm_bss_info_changed_station_common(mvm, vif, &vif->bss_conf, + changes); } bool iwl_mvm_start_ap_ibss_common(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 15beed41b305..80f1a1ccf16d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -516,7 +516,7 @@ iwl_mvm_mld_bss_info_changed_station(struct iwl_mvm *mvm, if (vif->p2p) { iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_PROT, - IEEE80211_SMPS_DYNAMIC); + IEEE80211_SMPS_DYNAMIC, 0); } } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { iwl_mvm_mei_host_disassociated(mvm); @@ -557,7 +557,7 @@ iwl_mvm_mld_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes); } - iwl_mvm_bss_info_changed_station_common(mvm, vif, changes); + iwl_mvm_bss_info_changed_station_common(mvm, vif, &vif->bss_conf, changes); } static void diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9b04ae9c41ff..d62341269744 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1841,9 +1841,11 @@ iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, struct iwl_mvm_bss_info_changed_ops *callbacks, u64 changes); -void iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u64 changes); +void +iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + u64 changes); void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u64 changes); @@ -2057,10 +2059,17 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, /* SMPS */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, - enum ieee80211_smps_mode smps_request); + enum ieee80211_smps_mode smps_request, + unsigned int link_id); +void +iwl_mvm_update_smps_on_active_links(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + enum iwl_mvm_smps_type_request req_type, + enum ieee80211_smps_mode smps_request); bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); -void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif); +void iwl_mvm_update_link_smps(struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); /* Low latency */ int iwl_mvm_update_low_latency(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 b355b9ebad0a..4a679ac132c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -209,24 +209,37 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, ieee80211_disconnect(vif, true); } -void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) +void iwl_mvm_update_link_smps(struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; enum ieee80211_smps_mode mode = IEEE80211_SMPS_AUTOMATIC; + if (!link_conf) + return; + if (mvm->fw_static_smps_request && - vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_160 && - vif->bss_conf.he_support) + link_conf->chandef.width == NL80211_CHAN_WIDTH_160 && + link_conf->he_support) mode = IEEE80211_SMPS_STATIC; - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode); + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode, + link_conf->link_id); } static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, struct ieee80211_vif *vif) { - iwl_mvm_apply_fw_smps_request(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + + rcu_read_lock(); + + for_each_vif_active_link(vif, link_conf, link_id) + iwl_mvm_update_link_smps(vif, link_conf); + + rcu_read_unlock(); } static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 232c200af38f..4d0e161a92e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2019-2021 Intel Corporation + * Copyright (C) 2012-2014, 2019-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2016 Intel Deutschland GmbH */ @@ -334,7 +334,7 @@ static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac, if (vif->type != NL80211_IFTYPE_STATION) return; - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode); + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode, 0); } static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 026856c8f5f2..cf72b9377411 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -272,13 +272,15 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq) * @vif: Pointer to the ieee80211_vif structure * @req_type: The part of the driver who call for a change. * @smps_request: The request to change the SMPS mode. + * @link_id: for MLO link_id, otherwise 0 (deflink) * * Get a requst to change the SMPS mode, * and change it according to all other requests in the driver. */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, - enum ieee80211_smps_mode smps_request) + enum ieee80211_smps_mode smps_request, + unsigned int link_id) { struct iwl_mvm_vif *mvmvif; enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; @@ -294,17 +296,34 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return; mvmvif = iwl_mvm_vif_from_mac80211(vif); - mvmvif->deflink.smps_requests[req_type] = smps_request; + mvmvif->link[link_id]->smps_requests[req_type] = smps_request; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { - if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_STATIC) { + if (mvmvif->link[link_id]->smps_requests[i] == + IEEE80211_SMPS_STATIC) { smps_mode = IEEE80211_SMPS_STATIC; break; } - if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_DYNAMIC) + if (mvmvif->link[link_id]->smps_requests[i] == + IEEE80211_SMPS_DYNAMIC) smps_mode = IEEE80211_SMPS_DYNAMIC; } - ieee80211_request_smps(vif, 0, smps_mode); + ieee80211_request_smps(vif, link_id, smps_mode); +} + +void iwl_mvm_update_smps_on_active_links(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + enum iwl_mvm_smps_type_request req_type, + enum ieee80211_smps_mode smps_request) +{ + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + + rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) + iwl_mvm_update_smps(mvm, vif, req_type, smps_request, + link_id); + rcu_read_unlock(); } static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait, -- cgit v1.2.3