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_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 QCA_MCL_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 123 if (!scn || !data) { 124 target_if_err("scn: %pK, data: %pK", scn, data); 125 return -EINVAL; 126 } 127 psoc = target_if_get_psoc_from_scn_hdl(scn); 128 if (!psoc) { 129 target_if_err("null psoc"); 130 return -EINVAL; 131 } 132 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 133 134 if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_phyerr_filter_offload) { 135 target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops); 136 return -EINVAL; 137 } 138 if (QDF_IS_STATUS_ERROR(wmi_extract_wlan_radar_event_info( 139 GET_WMI_HDL_FROM_PSOC(psoc), data, 140 &wlan_radar_event, datalen))) { 141 target_if_err("failed to extract wlan radar event"); 142 return -EFAULT; 143 } 144 pdev = wlan_objmgr_get_pdev_by_id(psoc, wlan_radar_event.pdev_id, 145 WLAN_DFS_ID); 146 if (!pdev) { 147 target_if_err("null pdev"); 148 return -EINVAL; 149 } 150 dfs_rx_ops->dfs_process_phyerr_filter_offload(pdev, 151 &wlan_radar_event); 152 wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID); 153 154 return 0; 155 } 156 157 /** 158 * target_if_reg_phyerr_events() - register dfs phyerr radar event. 159 * @psoc: pointer to psoc. 160 * @pdev: pointer to pdev. 161 * 162 * Return: QDF_STATUS. 163 */ 164 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 165 struct wlan_objmgr_psoc *psoc) 166 { 167 int ret = -1; 168 struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; 169 bool is_phyerr_filter_offload; 170 171 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 172 173 if (dfs_rx_ops && dfs_rx_ops->dfs_is_phyerr_filter_offload) 174 if (QDF_IS_STATUS_SUCCESS( 175 dfs_rx_ops->dfs_is_phyerr_filter_offload(psoc, 176 &is_phyerr_filter_offload))) 177 if (is_phyerr_filter_offload) 178 ret = wmi_unified_register_event( 179 get_wmi_unified_hdl_from_psoc(psoc), 180 wmi_dfs_radar_event_id, 181 target_if_radar_event_handler); 182 183 if (ret) { 184 target_if_err("failed to register wmi_dfs_radar_event_id"); 185 return QDF_STATUS_E_FAILURE; 186 } 187 188 return QDF_STATUS_SUCCESS; 189 } 190 #else 191 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 192 struct wlan_objmgr_psoc *psoc) 193 { 194 return QDF_STATUS_SUCCESS; 195 } 196 #endif 197 198 static bool target_if_dfs_offload(struct wlan_objmgr_psoc *psoc) 199 { 200 return wmi_service_enabled(get_wmi_unified_hdl_from_psoc(psoc), 201 wmi_service_dfs_phyerr_offload); 202 } 203 204 static QDF_STATUS target_if_dfs_register_event_handler( 205 struct wlan_objmgr_psoc *psoc) 206 { 207 struct target_psoc_info *tgt_psoc_info; 208 209 if (!psoc) { 210 target_if_err("null psoc"); 211 return QDF_STATUS_E_FAILURE; 212 } 213 214 if (!target_if_dfs_offload(psoc)) { 215 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 216 if (!tgt_psoc_info) { 217 target_if_err("null tgt_psoc_info"); 218 return QDF_STATUS_E_FAILURE; 219 } 220 221 target_if_dfs_register_host_status_check_event(psoc); 222 223 if (target_if_is_dfs_3( 224 target_psoc_get_target_type(tgt_psoc_info))) 225 return target_if_dfs_reg_phyerr_events(psoc); 226 else 227 return target_if_reg_phyerr_events_dfs2(psoc); 228 } else { 229 return target_if_dfs_reg_offload_events(psoc); 230 } 231 } 232 233 static QDF_STATUS target_if_dfs_is_pdev_5ghz(struct wlan_objmgr_pdev *pdev, 234 bool *is_5ghz) 235 { 236 struct wlan_objmgr_psoc *psoc; 237 uint8_t pdev_id; 238 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr; 239 240 psoc = wlan_pdev_get_psoc(pdev); 241 if (!psoc) { 242 target_if_err("dfs: null psoc"); 243 return QDF_STATUS_E_FAILURE; 244 } 245 246 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 247 248 reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc); 249 if (!reg_cap_ptr) { 250 target_if_err("dfs: reg cap null"); 251 return QDF_STATUS_E_FAILURE; 252 } 253 254 if (reg_cap_ptr[pdev_id].wireless_modes & 255 WMI_HOST_REGDMN_MODE_11A) 256 *is_5ghz = true; 257 else 258 *is_5ghz = false; 259 260 return QDF_STATUS_SUCCESS; 261 } 262 263 #ifdef QCA_MCL_DFS_SUPPORT 264 /** 265 * target_if_dfs_set_phyerr_filter_offload() - config phyerr filter offload. 266 * @pdev: Pointer to DFS pdev object. 267 * @dfs_phyerr_filter_offload: Phyerr filter offload value. 268 * 269 * Return: QDF_STATUS 270 */ 271 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 272 struct wlan_objmgr_pdev *pdev, 273 bool dfs_phyerr_filter_offload) 274 { 275 QDF_STATUS status; 276 void *wmi_handle; 277 278 if (!pdev) { 279 target_if_err("null pdev"); 280 return QDF_STATUS_E_FAILURE; 281 } 282 283 wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 284 if (!wmi_handle) { 285 target_if_err("null wmi_handle"); 286 return QDF_STATUS_E_FAILURE; 287 } 288 289 status = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wmi_handle, 290 dfs_phyerr_filter_offload); 291 if (QDF_IS_STATUS_ERROR(status)) 292 target_if_err("phyerr filter offload %d set fail: %d", 293 dfs_phyerr_filter_offload, status); 294 295 return status; 296 } 297 #else 298 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 299 struct wlan_objmgr_pdev *pdev, 300 bool dfs_phyerr_filter_offload) 301 { 302 return QDF_STATUS_SUCCESS; 303 } 304 #endif 305 306 static QDF_STATUS target_send_dfs_offload_enable_cmd( 307 struct wlan_objmgr_pdev *pdev, bool enable) 308 { 309 QDF_STATUS status = QDF_STATUS_SUCCESS; 310 uint8_t pdev_id; 311 void *wmi_hdl; 312 313 if (!pdev) { 314 target_if_err("null pdev"); 315 return QDF_STATUS_E_FAILURE; 316 } 317 318 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev); 319 if (!wmi_hdl) { 320 target_if_err("null wmi_hdl"); 321 return QDF_STATUS_E_FAILURE; 322 } 323 324 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 325 326 if (enable) 327 status = wmi_unified_dfs_phyerr_offload_en_cmd(wmi_hdl, 328 pdev_id); 329 else 330 status = wmi_unified_dfs_phyerr_offload_dis_cmd(wmi_hdl, 331 pdev_id); 332 333 if (QDF_IS_STATUS_ERROR(status)) 334 target_if_err("dfs: dfs offload cmd failed, enable:%d, pdev:%d", 335 enable, pdev_id); 336 else 337 target_if_debug("dfs: sent dfs offload cmd, enable:%d, pdev:%d", 338 enable, pdev_id); 339 340 return status; 341 } 342 343 QDF_STATUS target_if_register_dfs_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 344 { 345 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops; 346 347 if (!tx_ops) { 348 target_if_err("invalid tx_ops"); 349 return QDF_STATUS_E_FAILURE; 350 } 351 352 dfs_tx_ops = &tx_ops->dfs_tx_ops; 353 dfs_tx_ops->dfs_reg_ev_handler = &target_if_dfs_register_event_handler; 354 355 dfs_tx_ops->dfs_process_emulate_bang_radar_cmd = 356 &target_process_bang_radar_cmd; 357 dfs_tx_ops->dfs_is_pdev_5ghz = &target_if_dfs_is_pdev_5ghz; 358 dfs_tx_ops->dfs_send_offload_enable_cmd = 359 &target_send_dfs_offload_enable_cmd; 360 361 dfs_tx_ops->dfs_set_phyerr_filter_offload = 362 &target_if_dfs_set_phyerr_filter_offload; 363 364 dfs_tx_ops->dfs_get_caps = &target_if_dfs_get_caps; 365 dfs_tx_ops->dfs_send_avg_radar_params_to_fw = 366 &target_if_dfs_send_avg_params_to_fw; 367 dfs_tx_ops->dfs_is_tgt_offload = &target_if_dfs_offload; 368 369 return QDF_STATUS_SUCCESS; 370 } 371