--- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -909,6 +909,13 @@ static void ath11k_peer_assoc_h_ht(struc arg->bw_40 = true; arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; } + /* As firmware handles this two flags (IEEE80211_HT_CAP_SGI_20 + * and IEEE80211_HT_CAP_SGI_40) for enabling SGI, we reset + * both flags if guard interval is Default GI + */ + if (arvif->bitrate_mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI) + arg->peer_ht_caps &= ~(IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40); if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | @@ -1309,7 +1316,11 @@ static void ath11k_peer_assoc_h_he(struc for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { he_mcs = __le16_to_cpu(he_tx_mcs) >> (2 * i) & 3; - if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED && + /* In case of fixed rates, MCS Range in he_tx_mcs might have + * unsupported range, with he_mcs_mask set, so check either of them + * to find nss. + */ + if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED || he_mcs_mask[i]) max_nss = i + 1; } @@ -2762,6 +2773,10 @@ 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); @@ -2808,6 +2823,11 @@ 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); @@ -2837,7 +2857,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; + u8 num_vht_rates, num_he_rates; lockdep_assert_held(&ar->conf_mutex); @@ -2863,9 +2883,10 @@ static int ath11k_station_assoc(struct a } 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); - /* If single VHT rate is configured (by set_bitrate_mask()), - * peer_assoc will disable VHT. This is now enabled by a peer specific + /* 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. * Note that all other rates and NSS will be disabled for this peer. */ @@ -2874,6 +2895,11 @@ static int ath11k_station_assoc(struct a 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); + if (ret) + return ret; } /* Re-assoc is run only to update supported rates for given station. It @@ -3036,10 +3062,21 @@ static void ath11k_sta_rc_update_wk(stru ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, band); } else { - /* If the peer is non-VHT or no fixed VHT rate + /* If the peer is non-VHT/HE or no fixed VHT/HE rate * is provided in the new bitrate mask we set the - * other rates using peer_assoc command. + * other rates using peer_assoc command. Also clear + * the peer fixed rate settings as it has higher proprity + * than peer assoc */ + err = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + WMI_FIXED_RATE_NONE); + if (err) + ath11k_warn(ar->ab, + "failed to disable peer fixed rate for STA %pM ret %d\n", + sta->addr, err); + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); @@ -4498,6 +4535,7 @@ static int ath11k_mac_op_add_interface(s for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { arvif->bitrate_mask.control[i].legacy = 0xffffffff; + arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_FORCE_SGI; memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].ht_mcs)); memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, @@ -5762,6 +5800,53 @@ static void ath11k_mac_disable_peer_fixe sta->addr, ret); } +static bool +ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + bool he_fixed_rate = false, vht_fixed_rate = false; + struct ath11k_peer *peer, *tmp; + const u16 *vht_mcs_mask, *he_mcs_mask; + u8 vht_nss, he_nss; + bool ret = true; + + vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; + + if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1) + vht_fixed_rate = true; + + if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1) + he_fixed_rate = true; + + if(!vht_fixed_rate && !he_fixed_rate) + return true; + + vht_nss = ath11k_mac_max_vht_nss(vht_mcs_mask); + he_nss = ath11k_mac_max_he_nss(he_mcs_mask); + + rcu_read_lock(); + spin_lock_bh(&ar->ab->base_lock); + list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { + if (peer->sta) { + if (vht_fixed_rate && (!peer->sta->vht_cap.vht_supported || + peer->sta->rx_nss < vht_nss)) { + ret = false; + goto exit; + } + if (he_fixed_rate && (!peer->sta->he_cap.has_he || + peer->sta->rx_nss < he_nss)) { + ret = false; + goto exit; + } + } + } +exit: + spin_unlock_bh(&ar->ab->base_lock); + rcu_read_unlock(); + return ret; +} + static int ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -5824,6 +5909,11 @@ ath11k_mac_op_set_bitrate_mask(struct ie nss = single_nss; } else { rate = WMI_FIXED_RATE_NONE; + + if (!ath11k_mac_validate_vht_he_fixed_rate_settings(ar, band, mask)) + ath11k_warn(ar->ab, + "could not update fixed rate settings to all peers due to mcs/nss incompaitiblity\n"); + nss = min_t(u32, ar->num_tx_chains, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), ath11k_mac_max_vht_nss(vht_mcs_mask)), @@ -5872,10 +5962,6 @@ ath11k_mac_op_set_bitrate_mask(struct ie return -EINVAL; } - ieee80211_iterate_stations_atomic(ar->hw, - ath11k_mac_disable_peer_fixed_rate, - arvif); - mutex_lock(&ar->conf_mutex); arvif->bitrate_mask = *mask;