aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-09-21 00:23:32 -0400
committerLuciano Coelho <luciano.coelho@nokia.com>2010-09-28 05:30:05 -0400
commit78abd3207438b20e099b41cbed58d640cbd237a6 (patch)
treef09eacf311e167b8d219eda3af52975e985df7c3 /drivers
parent52b0e7a61fd4b67fe8efe295297d8549f052f786 (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.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.c30
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.h2
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 {
296struct wl1271_scan { 296struct 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
31void wl1271_scan_complete_work(struct work_struct *work) 31void 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
192void wl1271_scan_stm(struct wl1271 *wl) 200void 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
253int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, 270int 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
49enum { 51enum {
50 WL1271_SCAN_STATE_IDLE, 52 WL1271_SCAN_STATE_IDLE,
51 WL1271_SCAN_STATE_2GHZ_ACTIVE, 53 WL1271_SCAN_STATE_2GHZ_ACTIVE,