aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
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;