summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/wil6210/main.c
diff options
context:
space:
mode:
authorDedy Lansky <qca_dlansky@qca.qualcomm.com>2014-09-10 17:34:38 +0400
committerJohn W. Linville <linville@tuxdriver.com>2014-09-11 23:27:37 +0400
commitf172b56309fbc4835b3f258df6865309dc02e80c (patch)
tree707d2f595e540cb02ab4f98f67ed04ca59ad4553 /drivers/net/wireless/ath/wil6210/main.c
parent69778059734b38ea6f4aa9d31262ad03e77b1b06 (diff)
downloadlinux-f172b56309fbc4835b3f258df6865309dc02e80c.tar.xz
wil6210: fix for memory corruption upon rmmod
Driver disabled PCI master before making sure HW is idle. This caused memory corruption in case HW access system memory after PCI master got disabled. The fix is to change uninit sequence. Make sure FW/HW is idle before disabling PCI Signed-off-by: Dedy Lansky <qca_dlansky@qca.qualcomm.com> Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/main.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 696be3e71a82..22e9b8aeb1cf 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -20,6 +20,10 @@
#include "wil6210.h"
#include "txrx.h"
+#include "wmi.h"
+
+#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
+#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
@@ -631,6 +635,9 @@ int wil_up(struct wil6210_priv *wil)
static int __wil_down(struct wil6210_priv *wil)
{
+ int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
+ WAIT_FOR_DISCONNECT_INTERVAL_MS;
+
WARN_ON(!mutex_is_locked(&wil->mutex));
if (wil->platform_ops.bus_request)
@@ -648,7 +655,24 @@ static int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- wil6210_disconnect(wil, NULL);
+ if (test_bit(wil_status_fwconnected, &wil->status) ||
+ test_bit(wil_status_fwconnecting, &wil->status))
+ wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+
+ /* make sure wil is idle (not connected) */
+ mutex_unlock(&wil->mutex);
+ while (iter--) {
+ int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
+ !test_bit(wil_status_fwconnecting, &wil->status);
+ if (idle)
+ break;
+ msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
+ }
+ mutex_lock(&wil->mutex);
+
+ if (!iter)
+ wil_err(wil, "timeout waiting for idle FW/HW\n");
+
wil_rx_fini(wil);
return 0;