xref: /wlan-dirver/qca-wifi-host-cmn/target_if/dfs/src/target_if_dfs_full_offload.c (revision 503663c6daafffe652fa360bde17243568cd6d2a)
1 /*
2  * Copyright (c) 2017-2019 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 #define QUICK_OCAC_MODE 0
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 /**
189  * target_if_dfs_radar_detection_event_handler() - Indicate RADAR detection and
190  * process RADAR detection.
191  * @scn: scn handle.
192  * @data: pointer to data buffer.
193  * @datalen: data length.
194  *
195  * Return: 0 on successful indication.
196  */
197 static int target_if_dfs_radar_detection_event_handler(
198 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
199 {
200 	struct radar_found_info radar;
201 	struct wlan_objmgr_psoc *psoc = NULL;
202 	struct wlan_objmgr_pdev *pdev = NULL;
203 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
204 	int ret = 0;
205 	struct wmi_unified *wmi_handle;
206 
207 	if (!scn || !data) {
208 		target_if_err("scn: %pK, data: %pK", scn, data);
209 		return -EINVAL;
210 	}
211 
212 	psoc = target_if_get_psoc_from_scn_hdl(scn);
213 	if (!psoc) {
214 		target_if_err("null psoc");
215 		return -EINVAL;
216 	}
217 
218 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
219 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_radar_ind) {
220 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
221 		return -EINVAL;
222 	}
223 
224 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
225 	if (!wmi_handle) {
226 		target_if_err("Invalid WMI handle");
227 		return -EINVAL;
228 	}
229 
230 	if (wmi_extract_dfs_radar_detection_event(wmi_handle, data, &radar,
231 						  datalen)
232 	    != QDF_STATUS_SUCCESS) {
233 		target_if_err("failed to extract cac complete event");
234 		return -EFAULT;
235 	}
236 
237 	pdev = wlan_objmgr_get_pdev_by_id(psoc, radar.pdev_id, WLAN_DFS_ID);
238 	if (!pdev) {
239 		target_if_err("null pdev");
240 		return -EINVAL;
241 	}
242 
243 	if (dfs_rx_ops->dfs_process_radar_ind(pdev,
244 				&radar) != QDF_STATUS_SUCCESS) {
245 		target_if_err("dfs_process_radar_ind failed pdev_id=%d",
246 			      radar.pdev_id);
247 		ret = -EINVAL;
248 	}
249 
250 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID);
251 
252 	return ret;
253 }
254 
255 /**
256  * target_if_dfs_reg_ocac_event() - registers dfs off channel event
257  * for full offload.
258  * @psoc: Pointer to psoc object.
259  *
260  * Return: 0 on successful registration.
261  */
262 #if defined(QCA_SUPPORT_AGILE_DFS)
263 static int target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc)
264 {
265 	return wmi_unified_register_event(
266 			get_wmi_unified_hdl_from_psoc(psoc),
267 			wmi_vdev_ocac_complete_event_id,
268 			target_if_dfs_ocac_complete_event_handler);
269 }
270 #else
271 static int target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc)
272 {
273 	return 0;
274 }
275 #endif
276 
277 #if defined(WLAN_DFS_FULL_OFFLOAD)
278 QDF_STATUS target_if_dfs_reg_offload_events(
279 		struct wlan_objmgr_psoc *psoc)
280 {
281 	int ret1, ret2, ret3;
282 
283 	ret1 = wmi_unified_register_event(
284 			get_wmi_unified_hdl_from_psoc(psoc),
285 			wmi_dfs_radar_detection_event_id,
286 			target_if_dfs_radar_detection_event_handler);
287 	target_if_debug("wmi_dfs_radar_detection_event_id ret=%d", ret1);
288 
289 	ret2 = wmi_unified_register_event(
290 			get_wmi_unified_hdl_from_psoc(psoc),
291 			wmi_dfs_cac_complete_id,
292 			target_if_dfs_cac_complete_event_handler);
293 	target_if_debug("wmi_dfs_cac_complete_id ret=%d", ret2);
294 
295 	ret3 = target_if_dfs_reg_ocac_event(psoc);
296 	target_if_debug("wmi_vdev_ocac_complete_event_id ret=%d", ret3);
297 
298 	if (ret1 || ret2 || 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 = QUICK_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_chan;
379 	param.chan_width = adfs_param->precac_chwidth;
380 	param.center_freq = adfs_param->precac_chan;
381 
382 	status = wmi_unified_send_vdev_adfs_ch_cfg_cmd(wmi_handle, &param);
383 	if (QDF_IS_STATUS_ERROR(status))
384 		target_if_err("dfs: unit_test_cmd send failed %d", status);
385 
386 free_vdevref:
387 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
388 
389 	return status;
390 }
391 #endif
392 
393 #if (defined(WLAN_DFS_FULL_OFFLOAD) || defined(QCA_WIFI_QCA8074) || \
394 	defined(QCA_WIFI_QCA6018))
395 QDF_STATUS target_process_bang_radar_cmd(
396 		struct wlan_objmgr_pdev *pdev,
397 		struct dfs_emulate_bang_radar_test_cmd *dfs_unit_test)
398 {
399 	QDF_STATUS status;
400 	struct wmi_unit_test_cmd wmi_utest;
401 	int i;
402 	wmi_unified_t wmi_handle;
403 	uint32_t target_pdev_id = 0;
404 
405 	if (!pdev) {
406 		target_if_err("null pdev");
407 		return QDF_STATUS_E_FAILURE;
408 	}
409 
410 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
411 	if (!wmi_handle) {
412 		target_if_err("null wmi_handle");
413 		return QDF_STATUS_E_FAILURE;
414 	}
415 
416 	wmi_utest.vdev_id = dfs_unit_test->vdev_id;
417 	wmi_utest.module_id = WLAN_MODULE_PHYERR_DFS;
418 	wmi_utest.num_args = dfs_unit_test->num_args;
419 
420 	for (i = 0; i < dfs_unit_test->num_args; i++)
421 		wmi_utest.args[i] = dfs_unit_test->args[i];
422 	/*
423 	 * Host to Target  conversion for pdev id required
424 	 * before we send a wmi unit test command
425 	 */
426 	if (wmi_convert_pdev_id_host_to_target(
427 				wmi_handle, pdev->pdev_objmgr.wlan_pdev_id,
428 				&target_pdev_id) != QDF_STATUS_SUCCESS) {
429 		target_if_err("failed to convert host pdev id to target");
430 		return QDF_STATUS_E_FAILURE;
431 	}
432 
433 	wmi_utest.args[IDX_PDEV_ID] = target_pdev_id;
434 
435 	status = wmi_unified_unit_test_cmd(wmi_handle, &wmi_utest);
436 	if (QDF_IS_STATUS_ERROR(status))
437 		target_if_err("dfs: unit_test_cmd send failed %d", status);
438 	return status;
439 }
440 #endif
441 
442 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
443 QDF_STATUS target_send_usenol_pdev_param(struct wlan_objmgr_pdev *pdev,
444 					 bool usenol)
445 {
446 	QDF_STATUS status;
447 	wmi_unified_t wmi_handle;
448 
449 	if (!pdev) {
450 		target_if_err("null pdev");
451 		return QDF_STATUS_E_FAILURE;
452 	}
453 
454 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
455 	if (!wmi_handle) {
456 		target_if_err("null wmi_handle");
457 		return QDF_STATUS_E_FAILURE;
458 	}
459 	status = wmi_send_usenol_pdev_param(wmi_handle, usenol, pdev);
460 
461 	if (QDF_IS_STATUS_ERROR(status))
462 		target_if_err("dfs: usenol_pdev_param send failed %d", status);
463 	return status;
464 }
465 
466 QDF_STATUS
467 target_send_subchan_marking_pdev_param(struct wlan_objmgr_pdev *pdev,
468 				       bool subchanmark)
469 {
470 	QDF_STATUS status;
471 	wmi_unified_t wmi_handle;
472 
473 	if (!pdev) {
474 		target_if_err("null pdev");
475 		return QDF_STATUS_E_FAILURE;
476 	}
477 
478 	wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
479 	if (!wmi_handle) {
480 		target_if_err("null wmi_handle");
481 		return QDF_STATUS_E_FAILURE;
482 	}
483 	status = wmi_send_subchan_marking_pdev_param(wmi_handle,
484 						     subchanmark, pdev);
485 
486 	if (QDF_IS_STATUS_ERROR(status))
487 		target_if_err("dfs: subchan_marking_pdev_param send failed %d",
488 			      status);
489 
490 	return status;
491 }
492 #endif
493