Files
linux/drivers/net/wireless/intel/iwlwifi/mvm/link.c
Johannes Berg cb145863e7 wifi: iwlwifi: mvm: add link to firmware earlier
The firmware now allows adding a link that's not yet bound
to a PHY context. Make use of that to align the driver with
mac80211's API expectations. For now, just add the link at
the same time as the MAC since we don't yet have real MLD
support, but that'll obviously change later. This fixes an
issue with apStaId tracking in the firmware.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230328104949.097e5008b637.I4e75c6c11e21c08d28ff6a066be36629d3975db6@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2023-03-30 12:07:54 +02:00

171 lines
4.9 KiB
C

// 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_mvm_phy_ctxt *phyctxt = mvmvif->deflink.phy_ctxt;
struct iwl_link_config_cmd cmd = {};
/* 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->id);
cmd.mac_id = cpu_to_le32(mvmvif->id);
/* P2P-Device already has a valid PHY context during add */
if (phyctxt)
cmd.phy_id = cpu_to_le32(phyctxt->id);
else
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
memcpy(cmd.local_link_addr, vif->addr, ETH_ALEN);
if (vif->type == NL80211_IFTYPE_ADHOC && vif->bss_conf.bssid)
memcpy(cmd.ibss_bssid_addr, vif->bss_conf.bssid, 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->deflink.phy_ctxt;
struct iwl_link_config_cmd cmd = {};
u32 ht_flag, flags = 0, flags_mask = 0;
cmd.link_id = cpu_to_le32(mvmvif->id);
/* The phy_id, link address and listen_lmac can be modified only until
* the link becomes active, otherwise they will be ignored.
*/
if (phyctxt)
cmd.phy_id = cpu_to_le32(phyctxt->id);
else
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
cmd.mac_id = cpu_to_le32(mvmvif->id);
memcpy(cmd.local_link_addr, vif->addr, ETH_ALEN);
cmd.active = cpu_to_le32(active);
if (vif->type == NL80211_IFTYPE_ADHOC && vif->bss_conf.bssid)
memcpy(cmd.ibss_bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
/* 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);
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);
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->deflink.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;
cmd.link_id = cpu_to_le32(mvmvif->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;
}