On Fri, 2010-05-14 at 02:32 -0700, Amitkumar Karwar wrote: > 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@xxxxxxxxxxx> > Signed-off-by: Kiran Divekar <dkiran@xxxxxxxxxxx> Looks OK to me... Acked-by: Dan Williams <dcbw@xxxxxxxxxx> > --- > drivers/net/wireless/libertas/cmd.c | 37 ++++++++++++-- > drivers/net/wireless/libertas/cmdresp.c | 30 ++--------- > drivers/net/wireless/libertas/decl.h | 2 +- > drivers/net/wireless/libertas/dev.h | 6 ++ > drivers/net/wireless/libertas/ethtool.c | 15 +++--- > drivers/net/wireless/libertas/if_sdio.c | 58 ++++++++++++++++++++++ > drivers/net/wireless/libertas/if_usb.c | 6 ++ > drivers/net/wireless/libertas/main.c | 79 +++++++++++++++++++++--------- > 8 files changed, 171 insertions(+), 62 deletions(-) > > diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c > index cdb9b96..0fa6b0e 100644 > --- a/drivers/net/wireless/libertas/cmd.c > +++ b/drivers/net/wireless/libertas/cmd.c > @@ -70,6 +70,8 @@ static u8 is_command_allowed_in_ps(u16 cmd) > switch (cmd) { > case CMD_802_11_RSSI: > return 1; > + case CMD_802_11_HOST_SLEEP_CFG: > + return 1; > default: > break; > } > @@ -185,6 +187,23 @@ out: > return ret; > } > > +static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy, > + struct cmd_header *resp) > +{ > + lbs_deb_enter(LBS_DEB_CMD); > + if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { > + priv->is_host_sleep_configured = 0; > + if (priv->psstate == PS_STATE_FULL_POWER) { > + priv->is_host_sleep_activated = 0; > + wake_up_interruptible(&priv->host_sleep_q); > + } > + } else { > + priv->is_host_sleep_configured = 1; > + } > + lbs_deb_leave(LBS_DEB_CMD); > + return 0; > +} > + > int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, > struct wol_config *p_wol_config) > { > @@ -202,12 +221,11 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, > else > cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE; > > - ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); > + ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr, > + le16_to_cpu(cmd_config.hdr.size), > + lbs_ret_host_sleep_cfg, 0); > if (!ret) { > - if (criteria) { > - lbs_deb_cmd("Set WOL criteria to %x\n", criteria); > - priv->wol_criteria = criteria; > - } else > + if (p_wol_config) > memcpy((uint8_t *) p_wol_config, > (uint8_t *)&cmd_config.wol_conf, > sizeof(struct wol_config)); > @@ -712,6 +730,10 @@ static void lbs_queue_cmd(struct lbs_private *priv, > } > } > > + if (le16_to_cpu(cmdnode->cmdbuf->command) == > + CMD_802_11_WAKEUP_CONFIRM) > + addtail = 0; > + > spin_lock_irqsave(&priv->driver_lock, flags); > > if (addtail) > @@ -1353,6 +1375,11 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) > /* We don't get a response on the sleep-confirmation */ > priv->dnld_sent = DNLD_RES_RECEIVED; > > + if (priv->is_host_sleep_configured) { > + priv->is_host_sleep_activated = 1; > + wake_up_interruptible(&priv->host_sleep_q); > + } > + > /* If nothing to do, go back to sleep (?) */ > if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx]) > priv->psstate = PS_STATE_SLEEP; > diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c > index 88f7131..d6c3063 100644 > --- a/drivers/net/wireless/libertas/cmdresp.c > +++ b/drivers/net/wireless/libertas/cmdresp.c > @@ -17,6 +17,7 @@ > #include "dev.h" > #include "assoc.h" > #include "wext.h" > +#include "cmd.h" > > /** > * @brief This function handles disconnect event. it > @@ -341,32 +342,10 @@ done: > return ret; > } > > -static int lbs_send_confirmwake(struct lbs_private *priv) > -{ > - struct cmd_header cmd; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_HOST); > - > - cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); > - cmd.size = cpu_to_le16(sizeof(cmd)); > - cmd.seqnum = cpu_to_le16(++priv->seqnum); > - cmd.result = 0; > - > - lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd, > - sizeof(cmd)); > - > - ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd)); > - if (ret) > - lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n"); > - > - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); > - return ret; > -} > - > int lbs_process_event(struct lbs_private *priv, u32 event) > { > int ret = 0; > + struct cmd_header cmd; > > lbs_deb_enter(LBS_DEB_CMD); > > @@ -410,7 +389,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event) > if (priv->reset_deep_sleep_wakeup) > priv->reset_deep_sleep_wakeup(priv); > priv->is_deep_sleep = 0; > - lbs_send_confirmwake(priv); > + lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd, > + sizeof(cmd)); > + priv->is_host_sleep_activated = 0; > + wake_up_interruptible(&priv->host_sleep_q); > break; > > case MACREG_INT_CODE_DEEP_SLEEP_AWAKE: > diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h > index 709ffca..61db8bc 100644 > --- a/drivers/net/wireless/libertas/decl.h > +++ b/drivers/net/wireless/libertas/decl.h > @@ -38,7 +38,7 @@ int lbs_set_mac_address(struct net_device *dev, void *addr); > void lbs_set_multicast_list(struct net_device *dev); > > int lbs_suspend(struct lbs_private *priv); > -void lbs_resume(struct lbs_private *priv); > +int lbs_resume(struct lbs_private *priv); > > void lbs_queue_event(struct lbs_private *priv, u32 event); > void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); > diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h > index a54880e..71c5ad4 100644 > --- a/drivers/net/wireless/libertas/dev.h > +++ b/drivers/net/wireless/libertas/dev.h > @@ -75,6 +75,7 @@ struct lbs_private { > > /* Deep sleep */ > int is_deep_sleep; > + int deep_sleep_required; > int is_auto_deep_sleep_enabled; > int wakeup_dev_required; > int is_activity_detected; > @@ -82,6 +83,11 @@ struct lbs_private { > wait_queue_head_t ds_awake_q; > struct timer_list auto_deepsleep_timer; > > + /* Host sleep*/ > + int is_host_sleep_configured; > + int is_host_sleep_activated; > + wait_queue_head_t host_sleep_q; > + > /* Hardware access */ > void *card; > u8 fw_ready; > diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c > index 3804a58..6a36c99 100644 > --- a/drivers/net/wireless/libertas/ethtool.c > +++ b/drivers/net/wireless/libertas/ethtool.c > @@ -91,23 +91,22 @@ static int lbs_ethtool_set_wol(struct net_device *dev, > struct ethtool_wolinfo *wol) > { > struct lbs_private *priv = dev->ml_priv; > - uint32_t criteria = 0; > > if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY)) > return -EOPNOTSUPP; > > + priv->wol_criteria = 0; > if (wol->wolopts & WAKE_UCAST) > - criteria |= EHS_WAKE_ON_UNICAST_DATA; > + priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA; > if (wol->wolopts & WAKE_MCAST) > - criteria |= EHS_WAKE_ON_MULTICAST_DATA; > + priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA; > if (wol->wolopts & WAKE_BCAST) > - criteria |= EHS_WAKE_ON_BROADCAST_DATA; > + priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA; > if (wol->wolopts & WAKE_PHY) > - criteria |= EHS_WAKE_ON_MAC_EVENT; > + priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT; > if (wol->wolopts == 0) > - criteria |= EHS_REMOVE_WAKEUP; > - > - return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); > + priv->wol_criteria |= EHS_REMOVE_WAKEUP; > + return 0; > } > > const struct ethtool_ops lbs_ethtool_ops = { > diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c > index 64dd345..575d433 100644 > --- a/drivers/net/wireless/libertas/if_sdio.c > +++ b/drivers/net/wireless/libertas/if_sdio.c > @@ -1182,11 +1182,69 @@ static void if_sdio_remove(struct sdio_func *func) > lbs_deb_leave(LBS_DEB_SDIO); > } > > +static int if_sdio_suspend(struct device *dev) > +{ > + struct sdio_func *func = dev_to_sdio_func(dev); > + int ret; > + struct if_sdio_card *card = sdio_get_drvdata(func); > + > + mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); > + > + lbs_pr_info("%s: suspend: PM flags = 0x%x\n", > + sdio_func_id(func), flags); > + > + /* If we aren't being asked to wake on anything, we should bail out > + * and let the SD stack power down the card. > + */ > + if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { > + lbs_pr_info("Suspend without wake params -- " > + "powering down card."); > + return -ENOSYS; > + } > + > + if (!(flags & MMC_PM_KEEP_POWER)) { > + lbs_pr_err("%s: cannot remain alive while host is suspended\n", > + sdio_func_id(func)); > + return -ENOSYS; > + } > + > + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); > + if (ret) > + return ret; > + > + ret = lbs_suspend(card->priv); > + if (ret) > + return ret; > + > + return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); > +} > + > +static int if_sdio_resume(struct device *dev) > +{ > + struct sdio_func *func = dev_to_sdio_func(dev); > + struct if_sdio_card *card = sdio_get_drvdata(func); > + int ret; > + > + lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func)); > + > + ret = lbs_resume(card->priv); > + > + return ret; > +} > + > +static struct const dev_pm_ops if_sdio_pm_ops = { > + .suspend = if_sdio_suspend, > + .resume = if_sdio_resume, > +}; > + > static struct sdio_driver if_sdio_driver = { > .name = "libertas_sdio", > .id_table = if_sdio_ids, > .probe = if_sdio_probe, > .remove = if_sdio_remove, > + .drv = { > + .pm = &if_sdio_pm_ops, > + }, > }; > > /*******************************************************************/ > diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c > index fcea574..e5e6801 100644 > --- a/drivers/net/wireless/libertas/if_usb.c > +++ b/drivers/net/wireless/libertas/if_usb.c > @@ -1047,6 +1047,12 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) > if (priv->psstate != PS_STATE_FULL_POWER) > return -1; > > + if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { > + lbs_pr_info("Suspend attempt without " > + "configuring wake params!\n"); > + return -ENOSYS; > + } > + > ret = lbs_suspend(priv); > if (ret) > goto out; > diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c > index d35ebca..25c5734 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); -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html