Commit 3ae54225 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

ath10k: clean up set_bitrate_mask handling



The code was a bit convoluted. Clean it up and
prepare for future changes.

While at it this fixes incorrect verification of
'single nss' case when ss2 rates were missing
while ss1 and ss3 were requested resulting in
nss=3 being set:

  iw wlan1 set bitrates legacy-5 ht-mcs-5 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23 vht-mcs-5 1:0-9 3:0-9
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 039a0051
......@@ -348,9 +348,6 @@ struct ath10k_vif {
} ap;
} u;
u8 fixed_rate;
u8 fixed_nss;
u8 force_sgi;
bool use_cts_prot;
int num_legacy_stations;
int txpower;
......
......@@ -120,6 +120,16 @@ u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
return 0;
}
static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
{
switch ((mcs_map >> (2 * nss)) & 0x3) {
case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1;
case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1;
case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1;
}
return 0;
}
/**********/
/* Crypto */
/**********/
......@@ -5592,327 +5602,221 @@ exit:
return ret;
}
/* Check if only one bit set */
static int ath10k_check_single_mask(u32 mask)
{
int bit;
bit = ffs(mask);
if (!bit)
return 0;
mask &= ~BIT(bit - 1);
if (mask)
return 2;
return 1;
}
static bool
ath10k_default_bitrate_mask(struct ath10k *ar,
enum ieee80211_band band,
const struct cfg80211_bitrate_mask *mask)
ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
enum ieee80211_band band,
const struct cfg80211_bitrate_mask *mask)
{
u32 legacy = 0x00ff;
u8 ht = 0xff, i;
u16 vht = 0x3ff;
u16 nrf = ar->num_rf_chains;
if (ar->cfg_tx_chainmask)
nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
int num_rates = 0;
int i;
switch (band) {
case IEEE80211_BAND_2GHZ:
legacy = 0x00fff;
vht = 0;
break;
case IEEE80211_BAND_5GHZ:
break;
default:
return false;
}
num_rates += hweight32(mask->control[band].legacy);
if (mask->control[band].legacy != legacy)
return false;
for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
num_rates += hweight8(mask->control[band].ht_mcs[i]);
for (i = 0; i < nrf; i++)
if (mask->control[band].ht_mcs[i] != ht)
return false;
for (i = 0; i < nrf; i++)
if (mask->control[band].vht_mcs[i] != vht)
return false;
for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
num_rates += hweight16(mask->control[band].vht_mcs[i]);
return true;
return num_rates == 1;
}
static bool
ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_nss)
{
int ht_nss = 0, vht_nss = 0, i;
ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar,
enum ieee80211_band band,
const struct cfg80211_bitrate_mask *mask,
int *nss)
{
struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
u8 ht_nss_mask = 0;
u8 vht_nss_mask = 0;
int i;
/* check legacy */
if (ath10k_check_single_mask(mask->control[band].legacy))
if (mask->control[band].legacy)
return false;
/* check HT */
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
if (mask->control[band].ht_mcs[i] == 0xff)
for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
if (mask->control[band].ht_mcs[i] == 0)
continue;
else if (mask->control[band].ht_mcs[i] == 0x00)
break;
return false;
else if (mask->control[band].ht_mcs[i] ==
sband->ht_cap.mcs.rx_mask[i])
ht_nss_mask |= BIT(i);
else
return false;
}
ht_nss = i;
/* check VHT */
for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
if (mask->control[band].vht_mcs[i] == 0x03ff)
for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
if (mask->control[band].vht_mcs[i] == 0)
continue;
else if (mask->control[band].vht_mcs[i] == 0x0000)
break;
return false;
else if (mask->control[band].vht_mcs[i] ==
ath10k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
vht_nss_mask |= BIT(i);
else
return false;
}
vht_nss = i;
if (ht_nss > 0 && vht_nss > 0)
if (ht_nss_mask != vht_nss_mask)
return false;
if (ht_nss)
*fixed_nss = ht_nss;
else if (vht_nss)
*fixed_nss = vht_nss;
else
if (ht_nss_mask == 0)
return false;
return true;
}
static bool
ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
enum wmi_rate_preamble *preamble)
{
int legacy = 0, ht = 0, vht = 0, i;
*preamble = WMI_RATE_PREAMBLE_OFDM;
/* check legacy */
legacy = ath10k_check_single_mask(mask->control[band].legacy);
if (legacy > 1)
return false;
/* check HT */
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]);
if (ht > 1)
return false;
/* check VHT */
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]);
if (vht > 1)
return false;
/* Currently we support only one fixed_rate */
if ((legacy + ht + vht) != 1)
if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
return false;
if (ht)
*preamble = WMI_RATE_PREAMBLE_HT;
else if (vht)
*preamble = WMI_RATE_PREAMBLE_VHT;
*nss = fls(ht_nss_mask);
return true;
}
static bool
ath10k_bitrate_mask_rate(struct ath10k *ar,
const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_rate,
u8 *fixed_nss)
static int
ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
enum ieee80211_band band,
const struct cfg80211_bitrate_mask *mask,
u8 *rate, u8 *nss)
{
struct ieee80211_supported_band *sband;
u8 rate = 0, pream = 0, nss = 0, i;
enum wmi_rate_preamble preamble;
/* Check if single rate correct */
if (!ath10k_bitrate_mask_correct(mask, band, &preamble))
return false;
pream = preamble;
switch (preamble) {
case WMI_RATE_PREAMBLE_CCK:
case WMI_RATE_PREAMBLE_OFDM:
i = ffs(mask->control[band].legacy) - 1;
sband = &ar->mac.sbands[band];
if (WARN_ON(i >= sband->n_bitrates))
return false;
struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
int rate_idx;
int i;
u16 bitrate;
u8 preamble;
u8 hw_rate;
rate = sband->bitrates[i].hw_value;
break;
case WMI_RATE_PREAMBLE_HT:
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
if (mask->control[band].ht_mcs[i])
break;
if (hweight32(mask->control[band].legacy) == 1) {
rate_idx = ffs(mask->control[band].legacy) - 1;
if (i == IEEE80211_HT_MCS_MASK_LEN)
return false;
hw_rate = sband->bitrates[rate_idx].hw_value;
bitrate = sband->bitrates[rate_idx].bitrate;
rate = ffs(mask->control[band].ht_mcs[i]) - 1;
nss = i;
break;
case WMI_RATE_PREAMBLE_VHT:
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
if (mask->control[band].vht_mcs[i])
break;
if (ath10k_mac_bitrate_is_cck(bitrate))
preamble = WMI_RATE_PREAMBLE_CCK;
else
preamble = WMI_RATE_PREAMBLE_OFDM;
if (i == NL80211_VHT_NSS_MAX)
return false;
*nss = 1;
*rate = preamble << 6 |
(*nss - 1) << 4 |
hw_rate << 0;
rate = ffs(mask->control[band].vht_mcs[i]) - 1;
nss = i;
break;
return 0;
}
*fixed_nss = nss + 1;
nss <<= 4;
pream <<= 6;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
pream, nss, rate);
for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
*nss = i + 1;
*rate = WMI_RATE_PREAMBLE_HT << 6 |
(*nss - 1) << 4 |
(ffs(mask->control[band].ht_mcs[i]) - 1);
*fixed_rate = pream | nss | rate;
return 0;
}
}
return true;
}
for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
*nss = i + 1;
*rate = WMI_RATE_PREAMBLE_VHT << 6 |
(*nss - 1) << 4 |
(ffs(mask->control[band].vht_mcs[i]) - 1);
static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_rate,
u8 *fixed_nss)
{
/* First check full NSS mask, if we can simply limit NSS */
if (ath10k_bitrate_mask_nss(mask, band, fixed_nss))
return true;
return 0;
}
}
/* Next Check single rate is set */
return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
return -EINVAL;
}
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
u8 fixed_rate,
u8 fixed_nss,
u8 force_sgi)
static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
u8 rate, u8 nss, u8 sgi)
{
struct ath10k *ar = arvif->ar;
u32 vdev_param;
int ret = 0;
mutex_lock(&ar->conf_mutex);
if (arvif->fixed_rate == fixed_rate &&
arvif->fixed_nss == fixed_nss &&
arvif->force_sgi == force_sgi)
goto exit;
int ret;
if (fixed_rate == WMI_FIXED_RATE_NONE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
lockdep_assert_held(&ar->conf_mutex);
if (force_sgi)
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
arvif->vdev_id, rate, nss, sgi);
vdev_param = ar->wmi.vdev_param->fixed_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, fixed_rate);
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate);
if (ret) {
ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
fixed_rate, ret);
ret = -EINVAL;
goto exit;
rate, ret);
return ret;
}
arvif->fixed_rate = fixed_rate;
vdev_param = ar->wmi.vdev_param->nss;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, fixed_nss);
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss);
if (ret) {
ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
fixed_nss, ret);
ret = -EINVAL;
goto exit;
ath10k_warn(ar, "failed to set nss param %d: %d\n", nss, ret);
return ret;
}
arvif->fixed_nss = fixed_nss;
vdev_param = ar->wmi.vdev_param->sgi;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
force_sgi);
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, sgi);
if (ret) {
ath10k_warn(ar, "failed to set sgi param %d: %d\n",
force_sgi, ret);
ret = -EINVAL;
goto exit;
ath10k_warn(ar, "failed to set sgi param %d: %d\n", sgi, ret);
return ret;
}
arvif->force_sgi = force_sgi;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
return 0;
}
static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
struct ath10k *ar = arvif->ar;
enum ieee80211_band band;
u8 fixed_rate = WMI_FIXED_RATE_NONE;
u8 fixed_nss = ar->num_rf_chains;
u8 force_sgi;
u8 rate;
u8 nss;
u8 sgi;
int single_nss;
int ret;
if (ath10k_mac_vif_chan(vif, &def))
return -EPERM;
if (ar->cfg_tx_chainmask)
fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
band = def.chan->band;
force_sgi = mask->control[band].gi;
if (force_sgi == NL80211_TXRATE_FORCE_LGI)
sgi = mask->control[band].gi;
if (sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL;
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
if (!ath10k_get_fixed_rate_nss(ar, mask, band,
&fixed_rate,
&fixed_nss))
return -EINVAL;
if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
&rate, &nss);
if (ret) {
ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
} else if (ath10k_mac_bitrate_mask_get_single_nss(ar, band, mask,
&single_nss)) {
rate = WMI_FIXED_RATE_NONE;
nss = single_nss;
} else {
rate = WMI_FIXED_RATE_NONE;
nss = ar->num_rf_chains;
}
if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
return -EINVAL;
mutex_lock(&ar->conf_mutex);
ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
if (ret) {
ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
arvif->vdev_id, ret);
goto exit;
}
return ath10k_set_fixed_rate_param(arvif, fixed_rate,
fixed_nss, force_sgi);
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
......@@ -6335,7 +6239,7 @@ static const struct ieee80211_ops ath10k_ops = {
.get_antenna = ath10k_get_antenna,
.reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_set_bitrate_mask,
.set_bitrate_mask = ath10k_mac_op_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
......
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