xref: /wlan-dirver/qca-wifi-host-cmn/target_if/dfs/src/target_if_dfs_full_offload.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  *
6  * Permission to use, copy, modify, and/or distribute this software for
7  * any purpose with or without fee is hereby granted, provided that the
8  * above copyright notice and this permission notice appear in all
9  * copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
16  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
17  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18  * PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 /**
22  * DOC: target_if_dfs_full_offload.c
23  * This file contains dfs target interface for full offload
24  */
25 
26 #include <target_if.h>
27 #include <target_if_dfs.h>
28 #include <wmi_unified_dfs_api.h>
29 #include <init_deinit_lmac.h>
30 #include <wlan_module_ids.h>
31 #include <target_if_dfs_full_offload.h>
32 #include <wlan_dfs_tgt_api.h>
33 #include <wlan_objmgr_pdev_obj.h>
34 
35 #if defined(QCA_SUPPORT_AGILE_DFS)
36 #include <wlan_mlme_dispatcher.h>
37 #endif
38 /**
39  * target_if_dfs_cac_complete_event_handler() - CAC complete indication.
40  * @scn: scn handle.
41  * @data: Pointer to data buffer.
42  * @datalen: data length.
43  *
44  * Return: 0 on successful indication.
45  */
46 static int target_if_dfs_cac_complete_event_handler(
47 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
48 {
49 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
50 	struct wlan_objmgr_psoc *psoc;
51 	struct wlan_objmgr_vdev *vdev;
52 	struct wlan_objmgr_pdev *pdev;
53 	int ret = 0;
54 	uint32_t vdev_id = 0;
55 	struct wmi_unified *wmi_handle;
56 
57 	if (!scn || !data) {
58 		target_if_err("scn: %pK, data: %pK", scn, data);
59 		return -EINVAL;
60 	}
61 
62 	psoc = target_if_get_psoc_from_scn_hdl(scn);
63 	if (!psoc) {
64 		target_if_err("null psoc");
65 		return -EINVAL;
66 	}
67 
68 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
69 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_dfs_cac_complete_ind) {
70 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
71 		return -EINVAL;
72 	}
73 
74 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
75 	if (!wmi_handle) {
76 		target_if_err("Invalid WMI handle");
77 		return -EINVAL;
78 	}
79 
80 	if (wmi_extract_dfs_cac_complete_event(wmi_handle, data, &vdev_id,
81 					       datalen) != QDF_STATUS_SUCCESS) {
82 		target_if_err("failed to extract cac complete event");
83 		return -EFAULT;
84 	}
85 
86 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DFS_ID);
87 	if (!vdev) {
88 		target_if_err("null vdev");
89 		return -EINVAL;
90 	}
91 
92 	pdev = wlan_vdev_get_pdev(vdev);
93 	if (!pdev) {
94 		target_if_err("null pdev");
95 		ret = -EINVAL;
96 	}
97 
98 	if (!ret && (QDF_STATUS_SUCCESS !=
99 	    dfs_rx_ops->dfs_dfs_cac_complete_ind(pdev, vdev_id))) {
100 		target_if_err("dfs_dfs_cac_complete_ind failed");
101 		ret = -EINVAL;
102 	}
103 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
104 
105 	return ret;
106 }
107 
108 #if defined(QCA_SUPPORT_AGILE_DFS)
109 /**
110  * target_if_dfs_ocac_complete_event_handler() - Off Channel CAC complete
111  *						 indication.
112  * @scn: scn handle.
113  * @data: Pointer to data buffer.
114  * @datalen: data length.
115  *
116  * Return: 0 on successful indication.
117  */
118 static int target_if_dfs_ocac_complete_event_handler(
119 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
120 {
121 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
122 	struct wlan_objmgr_psoc *psoc;
123 	struct wlan_objmgr_vdev *vdev;
124 	struct wlan_objmgr_pdev *pdev;
125 	struct vdev_adfs_complete_status ocac_status;
126 	int ret = 0;
127 	struct wmi_unified *wmi_handle;
128 
129 	if (!scn || !data) {
130 		target_if_err("scn: %pK, data: %pK", scn, data);
131 		return -EINVAL;
132 	}
133 
134 	psoc = target_if_get_psoc_from_scn_hdl(scn);
135 	if (!psoc) {
136 		target_if_err("null psoc");
137 		return -EINVAL;
138 	}
139 
140 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
141 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_dfs_ocac_complete_ind) {
142 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
143 		return -EINVAL;
144 	}
145 
146 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
147 	if (!wmi_handle) {
148 		target_if_err("Invalid WMI handle");
149 		return -EINVAL;
150 	}
151 
152 	if (wmi_extract_dfs_ocac_complete_event(wmi_handle,
153 						data,
154 						&ocac_status)
155 						!= QDF_STATUS_SUCCESS) {
156 		target_if_err("failed to extract off channel cac complete event");
157 		return -EFAULT;
158 	}
159 
160 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
161 						    ocac_status.vdev_id,
162 						    WLAN_DFS_ID);
163 	if (!vdev) {
164 		target_if_err("null vdev");
165 		return -EINVAL;
166 	}
167 
168 	pdev = wlan_vdev_get_pdev(vdev);
169 	if (!pdev) {
170 		target_if_err("null pdev");
171 		ret = -EINVAL;
172 		goto free_vdevref;
173 	}
174 
175 	if (!ret && (QDF_STATUS_SUCCESS !=
176 	    dfs_rx_ops->dfs_dfs_ocac_complete_ind(pdev, &ocac_status))) {
177 		target_if_err("dfs_dfs_ocac_complete_ind failed");
178 		ret = -EINVAL;
179 	}
180 
181 free_vdevref:
182 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
183 
184 	return ret;
185 }
186 #endif
187 
188 #ifdef MOBILE_DFS_SUPPORT
189 /**
190  * target_if_dfs_get_pdev() -  retrieve pdev by id
191  * @psoc: PSOC object
192  * @id: pdev id
193  * @dbg_id: id of the caller
194  *
195  * Return: pdev pointer
196  *         NULL on FAILURE
197  */
198 static struct wlan_objmgr_pdev *target_if_dfs_get_pdev(
199 		struct wlan_objmgr_psoc *psoc, uint8_t id,
200 		wlan_objmgr_ref_dbgid dbg_id)
201 {
202 	struct wlan_objmgr_pdev *pdev;
203 
204 	pdev = wlan_objmgr_get_pdev_by_id(psoc, id, dbg_id);
205 	if (!pdev) {
206 		pdev = wlan_objmgr_get_pdev_by_id(psoc, TGT_WMI_PDEV_ID_SOC,
207 						  dbg_id);
208 		if (!pdev)
209 			target_if_err("pdev id %d null pdev",
210 				      TGT_WMI_PDEV_ID_SOC);
211 	}
212 
213 	return pdev;
214 }
215 #else
216 static struct wlan_objmgr_pdev *target_if_dfs_get_pdev(
217 		struct wlan_objmgr_psoc *psoc, uint8_t id,
218 		wlan_objmgr_ref_dbgid dbg_id)
219 {
220 	return wlan_objmgr_get_pdev_by_id(psoc, id, dbg_id);
221 }
222 #endif
223 
224 /**
225  * target_if_dfs_radar_detection_event_handler() - Indicate RADAR detection and
226  * process RADAR detection.
227  * @scn: scn handle.
228  * @data: pointer to data buffer.
229  * @datalen: data length.
230  *
231  * Return: 0 on successful indication.
232  */
233 static int target_if_dfs_radar_detection_event_handler(
234 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
235 {
236 	struct radar_found_info radar;
237 	struct wlan_objmgr_psoc *psoc = NULL;
238 	struct wlan_objmgr_pdev *pdev = NULL;
239 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
240 	int ret = 0;
241 	struct wmi_unified *wmi_handle;
242 
243 	if (!scn || !data) {
244 		target_if_err("scn: %pK, data: %pK", scn, data);
245 		return -EINVAL;
246 	}
247 
248 	psoc = target_if_get_psoc_from_scn_hdl(scn);
249 	if (!psoc) {
250 		target_if_err("null psoc");
251 		return -EINVAL;
252 	}
253 
254 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
255 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_radar_ind) {
256 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
257 		return -EINVAL;
258 	}
259 
260 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
261 	if (!wmi_handle) {
262 		target_if_err("Invalid WMI handle");
263 		return -EINVAL;
264 	}
265 
266 	if (wmi_extract_dfs_radar_detection_event(wmi_handle, data, &radar,
267 						  datalen)
268 	    != QDF_STATUS_SUCCESS) {
269 		target_if_err("failed to extract cac complete event");
270 		return -EFAULT;
271 	}
272 
273 	pdev = target_if_dfs_get_pdev(psoc, radar.pdev_id, WLAN_DFS_ID);
274 	if (!pdev) {
275 		target_if_err("pdev id %d null pdev", radar.pdev_id);
276 		return -EINVAL;
277 	}
278 
279 	if (dfs_rx_ops->dfs_process_radar_ind(pdev,
280 				&radar) != QDF_STATUS_SUCCESS) {
281 		target_if_err("dfs_process_radar_ind failed pdev_id=%d",
282 			      radar.pdev_id);
283 		ret = -EINVAL;
284 	}
285 
286 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID);
287 
288 	return ret;
289 }
290 
291 /**
292  * target_if_dfs_reg_ocac_event() - registers dfs off channel event
293  * for full offload.
294  * @psoc: Pointer to psoc object.
295  *
296  * Return: QDF_STATUS_SUCCESS on successful registration.
297  */
298 #if defined(QCA_SUPPORT_AGILE_DFS)
299 static QDF_STATUS target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc)
300 {
301 	return wmi_unified_register_event(
302 			get_wmi_unified_hdl_from_psoc(psoc),
303 			wmi_vdev_ocac_complete_event_id,
304 			target_if_dfs_ocac_complete_event_handler);
305 }
306 #else
307 static QDF_STATUS target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc)
308 {
309 	return QDF_STATUS_SUCCESS;
310 }
311 #endif
312 
313 #if defined(WLAN_DFS_FULL_OFFLOAD)
314 QDF_STATUS target_if_dfs_reg_offload_events(
315 		struct wlan_objmgr_psoc *psoc)
316 {
317 	QDF_STATUS ret1, ret2, ret3;
318 
319 	ret1 = wmi_unified_register_event(
320 			get_wmi_unified_hdl_from_psoc(psoc),
321 			wmi_dfs_radar_detection_event_id,
322 			target_if_dfs_radar_detection_event_handler);
323 	target_if_debug("wmi_dfs_radar_detection_event_id ret=%d", ret1);
324 
325 	ret2 = wmi_unified_register_event(
326 			get_wmi_unified_hdl_from_psoc(psoc),
327 			wmi_dfs_cac_complete_id,
328 			target_if_dfs_cac_complete_event_handler);
329 	target_if_debug("wmi_dfs_cac_complete_id ret=%d", ret2);
330 
331 	ret3 = target_if_dfs_reg_ocac_event(psoc);
332 	target_if_debug("wmi_vdev_ocac_complete_event_id ret=%d", ret3);
333 
334 	if (QDF_IS_STATUS_ERROR(ret1) || QDF_IS_STATUS_ERROR(ret2) ||
335 	    QDF_IS_STATUS_ERROR(ret3))
336 		return QDF_STATUS_E_FAILURE;
337 	else
338 		return QDF_STATUS_SUCCESS;
339 }
340 #endif
341 
342 #if defined(QCA_SUPPORT_AGILE_DFS)
343 QDF_STATUS target_send_ocac_abort_cmd(struct wlan_objmgr_pdev *pdev)
344 {
345 	wmi_unified_t wmi_handle;
346 	struct vdev_adfs_abort_params param;
347 	struct wlan_objmgr_vdev *vdev;
348 	QDF_STATUS status;
349 
350 	if (!pdev) {
351 		target_if_err("null pdev");
352 		return QDF_STATUS_E_FAILURE;
353 	}
354 
355 	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_DFS_ID);
356 
357 	if (!vdev) {
358 		target_if_err("null vdev");
359 		return QDF_STATUS_E_FAILURE;
360 	}
361 
362 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
363 	if (!wmi_handle) {
364 		target_if_err("null wmi_handle");
365 		status = QDF_STATUS_E_FAILURE;
366 		goto free_vdevref;
367 	}
368 
369 	qdf_mem_set(&param, sizeof(param), 0);
370 	param.vdev_id = wlan_vdev_get_id(vdev);
371 	utils_dfs_cancel_precac_timer(pdev);
372 
373 	status = wmi_unified_send_vdev_adfs_ocac_abort_cmd(wmi_handle, &param);
374 	if (QDF_IS_STATUS_ERROR(status))
375 		target_if_err("dfs: unit_test_cmd send failed %d", status);
376 
377 free_vdevref:
378 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
379 
380 	return status;
381 }
382 
383 QDF_STATUS target_send_agile_ch_cfg_cmd(struct wlan_objmgr_pdev *pdev,
384 					struct dfs_agile_cac_params *adfs_param)
385 {
386 	wmi_unified_t wmi_handle;
387 	struct vdev_adfs_ch_cfg_params param;
388 	struct wlan_objmgr_vdev *vdev;
389 	QDF_STATUS status;
390 
391 	if (!pdev) {
392 		target_if_err("null pdev");
393 		return QDF_STATUS_E_FAILURE;
394 	}
395 
396 	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_DFS_ID);
397 
398 	if (!vdev) {
399 		target_if_err("null vdev");
400 		return QDF_STATUS_E_FAILURE;
401 	}
402 
403 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
404 	if (!wmi_handle) {
405 		target_if_err("null wmi_handle");
406 		status = QDF_STATUS_E_FAILURE;
407 		goto free_vdevref;
408 	}
409 
410 	qdf_mem_set(&param, sizeof(param), 0);
411 	param.vdev_id = wlan_vdev_get_id(vdev);
412 	param.ocac_mode = adfs_param->ocac_mode;
413 	param.min_duration_ms = adfs_param->min_precac_timeout;
414 	param.max_duration_ms = adfs_param->max_precac_timeout;
415 	param.chan_freq = adfs_param->precac_center_freq_1;
416 	param.chan_width = adfs_param->precac_chwidth;
417 	param.center_freq1 = adfs_param->precac_center_freq_1;
418 	param.center_freq2 = adfs_param->precac_center_freq_2;
419 
420 	status = wmi_unified_send_vdev_adfs_ch_cfg_cmd(wmi_handle, &param);
421 	if (QDF_IS_STATUS_ERROR(status))
422 		target_if_err("dfs: unit_test_cmd send failed %d", status);
423 
424 free_vdevref:
425 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
426 
427 	return status;
428 }
429 #endif
430 
431 #if (defined(WLAN_DFS_FULL_OFFLOAD) || defined(QCA_WIFI_QCA8074) || \
432 	defined(QCA_WIFI_QCA6018) || defined(QCA_WIFI_QCA5018) || \
433 	defined(QCA_WIFI_QCA9574))
434 QDF_STATUS target_process_bang_radar_cmd(
435 		struct wlan_objmgr_pdev *pdev,
436 		struct dfs_emulate_bang_radar_test_cmd *dfs_unit_test)
437 {
438 	QDF_STATUS status;
439 	struct wmi_unit_test_cmd wmi_utest;
440 	int i;
441 	wmi_unified_t wmi_handle;
442 	uint32_t target_pdev_id = 0;
443 
444 	if (!pdev) {
445 		target_if_err("null pdev");
446 		return QDF_STATUS_E_FAILURE;
447 	}
448 
449 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
450 	if (!wmi_handle) {
451 		target_if_err("null wmi_handle");
452 		return QDF_STATUS_E_FAILURE;
453 	}
454 
455 	wmi_utest.vdev_id = dfs_unit_test->vdev_id;
456 	wmi_utest.module_id = WLAN_MODULE_PHYERR_DFS;
457 	wmi_utest.num_args = dfs_unit_test->num_args;
458 
459 	for (i = 0; i < dfs_unit_test->num_args; i++)
460 		wmi_utest.args[i] = dfs_unit_test->args[i];
461 	/*
462 	 * Host to Target  conversion for pdev id required
463 	 * before we send a wmi unit test command
464 	 */
465 	if (wmi_convert_pdev_id_host_to_target(
466 				wmi_handle, pdev->pdev_objmgr.wlan_pdev_id,
467 				&target_pdev_id) != QDF_STATUS_SUCCESS) {
468 		target_if_err("failed to convert host pdev id to target");
469 		return QDF_STATUS_E_FAILURE;
470 	}
471 
472 	wmi_utest.args[IDX_PDEV_ID] = target_pdev_id;
473 
474 	status = wmi_unified_unit_test_cmd(wmi_handle, &wmi_utest);
475 	if (QDF_IS_STATUS_ERROR(status))
476 		target_if_err("dfs: unit_test_cmd send failed %d", status);
477 	return status;
478 }
479 #endif
480 
481 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
482 QDF_STATUS target_send_usenol_pdev_param(struct wlan_objmgr_pdev *pdev,
483 					 bool usenol)
484 {
485 	QDF_STATUS status;
486 	wmi_unified_t wmi_handle;
487 
488 	if (!pdev) {
489 		target_if_err("null pdev");
490 		return QDF_STATUS_E_FAILURE;
491 	}
492 
493 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
494 	if (!wmi_handle) {
495 		target_if_err("null wmi_handle");
496 		return QDF_STATUS_E_FAILURE;
497 	}
498 	status = wmi_send_usenol_pdev_param(wmi_handle, usenol, pdev);
499 
500 	if (QDF_IS_STATUS_ERROR(status))
501 		target_if_err("dfs: usenol_pdev_param send failed %d", status);
502 	return status;
503 }
504 
505 QDF_STATUS
506 target_send_subchan_marking_pdev_param(struct wlan_objmgr_pdev *pdev,
507 				       bool subchanmark)
508 {
509 	QDF_STATUS status;
510 	wmi_unified_t wmi_handle;
511 
512 	if (!pdev) {
513 		target_if_err("null pdev");
514 		return QDF_STATUS_E_FAILURE;
515 	}
516 
517 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
518 	if (!wmi_handle) {
519 		target_if_err("null wmi_handle");
520 		return QDF_STATUS_E_FAILURE;
521 	}
522 	status = wmi_send_subchan_marking_pdev_param(wmi_handle,
523 						     subchanmark, pdev);
524 
525 	if (QDF_IS_STATUS_ERROR(status))
526 		target_if_err("dfs: subchan_marking_pdev_param send failed %d",
527 			      status);
528 
529 	return status;
530 }
531 #endif
532