aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2010-07-07 21:13:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-12 16:05:31 -0400
commit1311843c58ca606bab8bfe4cf6c0fe50deb9986d (patch)
treef716fbf88c163e33ef622ecb5e9c1d37df006bc7
parent643f82e32f14faf0d0944c804203a6681b6b0a1e (diff)
libertas: Added support for host sleep feature
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> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/README12
-rw-r--r--drivers/net/wireless/libertas/cmd.c61
-rw-r--r--drivers/net/wireless/libertas/cmd.h2
-rw-r--r--drivers/net/wireless/libertas/debugfs.c66
-rw-r--r--drivers/net/wireless/libertas/main.c34
5 files changed, 142 insertions, 33 deletions
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 2726c044430f..60fd1afe89ac 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -226,6 +226,18 @@ setuserscan
226 All entries in the scan table (not just the new scan data when keep=1) 226 All entries in the scan table (not just the new scan data when keep=1)
227 will be displayed upon completion by use of the getscantable ioctl. 227 will be displayed upon completion by use of the getscantable ioctl.
228 228
229hostsleep
230 This command is used to enable/disable host sleep.
231 Note: Host sleep parameters should be configured using
232 "ethtool -s ethX wol X" command before enabling host sleep.
233
234 Path: /sys/kernel/debug/libertas_wireless/ethX/
235
236 Usage:
237 cat hostsleep: reads the current hostsleep state
238 echo "1" > hostsleep : enable host sleep.
239 echo "0" > hostsleep : disable host sleep
240
229======================== 241========================
230IWCONFIG COMMANDS 242IWCONFIG COMMANDS
231======================== 243========================
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6c8a9d952a01..749fbde4fd54 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,
181 struct cmd_header *resp) 181 struct cmd_header *resp)
182{ 182{
183 lbs_deb_enter(LBS_DEB_CMD); 183 lbs_deb_enter(LBS_DEB_CMD);
184 if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { 184 if (priv->is_host_sleep_activated) {
185 priv->is_host_sleep_configured = 0; 185 priv->is_host_sleep_configured = 0;
186 if (priv->psstate == PS_STATE_FULL_POWER) { 186 if (priv->psstate == PS_STATE_FULL_POWER) {
187 priv->is_host_sleep_activated = 0; 187 priv->is_host_sleep_activated = 0;
@@ -361,6 +361,65 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
361 return ret; 361 return ret;
362} 362}
363 363
364static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
365 unsigned long dummy,
366 struct cmd_header *cmd)
367{
368 lbs_deb_enter(LBS_DEB_FW);
369 priv->is_host_sleep_activated = 1;
370 wake_up_interruptible(&priv->host_sleep_q);
371 lbs_deb_leave(LBS_DEB_FW);
372 return 0;
373}
374
375int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
376{
377 struct cmd_header cmd;
378 int ret = 0;
379 uint32_t criteria = EHS_REMOVE_WAKEUP;
380
381 lbs_deb_enter(LBS_DEB_CMD);
382
383 if (host_sleep) {
384 if (priv->is_host_sleep_activated != 1) {
385 memset(&cmd, 0, sizeof(cmd));
386 ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
387 (struct wol_config *)NULL);
388 if (ret) {
389 lbs_pr_info("Host sleep configuration failed: "
390 "%d\n", ret);
391 return ret;
392 }
393 if (priv->psstate == PS_STATE_FULL_POWER) {
394 ret = __lbs_cmd(priv,
395 CMD_802_11_HOST_SLEEP_ACTIVATE,
396 &cmd,
397 sizeof(cmd),
398 lbs_ret_host_sleep_activate, 0);
399 if (ret)
400 lbs_pr_info("HOST_SLEEP_ACTIVATE "
401 "failed: %d\n", ret);
402 }
403
404 if (!wait_event_interruptible_timeout(
405 priv->host_sleep_q,
406 priv->is_host_sleep_activated,
407 (10 * HZ))) {
408 lbs_pr_err("host_sleep_q: timer expired\n");
409 ret = -1;
410 }
411 } else {
412 lbs_pr_err("host sleep: already enabled\n");
413 }
414 } else {
415 if (priv->is_host_sleep_activated)
416 ret = lbs_host_sleep_cfg(priv, criteria,
417 (struct wol_config *)NULL);
418 }
419
420 return ret;
421}
422
364/** 423/**
365 * @brief Set an SNMP MIB value 424 * @brief Set an SNMP MIB value
366 * 425 *
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index cb4138a55fdf..386e565d99ad 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);
127 127
128int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); 128int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
129 129
130int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
131
130#endif /* _LBS_CMD_H */ 132#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 17367463c855..acaf81164624 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -124,6 +124,70 @@ out_unlock:
124 return ret; 124 return ret;
125} 125}
126 126
127static ssize_t lbs_host_sleep_write(struct file *file,
128 const char __user *user_buf, size_t count,
129 loff_t *ppos)
130{
131 struct lbs_private *priv = file->private_data;
132 ssize_t buf_size, ret;
133 int host_sleep;
134 unsigned long addr = get_zeroed_page(GFP_KERNEL);
135 char *buf = (char *)addr;
136 if (!buf)
137 return -ENOMEM;
138
139 buf_size = min(count, len - 1);
140 if (copy_from_user(buf, user_buf, buf_size)) {
141 ret = -EFAULT;
142 goto out_unlock;
143 }
144 ret = sscanf(buf, "%d", &host_sleep);
145 if (ret != 1) {
146 ret = -EINVAL;
147 goto out_unlock;
148 }
149
150 if (host_sleep == 0)
151 ret = lbs_set_host_sleep(priv, 0);
152 else if (host_sleep == 1) {
153 if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
154 lbs_pr_info("wake parameters not configured");
155 ret = -EINVAL;
156 goto out_unlock;
157 }
158 ret = lbs_set_host_sleep(priv, 1);
159 } else {
160 lbs_pr_err("invalid option\n");
161 ret = -EINVAL;
162 }
163
164 if (!ret)
165 ret = count;
166
167out_unlock:
168 free_page(addr);
169 return ret;
170}
171
172static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
173 size_t count, loff_t *ppos)
174{
175 struct lbs_private *priv = file->private_data;
176 ssize_t ret;
177 size_t pos = 0;
178 unsigned long addr = get_zeroed_page(GFP_KERNEL);
179 char *buf = (char *)addr;
180 if (!buf)
181 return -ENOMEM;
182
183 pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
184
185 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
186
187 free_page(addr);
188 return ret;
189}
190
127/* 191/*
128 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might 192 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
129 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the 193 * 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[] = {
675 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, 739 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
676 { "sleepparams", 0644, FOPS(lbs_sleepparams_read, 740 { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
677 lbs_sleepparams_write), }, 741 lbs_sleepparams_write), },
742 { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
743 lbs_host_sleep_write), },
678}; 744};
679 745
680static const struct lbs_debugfs_files debugfs_events_files[] = { 746static 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 b519fc70f04f..2a0b590a93f1 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)
544 return 0; 544 return 0;
545} 545}
546 546
547static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
548 unsigned long dummy,
549 struct cmd_header *cmd)
550{
551 lbs_deb_enter(LBS_DEB_FW);
552 priv->is_host_sleep_activated = 1;
553 wake_up_interruptible(&priv->host_sleep_q);
554 lbs_deb_leave(LBS_DEB_FW);
555 return 0;
556}
557
558int lbs_suspend(struct lbs_private *priv) 547int lbs_suspend(struct lbs_private *priv)
559{ 548{
560 struct cmd_header cmd;
561 int ret; 549 int ret;
562 550
563 lbs_deb_enter(LBS_DEB_FW); 551 lbs_deb_enter(LBS_DEB_FW);
@@ -571,25 +559,8 @@ int lbs_suspend(struct lbs_private *priv)
571 priv->deep_sleep_required = 1; 559 priv->deep_sleep_required = 1;
572 } 560 }
573 561
574 memset(&cmd, 0, sizeof(cmd)); 562 ret = lbs_set_host_sleep(priv, 1);
575 ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
576 (struct wol_config *)NULL);
577 if (ret) {
578 lbs_pr_info("Host sleep configuration failed: %d\n", ret);
579 return ret;
580 }
581 if (priv->psstate == PS_STATE_FULL_POWER) {
582 ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
583 sizeof(cmd), lbs_ret_host_sleep_activate, 0);
584 if (ret)
585 lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
586 }
587 563
588 if (!wait_event_interruptible_timeout(priv->host_sleep_q,
589 priv->is_host_sleep_activated, (10 * HZ))) {
590 lbs_pr_err("host_sleep_q: timer expired\n");
591 ret = -1;
592 }
593 netif_device_detach(priv->dev); 564 netif_device_detach(priv->dev);
594 if (priv->mesh_dev) 565 if (priv->mesh_dev)
595 netif_device_detach(priv->mesh_dev); 566 netif_device_detach(priv->mesh_dev);
@@ -602,11 +573,10 @@ EXPORT_SYMBOL_GPL(lbs_suspend);
602int lbs_resume(struct lbs_private *priv) 573int lbs_resume(struct lbs_private *priv)
603{ 574{
604 int ret; 575 int ret;
605 uint32_t criteria = EHS_REMOVE_WAKEUP;
606 576
607 lbs_deb_enter(LBS_DEB_FW); 577 lbs_deb_enter(LBS_DEB_FW);
608 578
609 ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); 579 ret = lbs_set_host_sleep(priv, 0);
610 580
611 netif_device_attach(priv->dev); 581 netif_device_attach(priv->dev);
612 if (priv->mesh_dev) 582 if (priv->mesh_dev)