summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarak Bercovitz <barak@wizery.com>2013-08-21 12:36:50 +0400
committerArik Nemtsov <arik@wizery.com>2013-08-21 16:22:56 +0400
commit490227f2ad5d8269ec2243e5f20a425c59601f5b (patch)
treeeacd750a8d779348f0ae06596413be3fb513adf3
parente611d18893fbd66f6c303e111955d8a732fd0c34 (diff)
downloadwl18xx-490227f2ad5d8269ec2243e5f20a425c59601f5b.tar.xz
mac/cfg80211: reconfig sched scan after hw restart
Some implementations require that a sched scan that is stopped due to hw restart, is restarted. Sched scan reqeust parameters are kept and managed to do that. This also happens on suspend/resume without wowlan. Signed-off-by: Barak Bercovitz <barak@wizery.com>
-rw-r--r--include/net/cfg80211.h14
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/main.c6
-rw-r--r--net/mac80211/scan.c49
-rw-r--r--net/mac80211/util.c17
-rw-r--r--net/wireless/scan.c7
6 files changed, 76 insertions, 19 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8c02b1e55f2..03cbb70b24b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3349,6 +3349,20 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy);
void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
/**
+ * cfg80211_current_sched_scan_request - get current cached
+ * sched scan request
+ *
+ * @wiphy: the wiphy on which the scheduled scan is active
+ *
+ * The driver can call this function to get a reference of
+ * the current active scheduled scan request parameters.
+ *
+ * Return: A referenced struct, or NULL if request is no loner available.
+ */
+struct cfg80211_sched_scan_request *
+cfg80211_current_sched_scan_request(struct wiphy *wiphy);
+
+/**
* cfg80211_send_intermediate_result - inform userspace about new
* scan result.
*
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4eb491ed965..aaa4ed9d9ca 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -779,6 +779,8 @@ struct ieee80211_sub_if_data {
struct dentry *default_mgmt_key;
} debugfs;
#endif
+ bool sched_scan_stop_pending;
+ struct ieee80211_sched_scan_ies sched_scan_ies;
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 24a722d77fe..ca506a1369b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -260,10 +260,8 @@ static void ieee80211_restart_work(struct work_struct *work)
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__);
+ WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+ "%s called with hardware scan in progress\n", __func__);
mutex_unlock(&local->mtx);
rtnl_lock();
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 895af230c3f..c3835c026b3 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -947,11 +947,25 @@ out:
mutex_unlock(&local->mtx);
}
-int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_sched_scan_request *req)
+static void
+__ieee80211_free_sched_scan_ies(
+ struct ieee80211_sched_scan_ies *sched_scan_ies)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(sched_scan_ies->ie); i++) {
+ if (sched_scan_ies->len[i] > 0) {
+ kfree(sched_scan_ies->ie[i]);
+ sched_scan_ies->ie[i] = NULL;
+ sched_scan_ies->len[i] = 0;
+ }
+ }
+}
+
+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 = {};
int ret, i, iebufsz;
iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
@@ -977,25 +991,26 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
if (!local->hw.wiphy->bands[i])
continue;
- sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL);
- if (!sched_scan_ies.ie[i]) {
+ sdata->sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL);
+ if (!sdata->sched_scan_ies.ie[i]) {
ret = -ENOMEM;
goto out_free;
}
- sched_scan_ies.len[i] =
- ieee80211_build_preq_ies(local, sched_scan_ies.ie[i],
+ sdata->sched_scan_ies.len[i] =
+ ieee80211_build_preq_ies(local,
+ sdata->sched_scan_ies.ie[i],
iebufsz, req->ie, req->ie_len,
i, (u32) -1, 0);
}
- ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
- if (ret == 0)
- rcu_assign_pointer(local->sched_scan_sdata, sdata);
-
+ ret = drv_sched_scan_start(local, sdata, req, &sdata->sched_scan_ies);
+ if (ret)
+ goto out_free;
+ rcu_assign_pointer(local->sched_scan_sdata, sdata);
+ goto out;
out_free:
- while (i > 0)
- kfree(sched_scan_ies.ie[--i]);
+ __ieee80211_free_sched_scan_ies(&sdata->sched_scan_ies);
out:
mutex_unlock(&local->mtx);
return ret;
@@ -1013,8 +1028,10 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
goto out;
}
- if (rcu_access_pointer(local->sched_scan_sdata))
+ if (rcu_access_pointer(local->sched_scan_sdata)) {
+ sdata->sched_scan_stop_pending = 1;
drv_sched_scan_stop(local, sdata);
+ }
out:
mutex_unlock(&local->mtx);
@@ -1044,7 +1061,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
mutex_unlock(&local->mtx);
return;
}
-
+ local->sched_scan_sdata->sched_scan_stop_pending = 0;
+ __ieee80211_free_sched_scan_ies(
+ &local->sched_scan_sdata->sched_scan_ies);
rcu_assign_pointer(local->sched_scan_sdata, NULL);
mutex_unlock(&local->mtx);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 72e6292955b..180c23a86b9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1446,6 +1446,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_chanctx *ctx;
+ struct cfg80211_sched_scan_request *sched_scan_req;
struct sta_info *sta;
int res, i;
bool reconfig_due_to_wowlan = false;
@@ -1692,6 +1693,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (ieee80211_sdata_running(sdata))
ieee80211_enable_keys(sdata);
+ mutex_lock(&local->mtx);
+ sdata = rtnl_dereference(local->sched_scan_sdata);
+ if (sdata) {
+ if (sdata->sched_scan_stop_pending) {
+ ieee80211_sched_scan_stopped(&local->hw);
+ } else {
+ sched_scan_req = cfg80211_current_sched_scan_request(
+ local->hw.wiphy);
+ /* if sched_scan request is still available */
+ if (sched_scan_req)
+ drv_sched_scan_start(local, sdata,
+ sched_scan_req,
+ &sdata->sched_scan_ies);
+ }
+ }
+ mutex_unlock(&local->mtx);
wake_up:
local->in_reconfig = false;
barrier();
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 49d463c9c4f..6c4dfd2d468 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -296,6 +296,13 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
}
EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
+struct cfg80211_sched_scan_request *
+cfg80211_current_sched_scan_request(struct wiphy *wiphy)
+{
+ return wiphy_to_dev(wiphy)->sched_scan_req;
+}
+EXPORT_SYMBOL(cfg80211_current_sched_scan_request);
+
int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
bool driver_initiated)
{