/* If the association supports HE, HT/VHT rates will never be used for * Tx and therefor there's no need to set the * sgi-per-channel-width-support bits
*/ if (he_cap->has_he) return 0;
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ); if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ); if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ); if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
sgi_chwidths |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ);
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp); /* Check if VHT extended NSS indicates that the bandwidth/NSS * configuration is supported - only for MCS 0 since we already * decoded the MCS bits anyway ourselves.
*/ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160 &&
ieee80211_get_vht_max_nss(&ieee_vht_cap,
IEEE80211_VHT_CHANWIDTH_160MHZ,
0, true, nss) >= nss)
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80];
}
}
static u16 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs)
{ switch (mcs) { case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(IWL_TLC_MNG_HT_RATE_MCS7 + 1) - 1; case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(IWL_TLC_MNG_HT_RATE_MCS9 + 1) - 1; case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(IWL_TLC_MNG_HT_RATE_MCS11 + 1) - 1; case IEEE80211_HE_MCS_NOT_SUPPORTED: return 0;
}
/* If one side doesn't support - mark both as not supporting */ if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
_tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
_tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED;
} if (_mcs_80 > _tx_mcs_80)
_mcs_80 = _tx_mcs_80;
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] =
cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80));
/* If one side doesn't support - mark both as not supporting */ if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED ||
_tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) {
_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
_tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED;
} if (_mcs_160 > _tx_mcs_160)
_mcs_160 = _tx_mcs_160;
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] =
cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160));
}
}
static u8 iwl_mld_get_eht_max_nss(u8 rx_nss, u8 tx_nss)
{
u8 tx = u8_get_bits(tx_nss, IEEE80211_EHT_MCS_NSS_TX);
u8 rx = u8_get_bits(rx_nss, IEEE80211_EHT_MCS_NSS_RX); /* the max nss that can be used, * is the min with our tx capa and the peer rx capa.
*/ return min(tx, rx);
}
/* the station support only a single receive chain */ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC ||
link_sta->rx_nss < 2)
memset(cmd->ht_rates[IWL_TLC_NSS_2], 0, sizeof(cmd->ht_rates[IWL_TLC_NSS_2]));
}
/* the station support only a single receive chain */ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
0; else
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
cpu_to_le16(ht_cap->mcs.rx_mask[1]);
}
}
staticvoid iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, enum nl80211_band band)
{ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; conststruct ieee80211_sta_he_cap *own_he_cap =
ieee80211_get_he_iftype_cap_vif(sband, vif); conststruct ieee80211_sta_eht_cap *own_eht_cap =
ieee80211_get_eht_iftype_cap_vif(sband, vif); struct iwl_tlc_config_cmd_v4 cmd = { /* For AP mode, use 20 MHz until the STA is authorized */
.max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ?
iwl_mld_fw_bw_from_sta_bw(link_sta) :
IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = iwl_mld_get_tlc_cmd_flags(mld, vif, link_sta,
own_he_cap, own_eht_cap),
.chains = iwl_mld_get_fw_chains(mld),
.sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta),
.max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len),
}; int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); int ret;
/* Send async since this can be called within a RCU-read section */
ret = iwl_mld_send_cmd_with_flags_pdu(mld, WIDE_ID(DATA_PATH_GROUP,
TLC_MNG_CONFIG_CMD),
CMD_ASYNC, &cmd); if (ret)
IWL_ERR(mld, "Failed to send TLC cmd (%d)\n", ret);
}
if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan)) return;
/* Before we have information about a station, configure the A-MSDU RC * limit such that iwlmd and mac80211 would not be allowed to build * A-MSDUs.
*/ if (mld_sta->sta_state < IEEE80211_STA_ASSOC) {
link_sta->agg.max_rc_amsdu_len = 1;
ieee80211_sta_recalc_aggregates(link_sta->sta);
}
band = link_conf->chanreq.oper.chan->band;
iwl_mld_send_tlc_cmd(mld, vif, link_sta, band);
}
/* Don't send an AMSDU that will be longer than the TXF. * Add a security margin of 256 for the TX command + headers. * We also want to have the start of the next packet inside the * fifo to be able to send bursts.
*/
if (WARN_ON(tid >= ARRAY_SIZE(tid_to_mac80211_ac))) return 0;
ac = tid_to_mac80211_ac[tid];
/* For HE redirect to trigger based fifos */ if (link_sta->he_cap.has_he)
ac += 4;
txf = iwl_mld_mac80211_ac_to_fw_tx_fifo(ac);
/* Only one link: take the lmac according to the band */ if (hweight16(sta->valid_links) <= 1) { enum nl80211_band band; struct ieee80211_bss_conf *link =
wiphy_dereference(mld->wiphy,
vif->link_conf[link_sta->link_id]);
if (WARN_ON(!link || !link->chanreq.oper.chan))
band = NL80211_BAND_2GHZ; else
band = link->chanreq.oper.chan->band;
lmac = iwl_mld_get_lmac_id(mld, band);
/* More than one link but with 2 lmacs: take the minimum */
} elseif (fw_has_capa(&mld->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
lmac = IWL_LMAC_5G_INDEX;
result = min_t(unsignedint, result,
mld->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
lmac = IWL_LMAC_24G_INDEX; /* More than one link but only one lmac */
} else {
lmac = IWL_LMAC_24G_INDEX;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.