linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Added support for host sleep feature
@ 2010-07-08  1:13 Amitkumar Karwar
  2010-07-08 15:11 ` Paul Fox
  0 siblings, 1 reply; 4+ messages in thread
From: Amitkumar Karwar @ 2010-07-08  1:13 UTC (permalink / raw)
  To: linux-wireless; +Cc: libertas-dev

From: Amitkumar Karwar <akarwar@marvell.com>

Existing "ethtool -s ethX wol X" command configures hostsleep
parameters, but those are activated only during suspend/resume,
there is no way to configure host sleep without actual suspend.

This patch adds debugfs command to enable/disable host sleep based on
already configured host sleep parameters using wol command.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
---
 drivers/net/wireless/libertas/README    |   12 ++++++
 drivers/net/wireless/libertas/cmd.c     |   61 ++++++++++++++++++++++++++++-
 drivers/net/wireless/libertas/cmd.h     |    2 +
 drivers/net/wireless/libertas/debugfs.c |   66 +++++++++++++++++++++++++++++++
 drivers/net/wireless/libertas/main.c    |   34 +---------------
 5 files changed, 142 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 2726c04..60fd1af 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -226,6 +226,18 @@ setuserscan
     All entries in the scan table (not just the new scan data when keep=1)
     will be displayed upon completion by use of the getscantable ioctl.
 
+hostsleep
+	This command is used to enable/disable host sleep.
+	Note: Host sleep parameters should be configured using
+	"ethtool -s ethX wol X" command before enabling host sleep.
+
+	Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+	Usage:
+		cat hostsleep: reads the current hostsleep state
+		echo "1" > hostsleep : enable host sleep.
+		echo "0" > hostsleep : disable host sleep
+
 ========================
 IWCONFIG COMMANDS
 ========================
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6c8a9d9..749fbde 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -181,7 +181,7 @@ 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) {
+	if (priv->is_host_sleep_activated) {
 		priv->is_host_sleep_configured = 0;
 		if (priv->psstate == PS_STATE_FULL_POWER) {
 			priv->is_host_sleep_activated = 0;
@@ -361,6 +361,65 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
 	return ret;
 }
 
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+		unsigned long dummy,
+		struct cmd_header *cmd)
+{
+	lbs_deb_enter(LBS_DEB_FW);
+	priv->is_host_sleep_activated = 1;
+	wake_up_interruptible(&priv->host_sleep_q);
+	lbs_deb_leave(LBS_DEB_FW);
+	return 0;
+}
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
+{
+	struct cmd_header cmd;
+	int ret = 0;
+	uint32_t criteria = EHS_REMOVE_WAKEUP;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	if (host_sleep) {
+		if (priv->is_host_sleep_activated != 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);
+			}
+
+			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;
+			}
+		} else {
+			lbs_pr_err("host sleep: already enabled\n");
+		}
+	} else {
+		if (priv->is_host_sleep_activated)
+			ret = lbs_host_sleep_cfg(priv, criteria,
+					(struct wol_config *)NULL);
+	}
+
+	return ret;
+}
+
 /**
  *  @brief Set an SNMP MIB value
  *
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index cb4138a..386e565 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -127,4 +127,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
 
 int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
 
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
+
 #endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 1736746..acaf811 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -124,6 +124,70 @@ out_unlock:
 	return ret;
 }
 
+static ssize_t lbs_host_sleep_write(struct file *file,
+				const char __user *user_buf, size_t count,
+				loff_t *ppos)
+{
+	struct lbs_private *priv = file->private_data;
+	ssize_t buf_size, ret;
+	int host_sleep;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	if (!buf)
+		return -ENOMEM;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+	ret = sscanf(buf, "%d", &host_sleep);
+	if (ret != 1) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (host_sleep == 0)
+		ret = lbs_set_host_sleep(priv, 0);
+	else if (host_sleep == 1) {
+		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+			lbs_pr_info("wake parameters not configured");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		ret = lbs_set_host_sleep(priv, 1);
+	} else {
+		lbs_pr_err("invalid option\n");
+		ret = -EINVAL;
+	}
+
+	if (!ret)
+		ret = count;
+
+out_unlock:
+	free_page(addr);
+	return ret;
+}
+
+static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	struct lbs_private *priv = file->private_data;
+	ssize_t ret;
+	size_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	if (!buf)
+		return -ENOMEM;
+
+	pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return ret;
+}
+
 /*
  * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
  * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@@ -675,6 +739,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
 	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
 	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
 				lbs_sleepparams_write), },
+	{ "hostsleep", 0644, FOPS(lbs_host_sleep_read,
+				lbs_host_sleep_write), },
 };
 
 static const struct lbs_debugfs_files debugfs_events_files[] = {
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index b519fc7..2a0b590 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -544,20 +544,8 @@ static int lbs_thread(void *data)
 	return 0;
 }
 
-static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
-		unsigned long dummy,
-		struct cmd_header *cmd)
-{
-	lbs_deb_enter(LBS_DEB_FW);
-	priv->is_host_sleep_activated = 1;
-	wake_up_interruptible(&priv->host_sleep_q);
-	lbs_deb_leave(LBS_DEB_FW);
-	return 0;
-}
-
 int lbs_suspend(struct lbs_private *priv)
 {
-	struct cmd_header cmd;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_FW);
@@ -571,25 +559,8 @@ int lbs_suspend(struct lbs_private *priv)
 		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_set_host_sleep(priv, 1);
 
-	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);
@@ -602,11 +573,10 @@ EXPORT_SYMBOL_GPL(lbs_suspend);
 int lbs_resume(struct lbs_private *priv)
 {
 	int ret;
-	uint32_t criteria = EHS_REMOVE_WAKEUP;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
-	ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
+	ret = lbs_set_host_sleep(priv, 0);
 
 	netif_device_attach(priv->dev);
 	if (priv->mesh_dev)
-- 
1.5.3.4




^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] Added support for host sleep feature
  2010-07-08  1:13 [PATCH] Added support for host sleep feature Amitkumar Karwar
@ 2010-07-08 15:11 ` Paul Fox
  2010-07-09 13:01   ` Amitkumar Karwar
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Fox @ 2010-07-08 15:11 UTC (permalink / raw)
  To: Amitkumar Karwar; +Cc: linux-wireless, libertas-dev

amitkumar wrote:
 > From: Amitkumar Karwar <akarwar@marvell.com>
 > 
 > Existing "ethtool -s ethX wol X" command configures hostsleep
 > parameters, but those are activated only during suspend/resume,
 > there is no way to configure host sleep without actual suspend.

as background, can you expand on how this is useful?  i just spent
a bunch of time debugging issues with HOST_SLEEP_CFG and
HOST_SLEEP_ACTIVATE (which doesn't work on an 8388) on the XO-1
OLPC laptop, and i'm wondering whether or how this would have
helped.

as an aside, since i know you've helped OLPC with some of these
issues in the past, the pertinent results of my debugging are:
 http://dev.laptop.org/git/olpc-2.6/commit/?h=olpc-2.6.31&id=515dc7313c37218fa02888eb19fba065ca0ab63c
and
 http://dev.laptop.org/git/olpc-2.6/commit/?h=olpc-2.6.31&id=8db05fd8301980cf48ff10f61c977256e1f136b5

other nearby commits, all dated 6/22/2010, are related, but were
less central to the problems we were having.)

paul

 > 
 > This patch adds debugfs command to enable/disable host sleep based on
 > already configured host sleep parameters using wol command.
 > 
 > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
 > Signed-off-by: Kiran Divekar <dkiran@marvell.com>
 > ---
 >  drivers/net/wireless/libertas/README    |   12 ++++++
 >  drivers/net/wireless/libertas/cmd.c     |   61 ++++++++++++++++++++++++++++-
 >  drivers/net/wireless/libertas/cmd.h     |    2 +
 >  drivers/net/wireless/libertas/debugfs.c |   66 +++++++++++++++++++++++++++++++
 >  drivers/net/wireless/libertas/main.c    |   34 +---------------
 >  5 files changed, 142 insertions(+), 33 deletions(-)
 > 
....

=---------------------
 paul fox, pgf@laptop.org

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH] Added support for host sleep feature
  2010-07-08 15:11 ` Paul Fox
