mac80211: reschedule sched scan after HW restart
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>
This commit is contained in:
parent
0ae07968f6
commit
d43c6b6e6f
4 changed files with 68 additions and 20 deletions
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {};
|
||||
|
@ -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])
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue