aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2011-05-13 04:57:13 -0400
committerLuciano Coelho <coelho@ti.com>2011-05-13 07:55:49 -0400
commit9439064cd9fce8a4db716a748dbf581eb234f9c7 (patch)
treeb1dd09bc0a8a19c9ee1a71299b97ea0df6b4ba6a
parentf795ea8b2f047409c59e891d6e5e86a925048bf4 (diff)
wl12xx: enter/exit psm on wowlan suspend/resume
When operating as station, enter psm before suspending the device into wowlan state. Add a new completion event to signal when psm was entered successfully. Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-rw-r--r--drivers/net/wireless/wl12xx/event.c7
-rw-r--r--drivers/net/wireless/wl12xx/main.c81
-rw-r--r--drivers/net/wireless/wl12xx/ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h1
4 files changed, 91 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 1e4bd6a2c396..c3c554cd6580 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
135 135
136 /* enable beacon early termination */ 136 /* enable beacon early termination */
137 ret = wl1271_acx_bet_enable(wl, true); 137 ret = wl1271_acx_bet_enable(wl, true);
138 if (ret < 0)
139 break;
140
141 if (wl->ps_compl) {
142 complete(wl->ps_compl);
143 wl->ps_compl = NULL;
144 }
138 break; 145 break;
139 default: 146 default:
140 break; 147 break;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 8f9e6152f3b7..610be03a198b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1350,6 +1350,79 @@ static struct notifier_block wl1271_dev_notifier = {
1350 .notifier_call = wl1271_dev_notify, 1350 .notifier_call = wl1271_dev_notify,
1351}; 1351};
1352 1352
1353static int wl1271_configure_suspend(struct wl1271 *wl)
1354{
1355 int ret;
1356
1357 if (wl->bss_type != BSS_TYPE_STA_BSS)
1358 return 0;
1359
1360 mutex_lock(&wl->mutex);
1361
1362 ret = wl1271_ps_elp_wakeup(wl);
1363 if (ret < 0)
1364 goto out_unlock;
1365
1366 /* enter psm if needed*/
1367 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1368 DECLARE_COMPLETION_ONSTACK(compl);
1369
1370 wl->ps_compl = &compl;
1371 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1372 wl->basic_rate, true);
1373 if (ret < 0)
1374 goto out_sleep;
1375
1376 /* we must unlock here so we will be able to get events */
1377 wl1271_ps_elp_sleep(wl);
1378 mutex_unlock(&wl->mutex);
1379
1380 ret = wait_for_completion_timeout(
1381 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1382 if (ret <= 0) {
1383 wl1271_warning("couldn't enter ps mode!");
1384 ret = -EBUSY;
1385 goto out;
1386 }
1387
1388 /* take mutex again, and wakeup */
1389 mutex_lock(&wl->mutex);
1390
1391 ret = wl1271_ps_elp_wakeup(wl);
1392 if (ret < 0)
1393 goto out_unlock;
1394 }
1395out_sleep:
1396 wl1271_ps_elp_sleep(wl);
1397out_unlock:
1398 mutex_unlock(&wl->mutex);
1399out:
1400 return ret;
1401
1402}
1403
1404static void wl1271_configure_resume(struct wl1271 *wl)
1405{
1406 int ret;
1407
1408 if (wl->bss_type != BSS_TYPE_STA_BSS)
1409 return;
1410
1411 mutex_lock(&wl->mutex);
1412 ret = wl1271_ps_elp_wakeup(wl);
1413 if (ret < 0)
1414 goto out;
1415
1416 /* exit psm if it wasn't configured */
1417 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1418 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1419 wl->basic_rate, true);
1420
1421 wl1271_ps_elp_sleep(wl);
1422out:
1423 mutex_unlock(&wl->mutex);
1424}
1425
1353static int wl1271_op_suspend(struct ieee80211_hw *hw, 1426static int wl1271_op_suspend(struct ieee80211_hw *hw,
1354 struct cfg80211_wowlan *wow) 1427 struct cfg80211_wowlan *wow)
1355{ 1428{
@@ -1357,6 +1430,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
1357 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); 1430 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1358 wl->wow_enabled = !!wow; 1431 wl->wow_enabled = !!wow;
1359 if (wl->wow_enabled) { 1432 if (wl->wow_enabled) {
1433 int ret;
1434 ret = wl1271_configure_suspend(wl);
1435 if (ret < 0) {
1436 wl1271_warning("couldn't prepare device to suspend");
1437 return ret;
1438 }
1360 /* flush any remaining work */ 1439 /* flush any remaining work */
1361 wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); 1440 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1362 flush_delayed_work(&wl->scan_complete_work); 1441 flush_delayed_work(&wl->scan_complete_work);
@@ -1408,6 +1487,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
1408 wl1271_irq(0, wl); 1487 wl1271_irq(0, wl);
1409 wl1271_enable_interrupts(wl); 1488 wl1271_enable_interrupts(wl);
1410 } 1489 }
1490
1491 wl1271_configure_resume(wl);
1411 } 1492 }
1412 1493
1413 return 0; 1494 return 0;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index c41bd0a711bc..25eb9bc9b628 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work);
35void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); 35void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
36void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); 36void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
37 37
38#define WL1271_PS_COMPLETE_TIMEOUT 500
39
38#endif /* __WL1271_PS_H__ */ 40#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 2218b9c63844..fbe8f46d1232 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -513,6 +513,7 @@ struct wl1271 {
513 unsigned int rx_filter; 513 unsigned int rx_filter;
514 514
515 struct completion *elp_compl; 515 struct completion *elp_compl;
516 struct completion *ps_compl;
516 struct delayed_work elp_work; 517 struct delayed_work elp_work;
517 struct delayed_work pspoll_work; 518 struct delayed_work pspoll_work;
518 519