mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
wifi: iwlwifi: mld: add TLC support for NAN stations
In order to support NAN, TLC now has a station bitmap. Use this and update TLC for the NAN stations accordingly whenever links (and thus PHYs) change, and whenever else mac80211 might update the rate scale information. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20260511203428.ea4112d28331.Ie11049c12a4765a97f3e6dfd1ea4afb265c93817@changeid Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
This commit is contained in:
parent
2b7a3019b9
commit
bc2f28ead2
|
|
@ -7,6 +7,7 @@
|
|||
#include "iface.h"
|
||||
#include "link.h"
|
||||
#include "mlo.h"
|
||||
#include "tlc.h"
|
||||
#include "fw/api/mac-cfg.h"
|
||||
#include "fw/api/mac.h"
|
||||
#include "fw/api/rs.h"
|
||||
|
|
@ -437,15 +438,26 @@ iwl_mld_nan_link_add(struct iwl_mld *mld,
|
|||
}
|
||||
|
||||
static int iwl_mld_nan_link_set_active(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mld_nan_link *nan_link,
|
||||
bool active)
|
||||
{
|
||||
struct iwl_link_config_cmd cmd;
|
||||
struct ieee80211_sta *sta;
|
||||
int ret;
|
||||
|
||||
if (nan_link->active == active)
|
||||
return 0;
|
||||
|
||||
if (active) {
|
||||
for_each_station(sta, mld->hw) {
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
|
||||
if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI)
|
||||
iwl_mld_config_tlc(mld, mld_sta->vif, sta);
|
||||
}
|
||||
}
|
||||
|
||||
nan_link->active = active;
|
||||
|
||||
iwl_mld_nan_link_prep_cmd(mld, nan_link, &cmd,
|
||||
|
|
@ -457,8 +469,10 @@ static int iwl_mld_nan_link_set_active(struct iwl_mld *mld,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (!active)
|
||||
if (!active) {
|
||||
nan_link->chanctx = NULL;
|
||||
/* TODO: when FW is ready, Update phy in TLC to invalid after */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -590,7 +604,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
|
|||
if (links[i]) {
|
||||
added_links = true;
|
||||
link_used[links[i]->fw_id] = true;
|
||||
iwl_mld_nan_link_set_active(mld, links[i], true);
|
||||
iwl_mld_nan_link_set_active(mld, vif, links[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +644,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
|
|||
/* prepare stations for links we'll remove */
|
||||
for_each_mld_nan_valid_link(mld_vif, nan_link) {
|
||||
if (!link_used[nan_link->fw_id]) {
|
||||
iwl_mld_nan_link_set_active(mld, nan_link, false);
|
||||
iwl_mld_nan_link_set_active(mld, vif, nan_link, false);
|
||||
remove_link_ids |= BIT(nan_link->fw_id);
|
||||
/* mark unused for STA updates */
|
||||
nan_link->fw_id = FW_CTXT_ID_INVALID;
|
||||
|
|
@ -694,6 +708,15 @@ int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
|
|||
.len[1] = sched->ulw_size,
|
||||
.dataflags[1] = IWL_HCMD_DFL_DUP,
|
||||
};
|
||||
struct ieee80211_sta *iter;
|
||||
|
||||
/* Update TLC in case peer channels were added/removed/updated */
|
||||
for_each_station(iter, mld->hw) {
|
||||
struct iwl_mld_sta *tmp = iwl_mld_sta_from_mac80211(iter);
|
||||
|
||||
if (tmp->sta_type == STATION_TYPE_NAN_PEER_NDI)
|
||||
iwl_mld_config_tlc(mld, tmp->vif, iter);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(sched->maps); i++) {
|
||||
if (sched->maps[i].map_id == CFG80211_NAN_INVALID_MAP_ID)
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
|
|||
static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mld_sta *mld_sta,
|
||||
int fw_sta_id, int phy_id,
|
||||
int fw_sta_mask, int phy_id,
|
||||
struct iwl_mld_tlc_sta_capa *capa)
|
||||
{
|
||||
struct iwl_tlc_config_cmd cmd = {
|
||||
|
|
@ -550,10 +550,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
|
|||
u8 cmd_size;
|
||||
int ret;
|
||||
|
||||
if (fw_sta_id < 0)
|
||||
return;
|
||||
|
||||
cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id));
|
||||
cmd.sta_mask = cpu_to_le32(fw_sta_mask);
|
||||
cmd.phy_id = cpu_to_le32(phy_id);
|
||||
|
||||
iwl_mld_fill_supp_rates(mld, vif, capa, &cmd);
|
||||
|
|
@ -617,25 +614,27 @@ int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct ieee80211_link_sta *link_sta)
|
||||
static void _iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_chanctx_conf *chan_ctx,
|
||||
u32 fw_sta_mask,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct iwl_mld_tlc_sta_capa *capa)
|
||||
{
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
|
||||
struct ieee80211_chanctx_conf *chan_ctx;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct iwl_mld_tlc_sta_capa capa = {};
|
||||
unsigned long rates_bitmap;
|
||||
enum nl80211_band band;
|
||||
int fw_sta_id, i;
|
||||
int i;
|
||||
|
||||
if (WARN_ON_ONCE(!mld_link))
|
||||
return;
|
||||
/*
|
||||
* Note: Due to NAN, the chan_ctx here might not be the same as the
|
||||
* vif->links[link_sta->link_id] one (which is NULL in NAN), so some
|
||||
* care is needed in this function (and the 'capa' exists to make it
|
||||
* less error-prone, the other functions need not worry about it.)
|
||||
*/
|
||||
|
||||
chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx);
|
||||
if (WARN_ON_ONCE(!chan_ctx))
|
||||
if (WARN_ON(!chan_ctx))
|
||||
return;
|
||||
|
||||
band = chan_ctx->def.chan->band;
|
||||
|
|
@ -653,25 +652,18 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
|||
/* non HT rates */
|
||||
rates_bitmap = link_sta->supp_rates[sband->band];
|
||||
for_each_set_bit(i, &rates_bitmap, BITS_PER_LONG)
|
||||
capa.non_ht_rates |= BIT(sband->bitrates[i].hw_value);
|
||||
capa->non_ht_rates |= BIT(sband->bitrates[i].hw_value);
|
||||
|
||||
capa.rx_nss = link_sta->rx_nss;
|
||||
capa.smps_mode = link_sta->smps_mode;
|
||||
capa.bandwidth = link_sta->bandwidth;
|
||||
capa.max_amsdu_len = link_sta->agg.max_amsdu_len;
|
||||
capa.ht_cap = &link_sta->ht_cap;
|
||||
capa.vht_cap = &link_sta->vht_cap;
|
||||
capa.he_cap = &link_sta->he_cap;
|
||||
capa.eht_cap = &link_sta->eht_cap;
|
||||
capa.uhr_cap = &link_sta->uhr_cap;
|
||||
capa.own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
|
||||
capa.own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif);
|
||||
capa.own_uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, vif);
|
||||
capa->max_amsdu_len = link_sta->agg.max_amsdu_len;
|
||||
capa->ht_cap = &link_sta->ht_cap;
|
||||
capa->vht_cap = &link_sta->vht_cap;
|
||||
capa->he_cap = &link_sta->he_cap;
|
||||
capa->eht_cap = &link_sta->eht_cap;
|
||||
capa->uhr_cap = &link_sta->uhr_cap;
|
||||
|
||||
fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
|
||||
iwl_mld_send_tlc_cmd(mld, vif, mld_sta, fw_sta_id,
|
||||
iwl_mld_send_tlc_cmd(mld, vif, mld_sta, fw_sta_mask,
|
||||
iwl_mld_phy_from_mac80211(chan_ctx)->fw_id,
|
||||
&capa);
|
||||
capa);
|
||||
}
|
||||
|
||||
void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
|
|
@ -717,6 +709,136 @@ void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
|||
}
|
||||
}
|
||||
|
||||
static void iwl_mld_config_tlc_nan(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
int fw_sta_id)
|
||||
{
|
||||
struct ieee80211_nan_peer_sched *sched;
|
||||
struct iwl_mld_nan_link *nan_link;
|
||||
struct ieee80211_sta *nmi, *iter;
|
||||
struct iwl_mld_vif *nan_mld_vif;
|
||||
u32 fw_sta_mask;
|
||||
|
||||
nmi = wiphy_dereference(mld->wiphy, link_sta->sta->nmi);
|
||||
if (WARN_ON(!nmi))
|
||||
return;
|
||||
|
||||
sched = nmi->nan_sched;
|
||||
|
||||
/* This sta might not be in the list yet as it is just getting added */
|
||||
fw_sta_mask = BIT(fw_sta_id);
|
||||
for_each_station(iter, mld->hw) {
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(iter);
|
||||
struct ieee80211_sta *iter_nmi;
|
||||
|
||||
iter_nmi = wiphy_dereference(mld->wiphy, iter->nmi);
|
||||
|
||||
if (iter_nmi == nmi)
|
||||
fw_sta_mask |= BIT(mld_sta->deflink.fw_id);
|
||||
}
|
||||
|
||||
if (WARN_ON(!mld->nan_device_vif))
|
||||
return;
|
||||
|
||||
nan_mld_vif = iwl_mld_vif_from_mac80211(mld->nan_device_vif);
|
||||
|
||||
for_each_mld_nan_valid_link(nan_mld_vif, nan_link) {
|
||||
struct ieee80211_chanctx_conf *chan_ctx;
|
||||
struct iwl_mld_tlc_sta_capa capa = {};
|
||||
struct cfg80211_chan_def *chandef;
|
||||
bool common_channel = false;
|
||||
|
||||
chan_ctx = nan_link->chanctx;
|
||||
if (!chan_ctx)
|
||||
continue;
|
||||
|
||||
chandef = iwl_mld_get_chandef_from_chanctx(mld, chan_ctx);
|
||||
|
||||
capa.smps_mode = IEEE80211_SMPS_OFF; /* always off */
|
||||
|
||||
capa.rx_nss = 2; /* maximum we support */
|
||||
capa.bandwidth = ieee80211_chan_width_to_rx_bw(chandef->width);
|
||||
|
||||
for (int j = 0; j < (sched ? sched->n_channels : 0); j++) {
|
||||
enum ieee80211_sta_rx_bandwidth rx_bw;
|
||||
enum nl80211_chan_width width;
|
||||
int chains;
|
||||
|
||||
if (sched->channels[j].chanctx_conf != chan_ctx)
|
||||
continue;
|
||||
|
||||
common_channel = true;
|
||||
|
||||
width = sched->channels[j].chanreq.oper.width;
|
||||
rx_bw = ieee80211_chan_width_to_rx_bw(width);
|
||||
capa.bandwidth = min(capa.bandwidth, rx_bw);
|
||||
|
||||
chains = sched->channels[j].needed_rx_chains;
|
||||
capa.rx_nss = min(capa.rx_nss, chains);
|
||||
}
|
||||
|
||||
/* Apply minimum parameters if there is no common channel */
|
||||
if (!common_channel) {
|
||||
capa.bandwidth = IEEE80211_STA_RX_BW_20;
|
||||
capa.rx_nss = 1;
|
||||
}
|
||||
|
||||
capa.own_he_cap = &mld->wiphy->nan_capa.phy.he;
|
||||
/* no EHT/UHR for NAN */
|
||||
|
||||
_iwl_mld_config_tlc_link(mld, vif, chan_ctx, fw_sta_mask,
|
||||
link_sta, &capa);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
|
||||
int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
|
||||
struct ieee80211_chanctx_conf *chan_ctx;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct iwl_mld_tlc_sta_capa capa = {};
|
||||
struct cfg80211_chan_def *chandef;
|
||||
enum nl80211_band band;
|
||||
|
||||
if (fw_sta_id < 0)
|
||||
return;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
return;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_NAN_DATA) {
|
||||
iwl_mld_config_tlc_nan(mld, vif, link_sta, fw_sta_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!mld_link))
|
||||
return;
|
||||
|
||||
chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx);
|
||||
if (WARN_ON_ONCE(!chan_ctx))
|
||||
return;
|
||||
|
||||
chandef = &iwl_mld_phy_from_mac80211(chan_ctx)->chandef;
|
||||
band = chandef->chan->band;
|
||||
sband = mld->hw->wiphy->bands[band];
|
||||
|
||||
capa.smps_mode = link_sta->smps_mode;
|
||||
capa.rx_nss = link_sta->rx_nss;
|
||||
capa.bandwidth = ieee80211_chan_width_to_rx_bw(chandef->width);
|
||||
capa.bandwidth = min(capa.bandwidth, link_sta->bandwidth);
|
||||
capa.own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
|
||||
capa.own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif);
|
||||
capa.own_uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, vif);
|
||||
|
||||
_iwl_mld_config_tlc_link(mld, vif, chan_ctx, BIT(fw_sta_id),
|
||||
link_sta, &capa);
|
||||
}
|
||||
|
||||
void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
|
|
@ -725,6 +847,7 @@ void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
|||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
/* Note: for NAN this is only the mac80211-level deflink */
|
||||
for_each_vif_active_link(vif, link, link_id) {
|
||||
struct ieee80211_link_sta *link_sta =
|
||||
link_sta_dereference_check(sta, link_id);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user