From: David Woodhouse Date: Sun, 16 Dec 2007 00:33:43 +0000 (-0500) Subject: libertas: handle command timeout in main thread instead of directly in timer X-Git-Tag: v2.6.25-rc1~1162^2~312 X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=2a345099a4fbe551a1982630b3d89c85fa5a341d;p=linux-2.6-omap-h63xx.git 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 Signed-off-by: John W. Linville --- 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) /* Now we got response from FW, cancel the command timer */ del_timer(&priv->command_timer); + priv->cmd_timed_out = 0; + if (priv->nr_retries) { + lbs_pr_info("Received result %x to command %x after %d retries\n", + result, curcmd, priv->nr_retries); + priv->nr_retries = 0; + } /* Store the response code to cur_cmd_retcode. */ 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 { /** Timers */ struct timer_list command_timer; + int nr_retries; + int cmd_timed_out; u8 hisregcpy; 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) shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ else if (priv->intcounter) shouldsleep = 0; /* Interrupt pending. Deal with it now */ + else if (priv->cmd_timed_out) + shouldsleep = 0; /* Command timed out. Recover */ else if (!priv->fw_ready) shouldsleep = 1; /* Firmware not ready. We're waiting for it */ else if (priv->dnld_sent) @@ -740,6 +742,26 @@ static int lbs_thread(void *data) spin_lock_irq(&priv->driver_lock); } + if (priv->cmd_timed_out && priv->cur_cmd) { + struct cmd_ctrl_node *cmdnode = priv->cur_cmd; + + if (++priv->nr_retries > 10) { + lbs_pr_info("Excessive timeouts submitting command %x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); + lbs_complete_command(priv, cmdnode, -ETIMEDOUT); + priv->nr_retries = 0; + } else { + priv->cur_cmd = NULL; + lbs_pr_info("requeueing command %x due to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); + + /* Stick it back at the _top_ of the pending queue + for immediate resubmission */ + list_add(&cmdnode->list, &priv->cmdpendingq); + } + } + priv->cmd_timed_out = 0; + /* Any Card Event */ if (priv->hisregcpy & MRVDRV_CARDEVENT) { lbs_deb_thread("main-thread: Card Event Activity\n"); @@ -922,35 +944,21 @@ done: static void command_timer_fn(unsigned long data) { struct lbs_private *priv = (struct lbs_private *)data; - struct cmd_ctrl_node *node; unsigned long flags; - node = priv->cur_cmd; - if (node == NULL) { - lbs_deb_fw("ptempnode empty\n"); - return; - } + spin_lock_irqsave(&priv->driver_lock, flags); - if (!node->cmdbuf) { - lbs_deb_fw("cmd is NULL\n"); - return; + if (!priv->cur_cmd) { + lbs_pr_info("Command timer expired; no pending command\n"); + goto out; } - lbs_pr_info("command %x timed out\n", le16_to_cpu(node->cmdbuf->command)); - - if (!priv->fw_ready) - return; - - spin_lock_irqsave(&priv->driver_lock, flags); - priv->cur_cmd = NULL; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - lbs_deb_fw("re-sending same command because of timeout\n"); - lbs_queue_cmd(priv, node, 0); + lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); - - return; + out: + spin_unlock_irqrestore(&priv->driver_lock, flags); } static int lbs_init_adapter(struct lbs_private *priv)