aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2013-04-01 15:44:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-08 15:28:37 -0400
commit9908b07465556d4c96685d7f1ead0e17b01c662d (patch)
tree6361c56ff62efdeccfaa95ba52069eb42721bd00 /drivers/net/wireless
parent84bcc0c3c4b8ca4c0abed2d2dd63b7ce04f8be0e (diff)
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>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c35
-rw-r--r--drivers/net/wireless/mwifiex/init.c2
-rw-r--r--drivers/net/wireless/mwifiex/main.h2
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c3
-rw-r--r--drivers/net/wireless/mwifiex/util.c1
6 files changed, 29 insertions, 16 deletions
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 9a1302bd4c03..da469c336aa1 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
153 " or cmd size is 0, not sending\n"); 153 " or cmd size is 0, not sending\n");
154 if (cmd_node->wait_q_enabled) 154 if (cmd_node->wait_q_enabled)
155 adapter->cmd_wait_q.status = -1; 155 adapter->cmd_wait_q.status = -1;
156 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); 156 mwifiex_recycle_cmd_node(adapter, cmd_node);
157 return -1; 157 return -1;
158 } 158 }
159 159
@@ -167,7 +167,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
167 "DNLD_CMD: FW in reset state, ignore cmd %#x\n", 167 "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
168 cmd_code); 168 cmd_code);
169 mwifiex_complete_cmd(adapter, cmd_node); 169 mwifiex_complete_cmd(adapter, cmd_node);
170 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); 170 mwifiex_recycle_cmd_node(adapter, cmd_node);
171 return -1; 171 return -1;
172 } 172 }
173 173
@@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
228 adapter->cmd_sent = false; 228 adapter->cmd_sent = false;
229 if (cmd_node->wait_q_enabled) 229 if (cmd_node->wait_q_enabled)
230 adapter->cmd_wait_q.status = -1; 230 adapter->cmd_wait_q.status = -1;
231 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); 231 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
232 232
233 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 233 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
234 adapter->curr_cmd = NULL; 234 adapter->curr_cmd = NULL;
@@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
632 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); 632 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
633} 633}
634 634
635/* This function reuses a command node. */
636void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
637 struct cmd_ctrl_node *cmd_node)
638{
639 struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
640
641 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
642
643 atomic_dec(&adapter->cmd_pending);
644 dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
645 le16_to_cpu(host_cmd->command),
646 atomic_read(&adapter->cmd_pending));
647}
648
635/* 649/*
636 * This function queues a command to the command pending queue. 650 * This function queues a command to the command pending queue.
637 * 651 *
@@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
673 list_add(&cmd_node->list, &adapter->cmd_pending_q); 687 list_add(&cmd_node->list, &adapter->cmd_pending_q);
674 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); 688 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
675 689
676 dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); 690 atomic_inc(&adapter->cmd_pending);
691 dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
692 command, atomic_read(&adapter->cmd_pending));
677} 693}
678 694
679/* 695/*
@@ -783,7 +799,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
783 if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { 799 if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
784 dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", 800 dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
785 le16_to_cpu(resp->command)); 801 le16_to_cpu(resp->command));
786 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); 802 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
787 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 803 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
788 adapter->curr_cmd = NULL; 804 adapter->curr_cmd = NULL;
789 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); 805 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
833 if (adapter->curr_cmd->wait_q_enabled) 849 if (adapter->curr_cmd->wait_q_enabled)
834 adapter->cmd_wait_q.status = -1; 850 adapter->cmd_wait_q.status = -1;
835 851
836 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); 852 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
837 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 853 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
838 adapter->curr_cmd = NULL; 854 adapter->curr_cmd = NULL;
839 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); 855 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
865 if (adapter->curr_cmd->wait_q_enabled) 881 if (adapter->curr_cmd->wait_q_enabled)
866 adapter->cmd_wait_q.status = ret; 882 adapter->cmd_wait_q.status = ret;
867 883
868 /* Clean up and put current command back to cmd_free_q */ 884 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
869 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
870 885
871 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 886 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
872 adapter->curr_cmd = NULL; 887 adapter->curr_cmd = NULL;
@@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
993 mwifiex_complete_cmd(adapter, cmd_node); 1008 mwifiex_complete_cmd(adapter, cmd_node);
994 cmd_node->wait_q_enabled = false; 1009 cmd_node->wait_q_enabled = false;
995 } 1010 }
996 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); 1011 mwifiex_recycle_cmd_node(adapter, cmd_node);
997 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); 1012 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
998 } 1013 }
999 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); 1014 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
@@ -1040,7 +1055,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
1040 cmd_node = adapter->curr_cmd; 1055 cmd_node = adapter->curr_cmd;
1041 cmd_node->wait_q_enabled = false; 1056 cmd_node->wait_q_enabled = false;
1042 cmd_node->cmd_flag |= CMD_F_CANCELED; 1057 cmd_node->cmd_flag |= CMD_F_CANCELED;
1043 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); 1058 mwifiex_recycle_cmd_node(adapter, cmd_node);
1044 mwifiex_complete_cmd(adapter, adapter->curr_cmd); 1059 mwifiex_complete_cmd(adapter, adapter->curr_cmd);
1045 adapter->curr_cmd = NULL; 1060 adapter->curr_cmd = NULL;
1046 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); 1061 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index daf8801cecd2..003c014d2176 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -713,7 +713,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
713 if (adapter->curr_cmd) { 713 if (adapter->curr_cmd) {
714 dev_warn(adapter->dev, "curr_cmd is still in processing\n"); 714 dev_warn(adapter->dev, "curr_cmd is still in processing\n");
715 del_timer(&adapter->cmd_timer); 715 del_timer(&adapter->cmd_timer);
716 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); 716 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
717 adapter->curr_cmd = NULL; 717 adapter->curr_cmd = NULL;
718 } 718 }
719 719
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index cab8a8530944..fef89fd6d77b 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -798,6 +798,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
798 798
799void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, 799void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
800 struct cmd_ctrl_node *cmd_node); 800 struct cmd_ctrl_node *cmd_node);
801void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
802 struct cmd_ctrl_node *cmd_node);
801 803
802void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, 804void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
803 struct cmd_ctrl_node *cmd_node, 805 struct cmd_ctrl_node *cmd_node,
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index c7dc450f0bf3..9f990e14966e 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
95 break; 95 break;
96 } 96 }
97 /* Handling errors here */ 97 /* Handling errors here */
98 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); 98 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
99 99
100 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 100 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
101 adapter->curr_cmd = NULL; 101 adapter->curr_cmd = NULL;
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 8c943b6ebf45..e6c9b2ae22ed 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
59{ 59{
60 int status; 60 int status;
61 61
62 dev_dbg(adapter->dev, "cmd pending\n");
63 atomic_inc(&adapter->cmd_pending);
64
65 /* Wait for completion */ 62 /* Wait for completion */
66 status = wait_event_interruptible(adapter->cmd_wait_q.wait, 63 status = wait_event_interruptible(adapter->cmd_wait_q.wait,
67 *(cmd_queued->condition)); 64 *(cmd_queued->condition));
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 54667e65ca47..e57ac0dd3ab5 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -239,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
239int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, 239int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
240 struct cmd_ctrl_node *cmd_node) 240 struct cmd_ctrl_node *cmd_node)
241{ 241{
242 atomic_dec(&adapter->cmd_pending);
243 dev_dbg(adapter->dev, "cmd completed: status=%d\n", 242 dev_dbg(adapter->dev, "cmd completed: status=%d\n",
244 adapter->cmd_wait_q.status); 243 adapter->cmd_wait_q.status);
245 244