mirror of https://gitee.com/openkylin/linux.git
mwifiex: fix negative cmd_pending count
cmd_pending is increased in mwifiex_wait_queue_complete() and decreased in mwifiex_complete_cmd() currently. If there are two or more commands in the cmd_pending_q the main worker thread will pick up next command from cmd_pending_q automatically after finishing current command. As a result mwifiex_wait_queue_complete() will not be called because the command is alreay completed. This leads to a negative number in cmd_pending count. Fix it by increasing cmd_pending when a cmd is queued into cmd_pending_q and decreasing when that cmd is recycled. For scan commands we don't perform inc/dec operations until it's moved from scan_pending_q to cmd_pending_q. This covers both synchronous and asynchronous commands. Reported-by: Daniel Drake <dsd@laptop.org> Tested-by: Daniel Drake <dsd@laptop.org> Tested-by: Marco Cesarano <marco@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
84bcc0c3c4
commit
9908b07465
|
@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
|
|||
" or cmd size is 0, not sending\n");
|
||||
if (cmd_node->wait_q_enabled)
|
||||
adapter->cmd_wait_q.status = -1;
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
|
|||
"DNLD_CMD: FW in reset state, ignore cmd %#x\n",
|
||||
cmd_code);
|
||||
mwifiex_complete_cmd(adapter, cmd_node);
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
|
|||
adapter->cmd_sent = false;
|
||||
if (cmd_node->wait_q_enabled)
|
||||
adapter->cmd_wait_q.status = -1;
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->curr_cmd = NULL;
|
||||
|
@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
|
|||
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
|
||||
}
|
||||
|
||||
/* This function reuses a command node. */
|
||||
void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node)
|
||||
{
|
||||
struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
|
||||
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
|
||||
atomic_dec(&adapter->cmd_pending);
|
||||
dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
|
||||
le16_to_cpu(host_cmd->command),
|
||||
atomic_read(&adapter->cmd_pending));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function queues a command to the command pending queue.
|
||||
*
|
||||
|
@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
|
|||
list_add(&cmd_node->list, &adapter->cmd_pending_q);
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
|
||||
|
||||
dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
|
||||
atomic_inc(&adapter->cmd_pending);
|
||||
dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
|
||||
command, atomic_read(&adapter->cmd_pending));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -783,7 +799,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
|
|||
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
|
||||
dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
|
||||
le16_to_cpu(resp->command));
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->curr_cmd = NULL;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
|
||||
|
@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
|
|||
if (adapter->curr_cmd->wait_q_enabled)
|
||||
adapter->cmd_wait_q.status = -1;
|
||||
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->curr_cmd = NULL;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
|
||||
|
@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
|
|||
if (adapter->curr_cmd->wait_q_enabled)
|
||||
adapter->cmd_wait_q.status = ret;
|
||||
|
||||
/* Clean up and put current command back to cmd_free_q */
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->curr_cmd = NULL;
|
||||
|
@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
|
|||
mwifiex_complete_cmd(adapter, cmd_node);
|
||||
cmd_node->wait_q_enabled = false;
|
||||
}
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
|
||||
|
@ -1040,7 +1055,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
|
|||
cmd_node = adapter->curr_cmd;
|
||||
cmd_node->wait_q_enabled = false;
|
||||
cmd_node->cmd_flag |= CMD_F_CANCELED;
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
|
||||
adapter->curr_cmd = NULL;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
|
|
|
@ -713,7 +713,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
|
|||
if (adapter->curr_cmd) {
|
||||
dev_warn(adapter->dev, "curr_cmd is still in processing\n");
|
||||
del_timer(&adapter->cmd_timer);
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
adapter->curr_cmd = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -798,6 +798,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
|
|||
|
||||
void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node);
|
||||
void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node);
|
||||
|
||||
void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node,
|
||||
|
|
|
@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
|
|||
break;
|
||||
}
|
||||
/* Handling errors here */
|
||||
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
|
||||
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
|
||||
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->curr_cmd = NULL;
|
||||
|
|
|
@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
|
|||
{
|
||||
int status;
|
||||
|
||||
dev_dbg(adapter->dev, "cmd pending\n");
|
||||
atomic_inc(&adapter->cmd_pending);
|
||||
|
||||
/* Wait for completion */
|
||||
status = wait_event_interruptible(adapter->cmd_wait_q.wait,
|
||||
*(cmd_queued->condition));
|
||||
|
|
|
@ -239,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
|
|||
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node)
|
||||
{
|
||||
atomic_dec(&adapter->cmd_pending);
|
||||
dev_dbg(adapter->dev, "cmd completed: status=%d\n",
|
||||
adapter->cmd_wait_q.status);
|
||||
|
||||
|
|
Loading…
Reference in New Issue