Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
v6.8
  1// SPDX-License-Identifier: ISC
  2/*
  3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 
 
 
 
 
 
 
 
 
 
 
 
  5 */
  6
  7#include "wil6210.h"
  8#include "wmi.h"
  9
 10#define P2P_WILDCARD_SSID "DIRECT-"
 11#define P2P_DMG_SOCIAL_CHANNEL 2
 12#define P2P_SEARCH_DURATION_MS 500
 13#define P2P_DEFAULT_BI 100
 14
 15static int wil_p2p_start_listen(struct wil6210_vif *vif)
 16{
 17	struct wil6210_priv *wil = vif_to_wil(vif);
 18	struct wil_p2p_info *p2p = &vif->p2p;
 19	u8 channel = p2p->listen_chan.hw_value;
 20	int rc;
 21
 22	lockdep_assert_held(&wil->mutex);
 23
 24	rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
 25	if (rc) {
 26		wil_err(wil, "wmi_p2p_cfg failed\n");
 27		goto out;
 28	}
 29
 30	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
 31	if (rc) {
 32		wil_err(wil, "wmi_set_ssid failed\n");
 33		goto out_stop;
 34	}
 35
 36	rc = wmi_start_listen(vif);
 37	if (rc) {
 38		wil_err(wil, "wmi_start_listen failed\n");
 39		goto out_stop;
 40	}
 41
 42	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
 43	mod_timer(&p2p->discovery_timer,
 44		  jiffies + msecs_to_jiffies(p2p->listen_duration));
 45out_stop:
 46	if (rc)
 47		wmi_stop_discovery(vif);
 48
 49out:
 50	return rc;
 51}
 52
 53bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
 54{
 55	return (request->n_channels == 1) &&
 56	       (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
 57}
 58
 59int wil_p2p_search(struct wil6210_vif *vif,
 60		   struct cfg80211_scan_request *request)
 61{
 62	struct wil6210_priv *wil = vif_to_wil(vif);
 63	int rc;
 64	struct wil_p2p_info *p2p = &vif->p2p;
 65
 66	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
 67
 68	lockdep_assert_held(&wil->mutex);
 69
 70	if (p2p->discovery_started) {
 71		wil_err(wil, "search failed. discovery already ongoing\n");
 72		rc = -EBUSY;
 73		goto out;
 74	}
 75
 76	rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
 77	if (rc) {
 78		wil_err(wil, "wmi_p2p_cfg failed\n");
 79		goto out;
 80	}
 81
 82	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
 83	if (rc) {
 84		wil_err(wil, "wmi_set_ssid failed\n");
 85		goto out_stop;
 86	}
 87
 88	/* Set application IE to probe request and probe response */
 89	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
 90			request->ie_len, request->ie);
 91	if (rc) {
 92		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
 93		goto out_stop;
 94	}
 95
 96	/* supplicant doesn't provide Probe Response IEs. As a workaround -
 97	 * re-use Probe Request IEs
 98	 */
 99	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
100			request->ie_len, request->ie);
101	if (rc) {
102		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
103		goto out_stop;
104	}
105
106	rc = wmi_start_search(vif);
107	if (rc) {
108		wil_err(wil, "wmi_start_search failed\n");
109		goto out_stop;
110	}
111
112	p2p->discovery_started = 1;
113	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
114	mod_timer(&p2p->discovery_timer,
115		  jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
116
117out_stop:
118	if (rc)
119		wmi_stop_discovery(vif);
120
121out:
122	return rc;
123}
124
125int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
126		   unsigned int duration, struct ieee80211_channel *chan,
127		   u64 *cookie)
128{
129	struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
130	struct wil_p2p_info *p2p = &vif->p2p;
131	int rc;
132
133	if (!chan)
134		return -EINVAL;
135
136	wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
137
138	mutex_lock(&wil->mutex);
139
140	if (p2p->discovery_started) {
141		wil_err(wil, "discovery already ongoing\n");
142		rc = -EBUSY;
143		goto out;
144	}
145
146	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
147	*cookie = ++p2p->cookie;
148	p2p->listen_duration = duration;
149
150	mutex_lock(&wil->vif_mutex);
151	if (vif->scan_request) {
152		wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
153		p2p->pending_listen_wdev = wdev;
154		p2p->discovery_started = 1;
155		rc = 0;
156		mutex_unlock(&wil->vif_mutex);
157		goto out;
158	}
159	mutex_unlock(&wil->vif_mutex);
160
161	rc = wil_p2p_start_listen(vif);
162	if (rc)
163		goto out;
164
165	p2p->discovery_started = 1;
166	if (vif->mid == 0)
167		wil->radio_wdev = wdev;
168
169	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
170				  GFP_KERNEL);
171
172out:
173	mutex_unlock(&wil->mutex);
174	return rc;
175}
176
177u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
178{
179	struct wil_p2p_info *p2p = &vif->p2p;
180	u8 started = p2p->discovery_started;
181
182	if (p2p->discovery_started) {
183		if (p2p->pending_listen_wdev) {
184			/* discovery not really started, only pending */
185			p2p->pending_listen_wdev = NULL;
186		} else {
187			del_timer_sync(&p2p->discovery_timer);
188			wmi_stop_discovery(vif);
189		}
190		p2p->discovery_started = 0;
191	}
192
193	return started;
194}
195
196int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
197{
198	struct wil6210_priv *wil = vif_to_wil(vif);
199	struct wil_p2p_info *p2p = &vif->p2p;
200	u8 started;
201
202	mutex_lock(&wil->mutex);
203
204	if (cookie != p2p->cookie) {
205		wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
206			 p2p->cookie, cookie);
207		mutex_unlock(&wil->mutex);
208		return -ENOENT;
209	}
210
211	started = wil_p2p_stop_discovery(vif);
212
213	mutex_unlock(&wil->mutex);
214
215	if (!started) {
216		wil_err(wil, "listen not started\n");
217		return -ENOENT;
218	}
219
220	mutex_lock(&wil->vif_mutex);
221	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
222					   p2p->cookie,
223					   &p2p->listen_chan,
224					   GFP_KERNEL);
225	if (vif->mid == 0)
226		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
227	mutex_unlock(&wil->vif_mutex);
228	return 0;
229}
230
231void wil_p2p_listen_expired(struct work_struct *work)
232{
233	struct wil_p2p_info *p2p = container_of(work,
234			struct wil_p2p_info, discovery_expired_work);
235	struct wil6210_vif *vif = container_of(p2p,
236			struct wil6210_vif, p2p);
237	struct wil6210_priv *wil = vif_to_wil(vif);
238	u8 started;
239
240	wil_dbg_misc(wil, "p2p_listen_expired\n");
241
242	mutex_lock(&wil->mutex);
243	started = wil_p2p_stop_discovery(vif);
244	mutex_unlock(&wil->mutex);
245
246	if (!started)
247		return;
248
249	mutex_lock(&wil->vif_mutex);
250	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
251					   p2p->cookie,
252					   &p2p->listen_chan,
253					   GFP_KERNEL);
254	if (vif->mid == 0)
255		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
256	mutex_unlock(&wil->vif_mutex);
257}
258
259void wil_p2p_search_expired(struct work_struct *work)
260{
261	struct wil_p2p_info *p2p = container_of(work,
262			struct wil_p2p_info, discovery_expired_work);
263	struct wil6210_vif *vif = container_of(p2p,
264			struct wil6210_vif, p2p);
265	struct wil6210_priv *wil = vif_to_wil(vif);
266	u8 started;
267
268	wil_dbg_misc(wil, "p2p_search_expired\n");
269
270	mutex_lock(&wil->mutex);
271	started = wil_p2p_stop_discovery(vif);
272	mutex_unlock(&wil->mutex);
273
274	if (started) {
275		struct cfg80211_scan_info info = {
276			.aborted = false,
277		};
278
279		mutex_lock(&wil->vif_mutex);
280		if (vif->scan_request) {
281			cfg80211_scan_done(vif->scan_request, &info);
282			vif->scan_request = NULL;
283			if (vif->mid == 0)
284				wil->radio_wdev =
285					wil->main_ndev->ieee80211_ptr;
286		}
287		mutex_unlock(&wil->vif_mutex);
288	}
289}
290
291void wil_p2p_delayed_listen_work(struct work_struct *work)
292{
293	struct wil_p2p_info *p2p = container_of(work,
294			struct wil_p2p_info, delayed_listen_work);
295	struct wil6210_vif *vif = container_of(p2p,
296			struct wil6210_vif, p2p);
297	struct wil6210_priv *wil = vif_to_wil(vif);
298	int rc;
299
300	mutex_lock(&wil->mutex);
301
302	wil_dbg_misc(wil, "Checking delayed p2p listen\n");
303	if (!p2p->discovery_started || !p2p->pending_listen_wdev)
304		goto out;
305
306	mutex_lock(&wil->vif_mutex);
307	if (vif->scan_request) {
308		/* another scan started, wait again... */
309		mutex_unlock(&wil->vif_mutex);
310		goto out;
311	}
312	mutex_unlock(&wil->vif_mutex);
313
314	rc = wil_p2p_start_listen(vif);
315
316	mutex_lock(&wil->vif_mutex);
317	if (rc) {
318		cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
319						   p2p->cookie,
320						   &p2p->listen_chan,
321						   GFP_KERNEL);
322		if (vif->mid == 0)
323			wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
324	} else {
325		cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
326					  &p2p->listen_chan,
327					  p2p->listen_duration, GFP_KERNEL);
328		if (vif->mid == 0)
329			wil->radio_wdev = p2p->pending_listen_wdev;
330	}
331	p2p->pending_listen_wdev = NULL;
332	mutex_unlock(&wil->vif_mutex);
333
334out:
335	mutex_unlock(&wil->mutex);
336}
337
338void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
339{
340	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
341	struct wil_p2p_info *p2p = &vif->p2p;
342	struct cfg80211_scan_info info = {
343		.aborted = true,
344	};
345
346	lockdep_assert_held(&wil->mutex);
347	lockdep_assert_held(&wil->vif_mutex);
348
349	if (wil->radio_wdev != wil->p2p_wdev)
350		goto out;
351
352	if (!p2p->discovery_started) {
353		/* Regular scan on the p2p device */
354		if (vif->scan_request &&
355		    vif->scan_request->wdev == wil->p2p_wdev)
356			wil_abort_scan(vif, true);
357		goto out;
358	}
359
360	/* Search or listen on p2p device */
361	mutex_unlock(&wil->vif_mutex);
362	wil_p2p_stop_discovery(vif);
363	mutex_lock(&wil->vif_mutex);
364
365	if (vif->scan_request) {
366		/* search */
367		cfg80211_scan_done(vif->scan_request, &info);
368		vif->scan_request = NULL;
369	} else {
370		/* listen */
371		cfg80211_remain_on_channel_expired(wil->radio_wdev,
372						   p2p->cookie,
373						   &p2p->listen_chan,
374						   GFP_KERNEL);
375	}
376
377out:
378	wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
379}
v5.4
 
  1/*
  2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  4 *
  5 * Permission to use, copy, modify, and/or distribute this software for any
  6 * purpose with or without fee is hereby granted, provided that the above
  7 * copyright notice and this permission notice appear in all copies.
  8 *
  9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 16 */
 17
 18#include "wil6210.h"
 19#include "wmi.h"
 20
 21#define P2P_WILDCARD_SSID "DIRECT-"
 22#define P2P_DMG_SOCIAL_CHANNEL 2
 23#define P2P_SEARCH_DURATION_MS 500
 24#define P2P_DEFAULT_BI 100
 25
 26static int wil_p2p_start_listen(struct wil6210_vif *vif)
 27{
 28	struct wil6210_priv *wil = vif_to_wil(vif);
 29	struct wil_p2p_info *p2p = &vif->p2p;
 30	u8 channel = p2p->listen_chan.hw_value;
 31	int rc;
 32
 33	lockdep_assert_held(&wil->mutex);
 34
 35	rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
 36	if (rc) {
 37		wil_err(wil, "wmi_p2p_cfg failed\n");
 38		goto out;
 39	}
 40
 41	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
 42	if (rc) {
 43		wil_err(wil, "wmi_set_ssid failed\n");
 44		goto out_stop;
 45	}
 46
 47	rc = wmi_start_listen(vif);
 48	if (rc) {
 49		wil_err(wil, "wmi_start_listen failed\n");
 50		goto out_stop;
 51	}
 52
 53	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
 54	mod_timer(&p2p->discovery_timer,
 55		  jiffies + msecs_to_jiffies(p2p->listen_duration));
 56out_stop:
 57	if (rc)
 58		wmi_stop_discovery(vif);
 59
 60out:
 61	return rc;
 62}
 63
 64bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
 65{
 66	return (request->n_channels == 1) &&
 67	       (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
 68}
 69
 70int wil_p2p_search(struct wil6210_vif *vif,
 71		   struct cfg80211_scan_request *request)
 72{
 73	struct wil6210_priv *wil = vif_to_wil(vif);
 74	int rc;
 75	struct wil_p2p_info *p2p = &vif->p2p;
 76
 77	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
 78
 79	lockdep_assert_held(&wil->mutex);
 80
 81	if (p2p->discovery_started) {
 82		wil_err(wil, "search failed. discovery already ongoing\n");
 83		rc = -EBUSY;
 84		goto out;
 85	}
 86
 87	rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
 88	if (rc) {
 89		wil_err(wil, "wmi_p2p_cfg failed\n");
 90		goto out;
 91	}
 92
 93	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
 94	if (rc) {
 95		wil_err(wil, "wmi_set_ssid failed\n");
 96		goto out_stop;
 97	}
 98
 99	/* Set application IE to probe request and probe response */
100	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
101			request->ie_len, request->ie);
102	if (rc) {
103		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
104		goto out_stop;
105	}
106
107	/* supplicant doesn't provide Probe Response IEs. As a workaround -
108	 * re-use Probe Request IEs
109	 */
110	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
111			request->ie_len, request->ie);
112	if (rc) {
113		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
114		goto out_stop;
115	}
116
117	rc = wmi_start_search(vif);
118	if (rc) {
119		wil_err(wil, "wmi_start_search failed\n");
120		goto out_stop;
121	}
122
123	p2p->discovery_started = 1;
124	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
125	mod_timer(&p2p->discovery_timer,
126		  jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
127
128out_stop:
129	if (rc)
130		wmi_stop_discovery(vif);
131
132out:
133	return rc;
134}
135
136int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
137		   unsigned int duration, struct ieee80211_channel *chan,
138		   u64 *cookie)
139{
140	struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
141	struct wil_p2p_info *p2p = &vif->p2p;
142	int rc;
143
144	if (!chan)
145		return -EINVAL;
146
147	wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
148
149	mutex_lock(&wil->mutex);
150
151	if (p2p->discovery_started) {
152		wil_err(wil, "discovery already ongoing\n");
153		rc = -EBUSY;
154		goto out;
155	}
156
157	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
158	*cookie = ++p2p->cookie;
159	p2p->listen_duration = duration;
160
161	mutex_lock(&wil->vif_mutex);
162	if (vif->scan_request) {
163		wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
164		p2p->pending_listen_wdev = wdev;
165		p2p->discovery_started = 1;
166		rc = 0;
167		mutex_unlock(&wil->vif_mutex);
168		goto out;
169	}
170	mutex_unlock(&wil->vif_mutex);
171
172	rc = wil_p2p_start_listen(vif);
173	if (rc)
174		goto out;
175
176	p2p->discovery_started = 1;
177	if (vif->mid == 0)
178		wil->radio_wdev = wdev;
179
180	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
181				  GFP_KERNEL);
182
183out:
184	mutex_unlock(&wil->mutex);
185	return rc;
186}
187
188u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
189{
190	struct wil_p2p_info *p2p = &vif->p2p;
191	u8 started = p2p->discovery_started;
192
193	if (p2p->discovery_started) {
194		if (p2p->pending_listen_wdev) {
195			/* discovery not really started, only pending */
196			p2p->pending_listen_wdev = NULL;
197		} else {
198			del_timer_sync(&p2p->discovery_timer);
199			wmi_stop_discovery(vif);
200		}
201		p2p->discovery_started = 0;
202	}
203
204	return started;
205}
206
207int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
208{
209	struct wil6210_priv *wil = vif_to_wil(vif);
210	struct wil_p2p_info *p2p = &vif->p2p;
211	u8 started;
212
213	mutex_lock(&wil->mutex);
214
215	if (cookie != p2p->cookie) {
216		wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
217			 p2p->cookie, cookie);
218		mutex_unlock(&wil->mutex);
219		return -ENOENT;
220	}
221
222	started = wil_p2p_stop_discovery(vif);
223
224	mutex_unlock(&wil->mutex);
225
226	if (!started) {
227		wil_err(wil, "listen not started\n");
228		return -ENOENT;
229	}
230
231	mutex_lock(&wil->vif_mutex);
232	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
233					   p2p->cookie,
234					   &p2p->listen_chan,
235					   GFP_KERNEL);
236	if (vif->mid == 0)
237		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
238	mutex_unlock(&wil->vif_mutex);
239	return 0;
240}
241
242void wil_p2p_listen_expired(struct work_struct *work)
243{
244	struct wil_p2p_info *p2p = container_of(work,
245			struct wil_p2p_info, discovery_expired_work);
246	struct wil6210_vif *vif = container_of(p2p,
247			struct wil6210_vif, p2p);
248	struct wil6210_priv *wil = vif_to_wil(vif);
249	u8 started;
250
251	wil_dbg_misc(wil, "p2p_listen_expired\n");
252
253	mutex_lock(&wil->mutex);
254	started = wil_p2p_stop_discovery(vif);
255	mutex_unlock(&wil->mutex);
256
257	if (!started)
258		return;
259
260	mutex_lock(&wil->vif_mutex);
261	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
262					   p2p->cookie,
263					   &p2p->listen_chan,
264					   GFP_KERNEL);
265	if (vif->mid == 0)
266		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
267	mutex_unlock(&wil->vif_mutex);
268}
269
270void wil_p2p_search_expired(struct work_struct *work)
271{
272	struct wil_p2p_info *p2p = container_of(work,
273			struct wil_p2p_info, discovery_expired_work);
274	struct wil6210_vif *vif = container_of(p2p,
275			struct wil6210_vif, p2p);
276	struct wil6210_priv *wil = vif_to_wil(vif);
277	u8 started;
278
279	wil_dbg_misc(wil, "p2p_search_expired\n");
280
281	mutex_lock(&wil->mutex);
282	started = wil_p2p_stop_discovery(vif);
283	mutex_unlock(&wil->mutex);
284
285	if (started) {
286		struct cfg80211_scan_info info = {
287			.aborted = false,
288		};
289
290		mutex_lock(&wil->vif_mutex);
291		if (vif->scan_request) {
292			cfg80211_scan_done(vif->scan_request, &info);
293			vif->scan_request = NULL;
294			if (vif->mid == 0)
295				wil->radio_wdev =
296					wil->main_ndev->ieee80211_ptr;
297		}
298		mutex_unlock(&wil->vif_mutex);
299	}
300}
301
302void wil_p2p_delayed_listen_work(struct work_struct *work)
303{
304	struct wil_p2p_info *p2p = container_of(work,
305			struct wil_p2p_info, delayed_listen_work);
306	struct wil6210_vif *vif = container_of(p2p,
307			struct wil6210_vif, p2p);
308	struct wil6210_priv *wil = vif_to_wil(vif);
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->vif_mutex);
318	if (vif->scan_request) {
319		/* another scan started, wait again... */
320		mutex_unlock(&wil->vif_mutex);
321		goto out;
322	}
323	mutex_unlock(&wil->vif_mutex);
324
325	rc = wil_p2p_start_listen(vif);
326
327	mutex_lock(&wil->vif_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		if (vif->mid == 0)
334			wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
335	} else {
336		cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
337					  &p2p->listen_chan,
338					  p2p->listen_duration, GFP_KERNEL);
339		if (vif->mid == 0)
340			wil->radio_wdev = p2p->pending_listen_wdev;
341	}
342	p2p->pending_listen_wdev = NULL;
343	mutex_unlock(&wil->vif_mutex);
344
345out:
346	mutex_unlock(&wil->mutex);
347}
348
349void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
350{
351	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
352	struct wil_p2p_info *p2p = &vif->p2p;
353	struct cfg80211_scan_info info = {
354		.aborted = true,
355	};
356
357	lockdep_assert_held(&wil->mutex);
358	lockdep_assert_held(&wil->vif_mutex);
359
360	if (wil->radio_wdev != wil->p2p_wdev)
361		goto out;
362
363	if (!p2p->discovery_started) {
364		/* Regular scan on the p2p device */
365		if (vif->scan_request &&
366		    vif->scan_request->wdev == wil->p2p_wdev)
367			wil_abort_scan(vif, true);
368		goto out;
369	}
370
371	/* Search or listen on p2p device */
372	mutex_unlock(&wil->vif_mutex);
373	wil_p2p_stop_discovery(vif);
374	mutex_lock(&wil->vif_mutex);
375
376	if (vif->scan_request) {
377		/* search */
378		cfg80211_scan_done(vif->scan_request, &info);
379		vif->scan_request = NULL;
380	} else {
381		/* listen */
382		cfg80211_remain_on_channel_expired(wil->radio_wdev,
383						   p2p->cookie,
384						   &p2p->listen_chan,
385						   GFP_KERNEL);
386	}
387
388out:
389	wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
390}