Skip to content

Commit

Permalink
mwifiex: use separate wait condition for each command node
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Amitkumar Karwar authored and John W. Linville committed Oct 14, 2011
1 parent 207ae4a commit efaaa8b
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 19 deletions.
23 changes: 14 additions & 9 deletions drivers/net/wireless/mwifiex/cmdevt.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ mwifiex_init_cmd_node(struct mwifiex_private *priv,
{
cmd_node->priv = priv;
cmd_node->cmd_oid = cmd_oid;
cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
priv->adapter->cmd_wait_q_required = false;
if (priv->adapter->cmd_wait_q_required) {
cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
priv->adapter->cmd_wait_q_required = false;
cmd_node->cmd_wait_q_woken = false;
cmd_node->condition = &cmd_node->cmd_wait_q_woken;
}
cmd_node->data_buf = data_buf;
cmd_node->cmd_skb = cmd_node->skb;
}
Expand Down Expand Up @@ -418,7 +422,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
struct mwifiex_adapter *adapter = priv->adapter;

adapter->cmd_wait_q_required = true;
adapter->cmd_wait_q.condition = false;

ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
data_buf);
Expand Down Expand Up @@ -511,10 +514,12 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
}

/* Send command */
if (cmd_no == HostCmd_CMD_802_11_SCAN)
if (cmd_no == HostCmd_CMD_802_11_SCAN) {
mwifiex_queue_scan_cmd(priv, cmd_node);
else
} else {
adapter->cmd_queued = cmd_node;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
}

return ret;
}
Expand All @@ -535,7 +540,7 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
return;

if (cmd_node->wait_q_enabled)
mwifiex_complete_cmd(adapter);
mwifiex_complete_cmd(adapter, cmd_node);
/* Clean the node */
mwifiex_clean_cmd_node(adapter, cmd_node);

Expand Down Expand Up @@ -882,7 +887,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
adapter->curr_cmd->wait_q_enabled = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
adapter->cmd_wait_q.status = -1;
mwifiex_complete_cmd(adapter);
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
/* Cancel all pending command */
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
Expand All @@ -893,7 +898,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)

if (cmd_node->wait_q_enabled) {
adapter->cmd_wait_q.status = -1;
mwifiex_complete_cmd(adapter);
mwifiex_complete_cmd(adapter, cmd_node);
cmd_node->wait_q_enabled = false;
}
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
Expand Down Expand Up @@ -976,7 +981,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
}
adapter->cmd_wait_q.status = -1;
mwifiex_complete_cmd(adapter);
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}

/*
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/mwifiex/decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ struct mwifiex_802_11_ssid {

struct mwifiex_wait_queue {
wait_queue_head_t wait;
u16 condition;
int status;
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/mwifiex/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
init_waitqueue_head(&adapter->hs_activate_wait_q);
adapter->cmd_wait_q_required = false;
init_waitqueue_head(&adapter->cmd_wait_q.wait);
adapter->cmd_wait_q.condition = false;
adapter->cmd_wait_q.status = 0;
adapter->scan_wait_q_woken = false;

adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
if (!adapter->workqueue)
Expand Down
7 changes: 6 additions & 1 deletion drivers/net/wireless/mwifiex/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,8 @@ struct cmd_ctrl_node {
void *data_buf;
u32 wait_q_enabled;
struct sk_buff *skb;
u8 *condition;
u8 cmd_wait_q_woken;
};

struct mwifiex_if_ops {
Expand Down Expand Up @@ -651,6 +653,8 @@ struct mwifiex_adapter {
u32 arp_filter_size;
u16 cmd_wait_q_required;
struct mwifiex_wait_queue cmd_wait_q;
u8 scan_wait_q_woken;
struct cmd_ctrl_node *cmd_queued;
};

int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
Expand All @@ -670,7 +674,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);

int mwifiex_process_event(struct mwifiex_adapter *adapter);

int mwifiex_complete_cmd(struct mwifiex_adapter *adapter);
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node);

int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid, void *data_buf);
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/wireless/mwifiex/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
{
int status;

priv->adapter->cmd_wait_q.condition = false;
priv->adapter->scan_wait_q_woken = false;

status = mwifiex_scan_networks(priv, scan_req);
if (!status)
Expand Down Expand Up @@ -1380,6 +1380,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
adapter->cmd_queued = cmd_node;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
} else {
Expand Down Expand Up @@ -1788,7 +1789,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
/* Need to indicate IOCTL complete */
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
mwifiex_complete_cmd(adapter);
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
if (priv->report_scan_result)
priv->report_scan_result = false;
Expand Down Expand Up @@ -1845,6 +1846,7 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
unsigned long flags;

cmd_node->wait_q_enabled = true;
cmd_node->condition = &adapter->scan_wait_q_woken;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
Expand Down Expand Up @@ -1911,7 +1913,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
}
priv->scan_pending_on_block = true;

priv->adapter->cmd_wait_q.condition = false;
priv->adapter->scan_wait_q_woken = false;

if (req_ssid && req_ssid->ssid_len != 0)
/* Specific SSID scan */
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/wireless/mwifiex/sta_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
{
bool cancel_flag = false;
int status = adapter->cmd_wait_q.status;
struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued;

adapter->cmd_queued = NULL;
dev_dbg(adapter->dev, "cmd pending\n");
atomic_inc(&adapter->cmd_pending);

Expand All @@ -64,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)

/* Wait for completion */
wait_event_interruptible(adapter->cmd_wait_q.wait,
adapter->cmd_wait_q.condition);
if (!adapter->cmd_wait_q.condition)
*(cmd_queued->condition));
if (!*(cmd_queued->condition))
cancel_flag = true;

if (cancel_flag) {
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/wireless/mwifiex/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,14 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
* corresponding waiting function. Otherwise, it processes the
* IOCTL response and frees the response buffer.
*/
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
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);

adapter->cmd_wait_q.condition = true;
*(cmd_node->condition) = true;

if (adapter->cmd_wait_q.status == -ETIMEDOUT)
dev_err(adapter->dev, "cmd timeout\n");
Expand Down

0 comments on commit efaaa8b

Please sign in to comment.