diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-02-07 05:47:44 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-15 03:41:30 -0500 |
commit | e1a0c6b3a4b27ed5f21291d0bbee2167ec201ef5 (patch) | |
tree | 18e5c9bd022ea469e7350a52ca67ce505a7608e6 /net/mac80211/ht.c | |
parent | 4a34215ef7487b1cbd783e7cc485eb03de893bd0 (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.c | 82 |
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 | ||
92 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 95 | bool 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 | ||
200 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 218 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |