1 /* 2 * Copyright (c) 2017-2019 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 #define QUICK_OCAC_MODE 0 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 /** 189 * target_if_dfs_radar_detection_event_handler() - Indicate RADAR detection and 190 * process RADAR detection. 191 * @scn: scn handle. 192 * @data: pointer to data buffer. 193 * @datalen: data length. 194 * 195 * Return: 0 on successful indication. 196 */ 197 static int target_if_dfs_radar_detection_event_handler( 198 ol_scn_t scn, uint8_t *data, uint32_t datalen) 199 { 200 struct radar_found_info radar; 201 struct wlan_objmgr_psoc *psoc = NULL; 202 struct wlan_objmgr_pdev *pdev = NULL; 203 struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; 204 int ret = 0; 205 struct wmi_unified *wmi_handle; 206 207 if (!scn || !data) { 208 target_if_err("scn: %pK, data: %pK", scn, data); 209 return -EINVAL; 210 } 211 212 psoc = target_if_get_psoc_from_scn_hdl(scn); 213 if (!psoc) { 214 target_if_err("null psoc"); 215 return -EINVAL; 216 } 217 218 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 219 if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_radar_ind) { 220 target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops); 221 return -EINVAL; 222 } 223 224 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 225 if (!wmi_handle) { 226 target_if_err("Invalid WMI handle"); 227 return -EINVAL; 228 } 229 230 if (wmi_extract_dfs_radar_detection_event(wmi_handle, data, &radar, 231 datalen) 232 != QDF_STATUS_SUCCESS) { 233 target_if_err("failed to extract cac complete event"); 234 return -EFAULT; 235 } 236 237 pdev = wlan_objmgr_get_pdev_by_id(psoc, radar.pdev_id, WLAN_DFS_ID); 238 if (!pdev) { 239 target_if_err("null pdev"); 240 return -EINVAL; 241 } 242 243 if (dfs_rx_ops->dfs_process_radar_ind(pdev, 244 &radar) != QDF_STATUS_SUCCESS) { 245 target_if_err("dfs_process_radar_ind failed pdev_id=%d", 246 radar.pdev_id); 247 ret = -EINVAL; 248 } 249 250 wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID); 251 252 return ret; 253 } 254 255 /** 256 * target_if_dfs_reg_ocac_event() - registers dfs off channel event 257 * for full offload. 258 * @psoc: Pointer to psoc object. 259 * 260 * Return: 0 on successful registration. 261 */ 262 #if defined(QCA_SUPPORT_AGILE_DFS) 263 static int target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc) 264 { 265 return wmi_unified_register_event( 266 get_wmi_unified_hdl_from_psoc(psoc), 267 wmi_vdev_ocac_complete_event_id, 268 target_if_dfs_ocac_complete_event_handler); 269 } 270 #else 271 static int target_if_dfs_reg_ocac_event(struct wlan_objmgr_psoc *psoc) 272 { 273 return 0; 274 } 275 #endif 276 277 #if defined(WLAN_DFS_FULL_OFFLOAD) 278 QDF_STATUS target_if_dfs_reg_offload_events( 279 struct wlan_objmgr_psoc *psoc) 280 { 281 int ret1, ret2, ret3; 282 283 ret1 = wmi_unified_register_event( 284 get_wmi_unified_hdl_from_psoc(psoc), 285 wmi_dfs_radar_detection_event_id, 286 target_if_dfs_radar_detection_event_handler); 287 target_if_debug("wmi_dfs_radar_detection_event_id ret=%d", ret1); 288 289 ret2 = wmi_unified_register_event( 290 get_wmi_unified_hdl_from_psoc(psoc), 291 wmi_dfs_cac_complete_id, 292 target_if_dfs_cac_complete_event_handler); 293 target_if_debug("wmi_dfs_cac_complete_id ret=%d", ret2); 294 295 ret3 = target_if_dfs_reg_ocac_event(psoc); 296 target_if_debug("wmi_vdev_ocac_complete_event_id ret=%d", ret3); 297 298 if (ret1 || ret2 || 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 = QUICK_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_chan; 379 param.chan_width = adfs_param->precac_chwidth; 380 param.center_freq = adfs_param->precac_chan; 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)) 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