aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-12-01 07:37:02 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-22 13:31:16 -0500
commit0f78231bffb868a30e8533aace142213266bb811 (patch)
tree317f65dc6d89e9a89ad83f94fadd780dd1e0ca83 /net/mac80211/mlme.c
parent18974b5b0b5e758d416c550553b143e5c8038281 (diff)
mac80211: enable spatial multiplexing powersave
Enable spatial multiplexing in mac80211 by telling the driver what to do and, where necessary, sending action frames to the AP to update the requested SMPS mode. Also includes a trivial implementation for hwsim that just logs the requested mode. For now, the userspace interface is in debugfs only, and let you toggle the requested mode at any time. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cd5dcc3d8c2b..0a762a9ba4df 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -398,6 +398,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
398 __le16 tmp; 398 __le16 tmp;
399 u32 flags = local->hw.conf.channel->flags; 399 u32 flags = local->hw.conf.channel->flags;
400 400
401 /* determine capability flags */
402
401 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 403 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
402 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 404 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
403 if (flags & IEEE80211_CHAN_NO_HT40PLUS) { 405 if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
@@ -413,17 +415,64 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
413 break; 415 break;
414 } 416 }
415 417
416 tmp = cpu_to_le16(cap); 418 /* set SM PS mode properly */
417 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); 419 cap &= ~IEEE80211_HT_CAP_SM_PS;
420 /* new association always uses requested smps mode */
421 if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
422 if (ifmgd->powersave)
423 ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
424 else
425 ifmgd->ap_smps = IEEE80211_SMPS_OFF;
426 } else
427 ifmgd->ap_smps = ifmgd->req_smps;
428
429 switch (ifmgd->ap_smps) {
430 case IEEE80211_SMPS_AUTOMATIC:
431 case IEEE80211_SMPS_NUM_MODES:
432 WARN_ON(1);
433 case IEEE80211_SMPS_OFF:
434 cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
435 IEEE80211_HT_CAP_SM_PS_SHIFT;
436 break;
437 case IEEE80211_SMPS_STATIC:
438 cap |= WLAN_HT_CAP_SM_PS_STATIC <<
439 IEEE80211_HT_CAP_SM_PS_SHIFT;
440 break;
441 case IEEE80211_SMPS_DYNAMIC:
442 cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
443 IEEE80211_HT_CAP_SM_PS_SHIFT;
444 break;
445 }
446
447 /* reserve and fill IE */
448
449 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
418 *pos++ = WLAN_EID_HT_CAPABILITY; 450 *pos++ = WLAN_EID_HT_CAPABILITY;
419 *pos++ = sizeof(struct ieee80211_ht_cap); 451 *pos++ = sizeof(struct ieee80211_ht_cap);
420 memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 452 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
453
454 /* capability flags */
455 tmp = cpu_to_le16(cap);
421 memcpy(pos, &tmp, sizeof(u16)); 456 memcpy(pos, &tmp, sizeof(u16));
422 pos += sizeof(u16); 457 pos += sizeof(u16);
423 /* TODO: needs a define here for << 2 */ 458
459 /* AMPDU parameters */
424 *pos++ = sband->ht_cap.ampdu_factor | 460 *pos++ = sband->ht_cap.ampdu_factor |
425 (sband->ht_cap.ampdu_density << 2); 461 (sband->ht_cap.ampdu_density <<
462 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
463
464 /* MCS set */
426 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 465 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
466 pos += sizeof(sband->ht_cap.mcs);
467
468 /* extended capabilities */
469 pos += sizeof(__le16);
470
471 /* BF capabilities */
472 pos += sizeof(__le32);
473
474 /* antenna selection */
475 pos += sizeof(u8);
427 } 476 }
428 477
429 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 478 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -932,6 +981,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
932 981
933 mutex_lock(&local->iflist_mtx); 982 mutex_lock(&local->iflist_mtx);
934 ieee80211_recalc_ps(local, -1); 983 ieee80211_recalc_ps(local, -1);
984 ieee80211_recalc_smps(local, sdata);
935 mutex_unlock(&local->iflist_mtx); 985 mutex_unlock(&local->iflist_mtx);
936 986
937 netif_start_queue(sdata->dev); 987 netif_start_queue(sdata->dev);
@@ -2327,6 +2377,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
2327 ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; 2377 ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
2328 2378
2329 mutex_init(&ifmgd->mtx); 2379 mutex_init(&ifmgd->mtx);
2380
2381 if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
2382 ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
2383 else
2384 ifmgd->req_smps = IEEE80211_SMPS_OFF;
2330} 2385}
2331 2386
2332/* scan finished notification */ 2387/* scan finished notification */