Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mwifiex: use separate wait condition for each command node

Currently global wait condition (adapter->cmd_wait_q.condition)
is used while sending synchronous commands to FW. When two threads
enter in mwifiex_send_cmd_sync() routine at the same time, both the
threads wait for their command responses. Since wait condition is
same for both, they wake up simultaneously after getting response
of 1st command. After this when a thread is waiting for command
response of 3rd command, it wakes up after getting response of 2nd
command and so on. Therefore we don't wait for the response of last
command(0xaa) during unload. Hence while next time loading the driver
command time out is seen for INIT command.

This problem is resolved by having separate wait condition flag for
each command(except scan command). Since scan command is treated
differently (by maintaining scan pending q etc.), newly defined flag
(scan_wait_q_woken) is used as a scan wait condition.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Amitkumar Karwar and committed by
John W. Linville
efaaa8b8 207ae4a3

+33 -19
+14 -9
drivers/net/wireless/mwifiex/cmdevt.c
··· 40 40 { 41 41 cmd_node->priv = priv; 42 42 cmd_node->cmd_oid = cmd_oid; 43 - cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; 44 - priv->adapter->cmd_wait_q_required = false; 43 + if (priv->adapter->cmd_wait_q_required) { 44 + cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; 45 + priv->adapter->cmd_wait_q_required = false; 46 + cmd_node->cmd_wait_q_woken = false; 47 + cmd_node->condition = &cmd_node->cmd_wait_q_woken; 48 + } 45 49 cmd_node->data_buf = data_buf; 46 50 cmd_node->cmd_skb = cmd_node->skb; 47 51 } ··· 422 418 struct mwifiex_adapter *adapter = priv->adapter; 423 419 424 420 adapter->cmd_wait_q_required = true; 425 - adapter->cmd_wait_q.condition = false; 426 421 427 422 ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, 428 423 data_buf); ··· 514 511 } 515 512 516 513 /* Send command */ 517 - if (cmd_no == HostCmd_CMD_802_11_SCAN) 514 + if (cmd_no == HostCmd_CMD_802_11_SCAN) { 518 515 mwifiex_queue_scan_cmd(priv, cmd_node); 519 - else 516 + } else { 517 + adapter->cmd_queued = cmd_node; 520 518 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); 519 + } 521 520 522 521 return ret; 523 522 } ··· 540 535 return; 541 536 542 537 if (cmd_node->wait_q_enabled) 543 - mwifiex_complete_cmd(adapter); 538 + mwifiex_complete_cmd(adapter, cmd_node); 544 539 /* Clean the node */ 545 540 mwifiex_clean_cmd_node(adapter, cmd_node); 546 541 ··· 887 882 adapter->curr_cmd->wait_q_enabled = false; 888 883 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); 889 884 adapter->cmd_wait_q.status = -1; 890 - mwifiex_complete_cmd(adapter); 885 + mwifiex_complete_cmd(adapter, adapter->curr_cmd); 891 886 } 892 887 /* Cancel all pending command */ 893 888 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); ··· 898 893 899 894 if (cmd_node->wait_q_enabled) { 900 895 adapter->cmd_wait_q.status = -1; 901 - mwifiex_complete_cmd(adapter); 896 + mwifiex_complete_cmd(adapter, cmd_node); 902 897 cmd_node->wait_q_enabled = false; 903 898 } 904 899 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ··· 981 976 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); 982 977 } 983 978 adapter->cmd_wait_q.status = -1; 984 - mwifiex_complete_cmd(adapter); 979 + mwifiex_complete_cmd(adapter, adapter->curr_cmd); 985 980 } 986 981 987 982 /*
-1
drivers/net/wireless/mwifiex/decl.h
··· 98 98 99 99 struct mwifiex_wait_queue { 100 100 wait_queue_head_t wait; 101 - u16 condition; 102 101 int status; 103 102 }; 104 103
+1 -1
drivers/net/wireless/mwifiex/main.c
··· 685 685 init_waitqueue_head(&adapter->hs_activate_wait_q); 686 686 adapter->cmd_wait_q_required = false; 687 687 init_waitqueue_head(&adapter->cmd_wait_q.wait); 688 - adapter->cmd_wait_q.condition = false; 689 688 adapter->cmd_wait_q.status = 0; 689 + adapter->scan_wait_q_woken = false; 690 690 691 691 adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); 692 692 if (!adapter->workqueue)
+6 -1
drivers/net/wireless/mwifiex/main.h
··· 520 520 void *data_buf; 521 521 u32 wait_q_enabled; 522 522 struct sk_buff *skb; 523 + u8 *condition; 524 + u8 cmd_wait_q_woken; 523 525 }; 524 526 525 527 struct mwifiex_if_ops { ··· 653 651 u32 arp_filter_size; 654 652 u16 cmd_wait_q_required; 655 653 struct mwifiex_wait_queue cmd_wait_q; 654 + u8 scan_wait_q_woken; 655 + struct cmd_ctrl_node *cmd_queued; 656 656 }; 657 657 658 658 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); ··· 674 670 675 671 int mwifiex_process_event(struct mwifiex_adapter *adapter); 676 672 677 - int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); 673 + int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, 674 + struct cmd_ctrl_node *cmd_node); 678 675 679 676 int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, 680 677 u16 cmd_action, u32 cmd_oid, void *data_buf);
+5 -3
drivers/net/wireless/mwifiex/scan.c
··· 185 185 { 186 186 int status; 187 187 188 - priv->adapter->cmd_wait_q.condition = false; 188 + priv->adapter->scan_wait_q_woken = false; 189 189 190 190 status = mwifiex_scan_networks(priv, scan_req); 191 191 if (!status) ··· 1380 1380 list_del(&cmd_node->list); 1381 1381 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, 1382 1382 flags); 1383 + adapter->cmd_queued = cmd_node; 1383 1384 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, 1384 1385 true); 1385 1386 } else { ··· 1789 1788 /* Need to indicate IOCTL complete */ 1790 1789 if (adapter->curr_cmd->wait_q_enabled) { 1791 1790 adapter->cmd_wait_q.status = 0; 1792 - mwifiex_complete_cmd(adapter); 1791 + mwifiex_complete_cmd(adapter, adapter->curr_cmd); 1793 1792 } 1794 1793 if (priv->report_scan_result) 1795 1794 priv->report_scan_result = false; ··· 1846 1845 unsigned long flags; 1847 1846 1848 1847 cmd_node->wait_q_enabled = true; 1848 + cmd_node->condition = &adapter->scan_wait_q_woken; 1849 1849 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); 1850 1850 list_add_tail(&cmd_node->list, &adapter->scan_pending_q); 1851 1851 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); ··· 1913 1911 } 1914 1912 priv->scan_pending_on_block = true; 1915 1913 1916 - priv->adapter->cmd_wait_q.condition = false; 1914 + priv->adapter->scan_wait_q_woken = false; 1917 1915 1918 1916 if (req_ssid && req_ssid->ssid_len != 0) 1919 1917 /* Specific SSID scan */
+4 -2
drivers/net/wireless/mwifiex/sta_ioctl.c
··· 55 55 { 56 56 bool cancel_flag = false; 57 57 int status = adapter->cmd_wait_q.status; 58 + struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued; 58 59 60 + adapter->cmd_queued = NULL; 59 61 dev_dbg(adapter->dev, "cmd pending\n"); 60 62 atomic_inc(&adapter->cmd_pending); 61 63 ··· 66 64 67 65 /* Wait for completion */ 68 66 wait_event_interruptible(adapter->cmd_wait_q.wait, 69 - adapter->cmd_wait_q.condition); 70 - if (!adapter->cmd_wait_q.condition) 67 + *(cmd_queued->condition)); 68 + if (!*(cmd_queued->condition)) 71 69 cancel_flag = true; 72 70 73 71 if (cancel_flag) {
+3 -2
drivers/net/wireless/mwifiex/util.c
··· 185 185 * corresponding waiting function. Otherwise, it processes the 186 186 * IOCTL response and frees the response buffer. 187 187 */ 188 - int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) 188 + int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, 189 + struct cmd_ctrl_node *cmd_node) 189 190 { 190 191 atomic_dec(&adapter->cmd_pending); 191 192 dev_dbg(adapter->dev, "cmd completed: status=%d\n", 192 193 adapter->cmd_wait_q.status); 193 194 194 - adapter->cmd_wait_q.condition = true; 195 + *(cmd_node->condition) = true; 195 196 196 197 if (adapter->cmd_wait_q.status == -ETIMEDOUT) 197 198 dev_err(adapter->dev, "cmd timeout\n");