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 #ifdef WLAN_FEATURE_11BE 218 /** 219 * target_if_dfs_is_radar_found_chan_freq_eq_center_freq: Check whether the 220 * service of 'radar_found_chan_freq' representing the center frequency of the 221 * radar segment is supported or not. If the service is not enabled, then 222 * chan_freq will indicate the channel's primary 20MHz center. 223 */ 224 static bool 225 target_if_dfs_is_radar_found_chan_freq_eq_center_freq( 226 struct wlan_objmgr_psoc *psoc) 227 { 228 wmi_unified_t wmi_handle; 229 230 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 231 if (!wmi_handle) { 232 target_if_err("null wmi_handle"); 233 return false; 234 } 235 return wmi_service_enabled 236 (wmi_handle, 237 wmi_service_radar_found_chan_freq_eq_center_freq); 238 } 239 #else 240 static bool 241 target_if_dfs_is_radar_found_chan_freq_eq_center_freq( 242 struct wlan_objmgr_psoc *psoc) 243 { 244 return false; 245 } 246 #endif 247 248 static QDF_STATUS target_if_dfs_get_target_type(struct wlan_objmgr_pdev *pdev, 249 uint32_t *target_type) 250 { 251 struct wlan_objmgr_psoc *psoc; 252 struct target_psoc_info *tgt_psoc_info; 253 254 psoc = wlan_pdev_get_psoc(pdev); 255 if (!psoc) { 256 target_if_err("null psoc"); 257 return QDF_STATUS_E_FAILURE; 258 } 259 260 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 261 if (!tgt_psoc_info) { 262 target_if_err("null tgt_psoc_info"); 263 return QDF_STATUS_E_FAILURE; 264 } 265 *target_type = target_psoc_get_target_type(tgt_psoc_info); 266 return QDF_STATUS_SUCCESS; 267 } 268 269 static QDF_STATUS target_if_dfs_register_event_handler( 270 struct wlan_objmgr_psoc *psoc) 271 { 272 struct target_psoc_info *tgt_psoc_info; 273 274 if (!psoc) { 275 target_if_err("null psoc"); 276 return QDF_STATUS_E_FAILURE; 277 } 278 279 if (!target_if_dfs_offload(psoc)) { 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 286 target_if_dfs_register_host_status_check_event(psoc); 287 288 if (target_if_is_dfs_3( 289 target_psoc_get_target_type(tgt_psoc_info))) 290 return target_if_dfs_reg_phyerr_events(psoc); 291 else 292 return target_if_reg_phyerr_events_dfs2(psoc); 293 } else { 294 return target_if_dfs_reg_offload_events(psoc); 295 } 296 } 297 298 static QDF_STATUS target_if_dfs_is_pdev_5ghz(struct wlan_objmgr_pdev *pdev, 299 bool *is_5ghz) 300 { 301 struct wlan_objmgr_psoc *psoc; 302 uint8_t pdev_id; 303 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr; 304 305 psoc = wlan_pdev_get_psoc(pdev); 306 if (!psoc) { 307 target_if_err("dfs: null psoc"); 308 return QDF_STATUS_E_FAILURE; 309 } 310 311 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 312 313 reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc); 314 if (!reg_cap_ptr) { 315 target_if_err("dfs: reg cap null"); 316 return QDF_STATUS_E_FAILURE; 317 } 318 319 if (reg_cap_ptr[pdev_id].wireless_modes & 320 HOST_REGDMN_MODE_11A) 321 *is_5ghz = true; 322 else 323 *is_5ghz = false; 324 325 return QDF_STATUS_SUCCESS; 326 } 327 328 #ifdef MOBILE_DFS_SUPPORT 329 /** 330 * target_if_dfs_set_phyerr_filter_offload() - config phyerr filter offload. 331 * @pdev: Pointer to DFS pdev object. 332 * @dfs_phyerr_filter_offload: Phyerr filter offload value. 333 * 334 * Return: QDF_STATUS 335 */ 336 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 337 struct wlan_objmgr_pdev *pdev, 338 bool dfs_phyerr_filter_offload) 339 { 340 QDF_STATUS status; 341 wmi_unified_t wmi_handle; 342 343 if (!pdev) { 344 target_if_err("null pdev"); 345 return QDF_STATUS_E_FAILURE; 346 } 347 348 wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 349 if (!wmi_handle) { 350 target_if_err("null wmi_handle"); 351 return QDF_STATUS_E_FAILURE; 352 } 353 354 status = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wmi_handle, 355 dfs_phyerr_filter_offload); 356 if (QDF_IS_STATUS_ERROR(status)) 357 target_if_err("phyerr filter offload %d set fail: %d", 358 dfs_phyerr_filter_offload, status); 359 360 return status; 361 } 362 #else 363 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 364 struct wlan_objmgr_pdev *pdev, 365 bool dfs_phyerr_filter_offload) 366 { 367 return QDF_STATUS_SUCCESS; 368 } 369 #endif 370 371 static QDF_STATUS target_send_dfs_offload_enable_cmd( 372 struct wlan_objmgr_pdev *pdev, bool enable) 373 { 374 QDF_STATUS status = QDF_STATUS_SUCCESS; 375 uint8_t pdev_id; 376 void *wmi_hdl; 377 378 if (!pdev) { 379 target_if_err("null pdev"); 380 return QDF_STATUS_E_FAILURE; 381 } 382 383 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev); 384 if (!wmi_hdl) { 385 target_if_err("null wmi_hdl"); 386 return QDF_STATUS_E_FAILURE; 387 } 388 389 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 390 391 if (enable) 392 status = wmi_unified_dfs_phyerr_offload_en_cmd(wmi_hdl, 393 pdev_id); 394 else 395 status = wmi_unified_dfs_phyerr_offload_dis_cmd(wmi_hdl, 396 pdev_id); 397 398 if (QDF_IS_STATUS_ERROR(status)) 399 target_if_err("dfs: dfs offload cmd failed, enable:%d, pdev:%d", 400 enable, pdev_id); 401 else 402 target_if_debug("dfs: sent dfs offload cmd, enable:%d, pdev:%d", 403 enable, pdev_id); 404 405 return status; 406 } 407 408 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) 409 static void target_if_register_dfs_tx_ops_send_avg( 410 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops) 411 { 412 dfs_tx_ops->dfs_send_avg_radar_params_to_fw = 413 &target_if_dfs_send_avg_params_to_fw; 414 } 415 #else 416 static inline void target_if_register_dfs_tx_ops_send_avg( 417 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops) 418 { 419 } 420 #endif 421 422 QDF_STATUS target_if_register_dfs_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 423 { 424 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops; 425 426 if (!tx_ops) { 427 target_if_err("invalid tx_ops"); 428 return QDF_STATUS_E_FAILURE; 429 } 430 431 dfs_tx_ops = &tx_ops->dfs_tx_ops; 432 dfs_tx_ops->dfs_reg_ev_handler = &target_if_dfs_register_event_handler; 433 434 dfs_tx_ops->dfs_process_emulate_bang_radar_cmd = 435 &target_process_bang_radar_cmd; 436 dfs_tx_ops->dfs_agile_ch_cfg_cmd = 437 &target_send_agile_ch_cfg_cmd; 438 dfs_tx_ops->dfs_ocac_abort_cmd = 439 &target_send_ocac_abort_cmd; 440 dfs_tx_ops->dfs_is_pdev_5ghz = &target_if_dfs_is_pdev_5ghz; 441 dfs_tx_ops->dfs_send_offload_enable_cmd = 442 &target_send_dfs_offload_enable_cmd; 443 444 dfs_tx_ops->dfs_set_phyerr_filter_offload = 445 &target_if_dfs_set_phyerr_filter_offload; 446 447 dfs_tx_ops->dfs_get_caps = &target_if_dfs_get_caps; 448 449 target_if_register_dfs_tx_ops_send_avg(dfs_tx_ops); 450 451 dfs_tx_ops->dfs_is_tgt_offload = &target_if_dfs_offload; 452 dfs_tx_ops->dfs_is_tgt_radar_found_chan_freq_eq_center_freq = 453 &target_if_dfs_is_radar_found_chan_freq_eq_center_freq; 454 455 dfs_tx_ops->dfs_send_usenol_pdev_param = 456 &target_send_usenol_pdev_param; 457 dfs_tx_ops->dfs_send_subchan_marking_pdev_param = 458 &target_send_subchan_marking_pdev_param; 459 dfs_tx_ops->dfs_get_target_type = &target_if_dfs_get_target_type; 460 return QDF_STATUS_SUCCESS; 461 } 462