summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath9k/wmi.c
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-04-16 06:24:01 (GMT)
committerJohn W. Linville <linville@tuxdriver.com>2010-04-16 19:47:12 (GMT)
commit6ce34ec11c6297562e70e27c57a24cd27d4cd2b1 (patch)
treee2cc737d1c962cca801d61aa7a609df9dfc3bdef /drivers/net/wireless/ath/ath9k/wmi.c
parenteac8e385e9446e591aacbc9ef2c2a3b0836dd2d4 (diff)
downloadlinux-fsl-qoriq-6ce34ec11c6297562e70e27c57a24cd27d4cd2b1.tar.xz
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/net/wireless/ath/ath9k/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 355e0db..afbf63d 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,
return;
}
+ /* Check if there has been a timeout. */
+ spin_lock(&wmi->wmi_lock);
+ if (cmd_id != wmi->last_cmd_id) {
+ spin_unlock(&wmi->wmi_lock);
+ goto free_skb;
+ }
+ spin_unlock(&wmi->wmi_lock);
+
/* WMI command response */
ath9k_wmi_rsp_callback(wmi, skb);
@@ -266,6 +274,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
struct sk_buff *skb;
u8 *data;
int time_left, ret = 0;
+ unsigned long flags;
if (!wmi)
return -EINVAL;
@@ -297,6 +306,10 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
if (ret)
goto out;
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ wmi->last_cmd_id = cmd_id;
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
if (!time_left) {
ath_print(common, ATH_DBG_WMI,