mac80211: separate Tx and Rx MCS when configuring HT

This patch follows the 11n spec in separation between Tx and Rx MCS
capabilities. Up until now, when configuring the HT possible set of Tx
MCS only Rx MCS were considered, assuming they are the same as the Tx MCS.
This patch fixed this by looking at low level driver Tx capabilities.

Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Ron Rindjunsky
2008-05-15 13:53:55 +08:00
committed by John W. Linville
parent 0b794d63c5
commit edcdf8b21a
3 changed files with 87 additions and 49 deletions

View File

@@ -35,8 +35,6 @@
#include "debugfs.h"
#include "debugfs_netdev.h"
#define SUPP_MCS_SET_LEN 16
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
@@ -1068,56 +1066,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_supported_band *sband;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
int i;
u32 changed = 0;
int i;
u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
u8 tx_mcs_set_cap;
sband = local->hw.wiphy->bands[conf->channel->band];
/* HT is not supported */
if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
return 0;
}
memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
if (enable_ht) {
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
changed |= BSS_CHANGED_HT;
/* HT is not supported */
if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
goto out;
}
conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
ht_conf.ht_supported = 1;
ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
for (i = 0; i < SUPP_MCS_SET_LEN; i++)
ht_conf.supp_mcs_set[i] =
sband->ht_info.supp_mcs_set[i] &
req_ht_cap->supp_mcs_set[i];
ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
ht_conf.ampdu_density = req_ht_cap->ampdu_density;
/* if bss configuration changed store the new one */
if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
changed |= BSS_CHANGED_HT;
memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
}
} else {
/* disable HT */
if (!enable_ht) {
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
changed |= BSS_CHANGED_HT;
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
conf->ht_conf.ht_supported = 0;
goto out;
}
if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
changed |= BSS_CHANGED_HT;
conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
ht_conf.ht_supported = 1;
ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
ht_conf.ampdu_density = req_ht_cap->ampdu_density;
/* Bits 96-100 */
tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
/* configure suppoerted Tx MCS according to requested MCS
* (based in most cases on Rx capabilities of peer) and self
* Tx MCS capabilities (as defined by low level driver HW
* Tx capabilities) */
if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
goto check_changed;
/* Counting from 0 therfore + 1 */
if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
max_tx_streams = ((tx_mcs_set_cap &
IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
for (i = 0; i < max_tx_streams; i++)
ht_conf.supp_mcs_set[i] =
sband->ht_info.supp_mcs_set[i] &
req_ht_cap->supp_mcs_set[i];
if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
for (i = IEEE80211_SUPP_MCS_SET_UEQM;
i < IEEE80211_SUPP_MCS_SET_LEN; i++)
ht_conf.supp_mcs_set[i] =
sband->ht_info.supp_mcs_set[i] &
req_ht_cap->supp_mcs_set[i];
check_changed:
/* if bss configuration changed store the new one */
if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
changed |= BSS_CHANGED_HT;
memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
}
out:
return changed;
}