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(¶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 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)) 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