From 3db24065c2c824e9ea419c453b810b5f301d91c8 Mon Sep 17 00:00:00 2001 From: Lei Wang Date: Mon, 30 Mar 2020 18:56:31 +0530 Subject: [PATCH] ath10k: enable VHT160 and VHT80+80 modes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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: Sebastian Gottschall Signed-off-by: Sebastian Gottschall Co-developed-by: Rick Wu Signed-off-by: Rick Wu Signed-off-by: Lei Wang Signed-off-by: Sowmiya Sree Elavalagan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1585574792-719-1-git-send-email-ssreeela@codeaurora.org --- drivers/net/wireless/ath/ath10k/mac.c | 84 +++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/wmi.c | 23 +++++--- drivers/net/wireless/ath/ath10k/wmi.h | 5 +- 3 files changed, 80 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2d03b8dd3b8c..a59a7a5631a8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -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 }, }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2ea77bb880b1..db6f4c751485 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -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 diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6df415778374..5ba0c9a7d18c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -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; -- 2.20.1