@ 2010-07-09 13:01   ` Amitkumar Karwar
  2010-07-13  8:33     ` Alberto Panizzo
  0 siblings, 1 reply; 4+ messages in thread
From: Amitkumar Karwar @ 2010-07-09 13:01 UTC (permalink / raw)
  To: 'Paul Fox'
  Cc: linux-wireless@vger.kernel.org, libertas-dev@lists.infradead.org



> amitkumar wrote:
>  > From: Amitkumar Karwar <akarwar@marvell.com>
>  >
>  > Existing "ethtool -s ethX wol X" command configures hostsleep
>  > parameters, but those are activated only during suspend/resume,
>  > there is no way to configure host sleep without actual suspend.
> 
> as background, can you expand on how this is useful?  i just spent
> a bunch of time debugging issues with HOST_SLEEP_CFG and
> HOST_SLEEP_ACTIVATE (which doesn't work on an 8388) on the XO-1
> OLPC laptop, and i'm wondering whether or how this would have
> helped.

This patch is useful if someone wants to enable host sleep feature without the device entering suspend state.

The host sleep using device suspend feature is also intact.

Thanks,
Amitkumar Karwar

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH] Added support for host sleep feature
  2010-07-09 13:01   ` Amitkumar Karwar
@ 2010-07-13  8:33     ` Alberto Panizzo
  0 siblings, 0 replies; 4+ messages in thread
From: Alberto Panizzo @ 2010-07-13  8:33 UTC (permalink / raw)
  To: Amitkumar Karwar
  Cc: 'Paul Fox', linux-wireless@vger.kernel.org,
	libertas-dev@lists.infradead.org

On ven, 2010-07-09 at 06:01 -0700, Amitkumar Karwar wrote:
> 
> > amitkumar wrote:
> >  > From: Amitkumar Karwar <akarwar@marvell.com>
> >  >
> >  > Existing "ethtool -s ethX wol X" command configures hostsleep
> >  > parameters, but those are activated only during suspend/resume,
> >  > there is no way to configure host sleep without actual suspend.
> > 
> > as background, can you expand on how this is useful?  i just spent
> > a bunch of time debugging issues with HOST_SLEEP_CFG and
> > HOST_SLEEP_ACTIVATE (which doesn't work on an 8388) on the XO-1
> > OLPC laptop, and i'm wondering whether or how this would have
> > helped.
> 
> This patch is useful if someone wants to enable host sleep feature without the device entering suspend state.
> 
> The host sleep using device suspend feature is also intact.
> 
> Thanks,
> Amitkumar Karwar

Regards current consumption, maintaining a wireless connection active,
the device consumes circa 30 mA instead of 180 mA of full power idle
mode.
So for embedded devices powered from battery, enabling the Power Save
mode is a huge battery save task.

Best Regards,

-- 
Alberto!

        Be Persistent!
                - Greg Kroah-Hartman (FOSDEM 2010)


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-07-13  8:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-08  1:13 [PATCH] Added support for host sleep feature Amitkumar Karwar
2010-07-08 15:11 ` Paul Fox
2010-07-09 13:01   ` Amitkumar Karwar
2010-07-13  8:33     ` Alberto Panizzo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).