ath10k: apply chainmask settings to vdev on creation

It appears it takes more than just setting the
hardware's chainmask to make things work well.  Without
this patch, a vdev would only use 1x1 rates when chainmask
was set to 0x3.

Setting the 'nss' (number of spatial streams) on the vdev
helps the firmware's rate-control algorithm work properly.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
Ben Greear 2014-11-24 16:22:10 +02:00 committed by Kalle Valo
parent 3be004c3aa
commit 5572a95b4b

View File

@ -2414,12 +2414,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
{
/* It is not clear that allowing gaps in chainmask
* is helpful. Probably it will not do what user
* is hoping for, so warn in that case.
*/
if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0)
return;
ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
dbg, cm);
}
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
{
int ret;
lockdep_assert_held(&ar->conf_mutex);
ath10k_check_chain_mask(ar, tx_ant, "tx");
ath10k_check_chain_mask(ar, rx_ant, "rx");
ar->cfg_tx_chainmask = tx_ant;
ar->cfg_rx_chainmask = rx_ant;
@ -2782,6 +2798,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
return ret;
}
static u32 get_nss_from_chainmask(u16 chain_mask)
{
if ((chain_mask & 0x15) == 0x15)
return 4;
else if ((chain_mask & 0x7) == 0x7)
return 3;
else if ((chain_mask & 0x3) == 0x3)
return 2;
return 1;
}
/*
* TODO:
* Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
@ -2914,6 +2941,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_vdev_delete;
}
if (ar->cfg_tx_chainmask) {
u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
vdev_param = ar->wmi.vdev_param->nss;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
nss);
if (ret) {
ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n",
arvif->vdev_id, ar->cfg_tx_chainmask, nss,
ret);
goto err_vdev_delete;
}
}
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
if (ret) {