Commit 90046f50 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: fix SMPS support

Firmware ignores SMPS flags in peer assoc command.

For SMPS to work it is necessary to set peer
parameter after peer assoc command so that tx
chainmask is setup properly.

This should fix packet loss and improve throughput
with stations that have SMPS enabled upon
association.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 75459e33
...@@ -1082,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1082,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg) struct wmi_peer_assoc_complete_arg *arg)
{ {
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
int smps;
int i, n; int i, n;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -1128,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -1128,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_flags |= WMI_PEER_STBC; arg->peer_flags |= WMI_PEER_STBC;
} }
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
} else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
}
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
arg->peer_rate_caps |= WMI_RC_TS_FLAG; arg->peer_rate_caps |= WMI_RC_TS_FLAG;
else if (ht_cap->mcs.rx_mask[1]) else if (ht_cap->mcs.rx_mask[1])
...@@ -1378,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, ...@@ -1378,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
return 0; return 0;
} }
static const u32 ath10k_smps_map[] = {
[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
};
static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
const u8 *addr,
const struct ieee80211_sta_ht_cap *ht_cap)
{
int smps;
if (!ht_cap->ht_supported)
return 0;
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
if (smps >= ARRAY_SIZE(ath10k_smps_map))
return -EINVAL;
return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
WMI_PEER_SMPS_STATE,
ath10k_smps_map[smps]);
}
/* can be called only in mac80211 callbacks due to `key_count` usage */ /* can be called only in mac80211 callbacks due to `key_count` usage */
static void ath10k_bss_assoc(struct ieee80211_hw *hw, static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -1385,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1385,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ieee80211_sta_ht_cap ht_cap;
struct wmi_peer_assoc_complete_arg peer_arg; struct wmi_peer_assoc_complete_arg peer_arg;
struct ieee80211_sta *ap_sta; struct ieee80211_sta *ap_sta;
int ret; int ret;
...@@ -1401,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1401,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
return; return;
} }
/* ap_sta must be accessed only within rcu section which must be left
* before calling ath10k_setup_peer_smps() which might sleep. */
ht_cap = ap_sta->ht_cap;
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg); bss_conf, &peer_arg);
if (ret) { if (ret) {
...@@ -1419,6 +1439,12 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1419,6 +1439,12 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
return; return;
} }
ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
if (ret) {
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
return;
}
ath10k_dbg(ATH10K_DBG_MAC, ath10k_dbg(ATH10K_DBG_MAC,
"mac vdev %d up (associated) bssid %pM aid %d\n", "mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid); arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
...@@ -1500,6 +1526,12 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ...@@ -1500,6 +1526,12 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
return ret; return ret;
} }
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
if (ret) {
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
return ret;
}
ret = ath10k_install_peer_wep_keys(arvif, sta->addr); ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) { if (ret) {
ath10k_warn("could not install peer wep keys (%d)\n", ret); ath10k_warn("could not install peer wep keys (%d)\n", ret);
......
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