From: Jérôme Pouiller <jerome.pouiller@xxxxxxxxxx> 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.pouiller@xxxxxxxxxx> --- 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