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_ucfg.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_is_dfs_3() - Is dfs3 support or not 45 * @target_type: target type being used. 46 * 47 * Return: true if dfs3 is supported, false otherwise. 48 */ 49 static bool target_if_is_dfs_3(uint32_t target_type) 50 { 51 bool is_dfs_3; 52 53 switch (target_type) { 54 case TARGET_TYPE_AR6320: 55 is_dfs_3 = false; 56 break; 57 case TARGET_TYPE_ADRASTEA: 58 is_dfs_3 = true; 59 break; 60 default: 61 is_dfs_3 = true; 62 } 63 64 return is_dfs_3; 65 } 66 67 #ifdef QCA_MCL_DFS_SUPPORT 68 /** 69 * target_if_radar_event_handler() - handle radar event when 70 * phyerr filter offload is enabled. 71 * @scn: Handle to HIF context 72 * @data: radar event buffer 73 * @datalen: radar event buffer length 74 * 75 * Return: 0 on success; error code otherwise 76 */ 77 static int target_if_radar_event_handler( 78 ol_scn_t scn, uint8_t *data, uint32_t datalen) 79 { 80 struct radar_event_info wlan_radar_event; 81 struct wlan_objmgr_psoc *psoc; 82 struct wlan_objmgr_pdev *pdev; 83 struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; 84 85 if (!scn || !data) { 86 target_if_err("scn: %pK, data: %pK", scn, data); 87 return -EINVAL; 88 } 89 psoc = target_if_get_psoc_from_scn_hdl(scn); 90 if (!psoc) { 91 target_if_err("null psoc"); 92 return -EINVAL; 93 } 94 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 95 96 if (!dfs_rx_ops || !dfs_rx_ops->dfs_process_phyerr_filter_offload) { 97 target_if_err("Invalid dfs_rx_ops: %pK", dfs_rx_ops); 98 return -EINVAL; 99 } 100 if (QDF_IS_STATUS_ERROR(wmi_extract_wlan_radar_event_info( 101 GET_WMI_HDL_FROM_PSOC(psoc), data, 102 &wlan_radar_event, datalen))) { 103 target_if_err("failed to extract wlan radar event"); 104 return -EFAULT; 105 } 106 pdev = wlan_objmgr_get_pdev_by_id(psoc, wlan_radar_event.pdev_id, 107 WLAN_DFS_ID); 108 if (!pdev) { 109 target_if_err("null pdev"); 110 return -EINVAL; 111 } 112 dfs_rx_ops->dfs_process_phyerr_filter_offload(pdev, 113 &wlan_radar_event); 114 wlan_objmgr_pdev_release_ref(pdev, WLAN_DFS_ID); 115 116 return 0; 117 } 118 119 /** 120 * target_if_reg_phyerr_events() - register dfs phyerr radar event. 121 * @psoc: pointer to psoc. 122 * @pdev: pointer to pdev. 123 * 124 * Return: QDF_STATUS. 125 */ 126 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 127 struct wlan_objmgr_psoc *psoc) 128 { 129 int ret = -1; 130 struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; 131 bool is_phyerr_filter_offload; 132 133 dfs_rx_ops = target_if_dfs_get_rx_ops(psoc); 134 135 if (dfs_rx_ops && dfs_rx_ops->dfs_is_phyerr_filter_offload) 136 if (QDF_IS_STATUS_SUCCESS( 137 dfs_rx_ops->dfs_is_phyerr_filter_offload(psoc, 138 &is_phyerr_filter_offload))) 139 if (is_phyerr_filter_offload) 140 ret = wmi_unified_register_event( 141 GET_WMI_HDL_FROM_PSOC(psoc), 142 wmi_dfs_radar_event_id, 143 target_if_radar_event_handler); 144 145 if (ret) { 146 target_if_err("failed to register wmi_dfs_radar_event_id"); 147 return QDF_STATUS_E_FAILURE; 148 } 149 150 return QDF_STATUS_SUCCESS; 151 } 152 #else 153 static QDF_STATUS target_if_reg_phyerr_events_dfs2( 154 struct wlan_objmgr_psoc *psoc) 155 { 156 return QDF_STATUS_SUCCESS; 157 } 158 #endif 159 160 static QDF_STATUS target_if_dfs_register_event_handler( 161 struct wlan_objmgr_psoc *psoc, 162 bool dfs_offload) 163 { 164 struct target_psoc_info *tgt_psoc_info; 165 166 if (!psoc) { 167 target_if_err("null psoc"); 168 return QDF_STATUS_E_FAILURE; 169 } 170 171 if (!dfs_offload) { 172 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 173 if (!tgt_psoc_info) { 174 target_if_err("null tgt_psoc_info"); 175 return QDF_STATUS_E_FAILURE; 176 } 177 if (target_if_is_dfs_3( 178 target_psoc_get_target_type(tgt_psoc_info))) 179 return target_if_dfs_reg_phyerr_events(psoc); 180 else 181 return target_if_reg_phyerr_events_dfs2(psoc); 182 } else { 183 return target_if_dfs_reg_offload_events(psoc); 184 } 185 } 186 187 static QDF_STATUS target_if_dfs_is_pdev_5ghz(struct wlan_objmgr_pdev *pdev, 188 bool *is_5ghz) 189 { 190 struct wlan_objmgr_psoc *psoc; 191 uint8_t pdev_id; 192 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr; 193 194 psoc = wlan_pdev_get_psoc(pdev); 195 if (!psoc) { 196 target_if_err("dfs: null psoc"); 197 return QDF_STATUS_E_FAILURE; 198 } 199 200 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 201 202 reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc); 203 if (!reg_cap_ptr) { 204 target_if_err("dfs: reg cap null"); 205 return QDF_STATUS_E_FAILURE; 206 } 207 208 if (reg_cap_ptr[pdev_id].wireless_modes & 209 WMI_HOST_REGDMN_MODE_11A) 210 *is_5ghz = true; 211 else 212 *is_5ghz = false; 213 214 return QDF_STATUS_SUCCESS; 215 } 216 217 #ifdef QCA_MCL_DFS_SUPPORT 218 /** 219 * target_if_dfs_set_phyerr_filter_offload() - config phyerr filter offload. 220 * @pdev: Pointer to DFS pdev object. 221 * @dfs_phyerr_filter_offload: Phyerr filter offload value. 222 * 223 * Return: QDF_STATUS 224 */ 225 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 226 struct wlan_objmgr_pdev *pdev, 227 bool dfs_phyerr_filter_offload) 228 { 229 QDF_STATUS status; 230 void *wmi_handle; 231 232 if (!pdev) { 233 target_if_err("null pdev"); 234 return QDF_STATUS_E_FAILURE; 235 } 236 237 wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); 238 if (!wmi_handle) { 239 target_if_err("null wmi_handle"); 240 return QDF_STATUS_E_FAILURE; 241 } 242 243 status = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wmi_handle, 244 dfs_phyerr_filter_offload); 245 if (QDF_IS_STATUS_ERROR(status)) 246 target_if_err("phyerr filter offload %d set fail: %d", 247 dfs_phyerr_filter_offload, status); 248 249 return status; 250 } 251 #else 252 static QDF_STATUS target_if_dfs_set_phyerr_filter_offload( 253 struct wlan_objmgr_pdev *pdev, 254 bool dfs_phyerr_filter_offload) 255 { 256 return QDF_STATUS_SUCCESS; 257 } 258 #endif 259 260 static QDF_STATUS target_send_dfs_offload_enable_cmd( 261 struct wlan_objmgr_pdev *pdev, bool enable) 262 { 263 QDF_STATUS status = QDF_STATUS_SUCCESS; 264 uint8_t pdev_id; 265 void *wmi_hdl; 266 267 if (!pdev) { 268 target_if_err("null pdev"); 269 return QDF_STATUS_E_FAILURE; 270 } 271 272 wmi_hdl = GET_WMI_HDL_FROM_PDEV(pdev); 273 if (!wmi_hdl) { 274 target_if_err("null wmi_hdl"); 275 return QDF_STATUS_E_FAILURE; 276 } 277 278 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 279 280 if (enable) 281 status = wmi_unified_dfs_phyerr_offload_en_cmd(wmi_hdl, 282 pdev_id); 283 else 284 status = wmi_unified_dfs_phyerr_offload_dis_cmd(wmi_hdl, 285 pdev_id); 286 287 if (QDF_IS_STATUS_ERROR(status)) 288 target_if_err("dfs: dfs offload cmd failed, enable:%d, pdev:%d", 289 enable, pdev_id); 290 else 291 target_if_debug("dfs: sent dfs offload cmd, enable:%d, pdev:%d", 292 enable, pdev_id); 293 294 return status; 295 } 296 297 QDF_STATUS target_if_register_dfs_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 298 { 299 struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops; 300 301 if (!tx_ops) { 302 target_if_err("invalid tx_ops"); 303 return QDF_STATUS_E_FAILURE; 304 } 305 306 dfs_tx_ops = &tx_ops->dfs_tx_ops; 307 dfs_tx_ops->dfs_reg_ev_handler = &target_if_dfs_register_event_handler; 308 309 dfs_tx_ops->dfs_process_emulate_bang_radar_cmd = 310 &target_process_bang_radar_cmd; 311 dfs_tx_ops->dfs_is_pdev_5ghz = &target_if_dfs_is_pdev_5ghz; 312 dfs_tx_ops->dfs_send_offload_enable_cmd = 313 &target_send_dfs_offload_enable_cmd; 314 315 dfs_tx_ops->dfs_set_phyerr_filter_offload = 316 &target_if_dfs_set_phyerr_filter_offload; 317 318 dfs_tx_ops->dfs_get_caps = &target_if_dfs_get_caps; 319 320 return QDF_STATUS_SUCCESS; 321 } 322