diff options
author | Eliad Peller <eliad@wizery.com> | 2011-05-13 04:57:13 -0400 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-05-13 07:55:49 -0400 |
commit | 9439064cd9fce8a4db716a748dbf581eb234f9c7 (patch) | |
tree | b1dd09bc0a8a19c9ee1a71299b97ea0df6b4ba6a | |
parent | f795ea8b2f047409c59e891d6e5e86a925048bf4 (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.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 81 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/ps.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 1 |
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 | ||
1353 | static 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 | } | ||
1395 | out_sleep: | ||
1396 | wl1271_ps_elp_sleep(wl); | ||
1397 | out_unlock: | ||
1398 | mutex_unlock(&wl->mutex); | ||
1399 | out: | ||
1400 | return ret; | ||
1401 | |||
1402 | } | ||
1403 | |||
1404 | static 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); | ||
1422 | out: | ||
1423 | mutex_unlock(&wl->mutex); | ||
1424 | } | ||
1425 | |||
1353 | static int wl1271_op_suspend(struct ieee80211_hw *hw, | 1426 | static 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); | |||
35 | void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); | 35 | void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); |
36 | void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); | 36 | void 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 | ||