Commit eae94cf8 authored by Luca Coelho's avatar Luca Coelho

iwlwifi: mvm: add support for 6GHz

Add support to the 6GHz band (aka. Ultra High Band or UHB).  This
allows us to scan and connect to channels in that band, including all
the relevant features, such as preferred scan channels, colocated
channels etc.
Co-developed-by: default avatarHaim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: default avatarHaim Dreyfuss <haim.dreyfuss@intel.com>
Co-developed-by: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Co-developed-by: default avatarTova Mussai <tova.mussai@intel.com>
Signed-off-by: default avatarTova Mussai <tova.mussai@intel.com>
Co-developed-by: default avatarAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: default avatarAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Co-developed-by: default avatarTali Levi Rovinsky <Tali.Levi-rovinsky@intel.com>
Signed-off-by: default avatarTali Levi Rovinsky <Tali.Levi-rovinsky@intel.com>
Co-developed-by: default avatarAvraham Stern <avraham.stern@intel.com>
Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
Co-developed-by: default avatarAyala Beker <ayala.beker@intel.com>
Signed-off-by: default avatarAyala Beker <ayala.beker@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20201210000657.0fdbfc3d7352.Idb648536faf21716e2ab2c6d6890d3e49f719cd3@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent d43ab298
......@@ -155,7 +155,8 @@ static const struct iwl_base_params iwl_ax210_base_params = {
static const struct iwl_ht_params iwl_22000_ht_params = {
.stbc = true,
.ldpc = true,
.ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ),
.ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) |
BIT(NL80211_BAND_6GHZ),
};
#define IWL_DEVICE_22000_COMMON \
......
......@@ -66,6 +66,7 @@
/* Supported bands */
#define PHY_BAND_5 (0)
#define PHY_BAND_24 (1)
#define PHY_BAND_6 (2)
/* Supported channel width, vary if there is VHT support */
#define PHY_VHT_CHANNEL_MODE20 (0x0)
......
......@@ -530,6 +530,11 @@ enum iwl_channel_flags {
IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = BIT(3),
};
enum iwl_uhb_chan_cfg_flags {
IWL_UHB_CHAN_CFG_FLAG_UNSOLICITED_PROBE_RES = BIT(24),
IWL_UHB_CHAN_CFG_FLAG_PSC_CHAN_NO_LISTEN = BIT(25),
IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE = BIT(26),
};
/**
* struct iwl_scan_dwell
* @active: default dwell time for active scan
......
......@@ -486,6 +486,11 @@ enum iwl_ucode_tlv_capa {
/* set 3 */
IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96,
/*
* @IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT: supports PSC channels
*/
IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98,
NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
/* sparse says it cannot increment the previous enum member */
......
......@@ -100,6 +100,11 @@ struct iwl_nvm_data {
bool vht160_supported;
struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
/*
* iftype data for low (2.4 GHz) and high (5 and 6 GHz) bands,
* we can use the same for 5 and 6 GHz bands because they have
* the same data
*/
struct {
struct ieee80211_sband_iftype_data low[2];
struct ieee80211_sband_iftype_data high[2];
......
......@@ -166,6 +166,7 @@ static const u16 iwl_uhb_nvm_channels[] = {
#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
#define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels)
#define NUM_2GHZ_CHANNELS 14
#define NUM_5GHZ_CHANNELS 37
#define FIRST_2GHZ_HT_MINUS 5
#define LAST_2GHZ_HT_PLUS 9
#define N_HW_ADDR_MASK 0xF
......@@ -389,6 +390,10 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band,
static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx)
{
if (ch_idx >= NUM_2GHZ_CHANNELS + NUM_5GHZ_CHANNELS) {
return NL80211_BAND_6GHZ;
}
if (ch_idx >= NUM_2GHZ_CHANNELS)
return NL80211_BAND_5GHZ;
return NL80211_BAND_2GHZ;
......@@ -480,6 +485,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
else
channel->flags = 0;
/* TODO: Don't put limitations on UHB devices as we still don't
* have NVM for them
*/
if (cfg->uhb_supported)
channel->flags = 0;
iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM,
channel->hw_value, ch_flags);
IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n",
......@@ -743,6 +753,52 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
},
};
static void iwl_init_he_6ghz_capa(struct iwl_trans *trans,
struct iwl_nvm_data *data,
struct ieee80211_supported_band *sband,
u8 tx_chains, u8 rx_chains)
{
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap = {};
struct ieee80211_sband_iftype_data *iftype_data;
u16 he_6ghz_capa = 0;
u32 exp;
int i;
if (sband->band != NL80211_BAND_6GHZ)
return;
/* grab HT/VHT capabilities and calculate HE 6 GHz capabilities */
iwl_init_ht_hw_capab(trans, data, &ht_cap, NL80211_BAND_5GHZ,
tx_chains, rx_chains);
WARN_ON(!ht_cap.ht_supported);
iwl_init_vht_hw_capab(trans, data, &vht_cap, tx_chains, rx_chains);
WARN_ON(!vht_cap.vht_supported);
he_6ghz_capa |=
u16_encode_bits(ht_cap.ampdu_density,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
exp = u32_get_bits(vht_cap.cap,
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
he_6ghz_capa |=
u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
exp = u32_get_bits(vht_cap.cap, IEEE80211_VHT_CAP_MAX_MPDU_MASK);
he_6ghz_capa |=
u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
/* we don't support extended_ht_cap_info anywhere, so no RD_RESPONDER */
if (vht_cap.cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN)
he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS;
if (vht_cap.cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN)
he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
IWL_DEBUG_EEPROM(trans->dev, "he_6ghz_capa=0x%x\n", he_6ghz_capa);
/* we know it's writable - we set it before ourselves */
iftype_data = (void *)sband->iftype_data;
for (i = 0; i < sband->n_iftype_data; i++)
iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa);
}
static void iwl_init_he_hw_capab(struct iwl_trans *trans,
struct iwl_nvm_data *data,
struct ieee80211_supported_band *sband,
......@@ -762,6 +818,7 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
iftype_data = data->iftd.low;
break;
case NL80211_BAND_5GHZ:
case NL80211_BAND_6GHZ:
iftype_data = data->iftd.high;
break;
default:
......@@ -787,6 +844,7 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
}
}
iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains);
}
static void iwl_init_sbands(struct iwl_trans *trans,
......@@ -829,6 +887,19 @@ static void iwl_init_sbands(struct iwl_trans *trans,
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
/* 6GHz band. */
sband = &data->bands[NL80211_BAND_6GHZ];
sband->band = NL80211_BAND_6GHZ;
/* use the same rates as 5GHz band */
sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
sband->n_bitrates = N_RATES_52;
n_used += iwl_init_sband_channels(data, sband, n_channels,
NL80211_BAND_6GHZ);
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
else
sband->n_channels = 0;
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
n_used, n_channels);
......
......@@ -165,5 +165,6 @@
#define IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT 20016
#define IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT 20016
#define IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC 2
#define IWL_MVM_DISABLE_AP_FILS false
#endif /* __MVM_CONSTANTS_H */
......@@ -61,6 +61,7 @@
*****************************************************************************/
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <net/mac80211.h>
#include "iwl-io.h"
#include "iwl-prph.h"
......@@ -980,12 +981,28 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
struct iwl_mac_beacon_cmd beacon_cmd = {};
u8 rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
u16 flags;
struct ieee80211_chanctx_conf *ctx;
int channel;
flags = iwl_mvm_mac80211_idx_to_hwrate(rate);
if (rate == IWL_FIRST_CCK_RATE)
flags |= IWL_MAC_BEACON_CCK;
/* Enable FILS on PSC channels only */
rcu_read_lock();
ctx = rcu_dereference(vif->chanctx_conf);
channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq);
WARN_ON(channel == 0);
if (cfg80211_channel_is_psc(ctx->def.chan) &&
!IWL_MVM_DISABLE_AP_FILS) {
flags |= IWL_MAC_BEACON_FILS;
beacon_cmd.short_ssid =
cpu_to_le32(~crc32_le(~0, vif->bss_conf.ssid,
vif->bss_conf.ssid_len));
}
rcu_read_unlock();
beacon_cmd.flags = cpu_to_le16(flags);
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
......
......@@ -566,6 +566,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;
hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
hw->wiphy->n_iface_combinations =
......@@ -619,6 +620,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap |=
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
}
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT) &&
mvm->nvm_data->bands[NL80211_BAND_6GHZ].n_channels)
hw->wiphy->bands[NL80211_BAND_6GHZ] =
&mvm->nvm_data->bands[NL80211_BAND_6GHZ];
hw->wiphy->hw_version = mvm->trans->hw_id;
......
......@@ -2100,6 +2100,8 @@ static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band)
return PHY_BAND_24;
case NL80211_BAND_5GHZ:
return PHY_BAND_5;
case NL80211_BAND_6GHZ:
return PHY_BAND_6;
default:
WARN_ONCE(1, "Unsupported band (%u)\n", band);
return PHY_BAND_5;
......
......@@ -420,9 +420,21 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
switch (le16_get_bits(sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
return IEEE80211_MAX_MPDU_LEN_VHT_7991;
default:
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
}
} else
if (vht_cap->vht_supported) {
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
......
......@@ -1591,6 +1591,8 @@ static inline u8 iwl_mvm_nl80211_band_from_rx_msdu(u8 phy_band)
return NL80211_BAND_2GHZ;
case PHY_BAND_5:
return NL80211_BAND_5GHZ;
case PHY_BAND_6:
return NL80211_BAND_6GHZ;
default:
WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band);
return NL80211_BAND_5GHZ;
......
......@@ -196,7 +196,16 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
mpdu_dens = sta->ht_cap.ampdu_density;
}
if (mvm_sta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
add_sta_cmd.station_flags_msk |=
cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK |
STA_FLG_AGG_MPDU_DENS_MSK);
mpdu_dens = le16_get_bits(sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
agg_size = le16_get_bits(sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
} else
if (sta->vht_cap.vht_supported) {
agg_size = sta->vht_cap.cap &
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment