diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2010-04-16 02:24:01 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-16 15:47:12 -0400 |
commit | 6ce34ec11c6297562e70e27c57a24cd27d4cd2b1 (patch) | |
tree | e2cc737d1c962cca801d61aa7a609df9dfc3bdef /drivers | |
parent | eac8e385e9446e591aacbc9ef2c2a3b0836dd2d4 (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.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.h | 1 |
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; |