aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-04-16 02:24:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-16 15:47:12 -0400
commit6ce34ec11c6297562e70e27c57a24cd27d4cd2b1 (patch)
treee2cc737d1c962cca801d61aa7a609df9dfc3bdef /drivers
parenteac8e385e9446e591aacbc9ef2c2a3b0836dd2d4 (diff)
ath9k_htc: Handle WMI timeouts properly
If a WMI command has timed out for some reason, a late WMI response would end up updating the response region of a new WMI request that has been issued in the meantime. Fix this race condition by dropping a WMI response if a new WMI command has been issued. Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h1
2 files changed, 14 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 355e0dbf3c66..afbf63daf551 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -204,6 +204,14 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
204 return; 204 return;
205 } 205 }
206 206
207 /* Check if there has been a timeout. */
208 spin_lock(&wmi->wmi_lock);
209 if (cmd_id != wmi->last_cmd_id) {
210 spin_unlock(&wmi->wmi_lock);
211 goto free_skb;
212 }
213 spin_unlock(&wmi->wmi_lock);
214
207 /* WMI command response */ 215 /* WMI command response */
208 ath9k_wmi_rsp_callback(wmi, skb); 216 ath9k_wmi_rsp_callback(wmi, skb);
209 217
@@ -266,6 +274,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
266 struct sk_buff *skb; 274 struct sk_buff *skb;
267 u8 *data; 275 u8 *data;
268 int time_left, ret = 0; 276 int time_left, ret = 0;
277 unsigned long flags;
269 278
270 if (!wmi) 279 if (!wmi)
271 return -EINVAL; 280 return -EINVAL;
@@ -297,6 +306,10 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
297 if (ret) 306 if (ret)
298 goto out; 307 goto out;
299 308
309 spin_lock_irqsave(&wmi->wmi_lock, flags);
310 wmi->last_cmd_id = cmd_id;
311 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
312
300 time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout); 313 time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
301 if (!time_left) { 314 if (!time_left) {
302 ath_print(common, ATH_DBG_WMI, 315 ath_print(common, ATH_DBG_WMI,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index fd8c9c5f4a05..611357158ecf 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -97,6 +97,7 @@ struct wmi {
97 enum htc_endpoint_id ctrl_epid; 97 enum htc_endpoint_id ctrl_epid;
98 struct mutex op_mutex; 98 struct mutex op_mutex;
99 struct completion cmd_wait; 99 struct completion cmd_wait;
100 enum wmi_cmd_id last_cmd_id;
100 u16 tx_seq_id; 101 u16 tx_seq_id;
101 u8 *cmd_rsp_buf; 102 u8 *cmd_rsp_buf;
102 u32 cmd_rsp_len; 103 u32 cmd_rsp_len;