aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-01-26 08:19:52 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-26 11:53:21 -0500
commit56007a028c51cbf800a6c969d6f6431d23443b99 (patch)
tree8bc0280467824ed3b5f95810444b1f8e1ebc2750
parentc21dbf9214bce129f92e1af05552553ff0e318ed (diff)
mac80211: wait for beacon before enabling powersave
Because DTIM information is required for powersave but is only conveyed in beacons, wait for a beacon before enabling powersave, and change the way the information is conveyed to the driver accordingly. mwl8k doesn't currently seem to implement PS but requires the DTIM period in a different way; after talking to Lennert we agreed to just have mwl8k do the parsing itself in the finalize_join work. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c2
-rw-r--r--drivers/net/wireless/mwl8k.c14
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c25
-rw-r--r--include/net/mac80211.h7
-rw-r--r--net/mac80211/mlme.c27
-rw-r--r--net/mac80211/scan.c4
7 files changed, 47 insertions, 35 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 8599444bef01..9e3ca0641451 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -319,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
319 priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; 319 priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
320 320
321 if (priv->vif) 321 if (priv->vif)
322 dtimper = priv->vif->bss_conf.dtim_period; 322 dtimper = priv->hw->conf.ps_dtim_period;
323 else 323 else
324 dtimper = 1; 324 dtimper = 1;
325 325
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 68546ca0ba37..f0f08f3919cc 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
3881 struct mwl8k_priv *priv = 3881 struct mwl8k_priv *priv =
3882 container_of(work, struct mwl8k_priv, finalize_join_worker); 3882 container_of(work, struct mwl8k_priv, finalize_join_worker);
3883 struct sk_buff *skb = priv->beacon_skb; 3883 struct sk_buff *skb = priv->beacon_skb;
3884 struct mwl8k_vif *mwl8k_vif; 3884 struct ieee80211_mgmt *mgmt = (void *)skb->data;
3885 int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
3886 const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM,
3887 mgmt->u.beacon.variable, len);
3888 int dtim_period = 1;
3889
3890 if (tim && tim[1] >= 2)
3891 dtim_period = tim[3];
3885 3892
3886 mwl8k_vif = mwl8k_first_vif(priv); 3893 mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period);
3887 if (mwl8k_vif != NULL)
3888 mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
3889 mwl8k_vif->vif->bss_conf.dtim_period);
3890 3894
3891 dev_kfree_skb(skb); 3895 dev_kfree_skb(skb);
3892 priv->beacon_skb = NULL; 3896 priv->beacon_skb = NULL;
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 6301578d1565..37c61c19cae5 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -341,9 +341,6 @@ struct wl1251 {
341 /* Are we currently scanning */ 341 /* Are we currently scanning */
342 bool scanning; 342 bool scanning;
343 343
344 /* Our association ID */
345 u16 aid;
346
347 /* Default key (for WEP) */ 344 /* Default key (for WEP) */
348 u32 default_key; 345 u32 default_key;
349 346
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 595f0f94d16e..a717dde4822e 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
617 617
618 wl->psm_requested = true; 618 wl->psm_requested = true;
619 619
620 wl->dtim_period = conf->ps_dtim_period;
621
622 ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
623 wl->dtim_period);
624
620 /* 625 /*
621 * We enter PSM only if we're already associated. 626 * mac80211 enables PSM only if we're already associated.
622 * If we're not, we'll enter it when joining an SSID,
623 * through the bss_info_changed() hook.
624 */ 627 */
625 ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); 628 ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
626 if (ret < 0) 629 if (ret < 0)
@@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
943 struct ieee80211_bss_conf *bss_conf, 946 struct ieee80211_bss_conf *bss_conf,
944 u32 changed) 947 u32 changed)
945{ 948{
946 enum wl1251_cmd_ps_mode mode;
947 struct wl1251 *wl = hw->priv; 949 struct wl1251 *wl = hw->priv;
948 struct sk_buff *beacon, *skb; 950 struct sk_buff *beacon, *skb;
949 int ret; 951 int ret;
@@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
984 if (changed & BSS_CHANGED_ASSOC) { 986 if (changed & BSS_CHANGED_ASSOC) {
985 if (bss_conf->assoc) { 987 if (bss_conf->assoc) {
986 wl->beacon_int = bss_conf->beacon_int; 988 wl->beacon_int = bss_conf->beacon_int;
987 wl->dtim_period = bss_conf->dtim_period;
988
989 ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
990 wl->dtim_period);
991 wl->aid = bss_conf->aid;
992 989
993 skb = ieee80211_pspoll_get(wl->hw, wl->vif); 990 skb = ieee80211_pspoll_get(wl->hw, wl->vif);
994 if (!skb) 991 if (!skb)
@@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
1001 if (ret < 0) 998 if (ret < 0)
1002 goto out_sleep; 999 goto out_sleep;
1003 1000
1004 ret = wl1251_acx_aid(wl, wl->aid); 1001 ret = wl1251_acx_aid(wl, bss_conf->aid);
1005 if (ret < 0) 1002 if (ret < 0)
1006 goto out_sleep; 1003 goto out_sleep;
1007
1008 /* If we want to go in PSM but we're not there yet */
1009 if (wl->psm_requested && !wl->psm) {
1010 mode = STATION_POWER_SAVE_MODE;
1011 ret = wl1251_ps_set_mode(wl, mode);
1012 if (ret < 0)
1013 goto out_sleep;
1014 }
1015 } else { 1004 } else {
1016 /* use defaults when not associated */ 1005 /* use defaults when not associated */
1017 wl->beacon_int = WL1251_DEFAULT_BEACON_INT; 1006 wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f64402f6312b..1e9c93024cf2 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -186,7 +186,8 @@ enum ieee80211_bss_change {
186 * @use_short_slot: use short slot time (only relevant for ERP); 186 * @use_short_slot: use short slot time (only relevant for ERP);
187 * if the hardware cannot handle this it must set the 187 * if the hardware cannot handle this it must set the
188 * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag 188 * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
189 * @dtim_period: num of beacons before the next DTIM, for PSM 189 * @dtim_period: num of beacons before the next DTIM, for beaconing,
190 * not valid in station mode (cf. hw conf ps_dtim_period)
190 * @timestamp: beacon timestamp 191 * @timestamp: beacon timestamp
191 * @beacon_int: beacon interval 192 * @beacon_int: beacon interval
192 * @assoc_capability: capabilities taken from assoc resp 193 * @assoc_capability: capabilities taken from assoc resp
@@ -648,6 +649,9 @@ enum ieee80211_smps_mode {
648 * value will be only achievable between DTIM frames, the hardware 649 * value will be only achievable between DTIM frames, the hardware
649 * needs to check for the multicast traffic bit in DTIM beacons. 650 * needs to check for the multicast traffic bit in DTIM beacons.
650 * This variable is valid only when the CONF_PS flag is set. 651 * This variable is valid only when the CONF_PS flag is set.
652 * @ps_dtim_period: The DTIM period of the AP we're connected to, for use
653 * in power saving. Power saving will not be enabled until a beacon
654 * has been received and the DTIM period is known.
651 * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the 655 * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
652 * powersave documentation below. This variable is valid only when 656 * powersave documentation below. This variable is valid only when
653 * the CONF_PS flag is set. 657 * the CONF_PS flag is set.
@@ -674,6 +678,7 @@ struct ieee80211_conf {
674 int max_sleep_period; 678 int max_sleep_period;
675 679
676 u16 listen_interval; 680 u16 listen_interval;
681 u8 ps_dtim_period;
677 682
678 u8 long_frame_max_tx_count, short_frame_max_tx_count; 683 u8 long_frame_max_tx_count, short_frame_max_tx_count;
679 684
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1e1d16c55ee5..86c6ad1b058d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
484 484
485 if (count == 1 && found->u.mgd.powersave && 485 if (count == 1 && found->u.mgd.powersave &&
486 found->u.mgd.associated && 486 found->u.mgd.associated &&
487 found->u.mgd.associated->beacon_ies &&
487 !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | 488 !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
488 IEEE80211_STA_CONNECTION_POLL))) { 489 IEEE80211_STA_CONNECTION_POLL))) {
489 s32 beaconint_us; 490 s32 beaconint_us;
@@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
497 if (beaconint_us > latency) { 498 if (beaconint_us > latency) {
498 local->ps_sdata = NULL; 499 local->ps_sdata = NULL;
499 } else { 500 } else {
500 u8 dtimper = found->vif.bss_conf.dtim_period; 501 struct ieee80211_bss *bss;
501 int maxslp = 1; 502 int maxslp = 1;
503 u8 dtimper;
502 504
503 if (dtimper > 1) 505 bss = (void *)found->u.mgd.associated->priv;
506 dtimper = bss->dtim_period;
507
508 /* If the TIM IE is invalid, pretend the value is 1 */
509 if (!dtimper)
510 dtimper = 1;
511 else if (dtimper > 1)
504 maxslp = min_t(int, dtimper, 512 maxslp = min_t(int, dtimper,
505 latency / beaconint_us); 513 latency / beaconint_us);
506 514
507 local->hw.conf.max_sleep_period = maxslp; 515 local->hw.conf.max_sleep_period = maxslp;
516 local->hw.conf.ps_dtim_period = dtimper;
508 local->ps_sdata = found; 517 local->ps_sdata = found;
509 } 518 }
510 } else { 519 } else {
@@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
702 /* set timing information */ 711 /* set timing information */
703 sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; 712 sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
704 sdata->vif.bss_conf.timestamp = cbss->tsf; 713 sdata->vif.bss_conf.timestamp = cbss->tsf;
705 sdata->vif.bss_conf.dtim_period = bss->dtim_period;
706 714
707 bss_info_changed |= BSS_CHANGED_BEACON_INT; 715 bss_info_changed |= BSS_CHANGED_BEACON_INT;
708 bss_info_changed |= ieee80211_handle_bss_capability(sdata, 716 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1168 int freq; 1176 int freq;
1169 struct ieee80211_bss *bss; 1177 struct ieee80211_bss *bss;
1170 struct ieee80211_channel *channel; 1178 struct ieee80211_channel *channel;
1179 bool need_ps = false;
1180
1181 if (sdata->u.mgd.associated) {
1182 bss = (void *)sdata->u.mgd.associated->priv;
1183 /* not previously set so we may need to recalc */
1184 need_ps = !bss->dtim_period;
1185 }
1171 1186
1172 if (elems->ds_params && elems->ds_params_len == 1) 1187 if (elems->ds_params && elems->ds_params_len == 1)
1173 freq = ieee80211_channel_to_frequency(elems->ds_params[0]); 1188 freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
@@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1187 if (!sdata->u.mgd.associated) 1202 if (!sdata->u.mgd.associated)
1188 return; 1203 return;
1189 1204
1205 if (need_ps) {
1206 mutex_lock(&local->iflist_mtx);
1207 ieee80211_recalc_ps(local, -1);
1208 mutex_unlock(&local->iflist_mtx);
1209 }
1210
1190 if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && 1211 if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
1191 (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, 1212 (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
1192 ETH_ALEN) == 0)) { 1213 ETH_ALEN) == 0)) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 9afe2f9885dc..bc061f629674 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
111 bss->dtim_period = tim_ie->dtim_period; 111 bss->dtim_period = tim_ie->dtim_period;
112 } 112 }
113 113
114 /* set default value for buggy AP/no TIM element */
115 if (bss->dtim_period == 0)
116 bss->dtim_period = 1;
117
118 bss->supp_rates_len = 0; 114 bss->supp_rates_len = 0;
119 if (elems->supp_rates) { 115 if (elems->supp_rates) {
120 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 116 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;