wl1271: Move scan complete invocation into work function
The current scan implementation can jam, if the scan request ends up
containing no work. This can especially happen if there is a scan request
with only 11a band channels for HW that does not support 11a.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 763ece8..272cff4 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -416,6 +416,7 @@
/* Are we currently scanning */
struct wl1271_scan scan;
+ struct work_struct scan_complete_work;
/* Our association ID */
u16 aid;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 4b8f366..0026e77 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -634,6 +634,8 @@
INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work);
+ INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+
return 0;
}
@@ -962,6 +964,8 @@
struct wl1271 *wl = hw->priv;
int i;
+ cancel_work_sync(&wl->scan_complete_work);
+
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
index 8d30150..9f1da82 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.c
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -28,6 +28,23 @@
#include "wl1271_scan.h"
#include "wl1271_acx.h"
+void wl1271_scan_complete_work(struct work_struct *work)
+{
+ struct wl1271 *wl =
+ container_of(work, struct wl1271, scan_complete_work);
+
+ wl1271_debug(DEBUG_SCAN, "Scanning complete");
+
+ mutex_lock(&wl->mutex);
+ wl->scan.state = WL1271_SCAN_STATE_IDLE;
+ kfree(wl->scan.scanned_ch);
+ wl->scan.scanned_ch = NULL;
+ mutex_unlock(&wl->mutex);
+
+ ieee80211_scan_completed(wl->hw, false);
+}
+
+
static int wl1271_get_scan_channels(struct wl1271 *wl,
struct cfg80211_scan_request *req,
struct basic_scan_channel_params *channels,
@@ -218,11 +235,7 @@
break;
case WL1271_SCAN_STATE_DONE:
- kfree(wl->scan.scanned_ch);
- wl->scan.scanned_ch = NULL;
-
- wl->scan.state = WL1271_SCAN_STATE_IDLE;
- ieee80211_scan_completed(wl->hw, false);
+ ieee80211_queue_work(wl->hw, &wl->scan_complete_work);
break;
default:
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h
index f181570..1404e00 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.h
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.h
@@ -32,6 +32,7 @@
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl);
+void wl1271_scan_complete_work(struct work_struct *work);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1