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