aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorLior David <qca_liord@qca.qualcomm.com>2016-11-28 06:49:00 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2016-12-01 06:20:26 -0500
commitbb6743f7c2ffc467002dfe24bea5dedc96c7da04 (patch)
tree48cd38ddcd12c62556c958ecbe10f5226dd22937 /drivers/net/wireless/ath
parent982a6151f6f1296725de241a17932a3ecdd359d2 (diff)
wil6210: delay remain on channel when scan is active
Currently it was possible to call remain_on_channel(ROC) while scan was active and this caused a crash in the FW. In order to fix this problem and make the behavior consistent with other drivers, queue the ROC in case a scan is active and try it again when scan is done. As part of the fix, clean up some locking issues and return error if scan is called while ROC is active. Signed-off-by: Lior David <qca_liord@qca.qualcomm.com> Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/p2p.c150
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h9
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c4
5 files changed, 149 insertions, 61 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 22078b0ffc8c..6aa3ff4240a9 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -354,14 +354,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
354 wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n", 354 wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n",
355 __func__, wdev, wdev->iftype); 355 __func__, wdev, wdev->iftype);
356 356
357 mutex_lock(&wil->p2p_wdev_mutex);
358 if (wil->scan_request) {
359 wil_err(wil, "Already scanning\n");
360 mutex_unlock(&wil->p2p_wdev_mutex);
361 return -EAGAIN;
362 }
363 mutex_unlock(&wil->p2p_wdev_mutex);
364
365 /* check we are client side */ 357 /* check we are client side */
366 switch (wdev->iftype) { 358 switch (wdev->iftype) {
367 case NL80211_IFTYPE_STATION: 359 case NL80211_IFTYPE_STATION:
@@ -378,12 +370,24 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
378 return -EBUSY; 370 return -EBUSY;
379 } 371 }
380 372
373 mutex_lock(&wil->mutex);
374
375 mutex_lock(&wil->p2p_wdev_mutex);
376 if (wil->scan_request || wil->p2p.discovery_started) {
377 wil_err(wil, "Already scanning\n");
378 mutex_unlock(&wil->p2p_wdev_mutex);
379 rc = -EAGAIN;
380 goto out;
381 }
382 mutex_unlock(&wil->p2p_wdev_mutex);
383
381 /* social scan on P2P_DEVICE is handled as p2p search */ 384 /* social scan on P2P_DEVICE is handled as p2p search */
382 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && 385 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
383 wil_p2p_is_social_scan(request)) { 386 wil_p2p_is_social_scan(request)) {
384 if (!wil->p2p.p2p_dev_started) { 387 if (!wil->p2p.p2p_dev_started) {
385 wil_err(wil, "P2P search requested on stopped P2P device\n"); 388 wil_err(wil, "P2P search requested on stopped P2P device\n");
386 return -EIO; 389 rc = -EIO;
390 goto out;
387 } 391 }
388 wil->scan_request = request; 392 wil->scan_request = request;
389 wil->radio_wdev = wdev; 393 wil->radio_wdev = wdev;
@@ -392,7 +396,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
392 wil->radio_wdev = wil_to_wdev(wil); 396 wil->radio_wdev = wil_to_wdev(wil);
393 wil->scan_request = NULL; 397 wil->scan_request = NULL;
394 } 398 }
395 return rc; 399 goto out;
396 } 400 }
397 401
398 (void)wil_p2p_stop_discovery(wil); 402 (void)wil_p2p_stop_discovery(wil);
@@ -415,7 +419,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
415 419
416 if (rc) { 420 if (rc) {
417 wil_err(wil, "set SSID for scan request failed: %d\n", rc); 421 wil_err(wil, "set SSID for scan request failed: %d\n", rc);
418 return rc; 422 goto out;
419 } 423 }
420 424
421 wil->scan_request = request; 425 wil->scan_request = request;
@@ -448,7 +452,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
448 452
449 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); 453 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
450 if (rc) 454 if (rc)
451 goto out; 455 goto out_restore;
452 456
453 if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) { 457 if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
454 cmd.cmd.discovery_mode = 1; 458 cmd.cmd.discovery_mode = 1;
@@ -459,13 +463,14 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
459 rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + 463 rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
460 cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); 464 cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
461 465
462out: 466out_restore:
463 if (rc) { 467 if (rc) {
464 del_timer_sync(&wil->scan_timer); 468 del_timer_sync(&wil->scan_timer);
465 wil->radio_wdev = wil_to_wdev(wil); 469 wil->radio_wdev = wil_to_wdev(wil);
466 wil->scan_request = NULL; 470 wil->scan_request = NULL;
467 } 471 }
468 472out:
473 mutex_unlock(&wil->mutex);
469 return rc; 474 return rc;
470} 475}
471 476
@@ -988,16 +993,8 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
988 wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n", 993 wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n",
989 __func__, chan->center_freq, duration, wdev->iftype); 994 __func__, chan->center_freq, duration, wdev->iftype);
990 995
991 rc = wil_p2p_listen(wil, duration, chan, cookie); 996 rc = wil_p2p_listen(wil, wdev, duration, chan, cookie);
992 if (rc) 997 return rc;
993 return rc;
994
995 wil->radio_wdev = wdev;
996
997 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
998 GFP_KERNEL);
999
1000 return 0;
1001} 998}
1002 999
1003static int wil_cancel_remain_on_channel(struct wiphy *wiphy, 1000static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 70f9c07749e3..e2e021bcaa03 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -518,6 +518,7 @@ int wil_priv_init(struct wil6210_priv *wil)
518 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); 518 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
519 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); 519 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
520 INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); 520 INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
521 INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
521 522
522 INIT_LIST_HEAD(&wil->pending_wmi_ev); 523 INIT_LIST_HEAD(&wil->pending_wmi_ev);
523 INIT_LIST_HEAD(&wil->probe_client_pending); 524 INIT_LIST_HEAD(&wil->probe_client_pending);
@@ -579,6 +580,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
579 cancel_work_sync(&wil->disconnect_worker); 580 cancel_work_sync(&wil->disconnect_worker);
580 cancel_work_sync(&wil->fw_error_worker); 581 cancel_work_sync(&wil->fw_error_worker);
581 cancel_work_sync(&wil->p2p.discovery_expired_work); 582 cancel_work_sync(&wil->p2p.discovery_expired_work);
583 cancel_work_sync(&wil->p2p.delayed_listen_work);
582 mutex_lock(&wil->mutex); 584 mutex_lock(&wil->mutex);
583 wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); 585 wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
584 mutex_unlock(&wil->mutex); 586 mutex_unlock(&wil->mutex);
diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c
index 4f0eab015a20..fbae99525e01 100644
--- a/drivers/net/wireless/ath/wil6210/p2p.c
+++ b/drivers/net/wireless/ath/wil6210/p2p.c
@@ -22,6 +22,43 @@
22#define P2P_SEARCH_DURATION_MS 500 22#define P2P_SEARCH_DURATION_MS 500
23#define P2P_DEFAULT_BI 100 23#define P2P_DEFAULT_BI 100
24 24
25static int wil_p2p_start_listen(struct wil6210_priv *wil)
26{
27 struct wil_p2p_info *p2p = &wil->p2p;
28 u8 channel = p2p->listen_chan.hw_value;
29 int rc;
30
31 lockdep_assert_held(&wil->mutex);
32
33 rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
34 if (rc) {
35 wil_err(wil, "wmi_p2p_cfg failed\n");
36 goto out;
37 }
38
39 rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
40 if (rc) {
41 wil_err(wil, "wmi_set_ssid failed\n");
42 goto out_stop;
43 }
44
45 rc = wmi_start_listen(wil);
46 if (rc) {
47 wil_err(wil, "wmi_start_listen failed\n");
48 goto out_stop;
49 }
50
51 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
52 mod_timer(&p2p->discovery_timer,
53 jiffies + msecs_to_jiffies(p2p->listen_duration));
54out_stop:
55 if (rc)
56 wmi_stop_discovery(wil);
57
58out:
59 return rc;
60}
61
25bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request) 62bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
26{ 63{
27 return (request->n_channels == 1) && 64 return (request->n_channels == 1) &&
@@ -46,7 +83,7 @@ int wil_p2p_search(struct wil6210_priv *wil,
46 wil_dbg_misc(wil, "%s: channel %d\n", 83 wil_dbg_misc(wil, "%s: channel %d\n",
47 __func__, P2P_DMG_SOCIAL_CHANNEL); 84 __func__, P2P_DMG_SOCIAL_CHANNEL);
48 85
49 mutex_lock(&wil->mutex); 86 lockdep_assert_held(&wil->mutex);
50 87
51 if (p2p->discovery_started) { 88 if (p2p->discovery_started) {
52 wil_err(wil, "%s: search failed. discovery already ongoing\n", 89 wil_err(wil, "%s: search failed. discovery already ongoing\n",
@@ -103,22 +140,19 @@ out_stop:
103 wmi_stop_discovery(wil); 140 wmi_stop_discovery(wil);
104 141
105out: 142out:
106 mutex_unlock(&wil->mutex);
107 return rc; 143 return rc;
108} 144}
109 145
110int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, 146int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
111 struct ieee80211_channel *chan, u64 *cookie) 147 unsigned int duration, struct ieee80211_channel *chan,
148 u64 *cookie)
112{ 149{
113 struct wil_p2p_info *p2p = &wil->p2p; 150 struct wil_p2p_info *p2p = &wil->p2p;
114 u8 channel = P2P_DMG_SOCIAL_CHANNEL;
115 int rc; 151 int rc;
116 152
117 if (!chan) 153 if (!chan)
118 return -EINVAL; 154 return -EINVAL;
119 155
120 channel = chan->hw_value;
121
122 wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); 156 wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
123 157
124 mutex_lock(&wil->mutex); 158 mutex_lock(&wil->mutex);
@@ -129,35 +163,30 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
129 goto out; 163 goto out;
130 } 164 }
131 165
132 rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); 166 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
133 if (rc) { 167 *cookie = ++p2p->cookie;
134 wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__); 168 p2p->listen_duration = duration;
135 goto out;
136 }
137
138 rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
139 if (rc) {
140 wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
141 goto out_stop;
142 }
143 169
144 rc = wmi_start_listen(wil); 170 mutex_lock(&wil->p2p_wdev_mutex);
145 if (rc) { 171 if (wil->scan_request) {
146 wil_err(wil, "%s: wmi_start_listen failed\n", __func__); 172 wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
147 goto out_stop; 173 p2p->pending_listen_wdev = wdev;
174 p2p->discovery_started = 1;
175 rc = 0;
176 mutex_unlock(&wil->p2p_wdev_mutex);
177 goto out;
148 } 178 }
179 mutex_unlock(&wil->p2p_wdev_mutex);
149 180
150 memcpy(&p2p->listen_chan, chan, sizeof(*chan)); 181 rc = wil_p2p_start_listen(wil);
151 *cookie = ++p2p->cookie; 182 if (rc)
183 goto out;
152 184
153 p2p->discovery_started = 1; 185 p2p->discovery_started = 1;
154 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); 186 wil->radio_wdev = wdev;
155 mod_timer(&p2p->discovery_timer,
156 jiffies + msecs_to_jiffies(duration));
157 187
158out_stop: 188 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
159 if (rc) 189 GFP_KERNEL);
160 wmi_stop_discovery(wil);
161 190
162out: 191out:
163 mutex_unlock(&wil->mutex); 192 mutex_unlock(&wil->mutex);
@@ -170,9 +199,14 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
170 u8 started = p2p->discovery_started; 199 u8 started = p2p->discovery_started;
171 200
172 if (p2p->discovery_started) { 201 if (p2p->discovery_started) {
173 del_timer_sync(&p2p->discovery_timer); 202 if (p2p->pending_listen_wdev) {
203 /* discovery not really started, only pending */
204 p2p->pending_listen_wdev = NULL;
205 } else {
206 del_timer_sync(&p2p->discovery_timer);
207 wmi_stop_discovery(wil);
208 }
174 p2p->discovery_started = 0; 209 p2p->discovery_started = 0;
175 wmi_stop_discovery(wil);
176 } 210 }
177 211
178 return started; 212 return started;
@@ -257,11 +291,57 @@ void wil_p2p_search_expired(struct work_struct *work)
257 }; 291 };
258 292
259 mutex_lock(&wil->p2p_wdev_mutex); 293 mutex_lock(&wil->p2p_wdev_mutex);
260 cfg80211_scan_done(wil->scan_request, &info); 294 if (wil->scan_request) {
261 wil->scan_request = NULL; 295 cfg80211_scan_done(wil->scan_request, &info);
262 wil->radio_wdev = wil->wdev; 296 wil->scan_request = NULL;
297 wil->radio_wdev = wil->wdev;
298 }
299 mutex_unlock(&wil->p2p_wdev_mutex);
300 }
301}
302
303void wil_p2p_delayed_listen_work(struct work_struct *work)
304{
305 struct wil_p2p_info *p2p = container_of(work,
306 struct wil_p2p_info, delayed_listen_work);
307 struct wil6210_priv *wil = container_of(p2p,
308 struct wil6210_priv, p2p);
309 int rc;
310
311 mutex_lock(&wil->mutex);
312
313 wil_dbg_misc(wil, "Checking delayed p2p listen\n");
314 if (!p2p->discovery_started || !p2p->pending_listen_wdev)
315 goto out;
316
317 mutex_lock(&wil->p2p_wdev_mutex);
318 if (wil->scan_request) {
319 /* another scan started, wait again... */
263 mutex_unlock(&wil->p2p_wdev_mutex); 320 mutex_unlock(&wil->p2p_wdev_mutex);
321 goto out;
264 } 322 }
323 mutex_unlock(&wil->p2p_wdev_mutex);
324
325 rc = wil_p2p_start_listen(wil);
326
327 mutex_lock(&wil->p2p_wdev_mutex);
328 if (rc) {
329 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
330 p2p->cookie,
331 &p2p->listen_chan,
332 GFP_KERNEL);
333 wil->radio_wdev = wil->wdev;
334 } else {
335 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
336 &p2p->listen_chan,
337 p2p->listen_duration, GFP_KERNEL);
338 wil->radio_wdev = p2p->pending_listen_wdev;
339 }
340 p2p->pending_listen_wdev = NULL;
341 mutex_unlock(&wil->p2p_wdev_mutex);
342
343out:
344 mutex_unlock(&wil->mutex);
265} 345}
266 346
267void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) 347void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b449f84bcc68..ef95db977bc6 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -461,8 +461,11 @@ struct wil_p2p_info {
461 u8 discovery_started; 461 u8 discovery_started;
462 u8 p2p_dev_started; 462 u8 p2p_dev_started;
463 u64 cookie; 463 u64 cookie;
464 struct wireless_dev *pending_listen_wdev;
465 unsigned int listen_duration;
464 struct timer_list discovery_timer; /* listen/search duration */ 466 struct timer_list discovery_timer; /* listen/search duration */
465 struct work_struct discovery_expired_work; /* listen/search expire */ 467 struct work_struct discovery_expired_work; /* listen/search expire */
468 struct work_struct delayed_listen_work; /* listen after scan done */
466}; 469};
467 470
468enum wil_sta_status { 471enum wil_sta_status {
@@ -843,13 +846,15 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
843void wil_p2p_discovery_timer_fn(ulong x); 846void wil_p2p_discovery_timer_fn(ulong x);
844int wil_p2p_search(struct wil6210_priv *wil, 847int wil_p2p_search(struct wil6210_priv *wil,
845 struct cfg80211_scan_request *request); 848 struct cfg80211_scan_request *request);
846int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, 849int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
847 struct ieee80211_channel *chan, u64 *cookie); 850 unsigned int duration, struct ieee80211_channel *chan,
851 u64 *cookie);
848u8 wil_p2p_stop_discovery(struct wil6210_priv *wil); 852u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
849int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie); 853int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
850void wil_p2p_listen_expired(struct work_struct *work); 854void wil_p2p_listen_expired(struct work_struct *work);
851void wil_p2p_search_expired(struct work_struct *work); 855void wil_p2p_search_expired(struct work_struct *work);
852void wil_p2p_stop_radio_operations(struct wil6210_priv *wil); 856void wil_p2p_stop_radio_operations(struct wil6210_priv *wil);
857void wil_p2p_delayed_listen_work(struct work_struct *work);
853 858
854/* WMI for P2P */ 859/* WMI for P2P */
855int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi); 860int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 2971ddf0bc44..d289a4d999b7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -441,6 +441,10 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
441 wil->radio_wdev = wil->wdev; 441 wil->radio_wdev = wil->wdev;
442 wil->scan_request = NULL; 442 wil->scan_request = NULL;
443 wake_up_interruptible(&wil->wq); 443 wake_up_interruptible(&wil->wq);
444 if (wil->p2p.pending_listen_wdev) {
445 wil_dbg_misc(wil, "Scheduling delayed listen\n");
446 schedule_work(&wil->p2p.delayed_listen_work);
447 }
444 } else { 448 } else {
445 wil_err(wil, "SCAN_COMPLETE while not scanning\n"); 449 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
446 } 450 }