wl1271: Fix PSM entry
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>
Thu, 18 Feb 2010 11:25:36 +0000 (13:25 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 19 Feb 2010 20:52:42 +0000 (15:52 -0500)
Currently the PSM entry function assumes successful operation, and enables
ELP, BET and beacon filtering right away. This is bad, because the PSM
entry may fail due to environmental issues, which will cause the ELP, BET and
beacon filtering to be illegally enabled (because FW remains in active state.)

Fix this by enabling ELP, BET and beacon filtering only after successful entry,
and by ensuring the firmware is in active mode after the failure.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_cmd.h
drivers/net/wireless/wl12xx/wl1271_event.c
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_ps.c
drivers/net/wireless/wl12xx/wl1271_ps.h

index a74259bb596bb99cd10ee3bc84630907dbf70b0f..dd2b5f0540a5ddaa712c6151c37f80391c162f64 100644 (file)
@@ -555,7 +555,7 @@ out:
        return ret;
 }
 
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
 {
        struct wl1271_cmd_ps_params *ps_params = NULL;
        int ret = 0;
@@ -576,7 +576,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
        }
 
        ps_params->ps_mode = ps_mode;
-       ps_params->send_null_data = 1;
+       ps_params->send_null_data = send;
        ps_params->retries = 5;
        ps_params->hang_over_period = 128;
        ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
index 09fe91297acfe7bd0e2ddaf2883b0520602db1ed..ba433f423c8bdc8cfdebf0d387e4cd7d29061a3b 100644 (file)
@@ -38,7 +38,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
 int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
index 0a145afc990592a20b5a1b976fb72616a0f9bdc4..cecbae2ded35eaa5318e6b0cc4bbd1b03857db2d 100644 (file)
@@ -78,24 +78,55 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 
        switch (mbox->ps_status) {
        case EVENT_ENTER_POWER_SAVE_FAIL:
+               wl1271_debug(DEBUG_PSM, "PSM entry failed");
+
                if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+                       /* remain in active mode */
                        wl->psm_entry_retry = 0;
                        break;
                }
 
                if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
                        wl->psm_entry_retry++;
-                       ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+                       ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+                                                true);
                } else {
                        wl1271_error("PSM entry failed, giving up.\n");
+                       /* make sure the firmware goes into active mode */
+                       ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+                                                false);
                        wl->psm_entry_retry = 0;
                }
                break;
        case EVENT_ENTER_POWER_SAVE_SUCCESS:
                wl->psm_entry_retry = 0;
+
+               /* enable beacon filtering */
+               ret = wl1271_acx_beacon_filter_opt(wl, true);
+               if (ret < 0)
+                       break;
+
+               /* enable beacon early termination */
+               ret = wl1271_acx_bet_enable(wl, true);
+               if (ret < 0)
+                       break;
+
+               /* go to extremely low power mode */
+               wl1271_ps_elp_sleep(wl);
+               if (ret < 0)
+                       break;
                break;
        case EVENT_EXIT_POWER_SAVE_FAIL:
-               wl1271_info("PSM exit failed");
+               wl1271_debug(DEBUG_PSM, "PSM exit failed");
+
+               if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+                       wl->psm_entry_retry = 0;
+                       break;
+               }
+
+               /* make sure the firmware goes to active mode */
+               ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+                                        false);
                break;
        case EVENT_EXIT_POWER_SAVE_SUCCESS:
        default:
index e4867b895c43b67fdc25e8c56b8ab949c34fff90..6f026fe63d7fea9230230dff54bd3500c181e692 100644 (file)
@@ -1248,7 +1248,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                 */
                if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
                        wl1271_info("psm enabled");
-                       ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+                       ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+                                                true);
                }
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@@ -1257,7 +1258,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
                if (test_bit(WL1271_FLAG_PSM, &wl->flags))
-                       ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
+                       ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+                                                true);
        }
 
        if (conf->power_level != wl->power_level) {
@@ -1637,7 +1639,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
                            !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                                mode = STATION_POWER_SAVE_MODE;
-                               ret = wl1271_ps_set_mode(wl, mode);
+                               ret = wl1271_ps_set_mode(wl, mode, true);
                                if (ret < 0)
                                        goto out_sleep;
                        }
index e407790f677131c2a38781b48dff31ab94bd3e63..29f670099d94bb2bd7144063922c67fa56425909 100644 (file)
@@ -118,7 +118,8 @@ out:
        return 0;
 }
 
-int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
+                      bool send)
 {
        int ret;
 
@@ -126,21 +127,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
        case STATION_POWER_SAVE_MODE:
                wl1271_debug(DEBUG_PSM, "entering psm");
 
-               /* enable beacon filtering */
-               ret = wl1271_acx_beacon_filter_opt(wl, true);
-               if (ret < 0)
-                       return ret;
-
-               /* enable beacon early termination */
-               ret = wl1271_acx_bet_enable(wl, true);
-               if (ret < 0)
-                       return ret;
-
-               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
-               if (ret < 0)
-                       return ret;
-
-               wl1271_ps_elp_sleep(wl);
+               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
                if (ret < 0)
                        return ret;
 
@@ -163,7 +150,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
                if (ret < 0)
                        return ret;
 
-               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
                if (ret < 0)
                        return ret;
 
index 779653d0ae85b25923708b9a2d03c065d45a43a2..940276f517a40bef3d649cc0522f5d989b9ba43f 100644 (file)
@@ -27,7 +27,8 @@
 #include "wl1271.h"
 #include "wl1271_acx.h"
 
-int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
+                      bool send);
 void wl1271_ps_elp_sleep(struct wl1271 *wl);
 int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
 void wl1271_elp_work(struct work_struct *work);