mac80211: track number of spatial streams
authorJohannes Berg <johannes.berg@intel.com>
Thu, 27 Dec 2012 17:26:42 +0000 (18:26 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 15 Feb 2013 08:41:31 +0000 (09:41 +0100)
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>
include/net/mac80211.h
net/mac80211/ieee80211_i.h
net/mac80211/rate.h
net/mac80211/vht.c

index 1e3b4f730397c86e56f7b9166be42692bb5aedf0..a608ab9879b41a2aefd1b389844d7484d45608ef 100644 (file)
@@ -1237,6 +1237,10 @@ enum ieee80211_sta_rx_bandwidth {
  *     if wme is supported.
  * @max_sp: max Service Period. Only valid if wme is supported.
  * @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 {
        u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -1247,6 +1251,7 @@ struct ieee80211_sta {
        bool wme;
        u8 uapsd_queues;
        u8 max_sp;
+       u8 rx_nss;
        enum ieee80211_sta_rx_bandwidth bandwidth;
 
        /* must be last */
index 6b41d7787a5a7d5ec0705aa1e79429e4878ef08f..3b13af4e6c49cf0a4d2effe5f40e04bc1eda5169 100644 (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 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 */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
index 301386dabf88da51f205d0961021e47cdbbb1ddf..d35a5dd3fb13d3f6d742cdc2ccbbeb823365ed63 100644 (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];
        rcu_read_unlock();
 
+       ieee80211_sta_set_rx_nss(sta);
+
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
        set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
 }
index 0fc9a2fb8d535efa929a27cf2a2c7d5f75ae2118..67436e3efbbd6cb3cc957877a9db3d4e256ae879 100644 (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;
        }
 }
+
+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);
+}