1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: offload lmac interface APIs definitions for scan
22  */
23 
24 #include <qdf_mem.h>
25 #include <qdf_status.h>
26 #include <target_if_scan.h>
27 #include <wmi_unified_priv.h>
28 #include <wmi_unified_param.h>
29 #include <wlan_objmgr_psoc_obj.h>
30 #include <wlan_scan_tgt_api.h>
31 #include <target_if.h>
32 
33 static inline struct wlan_lmac_if_scan_rx_ops *
target_if_scan_get_rx_ops(struct wlan_objmgr_psoc * psoc)34 target_if_scan_get_rx_ops(struct wlan_objmgr_psoc *psoc)
35 {
36 	struct wlan_lmac_if_rx_ops *rx_ops;
37 
38 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
39 	if (!rx_ops) {
40 		target_if_err("rx_ops is NULL");
41 		return NULL;
42 	}
43 
44 	return &rx_ops->scan;
45 }
46 
target_if_update_aux_support(struct wlan_objmgr_psoc * psoc)47 QDF_STATUS target_if_update_aux_support(struct wlan_objmgr_psoc *psoc)
48 {
49 	struct wmi_unified *wmi_handle;
50 	struct wlan_scan_obj *scan_obj;
51 
52 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
53 
54 	if (!wmi_handle) {
55 		target_if_err("null wmi handle");
56 		return QDF_STATUS_E_FAILURE;
57 	}
58 	scan_obj = wlan_psoc_get_scan_obj(psoc);
59 
60 	if (!scan_obj) {
61 		target_if_err("Failed to get scan object");
62 		return QDF_STATUS_E_FAILURE;
63 	}
64 	if (wmi_service_enabled(wmi_handle, wmi_service_aux_mac_support))
65 		scan_obj->aux_mac_support = true;
66 	else
67 		scan_obj->aux_mac_support = false;
68 
69 	target_if_debug("aux_mac_support:%d", scan_obj->aux_mac_support);
70 	return QDF_STATUS_SUCCESS;
71 }
72 
73 static int
target_if_scan_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)74 target_if_scan_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen)
75 {
76 	struct scan_event_info *event_info;
77 	struct wlan_objmgr_psoc *psoc;
78 	struct wmi_unified *wmi_handle;
79 	struct wlan_lmac_if_scan_rx_ops *scan_rx_ops;
80 	QDF_STATUS status;
81 
82 	if (!scn || !data) {
83 		target_if_err("scn: 0x%pK, data: 0x%pK\n", scn, data);
84 		return -EINVAL;
85 	}
86 	psoc = target_if_get_psoc_from_scn_hdl(scn);
87 	if (!psoc) {
88 		target_if_err("null psoc\n");
89 		return -EINVAL;
90 	}
91 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
92 
93 	if (!wmi_handle) {
94 		target_if_err("wmi_handle is NULL");
95 		return -EINVAL;
96 	}
97 
98 	event_info = qdf_mem_malloc(sizeof(*event_info));
99 
100 	if (!event_info)
101 		return -ENOMEM;
102 
103 	if (wmi_extract_vdev_scan_ev_param(wmi_handle, data,
104 	   &(event_info->event))) {
105 		target_if_err("Failed to extract wmi scan event");
106 		qdf_mem_free(event_info);
107 		return -EINVAL;
108 	}
109 
110 	scan_rx_ops = target_if_scan_get_rx_ops(psoc);
111 	if (!scan_rx_ops) {
112 		target_if_err("scan_rx_ops is NULL");
113 		return -EINVAL;
114 	}
115 
116 	if (scan_rx_ops->scan_ev_handler) {
117 		status = scan_rx_ops->scan_ev_handler(psoc, event_info);
118 		if (status != QDF_STATUS_SUCCESS) {
119 			qdf_mem_free(event_info);
120 			return -EINVAL;
121 		}
122 	} else {
123 		qdf_mem_free(event_info);
124 		return -EINVAL;
125 	}
126 
127 	return 0;
128 }
129 
130 #ifdef FEATURE_WLAN_SCAN_PNO
131 
target_if_nlo_complete_handler(ol_scn_t scn,uint8_t * data,uint32_t len)132 int target_if_nlo_complete_handler(ol_scn_t scn, uint8_t *data,
133 	uint32_t len)
134 {
135 	struct scan_event_info *event_info;
136 	struct wlan_objmgr_psoc *psoc;
137 	struct wmi_unified *wmi_handle;
138 	struct wlan_lmac_if_scan_rx_ops *scan_rx_ops;
139 	QDF_STATUS status;
140 
141 	if (!scn || !data) {
142 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
143 		return -EINVAL;
144 	}
145 
146 	psoc = target_if_get_psoc_from_scn_hdl(scn);
147 	if (!psoc) {
148 		target_if_err("null psoc");
149 		return -EINVAL;
150 	}
151 
152 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
153 	if (!wmi_handle) {
154 		target_if_err("wmi_handle is NULL");
155 		return -EINVAL;
156 	}
157 
158 	event_info = qdf_mem_malloc(sizeof(*event_info));
159 	if (!event_info)
160 		return -ENOMEM;
161 
162 	if (wmi_extract_nlo_complete_ev_param(wmi_handle, data,
163 					      &event_info->event)) {
164 		target_if_err("Failed to extract WMI PNO complete event");
165 		qdf_mem_free(event_info);
166 		return -EINVAL;
167 	}
168 
169 	target_if_debug("PNO complete event received for vdev %d",
170 			event_info->event.vdev_id);
171 
172 	scan_rx_ops = target_if_scan_get_rx_ops(psoc);
173 	if (!scan_rx_ops) {
174 		target_if_err("scan_rx_ops is NULL");
175 		return -EINVAL;
176 	}
177 
178 	if (scan_rx_ops->scan_ev_handler) {
179 		status = scan_rx_ops->scan_ev_handler(psoc, event_info);
180 		if (status != QDF_STATUS_SUCCESS) {
181 			qdf_mem_free(event_info);
182 			return -EINVAL;
183 		}
184 	} else {
185 		qdf_mem_free(event_info);
186 		return -EINVAL;
187 	}
188 
189 	return 0;
190 }
191 
target_if_nlo_match_event_handler(ol_scn_t scn,uint8_t * data,uint32_t len)192 int target_if_nlo_match_event_handler(ol_scn_t scn, uint8_t *data,
193 	uint32_t len)
194 {
195 	struct scan_event_info *event_info;
196 	struct wlan_objmgr_psoc *psoc;
197 	struct wmi_unified *wmi_handle;
198 	struct wlan_lmac_if_scan_rx_ops *scan_rx_ops;
199 	QDF_STATUS status;
200 
201 	if (!scn || !data) {
202 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
203 		return -EINVAL;
204 	}
205 
206 	psoc = target_if_get_psoc_from_scn_hdl(scn);
207 	if (!psoc) {
208 		target_if_err("null psoc");
209 		return -EINVAL;
210 	}
211 
212 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
213 	if (!wmi_handle) {
214 		target_if_err("wmi_handle is NULL");
215 		return -EINVAL;
216 	}
217 
218 	event_info = qdf_mem_malloc(sizeof(*event_info));
219 	if (!event_info)
220 		return -ENOMEM;
221 
222 	if (wmi_extract_nlo_match_ev_param(wmi_handle, data,
223 					   &event_info->event)) {
224 		target_if_err("Failed to extract WMI PNO match event");
225 		qdf_mem_free(event_info);
226 		return -EINVAL;
227 	}
228 
229 	target_if_debug("PNO match event received for vdev %d",
230 			event_info->event.vdev_id);
231 
232 	scan_rx_ops = target_if_scan_get_rx_ops(psoc);
233 	if (!scan_rx_ops) {
234 		target_if_err("scan_rx_ops is NULL");
235 		return -EINVAL;
236 	}
237 
238 	if (scan_rx_ops->scan_ev_handler) {
239 		status = scan_rx_ops->scan_ev_handler(psoc, event_info);
240 		if (status != QDF_STATUS_SUCCESS) {
241 			qdf_mem_free(event_info);
242 			return -EINVAL;
243 		}
244 	} else {
245 		qdf_mem_free(event_info);
246 		return -EINVAL;
247 	}
248 
249 	return 0;
250 }
251 
252 static QDF_STATUS
target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)253 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc,
254 	void *arg)
255 {
256 	QDF_STATUS status;
257 	struct wmi_unified *wmi_handle;
258 
259 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
260 	if (!wmi_handle) {
261 		target_if_err("Invalid WMI handle");
262 		return QDF_STATUS_E_FAILURE;
263 	}
264 
265 	status = wmi_unified_register_event(
266 			wmi_handle,
267 			wmi_nlo_match_event_id,
268 			target_if_nlo_match_event_handler);
269 	if (status) {
270 		target_if_err("Failed to register nlo match event cb");
271 		return QDF_STATUS_E_FAILURE;
272 	}
273 
274 	status = wmi_unified_register_event(
275 			wmi_handle,
276 			wmi_nlo_scan_complete_event_id,
277 			target_if_nlo_complete_handler);
278 	if (status) {
279 		target_if_err("Failed to register nlo scan comp event cb");
280 		return QDF_STATUS_E_FAILURE;
281 	}
282 
283 	return QDF_STATUS_SUCCESS;
284 }
285 
286 static QDF_STATUS
target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)287 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc,
288 		void *arg)
289 {
290 	QDF_STATUS status;
291 	struct wmi_unified *wmi_handle;
292 
293 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
294 	if (!wmi_handle) {
295 		target_if_err("Invalid WMI handle");
296 		return QDF_STATUS_E_FAILURE;
297 	}
298 
299 	status = wmi_unified_unregister_event(
300 			wmi_handle,
301 			wmi_nlo_match_event_id);
302 	if (status) {
303 		target_if_err("Failed to unregister nlo match event cb");
304 		return QDF_STATUS_E_FAILURE;
305 	}
306 
307 	status = wmi_unified_unregister_event(
308 			wmi_handle,
309 			wmi_nlo_scan_complete_event_id);
310 	if (status) {
311 		target_if_err("Failed to unregister nlo scan comp event cb");
312 		return QDF_STATUS_E_FAILURE;
313 	}
314 
315 	return QDF_STATUS_SUCCESS;
316 }
317 
318 static QDF_STATUS
target_if_pno_start(struct wlan_objmgr_psoc * psoc,struct pno_scan_req_params * req)319 target_if_pno_start(struct wlan_objmgr_psoc *psoc,
320 	struct pno_scan_req_params *req)
321 {
322 	QDF_STATUS status;
323 	struct wmi_unified *wmi_handle;
324 
325 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
326 	if (!wmi_handle) {
327 		target_if_err("Invalid WMI handle");
328 		return QDF_STATUS_E_FAILURE;
329 	}
330 
331 	status = wmi_unified_pno_start_cmd(wmi_handle, req);
332 	if (status == QDF_STATUS_SUCCESS) {
333 		if (req->mawc_params.enable)
334 			status = wmi_unified_nlo_mawc_cmd(wmi_handle,
335 							  &req->mawc_params);
336 	}
337 
338 	return status;
339 }
340 
341 static QDF_STATUS
target_if_pno_stop(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)342 target_if_pno_stop(struct wlan_objmgr_psoc *psoc,
343 	uint8_t vdev_id)
344 {
345 	struct wmi_unified *wmi_handle;
346 
347 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
348 	if (!wmi_handle) {
349 		target_if_err("Invalid WMI handle");
350 		return QDF_STATUS_E_FAILURE;
351 	}
352 
353 	return wmi_unified_pno_stop_cmd(wmi_handle, vdev_id);
354 }
355 
356 #else
357 
358 static inline QDF_STATUS
target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)359 target_if_scan_register_pno_event_handler(struct wlan_objmgr_psoc *psoc,
360 	void *arg)
361 {
362 	return QDF_STATUS_SUCCESS;
363 }
364 
365 static inline QDF_STATUS
target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)366 target_if_scan_unregister_pno_event_handler(struct wlan_objmgr_psoc *psoc,
367 	void *arg)
368 {
369 	return QDF_STATUS_SUCCESS;
370 }
371 
372 static inline QDF_STATUS
target_if_pno_start(struct wlan_objmgr_psoc * psoc,struct pno_scan_req_params * req)373 target_if_pno_start(struct wlan_objmgr_psoc *psoc,
374 	struct pno_scan_req_params *req)
375 {
376 	return QDF_STATUS_SUCCESS;
377 }
378 
379 static inline QDF_STATUS
target_if_pno_stop(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)380 target_if_pno_stop(struct wlan_objmgr_psoc *psoc,
381 	uint8_t vdev_id)
382 {
383 	return QDF_STATUS_SUCCESS;
384 }
385 #endif
386 
387 static QDF_STATUS
target_if_obss_scan_disable(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)388 target_if_obss_scan_disable(struct wlan_objmgr_psoc *psoc,
389 			    uint8_t vdev_id)
390 {
391 	struct wmi_unified *wmi_handle;
392 
393 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
394 	if (!wmi_handle) {
395 		target_if_err("Invalid WMI handle");
396 		return QDF_STATUS_E_FAILURE;
397 	}
398 
399 	return wmi_unified_obss_disable_cmd(wmi_handle, vdev_id);
400 }
401 
402 QDF_STATUS
target_if_scan_register_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)403 target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg)
404 {
405 	QDF_STATUS status;
406 	struct wmi_unified *wmi_handle;
407 
408 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
409 	if (!wmi_handle) {
410 		target_if_err("Invalid WMI handle");
411 		return QDF_STATUS_E_FAILURE;
412 	}
413 
414 	status = wmi_unified_register_event(
415 			wmi_handle,
416 			wmi_scan_event_id,
417 			target_if_scan_event_handler);
418 	if (status) {
419 		target_if_err("Failed to register Scan match event cb");
420 		return QDF_STATUS_E_FAILURE;
421 	}
422 
423 	status = target_if_scan_register_pno_event_handler(psoc, arg);
424 
425 	return status;
426 }
427 
428 QDF_STATUS
target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)429 target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
430 		void *arg)
431 {
432 	QDF_STATUS status;
433 	struct wmi_unified *wmi_handle;
434 
435 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
436 	if (!wmi_handle) {
437 		target_if_err("Invalid WMI handle");
438 		return QDF_STATUS_E_FAILURE;
439 	}
440 
441 	status = wmi_unified_unregister_event(
442 			wmi_handle,
443 			wmi_scan_event_id);
444 	if (status) {
445 		target_if_err("Failed to unregister Scan match event cb");
446 		return QDF_STATUS_E_FAILURE;
447 	}
448 
449 	status = target_if_scan_unregister_pno_event_handler(psoc, arg);
450 
451 	return status;
452 }
453 
454 QDF_STATUS
target_if_scan_start(struct wlan_objmgr_pdev * pdev,struct scan_start_request * req)455 target_if_scan_start(struct wlan_objmgr_pdev *pdev,
456 		struct scan_start_request *req)
457 {
458 	wmi_unified_t pdev_wmi_handle;
459 
460 	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
461 	if (!pdev_wmi_handle) {
462 		target_if_err("Invalid PDEV WMI handle");
463 		return QDF_STATUS_E_FAILURE;
464 	}
465 	return wmi_unified_scan_start_cmd_send(pdev_wmi_handle, &req->scan_req);
466 }
467 
468 QDF_STATUS
target_if_scan_cancel(struct wlan_objmgr_pdev * pdev,struct scan_cancel_param * req)469 target_if_scan_cancel(struct wlan_objmgr_pdev *pdev,
470 		struct scan_cancel_param *req)
471 {
472 	wmi_unified_t pdev_wmi_handle;
473 
474 	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
475 	if (!pdev_wmi_handle) {
476 		target_if_err("Invalid PDEV WMI handle");
477 		return QDF_STATUS_E_NULL_VALUE;
478 	}
479 	return wmi_unified_scan_stop_cmd_send(pdev_wmi_handle, req);
480 }
481 
482 #if defined(WLAN_FEATURE_11BE) && defined(WLAN_FEATURE_11BE_MLO_MBSSID)
target_if_is_platform_eht_capable(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)483 bool target_if_is_platform_eht_capable(struct wlan_objmgr_psoc *psoc,
484 				       uint8_t pdev_id)
485 {
486 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr, *mac_phy_cap;
487 
488 	if (psoc->tgt_if_handle) {
489 		mac_phy_cap_arr =
490 			target_psoc_get_mac_phy_cap(psoc->tgt_if_handle);
491 		if (!mac_phy_cap_arr)
492 			return false;
493 
494 		mac_phy_cap = &mac_phy_cap_arr[pdev_id];
495 		if (mac_phy_cap && mac_phy_cap->supports_11be)
496 			return true;
497 	}
498 
499 	return false;
500 }
501 #else
target_if_is_platform_eht_capable(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)502 bool target_if_is_platform_eht_capable(struct wlan_objmgr_psoc *psoc,
503 				       uint8_t pdev_id)
504 {
505 	return false;
506 }
507 #endif
508 
509 QDF_STATUS
target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops * tx_ops)510 target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
511 {
512 	struct wlan_lmac_if_scan_tx_ops *scan;
513 
514 	scan = &tx_ops->scan;
515 	if (!scan) {
516 		target_if_err("Scan txops NULL");
517 		return QDF_STATUS_E_FAILURE;
518 	}
519 
520 	scan->scan_start = target_if_scan_start;
521 	scan->scan_cancel = target_if_scan_cancel;
522 	scan->pno_start = target_if_pno_start;
523 	scan->pno_stop = target_if_pno_stop;
524 	scan->obss_disable = target_if_obss_scan_disable;
525 	scan->scan_reg_ev_handler = target_if_scan_register_event_handler;
526 	scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler;
527 	scan->is_platform_eht_capable = target_if_is_platform_eht_capable;
528 
529 	return QDF_STATUS_SUCCESS;
530 }
531 
532 QDF_STATUS
target_if_scan_set_max_active_scans(struct wlan_objmgr_psoc * psoc,uint32_t max_active_scans)533 target_if_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc,
534 		uint32_t max_active_scans)
535 {
536 	struct wlan_lmac_if_scan_rx_ops *scan_rx_ops;
537 	QDF_STATUS status;
538 
539 	scan_rx_ops = target_if_scan_get_rx_ops(psoc);
540 	if (!scan_rx_ops) {
541 		target_if_err("scan_rx_ops is NULL");
542 		return QDF_STATUS_E_FAILURE;
543 	}
544 
545 	if (scan_rx_ops->scan_set_max_active_scans) {
546 		status = scan_rx_ops->scan_set_max_active_scans(psoc,
547 				max_active_scans);
548 	} else {
549 		target_if_err("scan_set_max_active_scans uninitialized");
550 		status = QDF_STATUS_E_FAULT;
551 	}
552 
553 	return status;
554 }
555