From: Jérôme Pouiller <jerome.pouil...@silabs.com>

If the environment is noisy, the device may take time to send scan
requests. Thus, scan requests durations > 5s have already been observed.
During the scan, traffic is neither received, neither sent. From the
user point-of-view, the traffic is frozen for a long time.

This patch reworks the scan processing. It gives to the device a smaller
time budget than previously. However, it does not expect the scan to be
complete and it is able to send another scan request to finish the work.

A big part of the patch aims to avoid an infinite loop if the device
goes crazy.

Signed-off-by: Jérôme Pouiller <jerome.pouil...@silabs.com>
---
 drivers/staging/wfx/hif_rx.c |  3 ++-
 drivers/staging/wfx/scan.c   | 48 ++++++++++++++++++++++--------------
 drivers/staging/wfx/scan.h   |  2 +-
 drivers/staging/wfx/wfx.h    |  1 +
 4 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 9fca7f26372a..a60c4a4ba935 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -175,13 +175,14 @@ static int hif_scan_complete_indication(struct wfx_dev 
*wdev,
                                        const void *buf)
 {
        struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+       const struct hif_ind_scan_cmpl *body = buf;
 
        if (!wvif) {
                dev_warn(wdev->dev, "%s: received event for non-existent 
vif\n", __func__);
                return -EIO;
        }
 
-       wfx_scan_complete(wvif);
+       wfx_scan_complete(wvif, body->num_channels_completed);
 
        return 0;
 }
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
index 1e03b130049b..695b06974194 100644
--- a/drivers/staging/wfx/scan.c
+++ b/drivers/staging/wfx/scan.c
@@ -41,7 +41,7 @@ static int update_probe_tmpl(struct wfx_vif *wvif,
 static int send_scan_req(struct wfx_vif *wvif,
                         struct cfg80211_scan_request *req, int start_idx)
 {
-       int i, ret, timeout;
+       int i, ret;
        struct ieee80211_channel *ch_start, *ch_cur;
 
        for (i = start_idx; i < req->n_channels; i++) {
@@ -56,31 +56,31 @@ static int send_scan_req(struct wfx_vif *wvif,
        wfx_tx_lock_flush(wvif->wdev);
        wvif->scan_abort = false;
        reinit_completion(&wvif->scan_complete);
-       ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout);
+       ret = hif_scan(wvif, req, start_idx, i - start_idx, NULL);
        if (ret) {
-               ret = -EIO;
-               goto err_scan_start;
+               wfx_tx_unlock(wvif->wdev);
+               return -EIO;
        }
-       ret = wait_for_completion_timeout(&wvif->scan_complete, timeout);
+       ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
        if (!ret) {
-               dev_notice(wvif->wdev->dev, "scan timeout\n");
                hif_stop_scan(wvif);
                ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
-               if (!ret)
-                       dev_err(wvif->wdev->dev, "scan didn't stop\n");
+               dev_dbg(wvif->wdev->dev, "scan timeout (%d channels done)\n",
+                       wvif->scan_nb_chan_done);
+       }
+       if (!ret) {
+               dev_err(wvif->wdev->dev, "scan didn't stop\n");
                ret = -ETIMEDOUT;
-               goto err_timeout;
-       }
-       if (wvif->scan_abort) {
+       } else if (wvif->scan_abort) {
                dev_notice(wvif->wdev->dev, "scan abort\n");
                ret = -ECONNABORTED;
-               goto err_timeout;
+       } else if (wvif->scan_nb_chan_done > i - start_idx) {
+               ret = -EIO;
+       } else {
+               ret = wvif->scan_nb_chan_done;
        }
-       ret = i - start_idx;
-err_timeout:
        if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
                hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
-err_scan_start:
        wfx_tx_unlock(wvif->wdev);
        return ret;
 }
@@ -94,7 +94,7 @@ void wfx_hw_scan_work(struct work_struct *work)
 {
        struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
        struct ieee80211_scan_request *hw_req = wvif->scan_req;
-       int chan_cur, ret;
+       int chan_cur, ret, err;
 
        mutex_lock(&wvif->wdev->conf_mutex);
        mutex_lock(&wvif->scan_lock);
@@ -105,11 +105,20 @@ void wfx_hw_scan_work(struct work_struct *work)
        }
        update_probe_tmpl(wvif, &hw_req->req);
        chan_cur = 0;
+       err = 0;
        do {
                ret = send_scan_req(wvif, &hw_req->req, chan_cur);
-               if (ret > 0)
+               if (ret > 0) {
                        chan_cur += ret;
-       } while (ret > 0 && chan_cur < hw_req->req.n_channels);
+                       err = 0;
+               }
+               if (!ret)
+                       err++;
+               if (err > 2) {
+                       dev_err(wvif->wdev->dev, "scan has not been able to 
start\n");
+                       ret = -ETIMEDOUT;
+               }
+       } while (ret >= 0 && chan_cur < hw_req->req.n_channels);
        mutex_unlock(&wvif->scan_lock);
        mutex_unlock(&wvif->wdev->conf_mutex);
        __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
@@ -134,7 +143,8 @@ void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct 
ieee80211_vif *vif)
        hif_stop_scan(wvif);
 }
 
-void wfx_scan_complete(struct wfx_vif *wvif)
+void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done)
 {
+       wvif->scan_nb_chan_done = nb_chan_done;
        complete(&wvif->scan_complete);
 }
diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h
index c7496a766478..562ca1321daf 100644
--- a/drivers/staging/wfx/scan.h
+++ b/drivers/staging/wfx/scan.h
@@ -17,6 +17,6 @@ void wfx_hw_scan_work(struct work_struct *work);
 int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                struct ieee80211_scan_request *req);
 void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void wfx_scan_complete(struct wfx_vif *wvif);
+void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done);
 
 #endif /* WFX_SCAN_H */
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 94898680ccde..56f1e4bb0b57 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -85,6 +85,7 @@ struct wfx_vif {
        struct mutex            scan_lock;
        struct work_struct      scan_work;
        struct completion       scan_complete;
+       int                     scan_nb_chan_done;
        bool                    scan_abort;
        struct ieee80211_scan_request *scan_req;
 
-- 
2.33.0

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to