xref: /wlan-dirver/qca-wifi-host-cmn/target_if/dfs/src/target_if_dfs.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
1 /*
2  * Copyright (c) 2017-2018 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.c
22  * This file contains dfs target interface
23  */
24 
25 #include <target_if.h>
26 #include <qdf_types.h>
27 #include <qdf_status.h>
28 #include <target_if_dfs.h>
29 #include <wlan_module_ids.h>
30 #include <wmi_unified_api.h>
31 #include <wlan_lmac_if_def.h>
32 #include <wmi_unified_priv.h>
33 #include <wlan_scan_tgt_api.h>
34 #include <wmi_unified_param.h>
35 #include <wmi_unified_dfs_api.h>
36 #include "wlan_dfs_tgt_api.h"
37 #include "target_type.h"
38 #include <init_deinit_ucfg.h>
39 #include <wlan_reg_ucfg_api.h>
40 
41 static inline struct wlan_lmac_if_dfs_rx_ops *
42 target_if_dfs_get_rx_ops(struct wlan_objmgr_psoc *psoc)
43 {
44 	return &psoc->soc_cb.rx_ops.dfs_rx_ops;
45 }
46 
47 /**
48  * target_if_is_dfs_3() - Is dfs3 support or not
49  * @target_type: target type being used.
50  *
51  * Return: true if dfs3 is supported, false otherwise.
52  */
53 static bool target_if_is_dfs_3(uint32_t target_type)
54 {
55 	bool is_dfs_3;
56 
57 	switch (target_type) {
58 	case TARGET_TYPE_AR6320:
59 		is_dfs_3 = false;
60 		break;
61 	case TARGET_TYPE_ADRASTEA:
62 		is_dfs_3 = true;
63 		break;
64 	default:
65 		is_dfs_3 = true;
66 	}
67 
68 	return is_dfs_3;
69 }
70 
71 static int target_if_dfs_cac_complete_event_handler(
72 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
73 {
74 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
75 	struct wlan_objmgr_psoc *psoc;
76 	struct wlan_objmgr_vdev *vdev;
77 	struct wlan_objmgr_pdev *pdev;
78 	int ret = 0;
79 	uint32_t vdev_id = 0;
80 
81 	if (!scn || !data) {
82 		target_if_err("scn: %pK, data: %pK", scn, data);
83 		return -EINVAL;
84 	}
85 
86 	psoc = target_if_get_psoc_from_scn_hdl(scn);
87 	if (!psoc) {
88 		target_if_err("null psoc");
89 		return -EINVAL;
90 	}
91 
92 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
93 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_dfs_cac_complete_ind) {
94 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
95 		return -EINVAL;
96 	}
97 
98 	if (wmi_extract_dfs_cac_complete_event(GET_WMI_HDL_FROM_PSOC(psoc),
99 			data, &vdev_id, datalen) != QDF_STATUS_SUCCESS) {
100 		target_if_err("failed to extract cac complete event");
101 		return -EFAULT;
102 	}
103 
104 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DFS_ID);
105 	if (!vdev) {
106 		target_if_err("null vdev");
107 		return -EINVAL;
108 	}
109 
110 	pdev = wlan_vdev_get_pdev(vdev);
111 	if (!pdev) {
112 		target_if_err("null pdev");
113 		ret = -EINVAL;
114 	}
115 
116 	if (!ret && (QDF_STATUS_SUCCESS !=
117 	    dfs_rx_ops->dfs_dfs_cac_complete_ind(pdev, vdev_id))) {
118 		target_if_err("dfs_dfs_cac_complete_ind failed");
119 		ret = -EINVAL;
120 	}
121 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID);
122 
123 	return ret;
124 }
125 
126 static int target_if_dfs_radar_detection_event_handler(
127 		ol_scn_t scn, uint8_t *data, uint32_t datalen)
128 {
129 	struct radar_found_info radar;
130 	struct wlan_objmgr_psoc *psoc = NULL;
131 	struct wlan_objmgr_pdev *pdev = NULL;
132 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
133 	int ret = 0;
134 
135 	if (!scn || !data) {
136 		target_if_err("scn: %pK, data: %pK", scn, data);
137 		return -EINVAL;
138 	}
139 
140 	psoc = target_if_get_psoc_from_scn_hdl(scn);
141 	if (!psoc) {
142 		target_if_err("null psoc");
143 		return -EINVAL;
144 	}
145 
146 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
147 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_radar_ind) {
148 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
149 		return -EINVAL;
150 	}
151 
152 	if (wmi_extract_dfs_radar_detection_event(GET_WMI_HDL_FROM_PSOC(psoc),
153 			data, &radar, datalen) != QDF_STATUS_SUCCESS) {
154 		target_if_err("failed to extract cac complete event");
155 		return -EFAULT;
156 	}
157 
158 	pdev = wlan_objmgr_get_pdev_by_id(psoc, radar.pdev_id, WLAN_DFS_ID);
159 	if (!pdev) {
160 		target_if_err("null pdev");
161 		return -EINVAL;
162 	}
163 
164 	if (QDF_STATUS_SUCCESS != dfs_rx_ops->dfs_process_radar_ind(pdev,
165 				&radar)) {
166 		target_if_err("dfs_process_radar_ind failed pdev_id=%d",
167 			      radar.pdev_id);
168 		ret = -EINVAL;
169 	}
170 
171 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID);
172 
173 	return ret;
174 }
175 
176 static QDF_STATUS target_if_dfs_reg_offload_events(
177 		struct wlan_objmgr_psoc *psoc)
178 {
179 	int ret1, ret2;
180 
181 	ret1 = wmi_unified_register_event(GET_WMI_HDL_FROM_PSOC(psoc),
182 			wmi_dfs_radar_detection_event_id,
183 			target_if_dfs_radar_detection_event_handler);
184 	target_if_debug("wmi_dfs_radar_detection_event_id ret=%d", ret1);
185 
186 	ret2 = wmi_unified_register_event(GET_WMI_HDL_FROM_PSOC(psoc),
187 			wmi_dfs_cac_complete_id,
188 			target_if_dfs_cac_complete_event_handler);
189 	target_if_debug("wmi_dfs_cac_complete_id ret=%d", ret2);
190 
191 	if (ret1 || ret2)
192 		return QDF_STATUS_E_FAILURE;
193 	else
194 		return QDF_STATUS_SUCCESS;
195 }
196 
197 static QDF_STATUS target_if_dfs_reg_phyerr_events(struct wlan_objmgr_psoc *psoc)
198 {
199 	/* TODO: dfs non-offload case */
200 	return QDF_STATUS_SUCCESS;
201 }
202 
203 #ifdef QCA_MCL_DFS_SUPPORT
204 /**
205  * target_if_radar_event_handler() - handle radar event when
206  * phyerr filter offload is enabled.
207  * @scn: Handle to HIF context
208  * @data: radar event buffer
209  * @datalen: radar event buffer length
210  *
211  * Return: 0 on success; error code otherwise
212 */
213 static int target_if_radar_event_handler(
214 	ol_scn_t scn, uint8_t *data, uint32_t datalen)
215 {
216 	struct radar_event_info wlan_radar_event;
217 	struct wlan_objmgr_psoc *psoc;
218 	struct wlan_objmgr_pdev *pdev;
219 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
220 
221 	if (!scn || !data) {
222 		target_if_err("scn: %pK, data: %pK", scn, data);
223 		return -EINVAL;
224 	}
225 	psoc = target_if_get_psoc_from_scn_hdl(scn);
226 	if (!psoc) {
227 		target_if_err("null psoc");
228 		return -EINVAL;
229 	}
230 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
231 
232 	if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_phyerr_filter_offload) {
233 		target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops);
234 		return -EINVAL;
235 	}
236 	if (QDF_IS_STATUS_ERROR(wmi_extract_wlan_radar_event_info(
237 			GET_WMI_HDL_FROM_PSOC(psoc), data,
238 			&wlan_radar_event, datalen))) {
239 		target_if_err("failed to extract wlan radar event");
240 		return -EFAULT;
241 	}
242 	pdev = wlan_objmgr_get_pdev_by_id(psoc, wlan_radar_event.pdev_id,
243 					WLAN_DFS_ID);
244 	if (!pdev) {
245 		target_if_err("null pdev");
246 		return -EINVAL;
247 	}
248 	dfs_rx_ops->dfs_process_phyerr_filter_offload(pdev,
249 					&wlan_radar_event);
250 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID);
251 
252 	return 0;
253 }
254 
255 /**
256  * target_if_reg_phyerr_events() - register dfs phyerr radar event.
257  * @psoc: pointer to psoc.
258  * @pdev: pointer to pdev.
259  *
260  * Return: QDF_STATUS.
261  */
262 static QDF_STATUS target_if_reg_phyerr_events_dfs2(
263 				struct wlan_objmgr_psoc *psoc)
264 {
265 	int ret = -1;
266 	struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops;
267 	bool is_phyerr_filter_offload;
268 
269 	dfs_rx_ops = target_if_dfs_get_rx_ops(psoc);
270 
271 	if (dfs_rx_ops && dfs_rx_ops->dfs_is_phyerr_filter_offload)
272 		if (QDF_IS_STATUS_SUCCESS(
273 			dfs_rx_ops->dfs_is_phyerr_filter_offload(psoc,
274 						&is_phyerr_filter_offload)))
275 			if (is_phyerr_filter_offload)
276 				ret = wmi_unified_register_event(
277 					GET_WMI_HDL_FROM_PSOC(psoc),
278 					wmi_dfs_radar_event_id,
279 					target_if_radar_event_handler);
280 
281 	if (ret) {
282 		target_if_err("failed to register wmi_dfs_radar_event_id");
283 		return QDF_STATUS_E_FAILURE;
284 	}
285 
286 	return QDF_STATUS_SUCCESS;
287 }
288 #else
289 static QDF_STATUS target_if_reg_phyerr_events_dfs2(
290 				struct wlan_objmgr_psoc *psoc)
291 {
292 	return QDF_STATUS_SUCCESS;
293 }
294 #endif
295 
296 static QDF_STATUS target_if_dfs_register_event_handler(
297 		struct wlan_objmgr_psoc *psoc,
298 		bool dfs_offload)
299 {
300 	struct target_psoc_info *tgt_psoc_info;
301 
302 	if (!psoc) {
303 		target_if_err("null psoc");
304 		return QDF_STATUS_E_FAILURE;
305 	}
306 
307 	if (!dfs_offload) {
308 		tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
309 		if (!tgt_psoc_info) {
310 			target_if_err("null tgt_psoc_info");
311 			return QDF_STATUS_E_FAILURE;
312 		}
313 		if (target_if_is_dfs_3(
314 				target_psoc_get_target_type(tgt_psoc_info)))
315 			return target_if_dfs_reg_phyerr_events(psoc);
316 		else
317 			return target_if_reg_phyerr_events_dfs2(psoc);
318 	} else {
319 		return target_if_dfs_reg_offload_events(psoc);
320 	}
321 }
322 
323 #if (defined(CONFIG_MCL) || (QCA_WIFI_QCA8074))
324 static QDF_STATUS target_process_bang_radar_cmd(
325 		struct wlan_objmgr_pdev *pdev,
326 		struct dfs_emulate_bang_radar_test_cmd *dfs_unit_test)
327 {
328 	QDF_STATUS status;
329 	struct wmi_unit_test_cmd wmi_utest;
330 	int i;
331 	wmi_unified_t wmi_handle;
332 
333 	if (!pdev) {
334 		target_if_err("null pdev");
335 		return QDF_STATUS_E_FAILURE;
336 	}
337 
338 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
339 	if (!wmi_handle) {
340 		target_if_err("null wmi_handle");
341 		return QDF_STATUS_E_FAILURE;
342 	}
343 
344 	wmi_utest.vdev_id = dfs_unit_test->vdev_id;
345 	wmi_utest.module_id = WLAN_MODULE_PHYERR_DFS;
346 	wmi_utest.num_args = dfs_unit_test->num_args;
347 
348 	for (i = 0; i < dfs_unit_test->num_args; i++)
349 		wmi_utest.args[i] = dfs_unit_test->args[i];
350 	/*
351 	 * Host to Target  conversion for pdev id required
352 	 * before we send a wmi unit test command
353 	 */
354 	wmi_utest.args[IDX_PDEV_ID] = wmi_handle->ops->
355 		convert_pdev_id_host_to_target(pdev->pdev_objmgr.wlan_pdev_id);
356 
357 	status = wmi_unified_unit_test_cmd(wmi_handle, &wmi_utest);
358 	if (QDF_IS_STATUS_ERROR(status))
359 		target_if_err("dfs: unit_test_cmd send failed %d", status);
360 	return status;
361 }
362 #else
363 static QDF_STATUS target_process_bang_radar_cmd(
364 		struct wlan_objmgr_pdev *pdev,
365 		struct dfs_emulate_bang_radar_test_cmd *dfs_unit_test)
366 {
367 	return QDF_STATUS_SUCCESS;
368 }
369 #endif
370 
371 static QDF_STATUS target_if_dfs_is_pdev_5ghz(struct wlan_objmgr_pdev *pdev,
372 		bool *is_5ghz)
373 {
374 	struct wlan_objmgr_psoc *psoc;
375 	uint8_t pdev_id;
376 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr;
377 
378 	psoc = wlan_pdev_get_psoc(pdev);
379 	if (!psoc) {
380 		target_if_err("dfs: null psoc");
381 		return QDF_STATUS_E_FAILURE;
382 	}
383 
384 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
385 
386 	reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc);
387 	if (!reg_cap_ptr) {
388 		target_if_err("dfs: reg cap null");
389 		return QDF_STATUS_E_FAILURE;
390 	}
391 
392 	if (reg_cap_ptr[pdev_id].wireless_modes &
393 			WMI_HOST_REGDMN_MODE_11A)
394 		*is_5ghz = true;
395 	else
396 		*is_5ghz = false;
397 
398 	return QDF_STATUS_SUCCESS;
399 }
400 
401 #ifdef QCA_MCL_DFS_SUPPORT
402 /**
403  * target_if_dfs_set_phyerr_filter_offload() - config phyerr filter offload.
404  * @pdev: Pointer to DFS pdev object.
405  * @dfs_phyerr_filter_offload: Phyerr filter offload value.
406  *
407  * Return: QDF_STATUS
408  */
409 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload(
410 					struct wlan_objmgr_pdev *pdev,
411 					bool dfs_phyerr_filter_offload)
412 {
413 	QDF_STATUS status;
414 	void *wmi_handle;
415 
416 	if (!pdev) {
417 		target_if_err("null pdev");
418 		return QDF_STATUS_E_FAILURE;
419 	}
420 
421 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
422 	if (!wmi_handle) {
423 		target_if_err("null wmi_handle");
424 		return QDF_STATUS_E_FAILURE;
425 	}
426 
427 	status = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wmi_handle,
428 					dfs_phyerr_filter_offload);
429 	if (QDF_IS_STATUS_ERROR(status))
430 		target_if_err("phyerr filter offload %d set fail: %d",
431 			      dfs_phyerr_filter_offload, status);
432 
433 	return status;
434 }
435 #else
436 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload(
437 					struct wlan_objmgr_pdev *pdev,
438 					bool dfs_phyerr_filter_offload)
439 {
440 	return QDF_STATUS_SUCCESS;
441 }
442 #endif
443 
444 /**
445  * target_if_dfs_get_caps - get dfs caps.
446  * @pdev: Pointer to DFS pdev object.
447  * @dfs_caps: Pointer to dfs_caps structure.
448  *
449  * Return: QDF_STATUS
450  */
451 static QDF_STATUS target_if_dfs_get_caps(struct wlan_objmgr_pdev *pdev,
452 					struct wlan_dfs_caps *dfs_caps)
453 {
454 	struct wlan_objmgr_psoc *psoc = NULL;
455 	struct target_psoc_info *tgt_psoc_info;
456 
457 	if (!dfs_caps) {
458 		target_if_err("null dfs_caps");
459 		return QDF_STATUS_E_FAILURE;
460 	}
461 
462 	dfs_caps->wlan_dfs_combined_rssi_ok = 0;
463 	dfs_caps->wlan_dfs_ext_chan_ok = 0;
464 	dfs_caps->wlan_dfs_use_enhancement = 0;
465 	dfs_caps->wlan_strong_signal_diversiry = 0;
466 	dfs_caps->wlan_fastdiv_val = 0;
467 	dfs_caps->wlan_chip_is_bb_tlv = 1;
468 	dfs_caps->wlan_chip_is_over_sampled = 0;
469 	dfs_caps->wlan_chip_is_ht160 = 0;
470 	dfs_caps->wlan_chip_is_false_detect = 0;
471 
472 	psoc = wlan_pdev_get_psoc(pdev);
473 	if (!psoc) {
474 		target_if_err("null psoc");
475 		return QDF_STATUS_E_FAILURE;
476 	}
477 
478 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
479 	if (!tgt_psoc_info) {
480 		target_if_err("null tgt_psoc_info");
481 		return QDF_STATUS_E_FAILURE;
482 	}
483 
484 	switch (target_psoc_get_target_type(tgt_psoc_info)) {
485 	case TARGET_TYPE_AR900B:
486 		break;
487 
488 	case TARGET_TYPE_IPQ4019:
489 		dfs_caps->wlan_chip_is_false_detect = 0;
490 		break;
491 
492 	case TARGET_TYPE_AR9888:
493 		dfs_caps->wlan_chip_is_over_sampled = 1;
494 		break;
495 
496 	case TARGET_TYPE_QCA9984:
497 	case TARGET_TYPE_QCA9888:
498 		dfs_caps->wlan_chip_is_ht160 = 1;
499 		break;
500 	default:
501 		break;
502 	}
503 
504 	return QDF_STATUS_SUCCESS;
505 }
506 
507 static QDF_STATUS target_send_dfs_offload_enable_cmd(
508 		struct wlan_objmgr_pdev *pdev, bool enable)
509 {
510 	QDF_STATUS status = QDF_STATUS_SUCCESS;
511 	uint8_t pdev_id;
512 	void *wmi_hdl;
513 
514 	if (!pdev) {
515 		target_if_err("null pdev");
516 		return QDF_STATUS_E_FAILURE;
517 	}
518 
519 	wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev);
520 	if (!wmi_hdl) {
521 		target_if_err("null wmi_hdl");
522 		return QDF_STATUS_E_FAILURE;
523 	}
524 
525 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
526 
527 	if (enable)
528 		status = wmi_unified_dfs_phyerr_offload_en_cmd(wmi_hdl,
529 							       pdev_id);
530 	else
531 		status = wmi_unified_dfs_phyerr_offload_dis_cmd(wmi_hdl,
532 								pdev_id);
533 
534 	if (QDF_IS_STATUS_ERROR(status))
535 		target_if_err("dfs: dfs offload cmd failed, enable:%d, pdev:%d",
536 			      enable, pdev_id);
537 	else
538 		target_if_debug("dfs: sent dfs offload cmd, enable:%d, pdev:%d",
539 				enable, pdev_id);
540 
541 	return status;
542 }
543 
544 QDF_STATUS target_if_register_dfs_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
545 {
546 	struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops;
547 
548 	if (!tx_ops) {
549 		target_if_err("invalid tx_ops");
550 		return QDF_STATUS_E_FAILURE;
551 	}
552 
553 	dfs_tx_ops = &tx_ops->dfs_tx_ops;
554 	dfs_tx_ops->dfs_reg_ev_handler = &target_if_dfs_register_event_handler;
555 
556 	dfs_tx_ops->dfs_process_emulate_bang_radar_cmd =
557 				&target_process_bang_radar_cmd;
558 	dfs_tx_ops->dfs_is_pdev_5ghz = &target_if_dfs_is_pdev_5ghz;
559 	dfs_tx_ops->dfs_send_offload_enable_cmd =
560 		&target_send_dfs_offload_enable_cmd;
561 
562 	dfs_tx_ops->dfs_set_phyerr_filter_offload =
563 				&target_if_dfs_set_phyerr_filter_offload;
564 
565 	dfs_tx_ops->dfs_get_caps = &target_if_dfs_get_caps;
566 
567 	return QDF_STATUS_SUCCESS;
568 }
569