提交 9908b074 编写于 作者: B Bing Zhao 提交者: John W. Linville

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: NDaniel Drake <dsd@laptop.org>
Tested-by: NDaniel Drake <dsd@laptop.org>
Tested-by: NMarco Cesarano <marco@marvell.com>
Signed-off-by: NBing Zhao <bzhao@marvell.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 84bcc0c3
...@@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, ...@@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
" or cmd size is 0, not sending\n"); " or cmd size is 0, not sending\n");
if (cmd_node->wait_q_enabled) if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1; adapter->cmd_wait_q.status = -1;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node); mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1; return -1;
} }
...@@ -167,7 +167,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, ...@@ -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", "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code); cmd_code);
mwifiex_complete_cmd(adapter, cmd_node); mwifiex_complete_cmd(adapter, cmd_node);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node); mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1; return -1;
} }
...@@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, ...@@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
adapter->cmd_sent = false; adapter->cmd_sent = false;
if (cmd_node->wait_q_enabled) if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1; 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); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
...@@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, ...@@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); 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. * This function queues a command to the command pending queue.
* *
...@@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, ...@@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
list_add(&cmd_node->list, &adapter->cmd_pending_q); list_add(&cmd_node->list, &adapter->cmd_pending_q);
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); 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) ...@@ -783,7 +799,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
le16_to_cpu(resp->command)); 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); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
...@@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) ...@@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled) if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1; 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); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
...@@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) ...@@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled) if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = ret; adapter->cmd_wait_q.status = ret;
/* Clean up and put current command back to cmd_free_q */ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
...@@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) ...@@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
mwifiex_complete_cmd(adapter, cmd_node); mwifiex_complete_cmd(adapter, cmd_node);
cmd_node->wait_q_enabled = false; 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_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
} }
spin_unlock_irqrestore(&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) ...@@ -1040,7 +1055,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
cmd_node = adapter->curr_cmd; cmd_node = adapter->curr_cmd;
cmd_node->wait_q_enabled = false; cmd_node->wait_q_enabled = false;
cmd_node->cmd_flag |= CMD_F_CANCELED; 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); mwifiex_complete_cmd(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
......
...@@ -713,7 +713,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) ...@@ -713,7 +713,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd) { if (adapter->curr_cmd) {
dev_warn(adapter->dev, "curr_cmd is still in processing\n"); dev_warn(adapter->dev, "curr_cmd is still in processing\n");
del_timer(&adapter->cmd_timer); 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; adapter->curr_cmd = NULL;
} }
......
...@@ -798,6 +798,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); ...@@ -798,6 +798,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node); 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, void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node, struct cmd_ctrl_node *cmd_node,
......
...@@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, ...@@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break; break;
} }
/* Handling errors here */ /* 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); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL; adapter->curr_cmd = NULL;
......
...@@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, ...@@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
{ {
int status; int status;
dev_dbg(adapter->dev, "cmd pending\n");
atomic_inc(&adapter->cmd_pending);
/* Wait for completion */ /* Wait for completion */
status = wait_event_interruptible(adapter->cmd_wait_q.wait, status = wait_event_interruptible(adapter->cmd_wait_q.wait,
*(cmd_queued->condition)); *(cmd_queued->condition));
......
...@@ -239,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) ...@@ -239,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node) struct cmd_ctrl_node *cmd_node)
{ {
atomic_dec(&adapter->cmd_pending);
dev_dbg(adapter->dev, "cmd completed: status=%d\n", dev_dbg(adapter->dev, "cmd completed: status=%d\n",
adapter->cmd_wait_q.status); adapter->cmd_wait_q.status);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册