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