1 /* 2 * Copyright (c) 2017-2020 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: 0 on successful registration. 260 */ 261 #if defined(QCA_SUPPORT_AGILE_DFS) 262 static int 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 int target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc) 271 { 272 return 0; 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 int 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 (ret1 || ret2 || ret3) 298 return QDF_STATUS_E_FAILURE; 299 else 300 return QDF_STATUS_SUCCESS; 301 } 302 #endif 303 304 #if defined(QCA_SUPPORT_AGILE_DFS) 305 QDF_STATUS target_send_ocac_abort_cmd(struct wlan_objmgr_pdev *pdev) 306 { 307 wmi_unified_t wmi_handle; 308 struct vdev_adfs_abort_params param; 309 struct wlan_objmgr_vdev *vdev; 310 QDF_STATUS status; 311 312 if (!pdev) { 313 target_if_err("null pdev"); 314 return QDF_STATUS_E_FAILURE; 315 } 316 317 vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_DFS_ID); 318 319 if (!vdev) { 320 target_if_err("null vdev"); 321 return QDF_STATUS_E_FAILURE; 322 } 323 324 wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); 325 if (!wmi_handle) { 326 target_if_err("null wmi_handle"); 327 status = QDF_STATUS_E_FAILURE; 328 goto free_vdevref; 329 } 330 331 qdf_mem_set(¶m, sizeof(param), 0); 332 param.vdev_id = wlan_vdev_get_id(vdev); 333 utils_dfs_cancel_precac_timer(pdev); 334 335 status = wmi_unified_send_vdev_adfs_ocac_abort_cmd(wmi_handle, ¶m); 336 if (QDF_IS_STATUS_ERROR(status)) 337 target_if_err("dfs: unit_test_cmd send failed %d", status); 338 339 free_vdevref: 340 wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID); 341 342 return status; 343 } 344 345 QDF_STATUS target_send_agile_ch_cfg_cmd(struct wlan_objmgr_pdev *pdev, 346 struct dfs_agile_cac_params *adfs_param) 347 { 348 wmi_unified_t wmi_handle; 349 struct vdev_adfs_ch_cfg_params param; 350 struct wlan_objmgr_vdev *vdev; 351 QDF_STATUS status; 352 353 if (!pdev) { 354 target_if_err("null pdev"); 355 return QDF_STATUS_E_FAILURE; 356 } 357 358 vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_DFS_ID); 359 360 if (!vdev) { 361 target_if_err("null vdev"); 362 return QDF_STATUS_E_FAILURE; 363 } 364 365 wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); 366 if (!wmi_handle) { 367 target_if_err("null wmi_handle"); 368 status = QDF_STATUS_E_FAILURE; 369 goto free_vdevref; 370 } 371 372 qdf_mem_set(¶m, sizeof(param), 0); 373 param.vdev_id = wlan_vdev_get_id(vdev); 374 param.ocac_mode = adfs_param->ocac_mode; 375 param.min_duration_ms = adfs_param->min_precac_timeout; 376 param.max_duration_ms = adfs_param->max_precac_timeout; 377 param.chan_freq = adfs_param->precac_center_freq_1; 378 param.chan_width = adfs_param->precac_chwidth; 379 param.center_freq1 = adfs_param->precac_center_freq_1; 380 param.center_freq2 = adfs_param->precac_center_freq_2; 381 382 status = wmi_unified_send_vdev_adfs_ch_cfg_cmd(wmi_handle, ¶m); 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) || defined(QCA_WIFI_QCA5018)) 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