diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2010-01-26 08:19:52 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-26 11:53:21 -0500 |
commit | 56007a028c51cbf800a6c969d6f6431d23443b99 (patch) | |
tree | 8bc0280467824ed3b5f95810444b1f8e1ebc2750 | |
parent | c21dbf9214bce129f92e1af05552553ff0e318ed (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.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 25 | ||||
-rw-r--r-- | include/net/mac80211.h | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 27 | ||||
-rw-r--r-- | net/mac80211/scan.c | 4 |
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; |