From ddf4f23a95dd44931d695eb615c6b4e3869a0a56 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Fri, 9 Oct 2020 15:15:46 +0530 Subject: [PATCH] ath11k: allow multiple single rates from fixed rate settings Ath11k driver allows user to set either range of rates like 1:0-9 2:0-9 3:0-9 4:0-9 or single fixed rate like 1:9 from set bitrates command. This change allows user to set multiple vht/he single rates from set bitrates command like 1:9 2:9 3:9 4:9. And rate will be applied based on the best nss supported by the peer using peer fixed rate command. Signed-off-by: Venkateswara Naralasetty --- drivers/net/wireless/ath/ath11k/mac.c | 130 ++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 46 deletions(-) --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3581,6 +3581,28 @@ exit: } static int +ath11k_mac_bitrate_num_vht_single_rates(struct ath11k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + struct ieee80211_sta *sta) +{ + int num_single_rates = 0; + int i; + int rates; + int nss; + + nss = sta ? sta->rx_nss : ARRAY_SIZE(mask->control[band].vht_mcs); + + for (i = 0; i < nss; i++) { + rates = hweight16(mask->control[band].vht_mcs[i]); + if (rates == 1) + num_single_rates++; + } + + return num_single_rates; +} + +static int ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar, enum nl80211_band band, const struct cfg80211_bitrate_mask *mask) @@ -3595,6 +3617,28 @@ ath11k_mac_bitrate_mask_num_vht_rates(st } static int +ath11k_mac_bitrate_num_he_single_rates(struct ath11k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + struct ieee80211_sta *sta) +{ + int num_single_rates = 0; + int i; + int rates; + int nss; + + nss = sta ? sta->rx_nss : ARRAY_SIZE(mask->control[band].he_mcs); + + for (i = 0; i < nss; i++) { + rates = hweight16(mask->control[band].he_mcs[i]); + if (rates == 1) + num_single_rates++; + } + + return num_single_rates; +} + +static int ath11k_mac_bitrate_mask_num_he_rates(struct ath11k *ar, enum nl80211_band band, const struct cfg80211_bitrate_mask *mask) @@ -3623,7 +3667,7 @@ ath11k_mac_set_peer_vht_fixed_rate(struc nss = 0; - for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { + for (i = 0; i < sta->rx_nss; i++) { if (hweight16(mask->control[band].vht_mcs[i]) == 1) { nss = i + 1; vht_rate = ffs(mask->control[band].vht_mcs[i]) - 1; @@ -3636,10 +3680,6 @@ ath11k_mac_set_peer_vht_fixed_rate(struc return -EINVAL; } - /* Avoid updating invalid nss as fixed rate*/ - if (nss > sta->rx_nss) - return -EINVAL; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates", sta->addr); @@ -3673,7 +3713,7 @@ ath11k_mac_set_peer_he_fixed_rate(struct nss = 0; - for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + for (i = 0; i < sta->rx_nss; i++) { if (hweight16(mask->control[band].he_mcs[i]) == 1) { nss = i + 1; he_rate = ffs(mask->control[band].he_mcs[i]) - 1; @@ -3686,11 +3726,6 @@ ath11k_mac_set_peer_he_fixed_rate(struct return -EINVAL; } - /* Avoid updating invalid nss as fixed rate*/ - if (nss > sta->rx_nss) - return -EINVAL; - - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Setting Fixed HE Rate for peer %pM. Device will not switch to any other selected rates", sta->addr); @@ -3720,7 +3755,7 @@ static int ath11k_station_assoc(struct a struct cfg80211_chan_def def; enum nl80211_band band; struct cfg80211_bitrate_mask *mask; - u8 num_vht_rates, num_he_rates; + u8 num_vht_single_rates, num_he_single_rates; lockdep_assert_held(&ar->conf_mutex); @@ -3745,22 +3780,23 @@ static int ath11k_station_assoc(struct a return -ETIMEDOUT; } - num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); - num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask); + num_vht_single_rates = ath11k_mac_bitrate_num_vht_single_rates(ar, band, + mask, sta); + num_he_single_rates = ath11k_mac_bitrate_num_he_single_rates(ar, band, + mask, sta); /* If single VHT/HE rate is configured (by set_bitrate_mask()), * peer_assoc will disable VHT/HE. This is now enabled by a peer specific - * fixed param. + * fixed param. If multiple single VHT/HE rates like(1:9 2:9 3:9 4:9) + * are configured, apply rate with the best nss supported by the peer. * Note that all other rates and NSS will be disabled for this peer. */ - if (sta->vht_cap.vht_supported && num_vht_rates == 1) { - ret = ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, - band); + if (sta->vht_cap.vht_supported && num_vht_single_rates >= 1) { + ret = ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, band); if (ret) return ret; - } else if (sta->he_cap.has_he && num_he_rates == 1) { - ret = ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, - band); + } else if (sta->he_cap.has_he && num_he_single_rates >= 1) { + ret = ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, band); if (ret) return ret; } @@ -3835,7 +3871,7 @@ static void ath11k_sta_rc_update_wk(stru const u16 *vht_mcs_mask; const u16 *he_mcs_mask; u32 changed, bw, nss, smps; - int err, num_vht_rates, num_he_rates; + int err, num_vht_single_rates, num_he_single_rates; const struct cfg80211_bitrate_mask *mask; struct peer_assoc_params peer_arg; @@ -3902,26 +3938,27 @@ static void ath11k_sta_rc_update_wk(stru if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { mask = &arvif->bitrate_mask; - num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, - mask); - num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, - mask); + num_vht_single_rates = ath11k_mac_bitrate_num_vht_single_rates(ar, band, + mask, sta); + num_he_single_rates = ath11k_mac_bitrate_num_he_single_rates(ar, band, + mask, sta); /* Peer_assoc_prepare will reject vht rates in * bitrate_mask if its not available in range format and - * sets vht tx_rateset as unsupported. So multiple VHT MCS - * setting(eg. MCS 4,5,6) per peer is not supported here. - * But, Single rate in VHT mask can be set as per-peer - * fixed rate. But even if any HT rates are configured in - * the bitrate mask, device will not switch to those rates - * when per-peer Fixed rate is set. + * sets vht tx_rateset as unsupported. If multiple VHT MCS + * and NSS (or) single fixed rate are configured from set_bitrate() + * setting(eg. 1:9 2:9 3:9 4:9) select the best rate based on NSS + * supported by the peer and apply it as peer fixed rate. Also, + * if rate is configured as 1:9 2:0-9 will select 1:9 here. + * But even if any HT rates are configured in the bitrate mask, + * device will not switch to those rates when per-peer Fixed rate is set. * TODO: Check RATEMASK_CMDID to support auto rates selection * across HT/VHT and for multiple VHT MCS support. */ - if (sta->vht_cap.vht_supported && num_vht_rates == 1) { + if (sta->vht_cap.vht_supported && num_vht_single_rates >= 1) { ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, band); - } else if (sta->he_cap.has_he && num_he_rates == 1) { + } else if (sta->he_cap.has_he && num_he_single_rates >= 1) { ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, band); } else { @@ -7138,7 +7175,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie u8 he_gi = 0, he_ltf = 0; int single_nss; int ret; - int num_rates; + int num_single_rates; bool he_fixed_rate = false; if (ath11k_mac_vif_chan(vif, &def)) @@ -7215,37 +7252,38 @@ ath11k_mac_op_set_bitrate_mask(struct ie * the VHT rate as fixed rate for vht peers. * - Multiple VHT Rates : When Multiple VHT rates are given,this * can be set using RATEMASK CMD which uses FW rate-ctl alg. + * - Multiple VHT single Rates: like 1:9 2:9 3:9 4:9 provided in + * set_bitrates(), apply rate based on the best NSS supported by + * the peer through peer fixed rate command. * TODO: Setting multiple VHT MCS and replacing peer_assoc with * RATEMASK_CMDID can cover all use cases of setting rates * across multiple preambles and rates within same type. * But requires more validation of the command at this point. */ - num_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, - mask); + num_single_rates = ath11k_mac_bitrate_num_vht_single_rates(ar, band, + mask, NULL); if (!ath11k_mac_vht_mcs_range_present(ar, band, mask) && - num_rates > 1) { - /* TODO: Handle multiple VHT MCS values setting using - * RATEMASK CMD - */ + num_single_rates == 0) { ath11k_warn(ar->ab, "Setting VHT MCS range other than 0-7, 0-8 and 0-9 in bitrate mask not supported\n"); return -EINVAL; } - num_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, - mask); - if (num_rates == 1) - he_fixed_rate = true; + num_single_rates = ath11k_mac_bitrate_num_he_single_rates(ar, band, + mask, NULL); if (!ath11k_mac_he_mcs_range_present(ar, band, mask) && - num_rates > 1) { + num_single_rates == 0) { ath11k_warn(ar->ab, "Setting HE MCS range other than 0-7, 0-9 and 0-11 in bitrate mask not supported\n"); return -EINVAL; } + if (num_single_rates >= 1) + he_fixed_rate = true; + mutex_lock(&ar->conf_mutex); ieee80211_iterate_stations_atomic(ar->hw, ath11k_mac_disable_peer_fixed_rate,