summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2010-05-19 12:24:38 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-06-02 22:13:06 +0200
commit66fceb69b72ff7e9cd8da2ca70033982d5376e0e (patch)
treeaa91d0d6c1c9e620a9718798fe925ebc3bab3eb8 /drivers/net/wireless/libertas/main.c
parentwl1271: Add support for NVS files with 5GHz band parameters (diff)
downloadlinux-66fceb69b72ff7e9cd8da2ca70033982d5376e0e.tar.xz
linux-66fceb69b72ff7e9cd8da2ca70033982d5376e0e.zip
libertas: Added callback functions to support SDIO suspend/resume.
In suspend() host sleep is activated using already configured host sleep parameters through wol command, and in resume() host sleep is cancelled. Earlier priv->fw_ready flag used to reset and set in suspend and resume handler respectively. Since after suspend only host goes into sleep state and firmware is always ready, those changes in flag state are removed. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c79
1 files changed, 55 insertions, 24 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index d9b8ee130c45..abfecc4814b4 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -625,16 +625,13 @@ static int lbs_thread(void *data)
return 0;
}
-static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
- struct cmd_header *cmd)
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+ unsigned long dummy,
+ struct cmd_header *cmd)
{
lbs_deb_enter(LBS_DEB_FW);
-
- netif_device_detach(priv->dev);
- if (priv->mesh_dev)
- netif_device_detach(priv->mesh_dev);
-
- priv->fw_ready = 0;
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
lbs_deb_leave(LBS_DEB_FW);
return 0;
}
@@ -646,39 +643,65 @@ int lbs_suspend(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_FW);
- if (priv->wol_criteria == 0xffffffff) {
- lbs_pr_info("Suspend attempt without configuring wake params!\n");
- return -EINVAL;
+ if (priv->is_deep_sleep) {
+ ret = lbs_set_deep_sleep(priv, 0);
+ if (ret) {
+ lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ return ret;
+ }
+ priv->deep_sleep_required = 1;
}
memset(&cmd, 0, sizeof(cmd));
+ ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+ (struct wol_config *)NULL);
+ if (ret) {
+ lbs_pr_info("Host sleep configuration failed: %d\n", ret);
+ return ret;
+ }
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
+ sizeof(cmd), lbs_ret_host_sleep_activate, 0);
+ if (ret)
+ lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+ }
- ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
- sizeof(cmd), lbs_suspend_callback, 0);
- if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+ if (!wait_event_interruptible_timeout(priv->host_sleep_q,
+ priv->is_host_sleep_activated, (10 * HZ))) {
+ lbs_pr_err("host_sleep_q: timer expired\n");
+ ret = -1;
+ }
+ netif_device_detach(priv->dev);
+ if (priv->mesh_dev)
+ netif_device_detach(priv->mesh_dev);
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_suspend);
-void lbs_resume(struct lbs_private *priv)
+int lbs_resume(struct lbs_private *priv)
{
- lbs_deb_enter(LBS_DEB_FW);
+ int ret;
+ uint32_t criteria = EHS_REMOVE_WAKEUP;
- priv->fw_ready = 1;
+ lbs_deb_enter(LBS_DEB_FW);
- /* Firmware doesn't seem to give us RX packets any more
- until we send it some command. Might as well update */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- 0, 0, NULL);
+ ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
netif_device_attach(priv->dev);
if (priv->mesh_dev)
netif_device_attach(priv->mesh_dev);
- lbs_deb_leave(LBS_DEB_FW);
+ if (priv->deep_sleep_required) {
+ priv->deep_sleep_required = 0;
+ ret = lbs_set_deep_sleep(priv, 1);
+ if (ret)
+ lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(lbs_resume);
@@ -834,10 +857,13 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->psstate = PS_STATE_FULL_POWER;
priv->is_deep_sleep = 0;
priv->is_auto_deep_sleep_enabled = 0;
+ priv->deep_sleep_required = 0;
priv->wakeup_dev_required = 0;
init_waitqueue_head(&priv->ds_awake_q);
priv->authtype_auto = 1;
-
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ init_waitqueue_head(&priv->host_sleep_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
@@ -976,6 +1002,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
+ priv->wol_gap = 20;
goto done;
@@ -1031,6 +1058,10 @@ void lbs_remove_card(struct lbs_private *priv)
wake_up_interruptible(&priv->ds_awake_q);
}
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);