Skip to content

Commit

Permalink
libertas: Added callback functions to support SDIO suspend/resume.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Amitkumar Karwar authored and John W. Linville committed Jun 2, 2010
1 parent a7da74f commit 66fceb6
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 62 deletions.
37 changes: 32 additions & 5 deletions drivers/net/wireless/libertas/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -185,6 +187,23 @@ int lbs_update_hw_spec(struct lbs_private *priv)
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)
{
Expand All @@ -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));
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 6 additions & 24 deletions drivers/net/wireless/libertas/cmdresp.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "dev.h"
#include "assoc.h"
#include "wext.h"
#include "cmd.h"

/**
* @brief This function handles disconnect event. it
Expand Down Expand Up @@ -341,32 +342,10 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
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);

Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/libertas/decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/libertas/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,19 @@ 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;
int auto_deep_sleep_timeout; /* in ms */
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;
Expand Down
15 changes: 7 additions & 8 deletions drivers/net/wireless/libertas/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
58 changes: 58 additions & 0 deletions drivers/net/wireless/libertas/if_sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 const struct 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,
},
};

/*******************************************************************/
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/libertas/if_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,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;
Expand Down
Loading

0 comments on commit 66fceb6

Please sign in to comment.