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 */
target_if_dfs_cac_complete_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)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 */
target_if_dfs_ocac_complete_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)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 */
target_if_dfs_get_pdev(struct wlan_objmgr_psoc * psoc,uint8_t id,wlan_objmgr_ref_dbgid dbg_id)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
target_if_dfs_get_pdev(struct wlan_objmgr_psoc * psoc,uint8_t id,wlan_objmgr_ref_dbgid dbg_id)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 */
target_if_dfs_radar_detection_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)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)
target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc * psoc)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
target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc * psoc)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)
target_if_dfs_reg_offload_events(struct wlan_objmgr_psoc * psoc)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)
target_send_ocac_abort_cmd(struct wlan_objmgr_pdev * pdev)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(¶m, 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, ¶m);
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
target_send_agile_ch_cfg_cmd(struct wlan_objmgr_pdev * pdev,struct dfs_agile_cac_params * adfs_param)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(¶m, 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, ¶m);
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) || defined(QCA_WIFI_QCA5332))
target_process_bang_radar_cmd(struct wlan_objmgr_pdev * pdev,struct dfs_emulate_bang_radar_test_cmd * dfs_unit_test)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)
target_send_usenol_pdev_param(struct wlan_objmgr_pdev * pdev,bool usenol)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
target_send_subchan_marking_pdev_param(struct wlan_objmgr_pdev * pdev,bool subchanmark)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