aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-12-15 19:33:43 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:07:37 -0500
commit2a345099a4fbe551a1982630b3d89c85fa5a341d (patch)
tree6556158a8b8b3f63385e36a80b9b7d7f58e8fc92 /drivers
parent9fae899c2b5dc224042da63b14118abdb22ae9b6 (diff)
libertas: handle command timeout in main thread instead of directly in timer
And handle the case where it times out more than once, too, instead of locking up for ever. Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c6
-rw-r--r--drivers/net/wireless/libertas/dev.h2
-rw-r--r--drivers/net/wireless/libertas/main.c52
3 files changed, 38 insertions, 22 deletions
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 4c22e784951..ef63c376c55 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -667,6 +667,12 @@ int lbs_process_rx_command(struct lbs_private *priv)
667 667
668 /* Now we got response from FW, cancel the command timer */ 668 /* Now we got response from FW, cancel the command timer */
669 del_timer(&priv->command_timer); 669 del_timer(&priv->command_timer);
670 priv->cmd_timed_out = 0;
671 if (priv->nr_retries) {
672 lbs_pr_info("Received result %x to command %x after %d retries\n",
673 result, curcmd, priv->nr_retries);
674 priv->nr_retries = 0;
675 }
670 676
671 /* Store the response code to cur_cmd_retcode. */ 677 /* Store the response code to cur_cmd_retcode. */
672 priv->cur_cmd_retcode = result; 678 priv->cur_cmd_retcode = result;
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index e6f553d5d2c..465080fd060 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -201,6 +201,8 @@ struct lbs_private {
201 201
202 /** Timers */ 202 /** Timers */
203 struct timer_list command_timer; 203 struct timer_list command_timer;
204 int nr_retries;
205 int cmd_timed_out;
204 206
205 u8 hisregcpy; 207 u8 hisregcpy;
206 208
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 839ffe818c1..9677b0d7716 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -670,6 +670,8 @@ static int lbs_thread(void *data)
670 shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ 670 shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
671 else if (priv->intcounter) 671 else if (priv->intcounter)
672 shouldsleep = 0; /* Interrupt pending. Deal with it now */ 672 shouldsleep = 0; /* Interrupt pending. Deal with it now */
673 else if (priv->cmd_timed_out)
674 shouldsleep = 0; /* Command timed out. Recover */
673 else if (!priv->fw_ready) 675 else if (!priv->fw_ready)
674 shouldsleep = 1; /* Firmware not ready. We're waiting for it */ 676 shouldsleep = 1; /* Firmware not ready. We're waiting for it */
675 else if (priv->dnld_sent) 677 else if (priv->dnld_sent)
@@ -740,6 +742,26 @@ static int lbs_thread(void *data)
740 spin_lock_irq(&priv->driver_lock); 742 spin_lock_irq(&priv->driver_lock);
741 } 743 }
742 744
745 if (priv->cmd_timed_out && priv->cur_cmd) {
746 struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
747
748 if (++priv->nr_retries > 10) {
749 lbs_pr_info("Excessive timeouts submitting command %x\n",
750 le16_to_cpu(cmdnode->cmdbuf->command));
751 lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
752 priv->nr_retries = 0;
753 } else {
754 priv->cur_cmd = NULL;
755 lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
756 le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
757
758 /* Stick it back at the _top_ of the pending queue
759 for immediate resubmission */
760 list_add(&cmdnode->list, &priv->cmdpendingq);
761 }
762 }
763 priv->cmd_timed_out = 0;
764
743 /* Any Card Event */ 765 /* Any Card Event */
744 if (priv->hisregcpy & MRVDRV_CARDEVENT) { 766 if (priv->hisregcpy & MRVDRV_CARDEVENT) {
745 lbs_deb_thread("main-thread: Card Event Activity\n"); 767 lbs_deb_thread("main-thread: Card Event Activity\n");
@@ -922,35 +944,21 @@ done:
922static void command_timer_fn(unsigned long data) 944static void command_timer_fn(unsigned long data)
923{ 945{
924 struct lbs_private *priv = (struct lbs_private *)data; 946 struct lbs_private *priv = (struct lbs_private *)data;
925 struct cmd_ctrl_node *node;
926 unsigned long flags; 947 unsigned long flags;
927 948
928 node = priv->cur_cmd; 949 spin_lock_irqsave(&priv->driver_lock, flags);
929 if (node == NULL) {
930 lbs_deb_fw("ptempnode empty\n");
931 return;
932 }
933 950
934 if (!node->cmdbuf) { 951 if (!priv->cur_cmd) {
935 lbs_deb_fw("cmd is NULL\n"); 952 lbs_pr_info("Command timer expired; no pending command\n");
936 return; 953 goto out;
937 } 954 }
938 955
939 lbs_pr_info("command %x timed out\n", le16_to_cpu(node->cmdbuf->command)); 956 lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
940
941 if (!priv->fw_ready)
942 return;
943
944 spin_lock_irqsave(&priv->driver_lock, flags);
945 priv->cur_cmd = NULL;
946 spin_unlock_irqrestore(&priv->driver_lock, flags);
947
948 lbs_deb_fw("re-sending same command because of timeout\n");
949 lbs_queue_cmd(priv, node, 0);
950 957
958 priv->cmd_timed_out = 1;
951 wake_up_interruptible(&priv->waitq); 959 wake_up_interruptible(&priv->waitq);
952 960 out:
953 return; 961 spin_unlock_irqrestore(&priv->driver_lock, flags);
954} 962}
955 963
956static int lbs_init_adapter(struct lbs_private *priv) 964static int lbs_init_adapter(struct lbs_private *priv)