diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-12-15 19:33:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:07:37 -0500 |
commit | 2a345099a4fbe551a1982630b3d89c85fa5a341d (patch) | |
tree | 6556158a8b8b3f63385e36a80b9b7d7f58e8fc92 /drivers/net/wireless/libertas/main.c | |
parent | 9fae899c2b5dc224042da63b14118abdb22ae9b6 (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/net/wireless/libertas/main.c')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 52 |
1 files changed, 30 insertions, 22 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 839ffe818c18..9677b0d77160 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: | |||
922 | static void command_timer_fn(unsigned long data) | 944 | static 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 | ||
956 | static int lbs_init_adapter(struct lbs_private *priv) | 964 | static int lbs_init_adapter(struct lbs_private *priv) |