diff options
| -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 | ||
