aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-09-11 08:34:12 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-17 05:02:09 -0400
commit04ecd2578e712c301fa1369d2a8f298a2b4b146a (patch)
tree81fc8135db27831f4456b61c3aeb5d332848b449 /net/mac80211/chan.c
parent55de908ab292c03f1eb280f51170ddb9c6b57e31 (diff)
mac80211: track needed RX chains for channel contexts
On each channel that the device is operating on, it may need to listen using one or more chains depending on the SMPS settings of the interfaces using it. The previous channel context changes completely removed this ability (before, it was available as the SMPS mode). Add per-context tracking of the required static and dynamic RX chains and notify the driver on changes. To achieve this, track the chains and SMPS mode used on each virtual interface and update the channel context whenever this changes. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 41e1aa69f7aa..bfaa486d928c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -118,6 +118,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
118 118
119 ctx->conf.channel = channel; 119 ctx->conf.channel = channel;
120 ctx->conf.channel_type = channel_type; 120 ctx->conf.channel_type = channel_type;
121 ctx->conf.rx_chains_static = 1;
122 ctx->conf.rx_chains_dynamic = 1;
121 ctx->mode = mode; 123 ctx->mode = mode;
122 124
123 if (!local->use_chanctx) { 125 if (!local->use_chanctx) {
@@ -222,8 +224,10 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
222 224
223 drv_unassign_vif_chanctx(local, sdata, ctx); 225 drv_unassign_vif_chanctx(local, sdata, ctx);
224 226
225 if (ctx->refcount > 0) 227 if (ctx->refcount > 0) {
226 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 228 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
229 ieee80211_recalc_smps_chanctx(local, ctx);
230 }
227} 231}
228 232
229static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 233static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
@@ -246,6 +250,89 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
246 ieee80211_free_chanctx(local, ctx); 250 ieee80211_free_chanctx(local, ctx);
247} 251}
248 252
253void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
254 struct ieee80211_chanctx *chanctx)
255{
256 struct ieee80211_sub_if_data *sdata;
257 u8 rx_chains_static, rx_chains_dynamic;
258
259 lockdep_assert_held(&local->chanctx_mtx);
260
261 rx_chains_static = 1;
262 rx_chains_dynamic = 1;
263
264 rcu_read_lock();
265 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
266 u8 needed_static, needed_dynamic;
267
268 if (!ieee80211_sdata_running(sdata))
269 continue;
270
271 if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
272 &chanctx->conf)
273 continue;
274
275 switch (sdata->vif.type) {
276 case NL80211_IFTYPE_P2P_DEVICE:
277 continue;
278 case NL80211_IFTYPE_STATION:
279 if (!sdata->u.mgd.associated)
280 continue;
281 break;
282 case NL80211_IFTYPE_AP_VLAN:
283 continue;
284 case NL80211_IFTYPE_AP:
285 case NL80211_IFTYPE_ADHOC:
286 case NL80211_IFTYPE_WDS:
287 case NL80211_IFTYPE_MESH_POINT:
288 break;
289 default:
290 WARN_ON_ONCE(1);
291 }
292
293 switch (sdata->smps_mode) {
294 default:
295 WARN_ONCE(1, "Invalid SMPS mode %d\n",
296 sdata->smps_mode);
297 /* fall through */
298 case IEEE80211_SMPS_OFF:
299 needed_static = sdata->needed_rx_chains;
300 needed_dynamic = sdata->needed_rx_chains;
301 break;
302 case IEEE80211_SMPS_DYNAMIC:
303 needed_static = 1;
304 needed_dynamic = sdata->needed_rx_chains;
305 break;
306 case IEEE80211_SMPS_STATIC:
307 needed_static = 1;
308 needed_dynamic = 1;
309 break;
310 }
311
312 rx_chains_static = max(rx_chains_static, needed_static);
313 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
314 }
315 rcu_read_unlock();
316
317 if (!local->use_chanctx) {
318 if (rx_chains_static > 1)
319 local->smps_mode = IEEE80211_SMPS_OFF;
320 else if (rx_chains_dynamic > 1)
321 local->smps_mode = IEEE80211_SMPS_DYNAMIC;
322 else
323 local->smps_mode = IEEE80211_SMPS_STATIC;
324 ieee80211_hw_config(local, 0);
325 }
326
327 if (rx_chains_static == chanctx->conf.rx_chains_static &&
328 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
329 return;
330
331 chanctx->conf.rx_chains_static = rx_chains_static;
332 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
333 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
334}
335
249int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, 336int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
250 struct ieee80211_channel *channel, 337 struct ieee80211_channel *channel,
251 enum nl80211_channel_type channel_type, 338 enum nl80211_channel_type channel_type,
@@ -278,6 +365,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
278 goto out; 365 goto out;
279 } 366 }
280 367
368 ieee80211_recalc_smps_chanctx(local, ctx);
281 out: 369 out:
282 mutex_unlock(&local->chanctx_mtx); 370 mutex_unlock(&local->chanctx_mtx);
283 return ret; 371 return ret;