Commit 78abd320 authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by Luciano Coelho

wl1271: Add handling for failing hardware scan command

Currently, the driver does not handle a failing hardware command to scan in
any way - effectively, the scan machine will jam until the driver is shut down,
and future scan requests will just return -EBUSY to user space, resulting in
a type of busy-loop. The same problem occurs if the firmware fails to deliver
the scan completion event - add timeout for this.
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
parent 52b0e7a6
...@@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr { ...@@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr {
struct wl1271_scan { struct wl1271_scan {
struct cfg80211_scan_request *req; struct cfg80211_scan_request *req;
bool *scanned_ch; bool *scanned_ch;
bool failed;
u8 state; u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1]; u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len; size_t ssid_len;
...@@ -419,7 +420,7 @@ struct wl1271 { ...@@ -419,7 +420,7 @@ struct wl1271 {
/* Are we currently scanning */ /* Are we currently scanning */
struct wl1271_scan scan; struct wl1271_scan scan;
struct work_struct scan_complete_work; struct delayed_work scan_complete_work;
/* Our association ID */ /* Our association ID */
u16 aid; u16 aid;
......
...@@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl) ...@@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl)
INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
return 0; return 0;
} }
...@@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) ...@@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->scan_complete_work); cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work); cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->pspoll_work); cancel_delayed_work_sync(&wl->pspoll_work);
......
...@@ -30,8 +30,11 @@ ...@@ -30,8 +30,11 @@
void wl1271_scan_complete_work(struct work_struct *work) void wl1271_scan_complete_work(struct work_struct *work)
{ {
struct wl1271 *wl = struct delayed_work *dwork;
container_of(work, struct wl1271, scan_complete_work); struct wl1271 *wl;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
wl1271_debug(DEBUG_SCAN, "Scanning complete"); wl1271_debug(DEBUG_SCAN, "Scanning complete");
...@@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false); ieee80211_scan_completed(wl->hw, false);
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
}
} }
...@@ -191,7 +199,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, ...@@ -191,7 +199,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
void wl1271_scan_stm(struct wl1271 *wl) void wl1271_scan_stm(struct wl1271 *wl)
{ {
int ret; int ret = 0;
switch (wl->scan.state) { switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE: case WL1271_SCAN_STATE_IDLE:
...@@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl) ...@@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
break; break;
case WL1271_SCAN_STATE_DONE: case WL1271_SCAN_STATE_DONE:
ieee80211_queue_work(wl->hw, &wl->scan_complete_work); wl->scan.failed = false;
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
break; break;
default: default:
wl1271_error("invalid scan state"); wl1271_error("invalid scan state");
break; break;
} }
if (ret < 0) {
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
}
} }
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
...@@ -270,6 +287,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, ...@@ -270,6 +287,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
wl->scan.scanned_ch = kzalloc(req->n_channels * wl->scan.scanned_ch = kzalloc(req->n_channels *
sizeof(*wl->scan.scanned_ch), sizeof(*wl->scan.scanned_ch),
GFP_KERNEL); GFP_KERNEL);
/* we assume failure so that timeout scenarios are handled correctly */
wl->scan.failed = true;
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
wl1271_scan_stm(wl); wl1271_scan_stm(wl);
return 0; return 0;
......
...@@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work); ...@@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work);
#define WL1271_SCAN_BAND_5_GHZ 1 #define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_PROBE_REQS 3 #define WL1271_SCAN_PROBE_REQS 3
#define WL1271_SCAN_TIMEOUT 10000 /* msec */
enum { enum {
WL1271_SCAN_STATE_IDLE, WL1271_SCAN_STATE_IDLE,
WL1271_SCAN_STATE_2GHZ_ACTIVE, WL1271_SCAN_STATE_2GHZ_ACTIVE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment