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: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
Michal Kazior 2015-03-31 10:49:20 +00:00 committed by Kalle Valo
parent 039a0051ec
commit 3ae5422574
2 changed files with 175 additions and 274 deletions

View File

@ -348,9 +348,6 @@ struct ath10k_vif {
} ap; } ap;
} u; } u;
u8 fixed_rate;
u8 fixed_nss;
u8 force_sgi;
bool use_cts_prot; bool use_cts_prot;
int num_legacy_stations; int num_legacy_stations;
int txpower; int txpower;

View File

@ -120,6 +120,16 @@ u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
return 0; 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 */ /* Crypto */
/**********/ /**********/
@ -5592,327 +5602,221 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
return ret; return ret;
} }
/* Check if only one bit set */ static bool
static int ath10k_check_single_mask(u32 mask) ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
enum ieee80211_band band,
const struct cfg80211_bitrate_mask *mask)
{ {
int bit; int num_rates = 0;
int i;
num_rates += hweight32(mask->control[band].legacy);
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 < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
num_rates += hweight16(mask->control[band].vht_mcs[i]);
return num_rates == 1;
}
static bool
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;
if (mask->control[band].legacy)
return false;
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] ==
sband->ht_cap.mcs.rx_mask[i])
ht_nss_mask |= BIT(i);
else
return false;
}
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] ==
ath10k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
vht_nss_mask |= BIT(i);
else
return false;
}
if (ht_nss_mask != vht_nss_mask)
return false;
if (ht_nss_mask == 0)
return false;
if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
return false;
*nss = fls(ht_nss_mask);
return true;
}
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 = &ar->mac.sbands[band];
int rate_idx;
int i;
u16 bitrate;
u8 preamble;
u8 hw_rate;
if (hweight32(mask->control[band].legacy) == 1) {
rate_idx = ffs(mask->control[band].legacy) - 1;
hw_rate = sband->bitrates[rate_idx].hw_value;
bitrate = sband->bitrates[rate_idx].bitrate;
if (ath10k_mac_bitrate_is_cck(bitrate))
preamble = WMI_RATE_PREAMBLE_CCK;
else
preamble = WMI_RATE_PREAMBLE_OFDM;
*nss = 1;
*rate = preamble << 6 |
(*nss - 1) << 4 |
hw_rate << 0;
bit = ffs(mask);
if (!bit)
return 0; 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)
{
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);
switch (band) {
case IEEE80211_BAND_2GHZ:
legacy = 0x00fff;
vht = 0;
break;
case IEEE80211_BAND_5GHZ:
break;
default:
return false;
} }
if (mask->control[band].legacy != legacy) for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
return false; 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);
for (i = 0; i < nrf; i++) return 0;
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;
return true;
}
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;
/* check legacy */
if (ath10k_check_single_mask(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)
continue;
else if (mask->control[band].ht_mcs[i] == 0x00)
break;
return false;
} }
ht_nss = i; 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);
/* check VHT */ return 0;
for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { }
if (mask->control[band].vht_mcs[i] == 0x03ff)
continue;
else if (mask->control[band].vht_mcs[i] == 0x0000)
break;
return false;
} }
vht_nss = i; return -EINVAL;
if (ht_nss > 0 && vht_nss > 0)
return false;
if (ht_nss)
*fixed_nss = ht_nss;
else if (vht_nss)
*fixed_nss = vht_nss;
else
return false;
return true;
} }
static bool static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask, u8 rate, u8 nss, u8 sgi)
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)
return false;
if (ht)
*preamble = WMI_RATE_PREAMBLE_HT;
else if (vht)
*preamble = WMI_RATE_PREAMBLE_VHT;
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)
{
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;
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 (i == IEEE80211_HT_MCS_MASK_LEN)
return false;
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 (i == NL80211_VHT_NSS_MAX)
return false;
rate = ffs(mask->control[band].vht_mcs[i]) - 1;
nss = i;
break;
}
*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);
*fixed_rate = pream | nss | rate;
return true;
}
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;
/* Next Check single rate is set */
return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
}
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
u8 fixed_rate,
u8 fixed_nss,
u8 force_sgi)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
u32 vdev_param; u32 vdev_param;
int ret = 0; int ret;
mutex_lock(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
if (arvif->fixed_rate == fixed_rate && ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
arvif->fixed_nss == fixed_nss && arvif->vdev_id, rate, nss, sgi);
arvif->force_sgi == force_sgi)
goto exit;
if (fixed_rate == WMI_FIXED_RATE_NONE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
if (force_sgi)
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
vdev_param = ar->wmi.vdev_param->fixed_rate; vdev_param = ar->wmi.vdev_param->fixed_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate);
vdev_param, fixed_rate);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n", ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
fixed_rate, ret); rate, ret);
ret = -EINVAL; return ret;
goto exit;
} }
arvif->fixed_rate = fixed_rate;
vdev_param = ar->wmi.vdev_param->nss; vdev_param = ar->wmi.vdev_param->nss;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss);
vdev_param, fixed_nss);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set fixed nss param %d: %d\n", ath10k_warn(ar, "failed to set nss param %d: %d\n", nss, ret);
fixed_nss, ret); return ret;
ret = -EINVAL;
goto exit;
} }
arvif->fixed_nss = fixed_nss;
vdev_param = ar->wmi.vdev_param->sgi; vdev_param = ar->wmi.vdev_param->sgi;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, sgi);
force_sgi);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set sgi param %d: %d\n", ath10k_warn(ar, "failed to set sgi param %d: %d\n", sgi, ret);
force_sgi, ret); return ret;
ret = -EINVAL;
goto exit;
} }
arvif->force_sgi = force_sgi; return 0;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
} }
static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask) const struct cfg80211_bitrate_mask *mask)
{ {
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct cfg80211_chan_def def; struct cfg80211_chan_def def;
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
enum ieee80211_band band; enum ieee80211_band band;
u8 fixed_rate = WMI_FIXED_RATE_NONE; u8 rate;
u8 fixed_nss = ar->num_rf_chains; u8 nss;
u8 force_sgi; u8 sgi;
int single_nss;
int ret;
if (ath10k_mac_vif_chan(vif, &def)) if (ath10k_mac_vif_chan(vif, &def))
return -EPERM; return -EPERM;
if (ar->cfg_tx_chainmask)
fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
band = def.chan->band; band = def.chan->band;
force_sgi = mask->control[band].gi; sgi = mask->control[band].gi;
if (force_sgi == NL80211_TXRATE_FORCE_LGI) if (sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL; return -EINVAL;
if (!ath10k_default_bitrate_mask(ar, band, mask)) { if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
if (!ath10k_get_fixed_rate_nss(ar, mask, band, ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
&fixed_rate, &rate, &nss);
&fixed_nss)) if (ret) {
return -EINVAL; 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) { mutex_lock(&ar->conf_mutex);
ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
return -EINVAL; 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, exit:
fixed_nss, force_sgi); mutex_unlock(&ar->conf_mutex);
return ret;
} }
static void ath10k_sta_rc_update(struct ieee80211_hw *hw, 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, .get_antenna = ath10k_get_antenna,
.reconfig_complete = ath10k_reconfig_complete, .reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey, .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, .sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf, .get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action, .ampdu_action = ath10k_ampdu_action,