Commit 5dca295d authored by Ilan Peer's avatar Ilan Peer Committed by Johannes Berg

mac80211: Add initial support for EHT and 320 MHz channels

Add initial support for EHT and 320 MHz bandwidth in mac80211.

As a new IEEE80211_STA_RX_BW_320 is added to
enum ieee80211_sta_rx_bandwidth, update the drivers to avoid
compilation warnings.
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Link: https://lore.kernel.org/r/20220214173004.0f144cc0bba6.Iad18111264da87eed5fd7b017f0cc6e58c604e07@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f0e6bea8
......@@ -87,6 +87,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_320:
case IEEE80211_STA_RX_BW_160:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ);
fallthrough;
......
......@@ -2195,6 +2195,7 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,
C(40);
C(80);
C(160);
C(320);
#undef C
}
......
......@@ -2005,6 +2005,7 @@ enum ieee80211_sta_state {
* @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz
* @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz
* (including 80+80 MHz)
* @IEEE80211_STA_RX_BW_320: station can receive up to 320 MHz
*
* Implementation note: 20 must be zero to be initialized
* correctly, the values must be sorted.
......@@ -2014,6 +2015,7 @@ enum ieee80211_sta_rx_bandwidth {
IEEE80211_STA_RX_BW_40,
IEEE80211_STA_RX_BW_80,
IEEE80211_STA_RX_BW_160,
IEEE80211_STA_RX_BW_320,
};
/**
......
......@@ -218,6 +218,8 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
* might be smaller than the configured bw (160).
*/
return NL80211_CHAN_WIDTH_160;
case IEEE80211_STA_RX_BW_320:
return NL80211_CHAN_WIDTH_320;
default:
WARN_ON(1);
return NL80211_CHAN_WIDTH_20;
......@@ -417,7 +419,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
{
u32 changed;
/* expected to handle only 20/40/80/160 channel widths */
/* expected to handle only 20/40/80/160/320 channel widths */
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
......@@ -425,6 +427,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
case NL80211_CHAN_WIDTH_320:
break;
default:
WARN_ON(1);
......
......@@ -366,6 +366,8 @@ enum ieee80211_sta_flags {
IEEE80211_STA_DISABLE_WMM = BIT(14),
IEEE80211_STA_ENABLE_RRM = BIT(15),
IEEE80211_STA_DISABLE_HE = BIT(16),
IEEE80211_STA_DISABLE_EHT = BIT(17),
IEEE80211_STA_DISABLE_320MHZ = BIT(18),
};
struct ieee80211_mgd_auth_data {
......@@ -2414,6 +2416,7 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
struct cfg80211_chan_def *chandef);
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Copyright (C) 2018 - 2020 Intel Corporation
* Copyright (C) 2018 - 2021 Intel Corporation
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
* Javier Cardona <javier@cozybit.com>
*/
......@@ -104,7 +104,8 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
ie->vht_operation, ie->ht_operation,
&sta_chan_def);
ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, &sta_chan_def);
ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, NULL,
&sta_chan_def);
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
&sta_chan_def))
......
This diff is collapsed.
......@@ -3086,6 +3086,10 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
else
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
break;
case NL80211_CHAN_WIDTH_320:
/* HT information element should not be included on 6GHz */
WARN_ON(1);
return pos;
default:
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
break;
......@@ -3125,6 +3129,10 @@ void ieee80211_ie_build_wide_bw_cs(u8 *pos,
case NL80211_CHAN_WIDTH_80P80:
*pos++ = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
break;
case NL80211_CHAN_WIDTH_320:
/* The behavior is not defined for 320 MHz channels */
WARN_ON(1);
fallthrough;
default:
*pos++ = IEEE80211_VHT_CHANWIDTH_USE_HT;
}
......@@ -3177,6 +3185,10 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
case NL80211_CHAN_WIDTH_80:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
break;
case NL80211_CHAN_WIDTH_320:
/* VHT information element should not be included on 6GHz */
WARN_ON(1);
return pos;
default:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
break;
......@@ -3237,6 +3249,13 @@ u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef)
he_6ghz_op->ccfs1 = 0;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_320:
/*
* TODO: mesh operation is not defined over 6GHz 320 MHz
* channels.
*/
WARN_ON(1);
break;
case NL80211_CHAN_WIDTH_160:
/* Convert 160 MHz channel width to new style as interop
* workaround.
......@@ -3425,17 +3444,19 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
const struct ieee80211_sta_he_cap *he_cap;
const struct ieee80211_sta_eht_cap *eht_cap;
struct cfg80211_chan_def he_chandef = *chandef;
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
bool support_80_80, support_160;
u8 he_phy_cap;
bool support_80_80, support_160, support_320;
u8 he_phy_cap, eht_phy_cap;
u32 freq;
if (chandef->chan->band != NL80211_BAND_6GHZ)
......@@ -3464,6 +3485,12 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
return false;
}
eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype);
if (!eht_cap) {
sdata_info(sdata, "Missing iftype sband data/EHT cap");
eht_oper = NULL;
}
he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
if (!he_6ghz_oper) {
......@@ -3473,6 +3500,11 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
return false;
}
/*
* The EHT operation IE does not contain the primary channel so the
* primary channel frequency should be taken from the 6 GHz operation
* information.
*/
freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary,
NL80211_BAND_6GHZ);
he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
......@@ -3490,43 +3522,80 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
break;
}
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_20;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_40;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_80;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_80;
if (!he_6ghz_oper->ccfs1)
if (!eht_oper) {
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_20;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_40;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_80;
break;
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_80;
if (!he_6ghz_oper->ccfs1)
break;
if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) {
if (support_160)
he_chandef.width = NL80211_CHAN_WIDTH_160;
} else {
if (support_80_80)
he_chandef.width = NL80211_CHAN_WIDTH_80P80;
}
break;
}
if (he_chandef.width == NL80211_CHAN_WIDTH_160) {
he_chandef.center_freq1 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
NL80211_BAND_6GHZ);
} else {
he_chandef.center_freq1 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0,
NL80211_BAND_6GHZ);
if (support_80_80 || support_160)
he_chandef.center_freq2 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
NL80211_BAND_6GHZ);
}
} else {
eht_phy_cap = eht_cap->eht_cap_elem.phy_cap_info[0];
support_320 =
eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
switch (u8_get_bits(eht_oper->chan_width,
IEEE80211_EHT_OPER_CHAN_WIDTH)) {
case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_20;
break;
case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_40;
break;
case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
he_chandef.width = NL80211_CHAN_WIDTH_80;
break;
if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) {
case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
if (support_160)
he_chandef.width = NL80211_CHAN_WIDTH_160;
} else {
if (support_80_80)
he_chandef.width = NL80211_CHAN_WIDTH_80P80;
else
he_chandef.width = NL80211_CHAN_WIDTH_80;
break;
case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
if (support_320)
he_chandef.width = NL80211_CHAN_WIDTH_320;
else if (support_160)
he_chandef.width = NL80211_CHAN_WIDTH_160;
else
he_chandef.width = NL80211_CHAN_WIDTH_80;
break;
}
break;
}
if (he_chandef.width == NL80211_CHAN_WIDTH_160) {
he_chandef.center_freq1 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
NL80211_BAND_6GHZ);
} else {
he_chandef.center_freq1 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0,
ieee80211_channel_to_frequency(eht_oper->ccfs,
NL80211_BAND_6GHZ);
if (support_80_80 || support_160)
he_chandef.center_freq2 =
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
NL80211_BAND_6GHZ);
}
if (!cfg80211_chandef_valid(&he_chandef)) {
......@@ -3998,6 +4067,15 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
ret = IEEE80211_STA_DISABLE_80P80MHZ |
IEEE80211_STA_DISABLE_160MHZ;
break;
case NL80211_CHAN_WIDTH_320:
/* n_P20 */
tmp = (150 + c->chan->center_freq - c->center_freq1) / 20;
/* n_P160 */
tmp /= 80;
c->center_freq1 = c->center_freq1 - 80 + 160 * tmp;
c->width = NL80211_CHAN_WIDTH_160;
ret = IEEE80211_STA_DISABLE_320MHZ;
break;
default:
case NL80211_CHAN_WIDTH_20_NOHT:
WARN_ON_ONCE(1);
......
......@@ -4,7 +4,7 @@
*
* Portions of this file
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright (C) 2018 - 2020 Intel Corporation
* Copyright (C) 2018 - 2021 Intel Corporation
*/
#include <linux/ieee80211.h>
......@@ -445,6 +445,8 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
case NL80211_CHAN_WIDTH_160:
case NL80211_CHAN_WIDTH_80P80:
return IEEE80211_STA_RX_BW_160;
case NL80211_CHAN_WIDTH_320:
return IEEE80211_STA_RX_BW_320;
default:
WARN_ON_ONCE(1);
return IEEE80211_STA_RX_BW_20;
......
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