mwifiex: fix negative cmd_pending count
authorBing Zhao <bzhao@marvell.com>
Mon, 1 Apr 2013 19:44:46 +0000 (12:44 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 8 Apr 2013 19:28:37 +0000 (15:28 -0400)
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>
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/util.c

index 9a1302bd4c030e36064bcc62d8fe9fcc9e053a8c..da469c336aa1ad36ad682ca3d06d9242b7212145 100644 (file)
@@ -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);
index daf8801cecd2fc4984b48957fd01bef220e15a1a..003c014d2176acc3c00c579d46d2dd5d368022ad 100644 (file)
@@ -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;
        }
 
index cab8a85309446dadef0e93ea837ad4ac4fc0cfe4..fef89fd6d77b8054c0160b47f1fe9b8db5175a5c 100644 (file)
@@ -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,
index c7dc450f0bf3eadfe855ac7e63b096f1f683d042..9f990e14966e8354a91b6e90bd69c413c3f562e7 100644 (file)
@@ -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;
index 8c943b6ebf4512034eb17349a9bb320c8f66cb4e..e6c9b2ae22ed707fbbfd53dc98a72fad18b563f9 100644 (file)
@@ -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));
index 54667e65ca47ba104764e99b2ce1fc95e9d183f7..e57ac0dd3ab55177512aeac08482e54e926696cd 100644 (file)
@@ -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);