mac80211: track number of spatial streams

With VHT, a station can change the number of spatial
streams it can receive on the fly, not unlike spatial
multiplexing in HT. Prepare for that by tracking the
maximum number of spatial streams it can receive when
the connection is established.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2012-12-27 18:26:42 +01:00
parent 7bf9b9a0f0
commit 8921d04e8d
4 changed files with 49 additions and 0 deletions

View File

@ -1237,6 +1237,10 @@ enum ieee80211_sta_rx_bandwidth {
* if wme is supported. * if wme is supported.
* @max_sp: max Service Period. Only valid if wme is supported. * @max_sp: max Service Period. Only valid if wme is supported.
* @bandwidth: current bandwidth the station can receive with * @bandwidth: current bandwidth the station can receive with
* @rx_nss: in HT/VHT, the maximum number of spatial streams the
* station can receive at the moment, changed by operating mode
* notifications and capabilities. The value is only valid after
* the station moves to associated state.
*/ */
struct ieee80211_sta { struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS]; u32 supp_rates[IEEE80211_NUM_BANDS];
@ -1247,6 +1251,7 @@ struct ieee80211_sta {
bool wme; bool wme;
u8 uapsd_queues; u8 uapsd_queues;
u8 max_sp; u8 max_sp;
u8 rx_nss;
enum ieee80211_sta_rx_bandwidth bandwidth; enum ieee80211_sta_rx_bandwidth bandwidth;
/* must be last */ /* must be last */

View File

@ -1432,6 +1432,7 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_vht_cap *vht_cap_ie, struct ieee80211_vht_cap *vht_cap_ie,
struct sta_info *sta); struct sta_info *sta);
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
void ieee80211_sta_set_rx_nss(struct sta_info *sta);
/* Spectrum management */ /* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,

View File

@ -68,6 +68,8 @@ static inline void rate_control_rate_init(struct sta_info *sta)
sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
rcu_read_unlock(); rcu_read_unlock();
ieee80211_sta_set_rx_nss(sta);
ref->ops->rate_init(ref->priv, sband, ista, priv_sta); ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL); set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
} }

View File

@ -74,3 +74,44 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
return IEEE80211_STA_RX_BW_80; return IEEE80211_STA_RX_BW_80;
} }
} }
void ieee80211_sta_set_rx_nss(struct sta_info *sta)
{
u8 ht_rx_nss = 0, vht_rx_nss = 0;
/* if we received a notification already don't overwrite it */
if (sta->sta.rx_nss)
return;
if (sta->sta.ht_cap.ht_supported) {
if (sta->sta.ht_cap.mcs.rx_mask[0])
ht_rx_nss++;
if (sta->sta.ht_cap.mcs.rx_mask[1])
ht_rx_nss++;
if (sta->sta.ht_cap.mcs.rx_mask[2])
ht_rx_nss++;
if (sta->sta.ht_cap.mcs.rx_mask[3])
ht_rx_nss++;
/* FIXME: consider rx_highest? */
}
if (sta->sta.vht_cap.vht_supported) {
int i;
u16 rx_mcs_map;
rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map);
for (i = 7; i >= 0; i--) {
u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
vht_rx_nss = i + 1;
break;
}
}
/* FIXME: consider rx_highest? */
}
ht_rx_nss = max(ht_rx_nss, vht_rx_nss);
sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
}