diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2010-09-21 00:23:32 -0400 |
---|---|---|
committer | Luciano Coelho <luciano.coelho@nokia.com> | 2010-09-28 05:30:05 -0400 |
commit | 78abd3207438b20e099b41cbed58d640cbd237a6 (patch) | |
tree | f09eacf311e167b8d219eda3af52975e985df7c3 /drivers | |
parent | 52b0e7a61fd4b67fe8efe295297d8549f052f786 (diff) |
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: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_scan.c | 30 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_scan.h | 2 |
4 files changed, 32 insertions, 7 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 3576c1cb067f..cae489300e06 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr { | |||
296 | struct wl1271_scan { | 296 | struct wl1271_scan { |
297 | struct cfg80211_scan_request *req; | 297 | struct cfg80211_scan_request *req; |
298 | bool *scanned_ch; | 298 | bool *scanned_ch; |
299 | bool failed; | ||
299 | u8 state; | 300 | u8 state; |
300 | u8 ssid[IW_ESSID_MAX_SIZE+1]; | 301 | u8 ssid[IW_ESSID_MAX_SIZE+1]; |
301 | size_t ssid_len; | 302 | size_t ssid_len; |
@@ -419,7 +420,7 @@ struct wl1271 { | |||
419 | 420 | ||
420 | /* Are we currently scanning */ | 421 | /* Are we currently scanning */ |
421 | struct wl1271_scan scan; | 422 | struct wl1271_scan scan; |
422 | struct work_struct scan_complete_work; | 423 | struct delayed_work scan_complete_work; |
423 | 424 | ||
424 | /* Our association ID */ | 425 | /* Our association ID */ |
425 | u16 aid; | 426 | u16 aid; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index fecb0c313a1d..c13175892960 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl) | |||
657 | 657 | ||
658 | INIT_WORK(&wl->irq_work, wl1271_irq_work); | 658 | INIT_WORK(&wl->irq_work, wl1271_irq_work); |
659 | INIT_WORK(&wl->tx_work, wl1271_tx_work); | 659 | INIT_WORK(&wl->tx_work, wl1271_tx_work); |
660 | INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); | ||
661 | INIT_WORK(&wl->recovery_work, wl1271_recovery_work); | 660 | INIT_WORK(&wl->recovery_work, wl1271_recovery_work); |
661 | INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); | ||
662 | 662 | ||
663 | return 0; | 663 | return 0; |
664 | } | 664 | } |
@@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) | |||
1013 | 1013 | ||
1014 | mutex_unlock(&wl->mutex); | 1014 | mutex_unlock(&wl->mutex); |
1015 | 1015 | ||
1016 | cancel_work_sync(&wl->scan_complete_work); | 1016 | cancel_delayed_work_sync(&wl->scan_complete_work); |
1017 | cancel_work_sync(&wl->irq_work); | 1017 | cancel_work_sync(&wl->irq_work); |
1018 | cancel_work_sync(&wl->tx_work); | 1018 | cancel_work_sync(&wl->tx_work); |
1019 | cancel_delayed_work_sync(&wl->pspoll_work); | 1019 | cancel_delayed_work_sync(&wl->pspoll_work); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 20caceba435e..37f9ccbe738f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c | |||
@@ -30,8 +30,11 @@ | |||
30 | 30 | ||
31 | void wl1271_scan_complete_work(struct work_struct *work) | 31 | void wl1271_scan_complete_work(struct work_struct *work) |
32 | { | 32 | { |
33 | struct wl1271 *wl = | 33 | struct delayed_work *dwork; |
34 | container_of(work, struct wl1271, scan_complete_work); | 34 | struct wl1271 *wl; |
35 | |||
36 | dwork = container_of(work, struct delayed_work, work); | ||
37 | wl = container_of(dwork, struct wl1271, scan_complete_work); | ||
35 | 38 | ||
36 | wl1271_debug(DEBUG_SCAN, "Scanning complete"); | 39 | wl1271_debug(DEBUG_SCAN, "Scanning complete"); |
37 | 40 | ||
@@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
48 | mutex_unlock(&wl->mutex); | 51 | mutex_unlock(&wl->mutex); |
49 | 52 | ||
50 | ieee80211_scan_completed(wl->hw, false); | 53 | ieee80211_scan_completed(wl->hw, false); |
54 | |||
55 | if (wl->scan.failed) { | ||
56 | wl1271_info("Scan completed due to error."); | ||
57 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | ||
58 | } | ||
51 | } | 59 | } |
52 | 60 | ||
53 | 61 | ||
@@ -191,7 +199,7 @@ out: | |||
191 | 199 | ||
192 | void wl1271_scan_stm(struct wl1271 *wl) | 200 | void wl1271_scan_stm(struct wl1271 *wl) |
193 | { | 201 | { |
194 | int ret; | 202 | int ret = 0; |
195 | 203 | ||
196 | switch (wl->scan.state) { | 204 | switch (wl->scan.state) { |
197 | case WL1271_SCAN_STATE_IDLE: | 205 | case WL1271_SCAN_STATE_IDLE: |
@@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl) | |||
241 | break; | 249 | break; |
242 | 250 | ||
243 | case WL1271_SCAN_STATE_DONE: | 251 | case WL1271_SCAN_STATE_DONE: |
244 | ieee80211_queue_work(wl->hw, &wl->scan_complete_work); | 252 | wl->scan.failed = false; |
253 | cancel_delayed_work(&wl->scan_complete_work); | ||
254 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
255 | msecs_to_jiffies(0)); | ||
245 | break; | 256 | break; |
246 | 257 | ||
247 | default: | 258 | default: |
248 | wl1271_error("invalid scan state"); | 259 | wl1271_error("invalid scan state"); |
249 | break; | 260 | break; |
250 | } | 261 | } |
262 | |||
263 | if (ret < 0) { | ||
264 | cancel_delayed_work(&wl->scan_complete_work); | ||
265 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
266 | msecs_to_jiffies(0)); | ||
267 | } | ||
251 | } | 268 | } |
252 | 269 | ||
253 | int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | 270 | 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 | wl->scan.scanned_ch = kzalloc(req->n_channels * | 287 | wl->scan.scanned_ch = kzalloc(req->n_channels * |
271 | sizeof(*wl->scan.scanned_ch), | 288 | sizeof(*wl->scan.scanned_ch), |
272 | GFP_KERNEL); | 289 | GFP_KERNEL); |
290 | /* we assume failure so that timeout scenarios are handled correctly */ | ||
291 | wl->scan.failed = true; | ||
292 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
293 | msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); | ||
294 | |||
273 | wl1271_scan_stm(wl); | 295 | wl1271_scan_stm(wl); |
274 | 296 | ||
275 | return 0; | 297 | return 0; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h index 1404e00dc963..bb7af2a102fa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h | |||
@@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work); | |||
46 | #define WL1271_SCAN_BAND_5_GHZ 1 | 46 | #define WL1271_SCAN_BAND_5_GHZ 1 |
47 | #define WL1271_SCAN_PROBE_REQS 3 | 47 | #define WL1271_SCAN_PROBE_REQS 3 |
48 | 48 | ||
49 | #define WL1271_SCAN_TIMEOUT 10000 /* msec */ | ||
50 | |||
49 | enum { | 51 | enum { |
50 | WL1271_SCAN_STATE_IDLE, | 52 | WL1271_SCAN_STATE_IDLE, |
51 | WL1271_SCAN_STATE_2GHZ_ACTIVE, | 53 | WL1271_SCAN_STATE_2GHZ_ACTIVE, |