Commit 3db24065 authored by Lei Wang's avatar Lei Wang Committed by Kalle Valo

ath10k: enable VHT160 and VHT80+80 modes

Set right channel frequencies in VHT160 mode according to the VHT160
interoperability workaround added as part of IEEE Std 802.11-2016 in
"Table 9-252—VHT Operation Information subfields", band_center_freq2
corresponds to CCFS1 in Table 9-253. Previous implementation
(band_center_freq2 = 0 for VHT160) is only deprecated.

Enable VHT80+80 mode and set the proper peer RX nss value for VHT160 and
VHT80+80 mode.

Based on patches by Sebastian Gottschall:

https://lkml.kernel.org/r/20180704095444.662-1-s.gottschall@dd-wrt.com

https://lkml.kernel.org/r/20180704120519.6479-1-s.gottschall@dd-wrt.com

Tested: qca9984 with firmware ver 10.4-3.10-00047
Co-developed-by: default avatarSebastian Gottschall <s.gottschall@dd-wrt.com>
Signed-off-by: default avatarSebastian Gottschall <s.gottschall@dd-wrt.com>
Co-developed-by: default avatarRick Wu <rwu@codeaurora.org>
Signed-off-by: default avatarRick Wu <rwu@codeaurora.org>
Signed-off-by: default avatarLei Wang <leiwa@codeaurora.org>
Signed-off-by: default avatarSowmiya Sree Elavalagan <ssreeela@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1585574792-719-1-git-send-email-ssreeela@codeaurora.org
parent 800113ff
......@@ -2505,6 +2505,30 @@ ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
return tx_mcs_set;
}
static u32 get_160mhz_nss_from_maxrate(int rate)
{
u32 nss;
switch (rate) {
case 780:
nss = 1;
break;
case 1560:
nss = 2;
break;
case 2106:
nss = 3; /* not support MCS9 from spec*/
break;
case 3120:
nss = 4;
break;
default:
nss = 1;
}
return nss;
}
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
......@@ -2512,6 +2536,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
{
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
struct ath10k_hw_params *hw = &ar->hw_params;
struct cfg80211_chan_def def;
enum nl80211_band band;
const u16 *vht_mcs_mask;
......@@ -2578,22 +2603,38 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
sta->addr, arg->peer_max_mpdu, arg->peer_flags);
/* Configure bandwidth-NSS mapping to FW
* for the chip's tx chains setting on 160Mhz bw
*/
if (arg->peer_phymode == MODE_11AC_VHT160 ||
arg->peer_phymode == MODE_11AC_VHT80_80) {
u32 rx_nss;
u32 max_rate;
if (arg->peer_vht_rates.rx_max_rate &&
(sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
switch (arg->peer_vht_rates.rx_max_rate) {
case 1560:
/* Must be 2x2 at 160Mhz is all it can do. */
arg->peer_bw_rxnss_override = 2;
break;
case 780:
/* Can only do 1x1 at 160Mhz (Long Guard Interval) */
arg->peer_bw_rxnss_override = 1;
break;
max_rate = arg->peer_vht_rates.rx_max_rate;
rx_nss = get_160mhz_nss_from_maxrate(max_rate);
if (rx_nss == 0)
rx_nss = arg->peer_num_spatial_streams;
else
rx_nss = min(arg->peer_num_spatial_streams, rx_nss);
max_rate = hw->vht160_mcs_tx_highest;
rx_nss = min(rx_nss, get_160mhz_nss_from_maxrate(max_rate));
arg->peer_bw_rxnss_override =
FIELD_PREP(WMI_PEER_NSS_MAP_ENABLE, 1) |
FIELD_PREP(WMI_PEER_NSS_160MHZ_MASK, (rx_nss - 1));
if (arg->peer_phymode == MODE_11AC_VHT80_80) {
arg->peer_bw_rxnss_override |=
FIELD_PREP(WMI_PEER_NSS_80_80MHZ_MASK, (rx_nss - 1));
}
}
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vht peer %pM max_mpdu %d flags 0x%x peer_rx_nss_override 0x%x\n",
sta->addr, arg->peer_max_mpdu,
arg->peer_flags, arg->peer_bw_rxnss_override);
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
......@@ -2745,9 +2786,9 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
return 0;
}
......@@ -4563,13 +4604,6 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
vht_cap.cap |= val;
}
/* Currently the firmware seems to be buggy, don't enable 80+80
* mode until that's resolved.
*/
if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) &&
(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0)
vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
mcs_map = 0;
for (i = 0; i < 8; i++) {
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
......@@ -8625,7 +8659,9 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80),
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_80P80) |
BIT(NL80211_CHAN_WIDTH_160),
#endif
},
};
......@@ -8643,7 +8679,9 @@ ieee80211_iface_combination ath10k_10_4_bcn_int_if_comb[] = {
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80),
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_80P80) |
BIT(NL80211_CHAN_WIDTH_160),
#endif
},
};
......
......@@ -1714,12 +1714,23 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
if (arg->chan_radar)
flags |= WMI_CHAN_FLAG_DFS;
ch->band_center_freq2 = 0;
ch->mhz = __cpu_to_le32(arg->freq);
ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
if (arg->mode == MODE_11AC_VHT80_80)
ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2);
else
ch->band_center_freq2 = 0;
if (arg->mode == MODE_11AC_VHT160) {
if (arg->freq > arg->band_center_freq1)
ch->band_center_freq1 =
__cpu_to_le32(arg->band_center_freq1 + 40);
else
ch->band_center_freq1 =
__cpu_to_le32(arg->band_center_freq1 - 40);
ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq1);
}
ch->min_power = arg->min_power;
ch->max_power = arg->max_power;
ch->reg_power = arg->max_reg_power;
......@@ -7628,12 +7639,8 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf,
struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
if (arg->peer_bw_rxnss_override)
cmd->peer_bw_rxnss_override =
__cpu_to_le32((arg->peer_bw_rxnss_override - 1) |
BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET));
else
cmd->peer_bw_rxnss_override = 0;
cmd->peer_bw_rxnss_override =
__cpu_to_le32(arg->peer_bw_rxnss_override);
}
static int
......
......@@ -6508,7 +6508,10 @@ struct wmi_10_2_peer_assoc_complete_cmd {
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed;
#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31
/* NSS Mapping to FW */
#define WMI_PEER_NSS_MAP_ENABLE BIT(31)
#define WMI_PEER_NSS_160MHZ_MASK GENMASK(2, 0)
#define WMI_PEER_NSS_80_80MHZ_MASK GENMASK(5, 3)
struct wmi_10_4_peer_assoc_complete_cmd {
struct wmi_10_2_peer_assoc_complete_cmd cmd;
......
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