wl1271: Add handling for failing hardware scan command
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>
Tue, 21 Sep 2010 04:23:32 +0000 (06:23 +0200)
committerLuciano Coelho <luciano.coelho@nokia.com>
Tue, 28 Sep 2010 09:30:05 +0000 (12:30 +0300)
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>
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_scan.c
drivers/net/wireless/wl12xx/wl1271_scan.h

index 3576c1cb067fd7b0efd01d2d53fcb8b3c622b877..cae489300e063294f89e4a576468d5ff99f7f92e 100644 (file)
@@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr {
 struct wl1271_scan {
        struct cfg80211_scan_request *req;
        bool *scanned_ch;
+       bool failed;
        u8 state;
        u8 ssid[IW_ESSID_MAX_SIZE+1];
        size_t ssid_len;
@@ -419,7 +420,7 @@ struct wl1271 {
 
        /* Are we currently scanning */
        struct wl1271_scan scan;
-       struct work_struct scan_complete_work;
+       struct delayed_work scan_complete_work;
 
        /* Our association ID */
        u16 aid;
index fecb0c313a1d6e0003095b13a8779f30856ec000..c13175892960c3aedaeab2bf822eebe4d8af18e7 100644 (file)
@@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl)
 
        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);
        INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
+       INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
 
        return 0;
 }
@@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 
        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->tx_work);
        cancel_delayed_work_sync(&wl->pspoll_work);
index 20caceba435e5ad71a2d7592b83d884346fd43dd..37f9ccbe738f60afd63974499252716464562261 100644 (file)
 
 void wl1271_scan_complete_work(struct work_struct *work)
 {
-       struct wl1271 *wl =
-               container_of(work, struct wl1271, scan_complete_work);
+       struct delayed_work *dwork;
+       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");
 
@@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work)
        mutex_unlock(&wl->mutex);
 
        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 @@ out:
 
 void wl1271_scan_stm(struct wl1271 *wl)
 {
-       int ret;
+       int ret = 0;
 
        switch (wl->scan.state) {
        case WL1271_SCAN_STATE_IDLE:
@@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        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;
 
        default:
                wl1271_error("invalid scan state");
                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,
@@ -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 *
                                      sizeof(*wl->scan.scanned_ch),
                                      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);
 
        return 0;
index 1404e00dc963067cf7593691d79c431439f6a002..bb7af2a102fa964777918b71e6caae7b354fb0cf 100644 (file)
@@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work);
 #define WL1271_SCAN_BAND_5_GHZ 1
 #define WL1271_SCAN_PROBE_REQS 3
 
+#define WL1271_SCAN_TIMEOUT    10000 /* msec */
+
 enum {
        WL1271_SCAN_STATE_IDLE,
        WL1271_SCAN_STATE_2GHZ_ACTIVE,