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>
This commit is contained in:
parent
c21dbf9214
commit
56007a028c
7 changed files with 47 additions and 35 deletions
|
@ -319,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
||||||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
|
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
|
||||||
|
|
||||||
if (priv->vif)
|
if (priv->vif)
|
||||||
dtimper = priv->vif->bss_conf.dtim_period;
|
dtimper = priv->hw->conf.ps_dtim_period;
|
||||||
else
|
else
|
||||||
dtimper = 1;
|
dtimper = 1;
|
||||||
|
|
||||||
|
|
|
@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
|
||||||
struct mwl8k_priv *priv =
|
struct mwl8k_priv *priv =
|
||||||
container_of(work, struct mwl8k_priv, finalize_join_worker);
|
container_of(work, struct mwl8k_priv, finalize_join_worker);
|
||||||
struct sk_buff *skb = priv->beacon_skb;
|
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;
|
||||||
|
|
||||||
mwl8k_vif = mwl8k_first_vif(priv);
|
if (tim && tim[1] >= 2)
|
||||||
if (mwl8k_vif != NULL)
|
dtim_period = tim[3];
|
||||||
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);
|
dev_kfree_skb(skb);
|
||||||
priv->beacon_skb = NULL;
|
priv->beacon_skb = NULL;
|
||||||
|
|
|
@ -341,9 +341,6 @@ struct wl1251 {
|
||||||
/* Are we currently scanning */
|
/* Are we currently scanning */
|
||||||
bool scanning;
|
bool scanning;
|
||||||
|
|
||||||
/* Our association ID */
|
|
||||||
u16 aid;
|
|
||||||
|
|
||||||
/* Default key (for WEP) */
|
/* Default key (for WEP) */
|
||||||
u32 default_key;
|
u32 default_key;
|
||||||
|
|
||||||
|
|
|
@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
|
|
||||||
wl->psm_requested = true;
|
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.
|
* mac80211 enables 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.
|
|
||||||
*/
|
*/
|
||||||
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
|
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_bss_conf *bss_conf,
|
struct ieee80211_bss_conf *bss_conf,
|
||||||
u32 changed)
|
u32 changed)
|
||||||
{
|
{
|
||||||
enum wl1251_cmd_ps_mode mode;
|
|
||||||
struct wl1251 *wl = hw->priv;
|
struct wl1251 *wl = hw->priv;
|
||||||
struct sk_buff *beacon, *skb;
|
struct sk_buff *beacon, *skb;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
if (changed & BSS_CHANGED_ASSOC) {
|
if (changed & BSS_CHANGED_ASSOC) {
|
||||||
if (bss_conf->assoc) {
|
if (bss_conf->assoc) {
|
||||||
wl->beacon_int = bss_conf->beacon_int;
|
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);
|
skb = ieee80211_pspoll_get(wl->hw, wl->vif);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
|
@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_sleep;
|
goto out_sleep;
|
||||||
|
|
||||||
ret = wl1251_acx_aid(wl, wl->aid);
|
ret = wl1251_acx_aid(wl, bss_conf->aid);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_sleep;
|
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 {
|
} else {
|
||||||
/* use defaults when not associated */
|
/* use defaults when not associated */
|
||||||
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
||||||
|
|
|
@ -186,7 +186,8 @@ enum ieee80211_bss_change {
|
||||||
* @use_short_slot: use short slot time (only relevant for ERP);
|
* @use_short_slot: use short slot time (only relevant for ERP);
|
||||||
* if the hardware cannot handle this it must set the
|
* if the hardware cannot handle this it must set the
|
||||||
* IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
|
* 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
|
* @timestamp: beacon timestamp
|
||||||
* @beacon_int: beacon interval
|
* @beacon_int: beacon interval
|
||||||
* @assoc_capability: capabilities taken from assoc resp
|
* @assoc_capability: capabilities taken from assoc resp
|
||||||
|
@ -648,6 +649,9 @@ enum ieee80211_smps_mode {
|
||||||
* value will be only achievable between DTIM frames, the hardware
|
* value will be only achievable between DTIM frames, the hardware
|
||||||
* needs to check for the multicast traffic bit in DTIM beacons.
|
* needs to check for the multicast traffic bit in DTIM beacons.
|
||||||
* This variable is valid only when the CONF_PS flag is set.
|
* 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
|
* @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
|
||||||
* powersave documentation below. This variable is valid only when
|
* powersave documentation below. This variable is valid only when
|
||||||
* the CONF_PS flag is set.
|
* the CONF_PS flag is set.
|
||||||
|
@ -674,6 +678,7 @@ struct ieee80211_conf {
|
||||||
int max_sleep_period;
|
int max_sleep_period;
|
||||||
|
|
||||||
u16 listen_interval;
|
u16 listen_interval;
|
||||||
|
u8 ps_dtim_period;
|
||||||
|
|
||||||
u8 long_frame_max_tx_count, short_frame_max_tx_count;
|
u8 long_frame_max_tx_count, short_frame_max_tx_count;
|
||||||
|
|
||||||
|
|
|
@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||||
|
|
||||||
if (count == 1 && found->u.mgd.powersave &&
|
if (count == 1 && found->u.mgd.powersave &&
|
||||||
found->u.mgd.associated &&
|
found->u.mgd.associated &&
|
||||||
|
found->u.mgd.associated->beacon_ies &&
|
||||||
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
|
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
|
||||||
IEEE80211_STA_CONNECTION_POLL))) {
|
IEEE80211_STA_CONNECTION_POLL))) {
|
||||||
s32 beaconint_us;
|
s32 beaconint_us;
|
||||||
|
@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||||
if (beaconint_us > latency) {
|
if (beaconint_us > latency) {
|
||||||
local->ps_sdata = NULL;
|
local->ps_sdata = NULL;
|
||||||
} else {
|
} else {
|
||||||
u8 dtimper = found->vif.bss_conf.dtim_period;
|
struct ieee80211_bss *bss;
|
||||||
int maxslp = 1;
|
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,
|
maxslp = min_t(int, dtimper,
|
||||||
latency / beaconint_us);
|
latency / beaconint_us);
|
||||||
|
|
||||||
local->hw.conf.max_sleep_period = maxslp;
|
local->hw.conf.max_sleep_period = maxslp;
|
||||||
|
local->hw.conf.ps_dtim_period = dtimper;
|
||||||
local->ps_sdata = found;
|
local->ps_sdata = found;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||||
/* set timing information */
|
/* set timing information */
|
||||||
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
|
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
|
||||||
sdata->vif.bss_conf.timestamp = cbss->tsf;
|
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 |= BSS_CHANGED_BEACON_INT;
|
||||||
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
|
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
|
||||||
|
@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||||
int freq;
|
int freq;
|
||||||
struct ieee80211_bss *bss;
|
struct ieee80211_bss *bss;
|
||||||
struct ieee80211_channel *channel;
|
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)
|
if (elems->ds_params && elems->ds_params_len == 1)
|
||||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
|
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,
|
||||||
if (!sdata->u.mgd.associated)
|
if (!sdata->u.mgd.associated)
|
||||||
return;
|
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) &&
|
if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
|
||||||
(memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
|
(memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
|
||||||
ETH_ALEN) == 0)) {
|
ETH_ALEN) == 0)) {
|
||||||
|
|
|
@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||||
bss->dtim_period = tim_ie->dtim_period;
|
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;
|
bss->supp_rates_len = 0;
|
||||||
if (elems->supp_rates) {
|
if (elems->supp_rates) {
|
||||||
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
|
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
|
||||||
|
|
Loading…
Add table
Reference in a new issue