diff options
author | Bing Zhao <bzhao@marvell.com> | 2013-04-01 15:44:46 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-08 15:28:37 -0400 |
commit | 9908b07465556d4c96685d7f1ead0e17b01c662d (patch) | |
tree | 6361c56ff62efdeccfaa95ba52069eb42721bd00 /drivers/net/wireless | |
parent | 84bcc0c3c4b8ca4c0abed2d2dd63b7ce04f8be0e (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.c | 35 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_ioctl.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/util.c | 1 |
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. */ | ||
636 | void 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 | ||
799 | void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, | 799 | void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, |
800 | struct cmd_ctrl_node *cmd_node); | 800 | struct cmd_ctrl_node *cmd_node); |
801 | void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter, | ||
802 | struct cmd_ctrl_node *cmd_node); | ||
801 | 803 | ||
802 | void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, | 804 | void 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) | |||
239 | int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, | 239 | int 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 | ||