aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-02-18 06:25:36 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-02-19 15:52:42 -0500
commitd8c42c0c282a5edd9ea2eef4c929d9cec2798653 (patch)
tree63af39e5de1c1c878d3abc72e42c380289704f39
parente2117cea27c6b27e1a379acac5eb0433eeb7033a (diff)
wl1271: Fix PSM entry
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>
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c35
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c8
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c21
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h3
6 files changed, 47 insertions, 26 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index a74259bb596b..dd2b5f0540a5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -555,7 +555,7 @@ out:
555 return ret; 555 return ret;
556} 556}
557 557
558int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) 558int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
559{ 559{
560 struct wl1271_cmd_ps_params *ps_params = NULL; 560 struct wl1271_cmd_ps_params *ps_params = NULL;
561 int ret = 0; 561 int ret = 0;
@@ -576,7 +576,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
576 } 576 }
577 577
578 ps_params->ps_mode = ps_mode; 578 ps_params->ps_mode = ps_mode;
579 ps_params->send_null_data = 1; 579 ps_params->send_null_data = send;
580 ps_params->retries = 5; 580 ps_params->retries = 5;
581 ps_params->hang_over_period = 128; 581 ps_params->hang_over_period = 128;
582 ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ 582 ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index 09fe91297acf..ba433f423c8b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -38,7 +38,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
38int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); 38int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
39int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); 39int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
40int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); 40int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
41int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); 41int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
42int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, 42int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
43 size_t len); 43 size_t len);
44int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, 44int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index 0a145afc9905..cecbae2ded35 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -78,24 +78,55 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
78 78
79 switch (mbox->ps_status) { 79 switch (mbox->ps_status) {
80 case EVENT_ENTER_POWER_SAVE_FAIL: 80 case EVENT_ENTER_POWER_SAVE_FAIL:
81 wl1271_debug(DEBUG_PSM, "PSM entry failed");
82
81 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { 83 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
84 /* remain in active mode */
82 wl->psm_entry_retry = 0; 85 wl->psm_entry_retry = 0;
83 break; 86 break;
84 } 87 }
85 88
86 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { 89 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
87 wl->psm_entry_retry++; 90 wl->psm_entry_retry++;
88 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); 91 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
92 true);
89 } else { 93 } else {
90 wl1271_error("PSM entry failed, giving up.\n"); 94 wl1271_error("PSM entry failed, giving up.\n");
95 /* make sure the firmware goes into active mode */
96 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
97 false);
91 wl->psm_entry_retry = 0; 98 wl->psm_entry_retry = 0;
92 } 99 }
93 break; 100 break;
94 case EVENT_ENTER_POWER_SAVE_SUCCESS: 101 case EVENT_ENTER_POWER_SAVE_SUCCESS:
95 wl->psm_entry_retry = 0; 102 wl->psm_entry_retry = 0;
103
104 /* enable beacon filtering */
105 ret = wl1271_acx_beacon_filter_opt(wl, true);
106 if (ret < 0)
107 break;
108
109 /* enable beacon early termination */
110 ret = wl1271_acx_bet_enable(wl, true);
111 if (ret < 0)
112 break;
113
114 /* go to extremely low power mode */
115 wl1271_ps_elp_sleep(wl);
116 if (ret < 0)
117 break;
96 break; 118 break;
97 case EVENT_EXIT_POWER_SAVE_FAIL: 119 case EVENT_EXIT_POWER_SAVE_FAIL:
98 wl1271_info("PSM exit failed"); 120 wl1271_debug(DEBUG_PSM, "PSM exit failed");
121
122 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
123 wl->psm_entry_retry = 0;
124 break;
125 }
126
127 /* make sure the firmware goes to active mode */
128 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
129 false);
99 break; 130 break;
100 case EVENT_EXIT_POWER_SAVE_SUCCESS: 131 case EVENT_EXIT_POWER_SAVE_SUCCESS:
101 default: 132 default:
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index e4867b895c43..6f026fe63d7f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1248,7 +1248,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1248 */ 1248 */
1249 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { 1249 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1250 wl1271_info("psm enabled"); 1250 wl1271_info("psm enabled");
1251 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); 1251 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1252 true);
1252 } 1253 }
1253 } else if (!(conf->flags & IEEE80211_CONF_PS) && 1254 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1254 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { 1255 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@@ -1257,7 +1258,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1257 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); 1258 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
1258 1259
1259 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) 1260 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
1260 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); 1261 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1262 true);
1261 } 1263 }
1262 1264
1263 if (conf->power_level != wl->power_level) { 1265 if (conf->power_level != wl->power_level) {
@@ -1637,7 +1639,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1637 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && 1639 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1638 !test_bit(WL1271_FLAG_PSM, &wl->flags)) { 1640 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1639 mode = STATION_POWER_SAVE_MODE; 1641 mode = STATION_POWER_SAVE_MODE;
1640 ret = wl1271_ps_set_mode(wl, mode); 1642 ret = wl1271_ps_set_mode(wl, mode, true);
1641 if (ret < 0) 1643 if (ret < 0)
1642 goto out_sleep; 1644 goto out_sleep;
1643 } 1645 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index e407790f6771..29f670099d94 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -118,7 +118,8 @@ out:
118 return 0; 118 return 0;
119} 119}
120 120
121int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) 121int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
122 bool send)
122{ 123{
123 int ret; 124 int ret;
124 125
@@ -126,21 +127,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
126 case STATION_POWER_SAVE_MODE: 127 case STATION_POWER_SAVE_MODE:
127 wl1271_debug(DEBUG_PSM, "entering psm"); 128 wl1271_debug(DEBUG_PSM, "entering psm");
128 129
129 /* enable beacon filtering */ 130 ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
130 ret = wl1271_acx_beacon_filter_opt(wl, true);
131 if (ret < 0)
132 return ret;
133
134 /* enable beacon early termination */
135 ret = wl1271_acx_bet_enable(wl, true);
136 if (ret < 0)
137 return ret;
138
139 ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
140 if (ret < 0)
141 return ret;
142
143 wl1271_ps_elp_sleep(wl);
144 if (ret < 0) 131 if (ret < 0)
145 return ret; 132 return ret;
146 133
@@ -163,7 +150,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
163 if (ret < 0) 150 if (ret < 0)
164 return ret; 151 return ret;
165 152
166 ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); 153 ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
167 if (ret < 0) 154 if (ret < 0)
168 return ret; 155 return ret;
169 156
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h
index 779653d0ae85..940276f517a4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.h
@@ -27,7 +27,8 @@
27#include "wl1271.h" 27#include "wl1271.h"
28#include "wl1271_acx.h" 28#include "wl1271_acx.h"
29 29
30int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); 30int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
31 bool send);
31void wl1271_ps_elp_sleep(struct wl1271 *wl); 32void wl1271_ps_elp_sleep(struct wl1271 *wl);
32int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); 33int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
33void wl1271_elp_work(struct work_struct *work); 34void wl1271_elp_work(struct work_struct *work);