Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a345099 authored by David Woodhouse's avatar David Woodhouse Committed by David S. Miller
Browse files

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: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9fae899c
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -201,6 +201,8 @@ struct lbs_private {

	/** Timers */
	struct timer_list command_timer;
	int nr_retries;
	int cmd_timed_out;

	u8 hisregcpy;

+30 −22
Original line number Diff line number Diff line
@@ -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 @@ static int lbs_setup_firmware(struct lbs_private *priv)
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)