From f1d63a59635feef3481ed1972a883a5d6be7f9bb Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 31 Jan 2012 11:57:21 +0200 Subject: wl12xx: add support for HW dynamic PS FW now supports dynamic PS so we don't need to use mac80211 support. FW will go to PSM after a specified timeout with no Rx/Tx traffic. - Changed FW API to include new PS mode (AUTO_MODE) and including timeout parameter - The default PS mode would be dynamic PS - Default timeout is 100ms (same as it used to be in mac80211) - Avoid using mac80211 APIs to disable/enable dynamic PS as we're not using mac80211 PS control anymore. - COEX is handled by the FW while in dynamic PS so removed handling of SOFT_GEMINI Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index a2bdacdd7e1d..60f03c4dfbe7 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -163,10 +163,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode, u32 rates, bool send) { int ret; + u16 timeout = wl->conf.conn.dynamic_ps_timeout; switch (mode) { - case STATION_POWER_SAVE_MODE: - wl1271_debug(DEBUG_PSM, "entering psm"); + case STATION_AUTO_PS_MODE: + wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", + mode, timeout); ret = wl1271_acx_wake_up_conditions(wl, wlvif); if (ret < 0) { @@ -174,14 +176,13 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, return ret; } - ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE); + ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout); if (ret < 0) return ret; set_bit(WLVIF_FLAG_PSM, &wlvif->flags); break; case STATION_ACTIVE_MODE: - default: wl1271_debug(DEBUG_PSM, "leaving psm"); /* disable beacon early termination */ @@ -191,12 +192,16 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, return ret; } - ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE); + ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0); if (ret < 0) return ret; clear_bit(WLVIF_FLAG_PSM, &wlvif->flags); break; + case STATION_POWER_SAVE_MODE: + default: + wl1271_warning("trying to set ps to unsupported mode %d", mode); + ret = -EINVAL; } return ret; -- cgit v1.2.3 From 248a0018f365c1fa51aa381e7b6f6e97eacf61ff Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 31 Jan 2012 11:57:23 +0200 Subject: wl12xx: remove 2 unused parameters in wl1271_ps_set_mode() cleanup 2 unused parameters of wl1271_ps_set_mode Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 4 +--- drivers/net/wireless/wl12xx/main.c | 10 +++------- drivers/net/wireless/wl12xx/ps.c | 2 +- drivers/net/wireless/wl12xx/ps.h | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 156a7741df34..4436851a4fa7 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -359,9 +359,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, wl12xx_for_each_wlvif_sta(wl, wlvif) { if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) - wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE, - wlvif->basic_rate, true); - + wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); } wl1271_ps_elp_sleep(wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6b240868ac75..97f7591c3b39 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2472,8 +2472,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { wl1271_debug(DEBUG_PSM, "psm enabled"); ret = wl1271_ps_set_mode(wl, wlvif, - STATION_POWER_SAVE_MODE, - wlvif->basic_rate, true); + STATION_AUTO_PS_MODE); } } else if (!(conf->flags & IEEE80211_CONF_PS) && test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { @@ -2483,8 +2482,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) ret = wl1271_ps_set_mode(wl, wlvif, - STATION_ACTIVE_MODE, - wlvif->basic_rate, true); + STATION_ACTIVE_MODE); } if (conf->power_level != wlvif->power_level) { @@ -3824,9 +3822,7 @@ sta_not_found: !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { ret = wl1271_ps_set_mode(wl, wlvif, - STATION_AUTO_PS_MODE, - wlvif->basic_rate, - true); + STATION_AUTO_PS_MODE); if (ret < 0) goto out; } diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 60f03c4dfbe7..5074c2af17c0 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -160,7 +160,7 @@ out: } int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum wl1271_cmd_ps_mode mode, u32 rates, bool send) + enum wl1271_cmd_ps_mode mode) { int ret; u16 timeout = wl->conf.conn.dynamic_ps_timeout; diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index a12052f02026..5f19d4fbbf27 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -28,7 +28,7 @@ #include "acx.h" int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum wl1271_cmd_ps_mode mode, u32 rates, bool send); + enum wl1271_cmd_ps_mode mode); void wl1271_ps_elp_sleep(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl); void wl1271_elp_work(struct work_struct *work); -- cgit v1.2.3 From ed471d3402b0fa77e52007c6f8d79b16c4194000 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 31 Jan 2012 11:57:24 +0200 Subject: wl12xx: enable/disable BET with AUTO_PS/ACTIVE While the FW with dynamic PS controls BET when going to PSM and back internally within the FW, there's still a need to enable it from the driver at least once (so enable on every entry to AUTO_PS) and disable it once we explicitly go back to STATION_ACTIVE_MODE. BET isn't relevant for 5GHz Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 5074c2af17c0..d7a91d3c398d 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -181,6 +181,13 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, return ret; set_bit(WLVIF_FLAG_PSM, &wlvif->flags); + + /* enable beacon early termination. Not relevant for 5GHz */ + if (wlvif->band == IEEE80211_BAND_2GHZ) { + ret = wl1271_acx_bet_enable(wl, wlvif, true); + if (ret < 0) + return ret; + } break; case STATION_ACTIVE_MODE: wl1271_debug(DEBUG_PSM, "leaving psm"); -- cgit v1.2.3 From d18da7fcca449f09c91a209b4f5006959c5a7656 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 31 Jan 2012 11:57:25 +0200 Subject: wl12xx: change WLVIF_FLAG_PSM name and remove WLVIF_FLAG_PSM_REQUESTED WLVIF_FLAG_PSM turned to WLVIF_FLAG_IN_AUTO_PS which marks that this vif is in AUTO PS. WLVIF_FLAG_PSM_REQUESTED is not required as mac80211 calls op_config with CONF_PS after association. wl12xx_config_vif() handling of CONF_PS was simplified and cleaned up. Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 2 +- drivers/net/wireless/wl12xx/main.c | 46 +++++++++++++---------------------- drivers/net/wireless/wl12xx/ps.c | 8 +++--- drivers/net/wireless/wl12xx/wl12xx.h | 3 +-- 4 files changed, 23 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 4436851a4fa7..4dcb3f758fe2 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -358,7 +358,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, */ wl12xx_for_each_wlvif_sta(wl, wlvif) { - if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) + if (test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 97f7591c3b39..4ca7278201ec 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1715,9 +1715,7 @@ static int wl1271_op_start(struct ieee80211_hw *hw) * is added. That is where we will initialize the hardware. */ - wl1271_error("wl12xx is in an ustable state (fw api update is " - "taking place). skip this commit when bisecting"); - return -EBUSY; + return 0; } static void wl1271_op_stop(struct ieee80211_hw *hw) @@ -2460,29 +2458,29 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, } } - if (conf->flags & IEEE80211_CONF_PS && - !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { - set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); + if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { + + if ((conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + !test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) { + + wl1271_debug(DEBUG_PSM, "auto ps enabled"); - /* - * 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. - */ - if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - wl1271_debug(DEBUG_PSM, "psm enabled"); ret = wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); - } - } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { - wl1271_debug(DEBUG_PSM, "psm disabled"); + if (ret < 0) + wl1271_warning("enter auto ps failed %d", ret); - clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) { + + wl1271_debug(DEBUG_PSM, "auto ps disabled"); - if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE); + if (ret < 0) + wl1271_warning("exit auto ps failed %d", ret); + } } if (conf->power_level != wlvif->power_level) { @@ -3816,16 +3814,6 @@ sta_not_found: if (ret < 0) goto out; } - - /* If we want to go in PSM but we're not there yet */ - if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) && - !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { - - ret = wl1271_ps_set_mode(wl, wlvif, - STATION_AUTO_PS_MODE); - if (ret < 0) - goto out; - } } /* Handle new association with HT. Do this after join. */ diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index d7a91d3c398d..e209e29ffb45 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work) if (wlvif->bss_type == BSS_TYPE_AP_BSS) goto out; - if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && + if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) goto out; } @@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) if (wlvif->bss_type == BSS_TYPE_AP_BSS) return; - if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && + if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return; } @@ -180,7 +180,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ret < 0) return ret; - set_bit(WLVIF_FLAG_PSM, &wlvif->flags); + set_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags); /* enable beacon early termination. Not relevant for 5GHz */ if (wlvif->band == IEEE80211_BAND_2GHZ) { @@ -203,7 +203,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ret < 0) return ret; - clear_bit(WLVIF_FLAG_PSM, &wlvif->flags); + clear_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags); break; case STATION_POWER_SAVE_MODE: default: diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index e18e6160fdab..9baed6be6a31 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -254,8 +254,7 @@ enum wl12xx_vif_flags { WLVIF_FLAG_STA_ASSOCIATED, WLVIF_FLAG_IBSS_JOINED, WLVIF_FLAG_AP_STARTED, - WLVIF_FLAG_PSM, - WLVIF_FLAG_PSM_REQUESTED, + WLVIF_FLAG_IN_AUTO_PS, WLVIF_FLAG_STA_STATE_SENT, WLVIF_FLAG_RX_STREAMING_STARTED, WLVIF_FLAG_PSPOLL_FAILURE, -- cgit v1.2.3 From dae728fe67c7c5ab10f91366bd9d1f8db203e123 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 2 Feb 2012 12:03:39 +0200 Subject: wl12xx: Set different wake up conditions in case of suspend Added ability to set different wake up conditions for suspend/resume. Set default values to wake up every 3 DTIMs while suspended and every 1 DTIM while resumed Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 10 +++++--- drivers/net/wireless/wl12xx/acx.h | 3 ++- drivers/net/wireless/wl12xx/conf.h | 13 ++++++++++ drivers/net/wireless/wl12xx/main.c | 51 +++++++++++++++++++++++++++++++++++--- drivers/net/wireless/wl12xx/ps.c | 4 ++- 5 files changed, 72 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index af2c3123d1d7..bc96db0683a5 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -34,12 +34,14 @@ #include "reg.h" #include "ps.h" -int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif) +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval) { struct acx_wake_up_condition *wake_up; int ret; - wl1271_debug(DEBUG_ACX, "acx wake up conditions"); + wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)", + wake_up_event, listen_interval); wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); if (!wake_up) { @@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif) } wake_up->role_id = wlvif->role_id; - wake_up->wake_up_event = wl->conf.conn.wake_up_event; - wake_up->listen_interval = wl->conf.conn.listen_interval; + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, wake_up, sizeof(*wake_up)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 0749df58c85d..a28fc044034c 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1226,7 +1226,8 @@ enum { int wl1271_acx_wake_up_conditions(struct wl1271 *wl, - struct wl12xx_vif *wlvif); + struct wl12xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, int power); diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 18637eec1e21..80eafadc389d 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -818,6 +818,19 @@ struct conf_conn_settings { */ u8 listen_interval; + /* + * Firmware wakeup conditions during suspend + * Range: CONF_WAKE_UP_EVENT_* + */ + u8 suspend_wake_up_event; + + /* + * Listen interval during suspend. + * Currently will be in DTIMs (1-10) + * + */ + u8 suspend_listen_interval; + /* * Enable or disable the beacon filtering. * diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index aa5d512c8f82..fa61dfd2084c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -221,6 +221,8 @@ static struct conf_drv_settings default_conf = { .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .listen_interval = 1, + .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, + .suspend_listen_interval = 3, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, .bcn_filt_ie_count = 2, .bcn_filt_ie = { @@ -1574,6 +1576,35 @@ static struct notifier_block wl1271_dev_notifier = { }; #ifdef CONFIG_PM +static int wl1271_configure_suspend_sta(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret = 0; + + mutex_lock(&wl->mutex); + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out_unlock; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + ret = wl1271_acx_wake_up_conditions(wl, wlvif, + wl->conf.conn.suspend_wake_up_event, + wl->conf.conn.suspend_listen_interval); + + if (ret < 0) + wl1271_error("suspend: set wake up conditions failed: %d", ret); + + + wl1271_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + return ret; + +} static int wl1271_configure_suspend_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) @@ -1601,6 +1632,8 @@ out_unlock: static int wl1271_configure_suspend(struct wl1271 *wl, struct wl12xx_vif *wlvif) { + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + return wl1271_configure_suspend_sta(wl, wlvif); if (wlvif->bss_type == BSS_TYPE_AP_BSS) return wl1271_configure_suspend_ap(wl, wlvif); return 0; @@ -1609,10 +1642,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl, static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - int ret; + int ret = 0; bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; - if (!is_ap) + if ((!is_ap) && (!is_sta)) return; mutex_lock(&wl->mutex); @@ -1620,7 +1654,18 @@ static void wl1271_configure_resume(struct wl1271 *wl, if (ret < 0) goto out; - wl1271_acx_beacon_filter_opt(wl, wlvif, false); + if (is_sta) { + ret = wl1271_acx_wake_up_conditions(wl, wlvif, + wl->conf.conn.wake_up_event, + wl->conf.conn.listen_interval); + + if (ret < 0) + wl1271_error("resume: wake up conditions failed: %d", + ret); + + } else if (is_ap) { + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); + } wl1271_ps_elp_sleep(wl); out: diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index e209e29ffb45..d1979223ad28 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -170,7 +170,9 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", mode, timeout); - ret = wl1271_acx_wake_up_conditions(wl, wlvif); + ret = wl1271_acx_wake_up_conditions(wl, wlvif, + wl->conf.conn.wake_up_event, + wl->conf.conn.listen_interval); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); return ret; -- cgit v1.2.3 From 5c0dc2fcfec606cf9f2d28ff31bbeb0a6225b27a Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 2 Feb 2012 19:06:45 +0200 Subject: wl12xx: add forced_ps mode For certain WiFi certification tests forcing PS is necessary. Since DPS is now enabled in the FW and this can't be achieved by using netlatency this required a new config option. Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/conf.h | 6 ++++++ drivers/net/wireless/wl12xx/debugfs.c | 2 +- drivers/net/wireless/wl12xx/main.c | 25 +++++++++++++++++++------ drivers/net/wireless/wl12xx/ps.c | 10 +++++----- drivers/net/wireless/wl12xx/wl12xx.h | 2 +- 5 files changed, 32 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 80eafadc389d..823535cdf150 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -942,6 +942,12 @@ struct conf_conn_settings { */ u16 dynamic_ps_timeout; + /* + * Specifies whether dynamic PS should be disabled and PSM forced. + * This is required for certain WiFi certification tests. + */ + u8 forced_ps; + /* * * Specifies the interval of the connection keep-alive null-func diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 15353fac0707..02da445ea98a 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -358,7 +358,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, */ wl12xx_for_each_wlvif_sta(wl, wlvif) { - if (test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) + if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index fa61dfd2084c..b828149a1655 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -247,6 +247,7 @@ static struct conf_drv_settings default_conf = { .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, .dynamic_ps_timeout = 100, + .forced_ps = false, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -2510,17 +2511,29 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, if ((conf->flags & IEEE80211_CONF_PS) && test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && - !test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) { + !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { - wl1271_debug(DEBUG_PSM, "auto ps enabled"); + int ps_mode; + char *ps_mode_str; + + if (wl->conf.conn.forced_ps) { + ps_mode = STATION_POWER_SAVE_MODE; + ps_mode_str = "forced"; + } else { + ps_mode = STATION_AUTO_PS_MODE; + ps_mode_str = "auto"; + } + + wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); + + ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); - ret = wl1271_ps_set_mode(wl, wlvif, - STATION_AUTO_PS_MODE); if (ret < 0) - wl1271_warning("enter auto ps failed %d", ret); + wl1271_warning("enter %s ps failed %d", + ps_mode_str, ret); } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) { + test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { wl1271_debug(DEBUG_PSM, "auto ps disabled"); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index d1979223ad28..23d67501c50a 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work) if (wlvif->bss_type == BSS_TYPE_AP_BSS) goto out; - if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) && + if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) goto out; } @@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) if (wlvif->bss_type == BSS_TYPE_AP_BSS) return; - if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) && + if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return; } @@ -167,6 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, switch (mode) { case STATION_AUTO_PS_MODE: + case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", mode, timeout); @@ -182,7 +183,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ret < 0) return ret; - set_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags); + set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); /* enable beacon early termination. Not relevant for 5GHz */ if (wlvif->band == IEEE80211_BAND_2GHZ) { @@ -205,9 +206,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ret < 0) return ret; - clear_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags); + clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); break; - case STATION_POWER_SAVE_MODE: default: wl1271_warning("trying to set ps to unsupported mode %d", mode); ret = -EINVAL; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9baed6be6a31..61c58c13fa90 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -254,7 +254,7 @@ enum wl12xx_vif_flags { WLVIF_FLAG_STA_ASSOCIATED, WLVIF_FLAG_IBSS_JOINED, WLVIF_FLAG_AP_STARTED, - WLVIF_FLAG_IN_AUTO_PS, + WLVIF_FLAG_IN_PS, WLVIF_FLAG_STA_STATE_SENT, WLVIF_FLAG_RX_STREAMING_STARTED, WLVIF_FLAG_PSPOLL_FAILURE, -- cgit v1.2.3 From 5af70c864a1539bd1d3f3fcb04ab9558491c9103 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 28 Feb 2012 00:41:28 +0200 Subject: wl12xx: set the ELP entry delay to the FW dyn-ps timeout With PSM handled in FW, the checks in wl1271_elp_work() are always true. Thus during active traffic we constantly enter and exit ELP (many times per second). As each ELP exit takes ~10ms, this can have an adverse effect on throughput and interactivity. Set the ELP timeout to the dyn-ps timeout. This period is longer and avoids the above problem. It also makes sense to stay out of ELP while we are awake on the network, to minimize delays in Tx/Rx. The same thing was done by the mac80211 dynamic-ps mechanism before the FW DPS changes. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 23d67501c50a..78f598b4f97b 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -69,8 +69,6 @@ out: mutex_unlock(&wl->mutex); } -#define ELP_ENTRY_DELAY 5 - /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { @@ -90,7 +88,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) } ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); + msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout)); } int wl1271_ps_elp_wakeup(struct wl1271 *wl) -- cgit v1.2.3