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