Skip to content

Commit

Permalink
mac80211: reschedule sched scan after HW restart
Browse files Browse the repository at this point in the history
Keep the sched scan req when starting sched scan, and reschedule
it in case of HW restart during sched scan.
The upper layer don't have to know about the restart.

Signed-off-by: David Spinadel <david.spinadel@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
David Spinadel authored and Johannes Berg committed Dec 16, 2013
1 parent 0ae0796 commit d43c6b6
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 20 deletions.
4 changes: 4 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,7 @@ struct ieee80211_local {

struct work_struct sched_scan_stopped_work;
struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
struct cfg80211_sched_scan_request *sched_scan_req;

unsigned long leave_oper_channel_time;
enum mac80211_scan_state next_scan_state;
Expand Down Expand Up @@ -1421,6 +1422,9 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);

/* scheduled scan handling */
int
__ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req);
int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req);
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
Expand Down
8 changes: 2 additions & 6 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,8 @@ static void ieee80211_restart_work(struct work_struct *work)
/* wait for scan work complete */
flush_workqueue(local->workqueue);

mutex_lock(&local->mtx);
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx)),
"%s called with hardware scan in progress\n", __func__);
mutex_unlock(&local->mtx);
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
"%s called with hardware scan in progress\n", __func__);

rtnl_lock();
ieee80211_scan_cancel(local);
Expand Down
53 changes: 39 additions & 14 deletions net/mac80211/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -971,8 +971,8 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
mutex_unlock(&local->mtx);
}

int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req)
int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sched_scan_ies sched_scan_ies = {};
Expand All @@ -982,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
local->scan_ies_len + req->ie_len;

mutex_lock(&local->mtx);
lockdep_assert_held(&local->mtx);

if (rcu_access_pointer(local->sched_scan_sdata)) {
ret = -EBUSY;
goto out;
}

if (!local->ops->sched_scan_start) {
ret = -ENOTSUPP;
goto out;
}
if (!local->ops->sched_scan_start)
return -ENOTSUPP;

for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
if (!local->hw.wiphy->bands[i])
Expand All @@ -1013,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
}

ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
if (ret == 0)
if (ret == 0) {
rcu_assign_pointer(local->sched_scan_sdata, sdata);
local->sched_scan_req = req;
}

out_free:
while (i > 0)
kfree(sched_scan_ies.ie[--i]);
out:

if (ret) {
/* Clean in case of failure after HW restart or upon resume. */
rcu_assign_pointer(local->sched_scan_sdata, NULL);
local->sched_scan_req = NULL;
}

return ret;
}

int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req)
{
struct ieee80211_local *local = sdata->local;
int ret;

mutex_lock(&local->mtx);

if (rcu_access_pointer(local->sched_scan_sdata)) {
mutex_unlock(&local->mtx);
return -EBUSY;
}

ret = __ieee80211_request_sched_scan_start(sdata, req);

mutex_unlock(&local->mtx);
return ret;
}
Expand All @@ -1036,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
goto out;
}

/* We don't want to restart sched scan anymore. */
local->sched_scan_req = NULL;

if (rcu_access_pointer(local->sched_scan_sdata))
drv_sched_scan_stop(local, sdata);

Expand Down Expand Up @@ -1070,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)

rcu_assign_pointer(local->sched_scan_sdata, NULL);

/* If sched scan was aborted by the driver. */
local->sched_scan_req = NULL;

mutex_unlock(&local->mtx);

cfg80211_sched_scan_stopped(local->hw.wiphy);
Expand Down
23 changes: 23 additions & 0 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct sta_info *sta;
int res, i;
bool reconfig_due_to_wowlan = false;
struct ieee80211_sub_if_data *sched_scan_sdata;
bool sched_scan_stopped = false;

#ifdef CONFIG_PM
if (local->suspended)
Expand Down Expand Up @@ -1765,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local)
#else
WARN_ON(1);
#endif

/*
* Reconfigure sched scan if it was interrupted by FW restart or
* suspend.
*/
mutex_lock(&local->mtx);
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx));
if (sched_scan_sdata && local->sched_scan_req)
/*
* Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule.
*/
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
local->sched_scan_req))
sched_scan_stopped = true;
mutex_unlock(&local->mtx);

if (sched_scan_stopped)
cfg80211_sched_scan_stopped(local->hw.wiphy);

return 0;
}

Expand Down

0 comments on commit d43c6b6

Please sign in to comment.