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(¶m, 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, ¶m); 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(¶m, 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, ¶m); 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