aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2009-09-30 23:04:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-07 16:39:43 -0400
commit4912545472d71e3dd546b18b397aec4c89fd7403 (patch)
treeb7b0d520cdbee35303caf69881f7898e38966bc7 /drivers/net/wireless/libertas/main.c
parent125b181aec7a67c71234284ecf6d9c729d05deda (diff)
libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
Add timer based auto deep sleep feature in libertas driver which can be configured using iwconfig command. This is tested on SD8688, SD8686 cards with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit platforms. Tests have been done for USB/CS cards to make sure that the patch won't break USB/CS code. We didn't test the if_spi driver. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c111
1 files changed, 97 insertions, 14 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 87b4e497faa..9b2a9174a01 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
574 priv->dnld_sent = DNLD_RES_RECEIVED; 574 priv->dnld_sent = DNLD_RES_RECEIVED;
575 575
576 /* Wake main thread if commands are pending */ 576 /* Wake main thread if commands are pending */
577 if (!priv->cur_cmd || priv->tx_pending_len > 0) 577 if (!priv->cur_cmd || priv->tx_pending_len > 0) {
578 wake_up_interruptible(&priv->waitq); 578 if (!priv->wakeup_dev_required)
579 wake_up_interruptible(&priv->waitq);
580 }
579 581
580 spin_unlock_irqrestore(&priv->driver_lock, flags); 582 spin_unlock_irqrestore(&priv->driver_lock, flags);
581 lbs_deb_leave(LBS_DEB_THREAD); 583 lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +772,8 @@ static int lbs_thread(void *data)
770 shouldsleep = 0; /* We have a command response */ 772 shouldsleep = 0; /* We have a command response */
771 else if (priv->cur_cmd) 773 else if (priv->cur_cmd)
772 shouldsleep = 1; /* Can't send a command; one already running */ 774 shouldsleep = 1; /* Can't send a command; one already running */
773 else if (!list_empty(&priv->cmdpendingq)) 775 else if (!list_empty(&priv->cmdpendingq) &&
776 !(priv->wakeup_dev_required))
774 shouldsleep = 0; /* We have a command to send */ 777 shouldsleep = 0; /* We have a command to send */
775 else if (__kfifo_len(priv->event_fifo)) 778 else if (__kfifo_len(priv->event_fifo))
776 shouldsleep = 0; /* We have an event to process */ 779 shouldsleep = 0; /* We have an event to process */
@@ -822,6 +825,26 @@ static int lbs_thread(void *data)
822 } 825 }
823 spin_unlock_irq(&priv->driver_lock); 826 spin_unlock_irq(&priv->driver_lock);
824 827
828 /* Process hardware events, e.g. card removed, link lost */
829 spin_lock_irq(&priv->driver_lock);
830 while (__kfifo_len(priv->event_fifo)) {
831 u32 event;
832 __kfifo_get(priv->event_fifo, (unsigned char *) &event,
833 sizeof(event));
834 spin_unlock_irq(&priv->driver_lock);
835 lbs_process_event(priv, event);
836 spin_lock_irq(&priv->driver_lock);
837 }
838 spin_unlock_irq(&priv->driver_lock);
839
840 if (priv->wakeup_dev_required) {
841 lbs_deb_thread("Waking up device...\n");
842 /* Wake up device */
843 if (priv->exit_deep_sleep(priv))
844 lbs_deb_thread("Wakeup device failed\n");
845 continue;
846 }
847
825 /* command timeout stuff */ 848 /* command timeout stuff */
826 if (priv->cmd_timed_out && priv->cur_cmd) { 849 if (priv->cmd_timed_out && priv->cur_cmd) {
827 struct cmd_ctrl_node *cmdnode = priv->cur_cmd; 850 struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +872,7 @@ static int lbs_thread(void *data)
849 } 872 }
850 priv->cmd_timed_out = 0; 873 priv->cmd_timed_out = 0;
851 874
852 /* Process hardware events, e.g. card removed, link lost */
853 spin_lock_irq(&priv->driver_lock);
854 while (__kfifo_len(priv->event_fifo)) {
855 u32 event;
856 875
857 __kfifo_get(priv->event_fifo, (unsigned char *) &event,
858 sizeof(event));
859 spin_unlock_irq(&priv->driver_lock);
860 lbs_process_event(priv, event);
861 spin_lock_irq(&priv->driver_lock);
862 }
863 spin_unlock_irq(&priv->driver_lock);
864 876
865 if (!priv->fw_ready) 877 if (!priv->fw_ready)
866 continue; 878 continue;
@@ -894,6 +906,9 @@ static int lbs_thread(void *data)
894 (priv->psstate == PS_STATE_PRE_SLEEP)) 906 (priv->psstate == PS_STATE_PRE_SLEEP))
895 continue; 907 continue;
896 908
909 if (priv->is_deep_sleep)
910 continue;
911
897 /* Execute the next command */ 912 /* Execute the next command */
898 if (!priv->dnld_sent && !priv->cur_cmd) 913 if (!priv->dnld_sent && !priv->cur_cmd)
899 lbs_execute_next_command(priv); 914 lbs_execute_next_command(priv);
@@ -928,6 +943,7 @@ static int lbs_thread(void *data)
928 } 943 }
929 944
930 del_timer(&priv->command_timer); 945 del_timer(&priv->command_timer);
946 del_timer(&priv->auto_deepsleep_timer);
931 wake_up_all(&priv->cmd_pending); 947 wake_up_all(&priv->cmd_pending);
932 948
933 lbs_deb_leave(LBS_DEB_THREAD); 949 lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +1066,60 @@ out:
1050 lbs_deb_leave(LBS_DEB_CMD); 1066 lbs_deb_leave(LBS_DEB_CMD);
1051} 1067}
1052 1068
1069/**
1070 * This function put the device back to deep sleep mode when timer expires
1071 * and no activity (command, event, data etc.) is detected.
1072 */
1073static void auto_deepsleep_timer_fn(unsigned long data)
1074{
1075 struct lbs_private *priv = (struct lbs_private *)data;
1076 int ret;
1077
1078 lbs_deb_enter(LBS_DEB_CMD);
1079
1080 if (priv->is_activity_detected) {
1081 priv->is_activity_detected = 0;
1082 } else {
1083 if (priv->is_auto_deep_sleep_enabled &&
1084 (!priv->wakeup_dev_required) &&
1085 (priv->connect_status != LBS_CONNECTED)) {
1086 lbs_deb_main("Entering auto deep sleep mode...\n");
1087 ret = lbs_prepare_and_send_command(priv,
1088 CMD_802_11_DEEP_SLEEP, 0,
1089 0, 0, NULL);
1090 }
1091 }
1092 mod_timer(&priv->auto_deepsleep_timer , jiffies +
1093 (priv->auto_deep_sleep_timeout * HZ)/1000);
1094 lbs_deb_leave(LBS_DEB_CMD);
1095}
1096
1097int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
1098{
1099 lbs_deb_enter(LBS_DEB_SDIO);
1100
1101 priv->is_auto_deep_sleep_enabled = 1;
1102 if (priv->is_deep_sleep)
1103 priv->wakeup_dev_required = 1;
1104 mod_timer(&priv->auto_deepsleep_timer ,
1105 jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
1106
1107 lbs_deb_leave(LBS_DEB_SDIO);
1108 return 0;
1109}
1110
1111int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
1112{
1113 lbs_deb_enter(LBS_DEB_SDIO);
1114
1115 priv->is_auto_deep_sleep_enabled = 0;
1116 priv->auto_deep_sleep_timeout = 0;
1117 del_timer(&priv->auto_deepsleep_timer);
1118
1119 lbs_deb_leave(LBS_DEB_SDIO);
1120 return 0;
1121}
1122
1053static void lbs_sync_channel_worker(struct work_struct *work) 1123static void lbs_sync_channel_worker(struct work_struct *work)
1054{ 1124{
1055 struct lbs_private *priv = container_of(work, struct lbs_private, 1125 struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
1099 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; 1169 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
1100 priv->psmode = LBS802_11POWERMODECAM; 1170 priv->psmode = LBS802_11POWERMODECAM;
1101 priv->psstate = PS_STATE_FULL_POWER; 1171 priv->psstate = PS_STATE_FULL_POWER;
1172 priv->is_deep_sleep = 0;
1173 priv->is_auto_deep_sleep_enabled = 0;
1174 priv->wakeup_dev_required = 0;
1175 init_waitqueue_head(&priv->ds_awake_q);
1102 1176
1103 mutex_init(&priv->lock); 1177 mutex_init(&priv->lock);
1104 1178
1105 setup_timer(&priv->command_timer, command_timer_fn, 1179 setup_timer(&priv->command_timer, command_timer_fn,
1106 (unsigned long)priv); 1180 (unsigned long)priv);
1181 setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
1182 (unsigned long)priv);
1107 1183
1108 INIT_LIST_HEAD(&priv->cmdfreeq); 1184 INIT_LIST_HEAD(&priv->cmdfreeq);
1109 INIT_LIST_HEAD(&priv->cmdpendingq); 1185 INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
1142 if (priv->event_fifo) 1218 if (priv->event_fifo)
1143 kfifo_free(priv->event_fifo); 1219 kfifo_free(priv->event_fifo);
1144 del_timer(&priv->command_timer); 1220 del_timer(&priv->command_timer);
1221 del_timer(&priv->auto_deepsleep_timer);
1145 kfree(priv->networks); 1222 kfree(priv->networks);
1146 priv->networks = NULL; 1223 priv->networks = NULL;
1147 1224
@@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
1272 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 1349 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1273 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); 1350 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1274 1351
1352 if (priv->is_deep_sleep) {
1353 priv->is_deep_sleep = 0;
1354 wake_up_interruptible(&priv->ds_awake_q);
1355 }
1356
1275 /* Stop the thread servicing the interrupts */ 1357 /* Stop the thread servicing the interrupts */
1276 priv->surpriseremoved = 1; 1358 priv->surpriseremoved = 1;
1277 kthread_stop(priv->main_thread); 1359 kthread_stop(priv->main_thread);
@@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)
1392 1474
1393 /* Delete the timeout of the currently processing command */ 1475 /* Delete the timeout of the currently processing command */
1394 del_timer_sync(&priv->command_timer); 1476 del_timer_sync(&priv->command_timer);
1477 del_timer_sync(&priv->auto_deepsleep_timer);
1395 1478
1396 /* Flush pending command nodes */ 1479 /* Flush pending command nodes */
1397 spin_lock_irqsave(&priv->driver_lock, flags); 1480 spin_lock_irqsave(&priv->driver_lock, flags);