Commit d43c6b6e authored by David Spinadel's avatar David Spinadel Committed by Johannes Berg

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: default avatarDavid Spinadel <david.spinadel@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0ae07968
......@@ -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 @@ out:
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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment