lkml.org 
[lkml]   [2019]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 50/55] staging: wfx: rewrite wfx_hw_scan()
    Date
    From: Jérôme Pouiller <jerome.pouiller@silabs.com>

    Scan requests from mac80211 must be splitted in a few hardware requests
    (it is necessary to split channels with active scan and channels with
    passive scan). Current code schedules a work_struct for each hardware
    request and one delayed_work to handle scan timeout.

    It is far simpler to run send all the hardware requests synchronously
    and replace delayed_work with a simple wait_for_completion_timeout().

    Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
    ---
    drivers/staging/wfx/hif_rx.c | 2 +-
    drivers/staging/wfx/scan.c | 225 ++++++++++-------------------------
    drivers/staging/wfx/scan.h | 23 +---
    drivers/staging/wfx/sta.c | 39 ++----
    drivers/staging/wfx/wfx.h | 4 +-
    5 files changed, 81 insertions(+), 212 deletions(-)

    diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
    index 8a3ccdc60b7d..408967a4c457 100644
    --- a/drivers/staging/wfx/hif_rx.c
    +++ b/drivers/staging/wfx/hif_rx.c
    @@ -206,7 +206,7 @@ static int hif_scan_complete_indication(struct wfx_dev *wdev,
    const struct hif_ind_scan_cmpl *body = buf;

    WARN_ON(!wvif);
    - wfx_scan_complete_cb(wvif, body);
    + wfx_scan_complete(wvif, body);

    return 0;
    }
    diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
    index c82c04ff5d06..b73e61e8da46 100644
    --- a/drivers/staging/wfx/scan.c
    +++ b/drivers/staging/wfx/scan.c
    @@ -22,33 +22,6 @@ static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw,
    ieee80211_scan_completed(hw, &info);
    }

    -static void wfx_scan_restart_delayed(struct wfx_vif *wvif)
    -{
    - if (wvif->delayed_unjoin) {
    - wvif->delayed_unjoin = false;
    - if (!schedule_work(&wvif->unjoin_work))
    - wfx_tx_unlock(wvif->wdev);
    - } else if (wvif->delayed_link_loss) {
    - wvif->delayed_link_loss = 0;
    - wfx_cqm_bssloss_sm(wvif, 1, 0, 0);
    - }
    -}
    -
    -static int wfx_scan_start(struct wfx_vif *wvif,
    - int chan_start_idx, int chan_num)
    -{
    - int tmo;
    -
    - if (wvif->state == WFX_STATE_PRE_STA)
    - return -EBUSY;
    -
    - atomic_set(&wvif->scan.in_progress, 1);
    -
    - tmo = hif_scan(wvif, wvif->scan.req, chan_start_idx, chan_num);
    - schedule_delayed_work(&wvif->scan.timeout, tmo);
    - return 0;
    -}
    -
    static int update_probe_tmpl(struct wfx_vif *wvif,
    struct cfg80211_scan_request *req)
    {
    @@ -65,153 +38,81 @@ static int update_probe_tmpl(struct wfx_vif *wvif,
    return 0;
    }

    -int wfx_hw_scan(struct ieee80211_hw *hw,
    - struct ieee80211_vif *vif,
    - struct ieee80211_scan_request *hw_req)
    +static int send_scan_req(struct wfx_vif *wvif,
    + struct cfg80211_scan_request *req, int start_idx)
    +{
    + int i, ret, timeout;
    + struct ieee80211_channel *ch_start, *ch_cur;
    +
    + for (i = start_idx; i < req->n_channels; i++) {
    + ch_start = req->channels[start_idx];
    + ch_cur = req->channels[i];
    + WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
    + if (ch_cur->max_power != ch_start->max_power)
    + break;
    + if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
    + break;
    + }
    + wfx_tx_lock_flush(wvif->wdev);
    + reinit_completion(&wvif->scan_complete);
    + ret = hif_scan(wvif, req, start_idx, i - start_idx);
    + if (ret < 0)
    + return ret;
    + timeout = ret;
    + ret = wait_for_completion_timeout(&wvif->scan_complete, timeout);
    + if (req->channels[start_idx]->max_power != wvif->wdev->output_power)
    + hif_set_output_power(wvif, wvif->wdev->output_power * 10);
    + wfx_tx_unlock(wvif->wdev);
    + if (!ret) {
    + dev_notice(wvif->wdev->dev, "scan timeout\n");
    + hif_stop_scan(wvif);
    + return -ETIMEDOUT;
    + }
    + return i - start_idx;
    +}
    +
    +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    + struct ieee80211_scan_request *hw_req)
    {
    struct wfx_dev *wdev = hw->priv;
    struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv;
    - struct cfg80211_scan_request *req = &hw_req->req;
    - int i, ret;
    + int chan_cur, ret;

    - if (!wvif)
    - return -EINVAL;
    + WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);

    - if (wvif->state == WFX_STATE_AP)
    + if (vif->type == NL80211_IFTYPE_AP)
    return -EOPNOTSUPP;

    - if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
    - req->n_ssids = 0;
    -
    - if (req->n_ssids > HIF_API_MAX_NB_SSIDS)
    - return -EINVAL;
    + if (wvif->state == WFX_STATE_PRE_STA)
    + return -EBUSY;

    + mutex_lock(&wvif->scan_lock);
    mutex_lock(&wdev->conf_mutex);
    -
    - ret = update_probe_tmpl(wvif, req);
    - if (ret)
    - goto failed;
    -
    - ret = wfx_fwd_probe_req(wvif, true);
    - if (ret)
    - goto failed;
    -
    - wfx_tx_lock_flush(wdev);
    -
    - WARN(wvif->scan.req, "unexpected concurrent scan");
    - wvif->scan.req = req;
    - wvif->scan.n_ssids = 0;
    - wvif->scan.status = 0;
    - wvif->scan.begin = &req->channels[0];
    - wvif->scan.curr = wvif->scan.begin;
    - wvif->scan.end = &req->channels[req->n_channels];
    - wvif->scan.output_power = wdev->output_power;
    -
    - for (i = 0; i < req->n_ssids; ++i) {
    - struct hif_ssid_def *dst = &wvif->scan.ssids[wvif->scan.n_ssids];
    -
    - memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid));
    - dst->ssid_length = req->ssids[i].ssid_len;
    - ++wvif->scan.n_ssids;
    - }
    - schedule_work(&wvif->scan.work);
    -
    -failed:
    + update_probe_tmpl(wvif, &hw_req->req);
    + wfx_fwd_probe_req(wvif, true);
    + chan_cur = 0;
    + do {
    + ret = send_scan_req(wvif, &hw_req->req, chan_cur);
    + if (ret > 0)
    + chan_cur += ret;
    + } while (ret > 0 && chan_cur < hw_req->req.n_channels);
    + __ieee80211_scan_completed_compat(hw, ret < 0);
    mutex_unlock(&wdev->conf_mutex);
    - return ret;
    -}
    -
    -void wfx_scan_work(struct work_struct *work)
    -{
    - struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan.work);
    - struct ieee80211_channel **it;
    - struct ieee80211_channel *first;
    - int i;
    -
    - down(&wvif->scan.lock);
    - mutex_lock(&wvif->wdev->conf_mutex);
    -
    -
    - if (!wvif->scan.req || wvif->scan.curr == wvif->scan.end) {
    - if (wvif->scan.output_power != wvif->wdev->output_power)
    - hif_set_output_power(wvif,
    - wvif->wdev->output_power * 10);
    -
    - if (wvif->scan.status < 0)
    - dev_warn(wvif->wdev->dev, "scan failed\n");
    - else if (wvif->scan.req)
    - dev_dbg(wvif->wdev->dev, "scan completed\n");
    - else
    - dev_dbg(wvif->wdev->dev, "scan canceled\n");
    -
    - wvif->scan.req = NULL;
    - wfx_scan_restart_delayed(wvif);
    - wfx_tx_unlock(wvif->wdev);
    - mutex_unlock(&wvif->wdev->conf_mutex);
    - __ieee80211_scan_completed_compat(wvif->wdev->hw,
    - wvif->scan.status ? 1 : 0);
    - up(&wvif->scan.lock);
    - return;
    - }
    - first = *wvif->scan.curr;
    -
    - for (it = wvif->scan.curr + 1, i = 1;
    - it != wvif->scan.end && i < HIF_API_MAX_NB_CHANNELS;
    - ++it, ++i) {
    - if ((*it)->band != first->band)
    - break;
    - if (((*it)->flags ^ first->flags) &
    - IEEE80211_CHAN_NO_IR)
    - break;
    - if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
    - (*it)->max_power != first->max_power)
    - break;
    - }
    - if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
    - wvif->scan.output_power != first->max_power) {
    - wvif->scan.output_power = first->max_power;
    - hif_set_output_power(wvif, wvif->scan.output_power * 10);
    + mutex_unlock(&wvif->scan_lock);
    + if (wvif->delayed_unjoin) {
    + wvif->delayed_unjoin = false;
    + wfx_tx_lock(wdev);
    + if (!schedule_work(&wvif->unjoin_work))
    + wfx_tx_unlock(wdev);
    + } else if (wvif->delayed_link_loss) {
    + wvif->delayed_link_loss = false;
    + wfx_cqm_bssloss_sm(wvif, 1, 0, 0);
    }
    - wvif->scan.status = wfx_scan_start(wvif,
    - wvif->scan.curr - wvif->scan.begin,
    - it - wvif->scan.curr);
    - if (wvif->scan.status)
    - goto fail;
    - wvif->scan.curr = it;
    - mutex_unlock(&wvif->wdev->conf_mutex);
    - return;
    -
    -fail:
    - wvif->scan.curr = wvif->scan.end;
    - mutex_unlock(&wvif->wdev->conf_mutex);
    - up(&wvif->scan.lock);
    - schedule_work(&wvif->scan.work);
    + return 0;
    }

    -void wfx_scan_complete_cb(struct wfx_vif *wvif,
    - const struct hif_ind_scan_cmpl *arg)
    +void wfx_scan_complete(struct wfx_vif *wvif,
    + const struct hif_ind_scan_cmpl *arg)
    {
    - if (cancel_delayed_work_sync(&wvif->scan.timeout) > 0) {
    - wvif->scan.status = 1;
    - schedule_work(&wvif->scan.timeout.work);
    - }
    -}
    -
    -void wfx_scan_timeout(struct work_struct *work)
    -{
    - struct wfx_vif *wvif = container_of(work, struct wfx_vif,
    - scan.timeout.work);
    -
    - if (atomic_xchg(&wvif->scan.in_progress, 0)) {
    - if (wvif->scan.status > 0) {
    - wvif->scan.status = 0;
    - } else if (!wvif->scan.status) {
    - dev_warn(wvif->wdev->dev, "timeout waiting for scan complete notification\n");
    - wvif->scan.status = -ETIMEDOUT;
    - wvif->scan.curr = wvif->scan.end;
    - hif_stop_scan(wvif);
    - }
    - up(&wvif->scan.lock);
    - wfx_scan_work(&wvif->scan.work);
    - }
    + complete(&wvif->scan_complete);
    }
    diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h
    index e71e5f0f522e..03bc6c7e562d 100644
    --- a/drivers/staging/wfx/scan.h
    +++ b/drivers/staging/wfx/scan.h
    @@ -8,8 +8,6 @@
    #ifndef WFX_SCAN_H
    #define WFX_SCAN_H

    -#include <linux/semaphore.h>
    -#include <linux/workqueue.h>
    #include <net/mac80211.h>

    #include "hif_api_cmd.h"
    @@ -17,26 +15,9 @@
    struct wfx_dev;
    struct wfx_vif;

    -struct wfx_scan {
    - struct semaphore lock;
    - struct work_struct work;
    - struct delayed_work timeout;
    - struct cfg80211_scan_request *req;
    - struct ieee80211_channel **begin;
    - struct ieee80211_channel **curr;
    - struct ieee80211_channel **end;
    - struct hif_ssid_def ssids[HIF_API_MAX_NB_SSIDS];
    - int output_power;
    - int n_ssids;
    - int status;
    - atomic_t in_progress;
    -};
    -
    int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    struct ieee80211_scan_request *req);
    -void wfx_scan_work(struct work_struct *work);
    -void wfx_scan_timeout(struct work_struct *work);
    -void wfx_scan_complete_cb(struct wfx_vif *wvif,
    - const struct hif_ind_scan_cmpl *arg);
    +void wfx_scan_complete(struct wfx_vif *wvif,
    + const struct hif_ind_scan_cmpl *ind);

    #endif /* WFX_SCAN_H */
    diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
    index ba3e81fd477b..16f5db873275 100644
    --- a/drivers/staging/wfx/sta.c
    +++ b/drivers/staging/wfx/sta.c
    @@ -277,13 +277,13 @@ void wfx_configure_filter(struct ieee80211_hw *hw,
    *total_flags &= FIF_OTHER_BSS | FIF_FCSFAIL | FIF_PROBE_REQ;

    while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
    - down(&wvif->scan.lock);
    + mutex_lock(&wvif->scan_lock);
    wvif->filter_bssid = (*total_flags &
    (FIF_OTHER_BSS | FIF_PROBE_REQ)) ? 0 : 1;
    wvif->disable_beacon_filter = !(*total_flags & FIF_PROBE_REQ);
    wfx_fwd_probe_req(wvif, true);
    wfx_update_filtering(wvif);
    - up(&wvif->scan.lock);
    + mutex_unlock(&wvif->scan_lock);
    }
    }

    @@ -433,9 +433,9 @@ static void wfx_event_handler_work(struct work_struct *work)
    switch (event->evt.event_id) {
    case HIF_EVENT_IND_BSSLOST:
    cancel_work_sync(&wvif->unjoin_work);
    - if (!down_trylock(&wvif->scan.lock)) {
    + if (mutex_trylock(&wvif->scan_lock)) {
    wfx_cqm_bssloss_sm(wvif, 1, 0, 0);
    - up(&wvif->scan.lock);
    + mutex_unlock(&wvif->scan_lock);
    } else {
    /* Scan is in progress. Delay reporting.
    * Scan complete will trigger bss_loss_work
    @@ -501,7 +501,7 @@ static void wfx_do_unjoin(struct wfx_vif *wvif)
    {
    mutex_lock(&wvif->wdev->conf_mutex);

    - if (atomic_read(&wvif->scan.in_progress)) {
    + if (!mutex_trylock(&wvif->scan_lock)) {
    if (wvif->delayed_unjoin)
    dev_dbg(wvif->wdev->dev,
    "delayed unjoin is already scheduled\n");
    @@ -509,6 +509,7 @@ static void wfx_do_unjoin(struct wfx_vif *wvif)
    wvif->delayed_unjoin = true;
    goto done;
    }
    + mutex_unlock(&wvif->scan_lock);

    wvif->delayed_link_loss = false;

    @@ -613,14 +614,6 @@ static void wfx_do_join(struct wfx_vif *wvif)

    mutex_lock(&wvif->wdev->conf_mutex);

    - /* Under the conf lock: check scan status and
    - * bail out if it is in progress.
    - */
    - if (atomic_read(&wvif->scan.in_progress)) {
    - wfx_tx_unlock(wvif->wdev);
    - goto done_put;
    - }
    -
    /* Sanity check basic rates */
    if (!join.basic_rate_set)
    join.basic_rate_set = 7;
    @@ -684,7 +677,6 @@ static void wfx_do_join(struct wfx_vif *wvif)
    }
    wfx_update_filtering(wvif);

    -done_put:
    mutex_unlock(&wvif->wdev->conf_mutex);
    if (bss)
    cfg80211_put_bss(wvif->wdev->hw->wiphy, bss);
    @@ -1346,7 +1338,7 @@ int wfx_config(struct ieee80211_hw *hw, u32 changed)
    return 0;
    }

    - down(&wvif->scan.lock);
    + mutex_lock(&wvif->scan_lock);
    mutex_lock(&wdev->conf_mutex);
    if (changed & IEEE80211_CONF_CHANGE_POWER) {
    wdev->output_power = conf->power_level;
    @@ -1361,7 +1353,7 @@ int wfx_config(struct ieee80211_hw *hw, u32 changed)
    }

    mutex_unlock(&wdev->conf_mutex);
    - up(&wvif->scan.lock);
    + mutex_unlock(&wvif->scan_lock);
    return ret;
    }

    @@ -1419,10 +1411,6 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
    wvif->wep_default_key_id = -1;
    INIT_WORK(&wvif->wep_key_work, wfx_wep_key_work);

    - sema_init(&wvif->scan.lock, 1);
    - INIT_WORK(&wvif->scan.work, wfx_scan_work);
    - INIT_DELAYED_WORK(&wvif->scan.timeout, wfx_scan_timeout);
    -
    spin_lock_init(&wvif->event_queue_lock);
    INIT_LIST_HEAD(&wvif->event_queue);
    INIT_WORK(&wvif->event_handler_work, wfx_event_handler_work);
    @@ -1435,8 +1423,11 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
    INIT_WORK(&wvif->bss_params_work, wfx_bss_params_work);
    INIT_WORK(&wvif->set_cts_work, wfx_set_cts_work);
    INIT_WORK(&wvif->unjoin_work, wfx_unjoin_work);
    -
    INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work);
    +
    + mutex_init(&wvif->scan_lock);
    + init_completion(&wvif->scan_complete);
    +
    mutex_unlock(&wdev->conf_mutex);

    hif_set_macaddr(wvif, vif->addr);
    @@ -1462,10 +1453,6 @@ void wfx_remove_interface(struct ieee80211_hw *hw,
    struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv;
    int i;

    - // If scan is in progress, stop it
    - while (down_trylock(&wvif->scan.lock))
    - schedule();
    - up(&wvif->scan.lock);
    wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300));

    mutex_lock(&wdev->conf_mutex);
    @@ -1505,8 +1492,6 @@ void wfx_remove_interface(struct ieee80211_hw *hw,
    /* FIXME: In add to reset MAC address, try to reset interface */
    hif_set_macaddr(wvif, NULL);

    - cancel_delayed_work_sync(&wvif->scan.timeout);
    -
    wfx_cqm_bssloss_sm(wvif, 0, 0, 0);
    cancel_work_sync(&wvif->unjoin_work);
    cancel_delayed_work_sync(&wvif->link_id_gc_work);
    diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
    index 35f5ddc2eeb3..3356d0cbf7af 100644
    --- a/drivers/staging/wfx/wfx.h
    +++ b/drivers/staging/wfx/wfx.h
    @@ -125,7 +125,9 @@ struct wfx_vif {
    bool delayed_unjoin;
    struct work_struct unjoin_work;

    - struct wfx_scan scan;
    + /* avoid some operations in parallel with scan */
    + struct mutex scan_lock;
    + struct completion scan_complete;

    struct completion set_pm_mode_complete;

    --
    2.20.1
    \
     
     \ /
      Last update: 2019-12-16 18:07    [W:4.343 / U:0.412 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site