aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-07 05:47:44 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:41:30 -0500
commite1a0c6b3a4b27ed5f21291d0bbee2167ec201ef5 (patch)
tree18e5c9bd022ea469e7350a52ca67ce505a7608e6 /net/mac80211/ht.c
parent4a34215ef7487b1cbd783e7cc485eb03de893bd0 (diff)
mac80211: stop toggling IEEE80211_HT_CAP_SUP_WIDTH_20_40
For VHT, many more bandwidth changes are possible. As a first step, stop toggling the IEEE80211_HT_CAP_SUP_WIDTH_20_40 flag in the HT capabilities and instead introduce a bandwidth field indicating the currently usable bandwidth to transmit to the station. Of course, make all drivers use it. To achieve this, make ieee80211_ht_cap_ie_to_sta_ht_cap() get the station as an argument, rather than the new capabilities, so it can set up the new bandwidth field. If the station is a VHT station and VHT bandwidth is in use, also set the bandwidth accordingly. Doing this allows us to get rid of the supports_40mhz flag as the HT capabilities now reflect the true capability instead of the current setting. While at it, also fix ieee80211_ht_cap_ie_to_sta_ht_cap() to not ignore HT cap overrides when MCS TX isn't supported (not that it really happens...) Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c82
1 files changed, 50 insertions, 32 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 9e7560becbbb..a64b4f0d373f 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
37 u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); 37 u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
38 int i; 38 int i;
39 39
40 if (!ht_cap->ht_supported)
41 return;
42
40 if (sdata->vif.type != NL80211_IFTYPE_STATION) { 43 if (sdata->vif.type != NL80211_IFTYPE_STATION) {
41 /* AP interfaces call this code when adding new stations, 44 /* AP interfaces call this code when adding new stations,
42 * so just silently ignore non station interfaces. 45 * so just silently ignore non station interfaces.
@@ -89,22 +92,23 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
89} 92}
90 93
91 94
92void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, 95bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
93 struct ieee80211_supported_band *sband, 96 struct ieee80211_supported_band *sband,
94 struct ieee80211_ht_cap *ht_cap_ie, 97 struct ieee80211_ht_cap *ht_cap_ie,
95 struct ieee80211_sta_ht_cap *ht_cap) 98 struct sta_info *sta)
96{ 99{
100 struct ieee80211_sta_ht_cap ht_cap;
97 u8 ampdu_info, tx_mcs_set_cap; 101 u8 ampdu_info, tx_mcs_set_cap;
98 int i, max_tx_streams; 102 int i, max_tx_streams;
103 bool changed;
104 enum ieee80211_sta_rx_bandwidth bw;
99 105
100 BUG_ON(!ht_cap); 106 memset(&ht_cap, 0, sizeof(ht_cap));
101
102 memset(ht_cap, 0, sizeof(*ht_cap));
103 107
104 if (!ht_cap_ie || !sband->ht_cap.ht_supported) 108 if (!ht_cap_ie || !sband->ht_cap.ht_supported)
105 return; 109 goto apply;
106 110
107 ht_cap->ht_supported = true; 111 ht_cap.ht_supported = true;
108 112
109 /* 113 /*
110 * The bits listed in this expression should be 114 * The bits listed in this expression should be
@@ -112,7 +116,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
112 * advertises more then we can't use those thus 116 * advertises more then we can't use those thus
113 * we mask them out. 117 * we mask them out.
114 */ 118 */
115 ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & 119 ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
116 (sband->ht_cap.cap | 120 (sband->ht_cap.cap |
117 ~(IEEE80211_HT_CAP_LDPC_CODING | 121 ~(IEEE80211_HT_CAP_LDPC_CODING |
118 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 122 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -121,44 +125,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
121 IEEE80211_HT_CAP_SGI_40 | 125 IEEE80211_HT_CAP_SGI_40 |
122 IEEE80211_HT_CAP_DSSSCCK40)); 126 IEEE80211_HT_CAP_DSSSCCK40));
123 127
124 /* Unset 40 MHz if we're not using a 40 MHz channel */
125 switch (sdata->vif.bss_conf.chandef.width) {
126 case NL80211_CHAN_WIDTH_20_NOHT:
127 case NL80211_CHAN_WIDTH_20:
128 ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40;
129 ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
130 break;
131 case NL80211_CHAN_WIDTH_40:
132 case NL80211_CHAN_WIDTH_80:
133 case NL80211_CHAN_WIDTH_80P80:
134 case NL80211_CHAN_WIDTH_160:
135 break;
136 }
137
138 /* 128 /*
139 * The STBC bits are asymmetric -- if we don't have 129 * The STBC bits are asymmetric -- if we don't have
140 * TX then mask out the peer's RX and vice versa. 130 * TX then mask out the peer's RX and vice versa.
141 */ 131 */
142 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) 132 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
143 ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; 133 ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
144 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) 134 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
145 ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 135 ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
146 136
147 ampdu_info = ht_cap_ie->ampdu_params_info; 137 ampdu_info = ht_cap_ie->ampdu_params_info;
148 ht_cap->ampdu_factor = 138 ht_cap.ampdu_factor =
149 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; 139 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
150 ht_cap->ampdu_density = 140 ht_cap.ampdu_density =
151 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; 141 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
152 142
153 /* own MCS TX capabilities */ 143 /* own MCS TX capabilities */
154 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; 144 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
155 145
156 /* Copy peer MCS TX capabilities, the driver might need them. */ 146 /* Copy peer MCS TX capabilities, the driver might need them. */
157 ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; 147 ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
158 148
159 /* can we TX with MCS rates? */ 149 /* can we TX with MCS rates? */
160 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) 150 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
161 return; 151 goto apply;
162 152
163 /* Counting from 0, therefore +1 */ 153 /* Counting from 0, therefore +1 */
164 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) 154 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
@@ -176,25 +166,53 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
176 * - remainder are multiple spatial streams using unequal modulation 166 * - remainder are multiple spatial streams using unequal modulation
177 */ 167 */
178 for (i = 0; i < max_tx_streams; i++) 168 for (i = 0; i < max_tx_streams; i++)
179 ht_cap->mcs.rx_mask[i] = 169 ht_cap.mcs.rx_mask[i] =
180 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; 170 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
181 171
182 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) 172 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
183 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; 173 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
184 i < IEEE80211_HT_MCS_MASK_LEN; i++) 174 i < IEEE80211_HT_MCS_MASK_LEN; i++)
185 ht_cap->mcs.rx_mask[i] = 175 ht_cap.mcs.rx_mask[i] =
186 sband->ht_cap.mcs.rx_mask[i] & 176 sband->ht_cap.mcs.rx_mask[i] &
187 ht_cap_ie->mcs.rx_mask[i]; 177 ht_cap_ie->mcs.rx_mask[i];
188 178
189 /* handle MCS rate 32 too */ 179 /* handle MCS rate 32 too */
190 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) 180 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
191 ht_cap->mcs.rx_mask[32/8] |= 1; 181 ht_cap.mcs.rx_mask[32/8] |= 1;
192 182
183 apply:
193 /* 184 /*
194 * If user has specified capability over-rides, take care 185 * If user has specified capability over-rides, take care
195 * of that here. 186 * of that here.
196 */ 187 */
197 ieee80211_apply_htcap_overrides(sdata, ht_cap); 188 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
189
190 changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
191
192 memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
193
194 switch (sdata->vif.bss_conf.chandef.width) {
195 default:
196 WARN_ON_ONCE(1);
197 /* fall through */
198 case NL80211_CHAN_WIDTH_20_NOHT:
199 case NL80211_CHAN_WIDTH_20:
200 bw = IEEE80211_STA_RX_BW_20;
201 break;
202 case NL80211_CHAN_WIDTH_40:
203 case NL80211_CHAN_WIDTH_80:
204 case NL80211_CHAN_WIDTH_80P80:
205 case NL80211_CHAN_WIDTH_160:
206 bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
207 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
208 break;
209 }
210
211 if (bw != sta->sta.bandwidth)
212 changed = true;
213 sta->sta.bandwidth = bw;
214
215 return changed;
198} 216}
199 217
200void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, 218void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,