diff options
| -rw-r--r-- | drivers/net/wireless/libertas/README | 12 | ||||
| -rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 61 | ||||
| -rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/libertas/debugfs.c | 66 | ||||
| -rw-r--r-- | 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 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 | ||
| 229 | hostsleep | ||
| 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 | ======================== |
| 230 | IWCONFIG COMMANDS | 242 | IWCONFIG 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 | ||
| 364 | static 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 | |||
| 375 | int 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 | ||
| 128 | int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); | 128 | int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); |
| 129 | 129 | ||
| 130 | int 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 | ||
| 127 | static 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 | |||
| 167 | out_unlock: | ||
| 168 | free_page(addr); | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | static 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 | ||
| 680 | static const struct lbs_debugfs_files debugfs_events_files[] = { | 746 | 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 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 | ||
| 547 | static 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 | |||
| 558 | int lbs_suspend(struct lbs_private *priv) | 547 | int 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); | |||
| 602 | int lbs_resume(struct lbs_private *priv) | 573 | int 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) |
