Skip to content

Commit

Permalink
mac80211: wait for beacon before enabling powersave
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Jan 26, 2010
1 parent c21dbf9 commit 56007a0
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 35 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/iwlwifi/iwl-power.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;

if (priv->vif)
dtimper = priv->vif->bss_conf.dtim_period;
dtimper = priv->hw->conf.ps_dtim_period;
else
dtimper = 1;

Expand Down
14 changes: 9 additions & 5 deletions drivers/net/wireless/mwl8k.c
Original file line number Diff line number Diff line change
Expand Up @@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
struct mwl8k_priv *priv =
container_of(work, struct mwl8k_priv, finalize_join_worker);
struct sk_buff *skb = priv->beacon_skb;
struct mwl8k_vif *mwl8k_vif;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM,
mgmt->u.beacon.variable, len);
int dtim_period = 1;

if (tim && tim[1] >= 2)
dtim_period = tim[3];

mwl8k_vif = mwl8k_first_vif(priv);
if (mwl8k_vif != NULL)
mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
mwl8k_vif->vif->bss_conf.dtim_period);
mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period);

dev_kfree_skb(skb);
priv->beacon_skb = NULL;
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/wireless/wl12xx/wl1251.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,6 @@ struct wl1251 {
/* Are we currently scanning */
bool scanning;

/* Our association ID */
u16 aid;

/* Default key (for WEP) */
u32 default_key;

Expand Down
25 changes: 7 additions & 18 deletions drivers/net/wireless/wl12xx/wl1251_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)

wl->psm_requested = true;

wl->dtim_period = conf->ps_dtim_period;

ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
wl->dtim_period);

/*
* We enter PSM only if we're already associated.
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
* mac80211 enables PSM only if we're already associated.
*/
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
Expand Down Expand Up @@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
enum wl1251_cmd_ps_mode mode;
struct wl1251 *wl = hw->priv;
struct sk_buff *beacon, *skb;
int ret;
Expand Down Expand Up @@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->beacon_int = bss_conf->beacon_int;
wl->dtim_period = bss_conf->dtim_period;

ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
wl->dtim_period);
wl->aid = bss_conf->aid;

skb = ieee80211_pspoll_get(wl->hw, wl->vif);
if (!skb)
Expand All @@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;

ret = wl1251_acx_aid(wl, wl->aid);
ret = wl1251_acx_aid(wl, bss_conf->aid);
if (ret < 0)
goto out_sleep;

/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
mode = STATION_POWER_SAVE_MODE;
ret = wl1251_ps_set_mode(wl, mode);
if (ret < 0)
goto out_sleep;
}
} else {
/* use defaults when not associated */
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
Expand Down
7 changes: 6 additions & 1 deletion include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ enum ieee80211_bss_change {
* @use_short_slot: use short slot time (only relevant for ERP);
* if the hardware cannot handle this it must set the
* IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
* @dtim_period: num of beacons before the next DTIM, for PSM
* @dtim_period: num of beacons before the next DTIM, for beaconing,
* not valid in station mode (cf. hw conf ps_dtim_period)
* @timestamp: beacon timestamp
* @beacon_int: beacon interval
* @assoc_capability: capabilities taken from assoc resp
Expand Down Expand Up @@ -648,6 +649,9 @@ enum ieee80211_smps_mode {
* value will be only achievable between DTIM frames, the hardware
* needs to check for the multicast traffic bit in DTIM beacons.
* This variable is valid only when the CONF_PS flag is set.
* @ps_dtim_period: The DTIM period of the AP we're connected to, for use
* in power saving. Power saving will not be enabled until a beacon
* has been received and the DTIM period is known.
* @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
* powersave documentation below. This variable is valid only when
* the CONF_PS flag is set.
Expand All @@ -674,6 +678,7 @@ struct ieee80211_conf {
int max_sleep_period;

u16 listen_interval;
u8 ps_dtim_period;

u8 long_frame_max_tx_count, short_frame_max_tx_count;

Expand Down
27 changes: 24 additions & 3 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)

if (count == 1 && found->u.mgd.powersave &&
found->u.mgd.associated &&
found->u.mgd.associated->beacon_ies &&
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
IEEE80211_STA_CONNECTION_POLL))) {
s32 beaconint_us;
Expand All @@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
if (beaconint_us > latency) {
local->ps_sdata = NULL;
} else {
u8 dtimper = found->vif.bss_conf.dtim_period;
struct ieee80211_bss *bss;
int maxslp = 1;
u8 dtimper;

if (dtimper > 1)
bss = (void *)found->u.mgd.associated->priv;
dtimper = bss->dtim_period;

/* If the TIM IE is invalid, pretend the value is 1 */
if (!dtimper)
dtimper = 1;
else if (dtimper > 1)
maxslp = min_t(int, dtimper,
latency / beaconint_us);

local->hw.conf.max_sleep_period = maxslp;
local->hw.conf.ps_dtim_period = dtimper;
local->ps_sdata = found;
}
} else {
Expand Down Expand Up @@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
/* set timing information */
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
sdata->vif.bss_conf.timestamp = cbss->tsf;
sdata->vif.bss_conf.dtim_period = bss->dtim_period;

bss_info_changed |= BSS_CHANGED_BEACON_INT;
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
Expand Down Expand Up @@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
int freq;
struct ieee80211_bss *bss;
struct ieee80211_channel *channel;
bool need_ps = false;

if (sdata->u.mgd.associated) {
bss = (void *)sdata->u.mgd.associated->priv;
/* not previously set so we may need to recalc */
need_ps = !bss->dtim_period;
}

if (elems->ds_params && elems->ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
Expand All @@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!sdata->u.mgd.associated)
return;

if (need_ps) {
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
}

if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
(memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
ETH_ALEN) == 0)) {
Expand Down
4 changes: 0 additions & 4 deletions net/mac80211/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
bss->dtim_period = tim_ie->dtim_period;
}

/* set default value for buggy AP/no TIM element */
if (bss->dtim_period == 0)
bss->dtim_period = 1;

bss->supp_rates_len = 0;
if (elems->supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
Expand Down

0 comments on commit 56007a0

Please sign in to comment.