1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 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_lmac.h> 39 #include <wlan_reg_ucfg_api.h> 40 #include <target_if_dfs_full_offload.h> 41 #include <target_if_dfs_partial_offload.h> 42 43 /** 44 * target_if_dfs_register_host_status_check_event() - Register host dfs 45 * confirmation event. 46 * @psoc: pointer to psoc. 47 * 48 * Return: QDF_STATUS. 49 */ 50 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) 51 static QDF_STATUS target_if_dfs_register_host_status_check_event( 52 struct wlan_objmgr_psoc *psoc) 53 54 { 55 wmi_unified_t wmi_handle; 56 QDF_STATUS retval; 57 58 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 59 if (!wmi_handle) { 60 target_if_err("null wmi_handle"); 61 return QDF_STATUS_E_FAILURE; 62 } 63 64 retval = wmi_unified_register_event(wmi_handle, 65 wmi_host_dfs_status_check_event_id, 66 target_if_dfs_status_check_event_handler); 67 if (QDF_IS_STATUS_ERROR(retval)) 68 target_if_err("wmi_dfs_radar_detection_event_id ret=%d", 69 retval); 70 71 return retval; 72 } 73 #else 74 static QDF_STATUS target_if_dfs_register_host_status_check_event( 75 struct wlan_objmgr_psoc *psoc) 76 { 77 return QDF_STATUS_SUCCESS; 78 } 79 #endif 80 81 /** 82 * target_if_is_dfs_3() - Is dfs3 support or not 83 * @target_type: target type being used. 84 * 85 * Return: true if dfs3 is supported, false otherwise. 86 */ 87 static bool target_if_is_dfs_3(uint32_t target_type) 88 { 89 bool is_dfs_3; 90 91 switch (target_type) { 92 case TARGET_TYPE_AR6320: 93 is_dfs_3 = false; 94 break; 95 case TARGET_TYPE_ADRASTEA: 96 is_dfs_3 = true; 97 break; 98 default: 99 is_dfs_3 = true; 100 } 101 102 return is_dfs_3; 103 } 104 105 #ifdef MOBILE_DFS_SUPPORT 106 /** 107 * target_if_radar_event_handler() - handle radar event when 108 * phyerr filter offload is enabled. 109 * @scn: Handle to HIF context 110 * @data: radar event buffer 111 * @datalen: radar event buffer length 112 * 113 * Return: 0 on success; error code otherwise 114 */ 115 static int target_if_radar_event_handler( 116 ol_scn_t scn, uint8_t *data, uint32_t datalen) 117 { 118 struct radar_event_info wlan_radar_event; 119 struct wlan_objmgr_psoc *psoc; 120 struct wlan_objmgr_pdev *pdev; 121 struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; 122 struct wmi_unified *wmi_handle; 123 124 if (!scn || !data) { 125 target_if_err("scn: %pK, data: %pK", scn, data); 126 return -EINVAL; 127 } 128 psoc = target_if_get_psoc_from_scn_hdl(scn); 129 if (!psoc) { 130 target_if_err("null psoc"); 131 return -EINVAL; 132 } 133 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 134 135 if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_phyerr_filter_offload) { 136 target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops); 137 return -EINVAL; 138 } 139 140 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 141 if (!wmi_handle) { 142 target_if_err("Invalid WMI context"); 143 return -EINVAL; 144 } 145 146 if (QDF_IS_STATUS_ERROR(wmi_extract_wlan_radar_event_info( 147 wmi_handle, data, 148 &wlan_radar_event, datalen))) { 149 target_if_err("failed to extract wlan radar event"); 150 return -EFAULT; 151 } 152 pdev = wlan_objmgr_get_pdev_by_id(psoc, wlan_radar_event.pdev_id, 153 WLAN_DFS_ID); 154 if (!pdev) { 155 target_if_err("null pdev"); 156 return -EINVAL; 157 } 158 dfs_rx_ops->dfs_process_phyerr_filter_offload(pdev, 159 &wlan_radar_event); 160 wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID); 161 162 return 0; 163 } 164 165 /** 166 * target_if_reg_phyerr_events_dfs2() - register dfs phyerr radar event. 167 * @psoc: pointer to psoc. 168 * 169 * Return: QDF_STATUS. 170 */ 171 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 172 struct wlan_objmgr_psoc *psoc) 173 { 174 QDF_STATUS ret; 175 wmi_unified_t wmi_handle; 176 177 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 178 if (!wmi_handle) { 179 target_if_err("null wmi_handle"); 180 return QDF_STATUS_E_INVAL; 181 } 182 183 ret = wmi_unified_register_event(wmi_handle, 184 wmi_dfs_radar_event_id, 185 target_if_radar_event_handler); 186 if (QDF_IS_STATUS_ERROR(ret)) { 187 target_if_err("failed to register wmi_dfs_radar_event_id"); 188 return QDF_STATUS_E_FAILURE; 189 } 190 191 return QDF_STATUS_SUCCESS; 192 } 193 #else 194 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 195 struct wlan_objmgr_psoc *psoc) 196 { 197 return QDF_STATUS_SUCCESS; 198 } 199 #endif 200 201 static bool target_if_dfs_offload(struct wlan_objmgr_psoc *psoc) 202 { 203 wmi_unified_t wmi_handle; 204 205 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 206 if (!wmi_handle) { 207 target_if_err("null wmi_handle"); 208 return false; 209 } 210 211 return wmi_service_enabled(wmi_handle, 212 wmi_service_dfs_phyerr_offload); 213 } 214 215 /** 216 * target_if_dfs_bangradar_320_supp: Check if bang radar 320 is supported 217 * @psoc: psoc handle 218 * 219 * Check the service of 'wmi_service_bang_radar_320_support' whether 220 * the bang radar 320 is supported or not. 221 * 222 * Return: true if the service is enabled, false otherwise 223 */ 224 225 static bool target_if_dfs_bangradar_320_supp(struct wlan_objmgr_psoc *psoc) 226 { 227 wmi_unified_t wmi_handle; 228 229 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 230 if (!wmi_handle) { 231 target_if_err("null wmi_handle"); 232 return false; 233 } 234 235 return wmi_service_enabled(wmi_handle, 236 wmi_service_bang_radar_320_support); 237 } 238 239 #ifdef WLAN_FEATURE_11BE 240 /** 241 * target_if_dfs_is_radar_found_chan_freq_eq_center_freq() - 242 * Check if service 'radar_found_chan_freq' is supported 243 * @psoc: psoc handle 244 * 245 * Check whether the service of 'radar_found_chan_freq' representing 246 * the center frequency of the radar segment is supported or not. If 247 * the service is not enabled, then chan_freq will indicate the 248 * channel's primary 20MHz center. 249 * 250 * Return: true if wmi_service_radar_found_chan_freq_eq_center_freq is 251 * supported, false otherwise 252 */ 253 static bool 254 target_if_dfs_is_radar_found_chan_freq_eq_center_freq( 255 struct wlan_objmgr_psoc *psoc) 256 { 257 wmi_unified_t wmi_handle; 258 259 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 260 if (!wmi_handle) { 261 target_if_err("null wmi_handle"); 262 return false; 263 } 264 return wmi_service_enabled 265 (wmi_handle, 266 wmi_service_radar_found_chan_freq_eq_center_freq); 267 } 268 #else 269 static bool 270 target_if_dfs_is_radar_found_chan_freq_eq_center_freq( 271 struct wlan_objmgr_psoc *psoc) 272 { 273 return false; 274 } 275 #endif 276 277 static QDF_STATUS target_if_dfs_get_target_type(struct wlan_objmgr_pdev *pdev, 278 uint32_t *target_type) 279 { 280 struct wlan_objmgr_psoc *psoc; 281 struct target_psoc_info *tgt_psoc_info; 282 283 psoc = wlan_pdev_get_psoc(pdev); 284 if (!psoc) { 285 target_if_err("null psoc"); 286 return QDF_STATUS_E_FAILURE; 287 } 288 289 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 290 if (!tgt_psoc_info) { 291 target_if_err("null tgt_psoc_info"); 292 return QDF_STATUS_E_FAILURE; 293 } 294 *target_type = target_psoc_get_target_type(tgt_psoc_info); 295 return QDF_STATUS_SUCCESS; 296 } 297 298 static QDF_STATUS target_if_dfs_register_event_handler( 299 struct wlan_objmgr_psoc *psoc) 300 { 301 struct target_psoc_info *tgt_psoc_info; 302 303 if (!psoc) { 304 target_if_err("null psoc"); 305 return QDF_STATUS_E_FAILURE; 306 } 307 308 if (!target_if_dfs_offload(psoc)) { 309 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 310 if (!tgt_psoc_info) { 311 target_if_err("null tgt_psoc_info"); 312 return QDF_STATUS_E_FAILURE; 313 } 314 315 target_if_dfs_register_host_status_check_event(psoc); 316 317 if (target_if_is_dfs_3( 318 target_psoc_get_target_type(tgt_psoc_info))) 319 return target_if_dfs_reg_phyerr_events(psoc); 320 else 321 return target_if_reg_phyerr_events_dfs2(psoc); 322 } else { 323 return target_if_dfs_reg_offload_events(psoc); 324 } 325 } 326 327 static QDF_STATUS target_if_dfs_is_pdev_5ghz(struct wlan_objmgr_pdev *pdev, 328 bool *is_5ghz) 329 { 330 struct wlan_objmgr_psoc *psoc; 331 uint8_t pdev_id; 332 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr; 333 334 psoc = wlan_pdev_get_psoc(pdev); 335 if (!psoc) { 336 target_if_err("dfs: null psoc"); 337 return QDF_STATUS_E_FAILURE; 338 } 339 340 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 341 342 reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc); 343 if (!reg_cap_ptr) { 344 target_if_err("dfs: reg cap null"); 345 return QDF_STATUS_E_FAILURE; 346 } 347 348 if (reg_cap_ptr[pdev_id].wireless_modes & 349 HOST_REGDMN_MODE_11A) 350 *is_5ghz = true; 351 else 352 *is_5ghz = false; 353 354 return QDF_STATUS_SUCCESS; 355 } 356 357 #ifdef MOBILE_DFS_SUPPORT 358 /** 359 * target_if_dfs_set_phyerr_filter_offload() - config phyerr filter offload. 360 * @pdev: Pointer to DFS pdev object. 361 * @dfs_phyerr_filter_offload: Phyerr filter offload value. 362 * 363 * Return: QDF_STATUS 364 */ 365 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 366 struct wlan_objmgr_pdev *pdev, 367 bool dfs_phyerr_filter_offload) 368 { 369 QDF_STATUS status; 370 wmi_unified_t wmi_handle; 371 372 if (!pdev) { 373 target_if_err("null pdev"); 374 return QDF_STATUS_E_FAILURE; 375 } 376 377 wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 378 if (!wmi_handle) { 379 target_if_err("null wmi_handle"); 380 return QDF_STATUS_E_FAILURE; 381 } 382 383 status = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wmi_handle, 384 dfs_phyerr_filter_offload); 385 if (QDF_IS_STATUS_ERROR(status)) 386 target_if_err("phyerr filter offload %d set fail: %d", 387 dfs_phyerr_filter_offload, status); 388 389 return status; 390 } 391 #else 392 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 393 struct wlan_objmgr_pdev *pdev, 394 bool dfs_phyerr_filter_offload) 395 { 396 return QDF_STATUS_SUCCESS; 397 } 398 #endif 399 400 static QDF_STATUS target_send_dfs_offload_enable_cmd( 401 struct wlan_objmgr_pdev *pdev, bool enable) 402 { 403 QDF_STATUS status = QDF_STATUS_SUCCESS; 404 uint8_t pdev_id; 405 void *wmi_hdl; 406 407 if (!pdev) { 408 target_if_err("null pdev"); 409 return QDF_STATUS_E_FAILURE; 410 } 411 412 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev); 413 if (!wmi_hdl) { 414 target_if_err("null wmi_hdl"); 415 return QDF_STATUS_E_FAILURE; 416 } 417 418 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 419 420 if (enable) 421 status = wmi_unified_dfs_phyerr_offload_en_cmd(wmi_hdl, 422 pdev_id); 423 else 424 status = wmi_unified_dfs_phyerr_offload_dis_cmd(wmi_hdl, 425 pdev_id); 426 427 if (QDF_IS_STATUS_ERROR(status)) 428 target_if_err("dfs: dfs offload cmd failed, enable:%d, pdev:%d", 429 enable, pdev_id); 430 else 431 target_if_debug("dfs: sent dfs offload cmd, enable:%d, pdev:%d", 432 enable, pdev_id); 433 434 return status; 435 } 436 437 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) 438 static void target_if_register_dfs_tx_ops_send_avg( 439 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops) 440 { 441 dfs_tx_ops->dfs_send_avg_radar_params_to_fw = 442 &target_if_dfs_send_avg_params_to_fw; 443 } 444 #else 445 static inline void target_if_register_dfs_tx_ops_send_avg( 446 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops) 447 { 448 } 449 #endif 450 451 QDF_STATUS target_if_register_dfs_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 452 { 453 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops; 454 455 if (!tx_ops) { 456 target_if_err("invalid tx_ops"); 457 return QDF_STATUS_E_FAILURE; 458 } 459 460 dfs_tx_ops = &tx_ops->dfs_tx_ops; 461 dfs_tx_ops->dfs_reg_ev_handler = &target_if_dfs_register_event_handler; 462 463 dfs_tx_ops->dfs_process_emulate_bang_radar_cmd = 464 &target_process_bang_radar_cmd; 465 dfs_tx_ops->dfs_agile_ch_cfg_cmd = 466 &target_send_agile_ch_cfg_cmd; 467 dfs_tx_ops->dfs_ocac_abort_cmd = 468 &target_send_ocac_abort_cmd; 469 dfs_tx_ops->dfs_is_pdev_5ghz = &target_if_dfs_is_pdev_5ghz; 470 dfs_tx_ops->dfs_send_offload_enable_cmd = 471 &target_send_dfs_offload_enable_cmd; 472 473 dfs_tx_ops->dfs_set_phyerr_filter_offload = 474 &target_if_dfs_set_phyerr_filter_offload; 475 476 dfs_tx_ops->dfs_get_caps = &target_if_dfs_get_caps; 477 478 target_if_register_dfs_tx_ops_send_avg(dfs_tx_ops); 479 480 dfs_tx_ops->dfs_is_tgt_offload = &target_if_dfs_offload; 481 dfs_tx_ops->dfs_is_tgt_bangradar_320_supp = 482 &target_if_dfs_bangradar_320_supp; 483 dfs_tx_ops->dfs_is_tgt_radar_found_chan_freq_eq_center_freq = 484 &target_if_dfs_is_radar_found_chan_freq_eq_center_freq; 485 486 dfs_tx_ops->dfs_send_usenol_pdev_param = 487 &target_send_usenol_pdev_param; 488 dfs_tx_ops->dfs_send_subchan_marking_pdev_param = 489 &target_send_subchan_marking_pdev_param; 490 dfs_tx_ops->dfs_get_target_type = &target_if_dfs_get_target_type; 491 return QDF_STATUS_SUCCESS; 492 } 493