1 /* 2 * Copyright (c) 2017-2019 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_reg.c 22 * This file contains regulatory target interfaces. 23 */ 24 25 #include <wmi_unified_api.h> 26 #include <reg_services_public_struct.h> 27 #include <wlan_reg_tgt_api.h> 28 #include <target_if.h> 29 #include <target_if_reg.h> 30 #include <wmi_unified_reg_api.h> 31 #include <qdf_platform.h> 32 #include <target_if_reg_11d.h> 33 #include <target_if_reg_lte.h> 34 #include <wlan_reg_ucfg_api.h> 35 36 /** 37 * get_chan_list_cc_event_id() - Get chan_list_cc event i 38 * 39 * Return: Event id 40 */ 41 static inline uint32_t get_chan_list_cc_event_id(void) 42 { 43 return wmi_reg_chan_list_cc_event_id; 44 } 45 46 /** 47 * tgt_if_regulatory_is_regdb_offloaded() - Check if regdb is offloaded 48 * @psoc: Pointer to psoc 49 * 50 * Return: true if regdb if offloaded, else false 51 */ 52 static bool tgt_if_regulatory_is_regdb_offloaded(struct wlan_objmgr_psoc *psoc) 53 { 54 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 55 struct wlan_lmac_if_reg_rx_ops *reg_rx_ops; 56 57 reg_rx_ops = target_if_regulatory_get_rx_ops(psoc); 58 59 if (!wmi_handle) 60 return false; 61 62 if (reg_rx_ops->reg_ignore_fw_reg_offload_ind && 63 reg_rx_ops->reg_ignore_fw_reg_offload_ind(psoc)) { 64 target_if_debug("User disabled regulatory offload from ini"); 65 return 0; 66 } 67 68 return wmi_service_enabled(wmi_handle, wmi_service_regulatory_db); 69 } 70 71 /** 72 * tgt_if_regulatory_is_6ghz_supported() - Check if 6ghz is supported 73 * @psoc: Pointer to psoc 74 * 75 * Return: true if regdb if offloaded, else false 76 */ 77 static bool tgt_if_regulatory_is_6ghz_supported(struct wlan_objmgr_psoc *psoc) 78 { 79 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 80 81 if (!wmi_handle) 82 return false; 83 84 return wmi_service_enabled(wmi_handle, wmi_service_6ghz_support); 85 } 86 87 /** 88 * tgt_if_regulatory_is_there_serv_ready_extn() - Check for service ready 89 * extension 90 * @psoc: Pointer to psoc object 91 * 92 * Return: true if service ready extension is present, else false. 93 */ 94 static bool tgt_if_regulatory_is_there_serv_ready_extn( 95 struct wlan_objmgr_psoc *psoc) 96 { 97 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 98 99 if (!wmi_handle) 100 return false; 101 102 return wmi_service_enabled(wmi_handle, wmi_service_ext_msg); 103 } 104 105 /** 106 * target_if_regulatory_get_rx_ops() - Get regdb rx ops 107 * @psoc: Pointer to psoc object 108 * 109 * Return: Reg rx_ops 110 */ 111 struct wlan_lmac_if_reg_rx_ops * 112 target_if_regulatory_get_rx_ops(struct wlan_objmgr_psoc *psoc) 113 { 114 return &psoc->soc_cb.rx_ops.reg_rx_ops; 115 } 116 117 QDF_STATUS target_if_reg_set_offloaded_info(struct wlan_objmgr_psoc *psoc) 118 { 119 struct wlan_lmac_if_reg_rx_ops *reg_rx_ops; 120 121 reg_rx_ops = target_if_regulatory_get_rx_ops(psoc); 122 if (!reg_rx_ops) { 123 target_if_err("reg_rx_ops is NULL"); 124 return QDF_STATUS_E_FAILURE; 125 } 126 127 if (reg_rx_ops->reg_set_regdb_offloaded) 128 reg_rx_ops->reg_set_regdb_offloaded( 129 psoc, 130 tgt_if_regulatory_is_regdb_offloaded(psoc)); 131 132 if (reg_rx_ops->reg_set_11d_offloaded) 133 reg_rx_ops->reg_set_11d_offloaded( 134 psoc, tgt_if_regulatory_is_11d_offloaded(psoc)); 135 136 return QDF_STATUS_SUCCESS; 137 } 138 139 QDF_STATUS target_if_reg_set_6ghz_info(struct wlan_objmgr_psoc *psoc) 140 { 141 struct wlan_lmac_if_reg_rx_ops *reg_rx_ops; 142 143 reg_rx_ops = target_if_regulatory_get_rx_ops(psoc); 144 if (!reg_rx_ops) { 145 target_if_err("reg_rx_ops is NULL"); 146 return QDF_STATUS_E_FAILURE; 147 } 148 149 if (reg_rx_ops->reg_set_6ghz_supported) 150 reg_rx_ops->reg_set_6ghz_supported( 151 psoc, 152 tgt_if_regulatory_is_6ghz_supported(psoc)); 153 154 return QDF_STATUS_SUCCESS; 155 } 156 157 /** 158 * tgt_reg_chan_list_update_handler() - Channel list update handler 159 * @handle: scn handle 160 * @event_buf: pointer to event buffer 161 * @len: buffer length 162 * 163 * Return: 0 on success 164 */ 165 static int tgt_reg_chan_list_update_handler(ol_scn_t handle, uint8_t *event_buf, 166 uint32_t len) 167 { 168 struct wlan_objmgr_psoc *psoc; 169 struct wlan_lmac_if_reg_rx_ops *reg_rx_ops; 170 struct cur_regulatory_info *reg_info; 171 QDF_STATUS status; 172 struct wmi_unified *wmi_handle; 173 int ret_val = 0; 174 175 TARGET_IF_ENTER(); 176 177 psoc = target_if_get_psoc_from_scn_hdl(handle); 178 if (!psoc) { 179 target_if_err("psoc ptr is NULL"); 180 return -EINVAL; 181 } 182 183 reg_rx_ops = target_if_regulatory_get_rx_ops(psoc); 184 if (!reg_rx_ops->master_list_handler) { 185 target_if_err("master_list_handler is NULL"); 186 return -EINVAL; 187 } 188 189 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 190 if (!wmi_handle) { 191 target_if_err("invalid wmi handle"); 192 return -EINVAL; 193 } 194 195 reg_info = qdf_mem_malloc(sizeof(*reg_info)); 196 if (!reg_info) 197 return -ENOMEM; 198 199 if (wmi_extract_reg_chan_list_update_event(wmi_handle, 200 event_buf, reg_info, len) 201 != QDF_STATUS_SUCCESS) { 202 target_if_err("Extraction of channel list event failed"); 203 ret_val = -EFAULT; 204 goto clean; 205 } 206 207 if (reg_info->phy_id >= PSOC_MAX_PHY_REG_CAP) { 208 target_if_err_rl("phy_id %d is out of bounds", 209 reg_info->phy_id); 210 ret_val = -EFAULT; 211 goto clean; 212 } 213 214 reg_info->psoc = psoc; 215 216 status = reg_rx_ops->master_list_handler(reg_info); 217 if (status != QDF_STATUS_SUCCESS) { 218 target_if_err("Failed to process master channel list handler"); 219 ret_val = -EFAULT; 220 } 221 222 clean: 223 qdf_mem_free(reg_info->reg_rules_2g_ptr); 224 qdf_mem_free(reg_info->reg_rules_5g_ptr); 225 qdf_mem_free(reg_info); 226 227 target_if_debug("processed reg channel list ret_val %d", ret_val); 228 229 return ret_val; 230 } 231 232 /** 233 * tgt_if_regulatory_register_master_list_handler() - Register master channel 234 * list 235 * @psoc: Pointer to psoc 236 * @arg: Pointer to argument list 237 * 238 * Return: QDF_STATUS 239 */ 240 static QDF_STATUS tgt_if_regulatory_register_master_list_handler( 241 struct wlan_objmgr_psoc *psoc, void *arg) 242 { 243 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 244 245 if (!wmi_handle) 246 return QDF_STATUS_E_FAILURE; 247 248 return wmi_unified_register_event_handler( 249 wmi_handle, wmi_reg_chan_list_cc_event_id, 250 tgt_reg_chan_list_update_handler, WMI_RX_UMAC_CTX); 251 } 252 253 /** 254 * tgt_if_regulatory_unregister_master_list_handler() - Unregister master 255 * channel list 256 * @psoc: Pointer to psoc 257 * @arg: Pointer to argument list 258 * 259 * Return: QDF_STATUS 260 */ 261 static QDF_STATUS tgt_if_regulatory_unregister_master_list_handler( 262 struct wlan_objmgr_psoc *psoc, void *arg) 263 { 264 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 265 266 if (!wmi_handle) 267 return QDF_STATUS_E_FAILURE; 268 269 return wmi_unified_unregister_event_handler( 270 wmi_handle, wmi_reg_chan_list_cc_event_id); 271 } 272 273 /** 274 * tgt_if_regulatory_set_country_code() - Set country code 275 * @psoc: Pointer to psoc 276 * @arg: Pointer to argument list 277 * 278 * Return: QDF_STATUS 279 */ 280 static QDF_STATUS tgt_if_regulatory_set_country_code( 281 struct wlan_objmgr_psoc *psoc, void *arg) 282 { 283 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 284 285 if (!wmi_handle) 286 return QDF_STATUS_E_FAILURE; 287 288 return wmi_unified_set_country_cmd_send(wmi_handle, arg); 289 } 290 291 /** 292 * tgt_if_regulatory_set_user_country_code() - Set user country code 293 * @psoc: Pointer to psoc 294 * @pdev_id: Pdev id 295 * @rd: Pointer to regdomain structure 296 * 297 * Return: QDF_STATUS 298 */ 299 static QDF_STATUS tgt_if_regulatory_set_user_country_code( 300 struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, struct cc_regdmn_s *rd) 301 { 302 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 303 304 if (!wmi_handle) 305 return QDF_STATUS_E_FAILURE; 306 307 if (wmi_unified_set_user_country_code_cmd_send( 308 wmi_handle, pdev_id, rd) != QDF_STATUS_SUCCESS 309 ) { 310 target_if_err("Set user country code failed"); 311 return QDF_STATUS_E_FAILURE; 312 } 313 314 return QDF_STATUS_SUCCESS; 315 } 316 317 QDF_STATUS tgt_if_regulatory_modify_freq_range(struct wlan_objmgr_psoc *psoc) 318 { 319 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap; 320 321 reg_cap = ucfg_reg_get_hal_reg_cap(psoc); 322 if (!reg_cap) { 323 target_if_err("reg cap is NULL"); 324 return QDF_STATUS_E_FAILURE; 325 } 326 327 if (!(reg_cap->wireless_modes & WMI_HOST_REGDMN_MODE_11A)) { 328 reg_cap->low_5ghz_chan = 0; 329 reg_cap->high_5ghz_chan = 0; 330 } 331 332 if (!(reg_cap->wireless_modes & 333 (WMI_HOST_REGDMN_MODE_11B | WMI_HOST_REGDMN_MODE_PUREG))) { 334 reg_cap->low_2ghz_chan = 0; 335 reg_cap->high_2ghz_chan = 0; 336 } 337 338 target_if_debug("phy_id = %d - low_2ghz_chan = %d high_2ghz_chan = %d low_5ghz_chan = %d high_5ghz_chan = %d", 339 reg_cap->phy_id, 340 reg_cap->low_2ghz_chan, 341 reg_cap->high_2ghz_chan, 342 reg_cap->low_5ghz_chan, 343 reg_cap->high_5ghz_chan); 344 345 return QDF_STATUS_SUCCESS; 346 } 347 348 #ifdef CONFIG_REG_CLIENT 349 /** 350 * tgt_if_regulatory_send_ctl_info() - Send CTL info to firmware 351 * @psoc: Pointer to psoc 352 * @params: Pointer to reg control params 353 * 354 * Return: QDF_STATUS 355 */ 356 static QDF_STATUS 357 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc, 358 struct reg_ctl_params *params) 359 { 360 wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 361 362 if (!wmi_handle) 363 return QDF_STATUS_E_FAILURE; 364 365 return wmi_unified_send_regdomain_info_to_fw_cmd(wmi_handle, 366 params->regd, 367 params->regd_2g, 368 params->regd_5g, 369 params->ctl_2g, 370 params->ctl_5g); 371 } 372 #else 373 static QDF_STATUS 374 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc, 375 struct reg_ctl_params *params) 376 { 377 return QDF_STATUS_SUCCESS; 378 } 379 #endif 380 381 QDF_STATUS target_if_register_regulatory_tx_ops( 382 struct wlan_lmac_if_tx_ops *tx_ops) 383 { 384 struct wlan_lmac_if_reg_tx_ops *reg_ops = &tx_ops->reg_ops; 385 386 reg_ops->register_master_handler = 387 tgt_if_regulatory_register_master_list_handler; 388 389 reg_ops->unregister_master_handler = 390 tgt_if_regulatory_unregister_master_list_handler; 391 392 reg_ops->set_country_code = tgt_if_regulatory_set_country_code; 393 394 reg_ops->fill_umac_legacy_chanlist = NULL; 395 396 reg_ops->set_country_failed = NULL; 397 398 reg_ops->register_11d_new_cc_handler = 399 tgt_if_regulatory_register_11d_new_cc_handler; 400 401 reg_ops->unregister_11d_new_cc_handler = 402 tgt_if_regulatory_unregister_11d_new_cc_handler; 403 404 reg_ops->start_11d_scan = tgt_if_regulatory_start_11d_scan; 405 406 reg_ops->stop_11d_scan = tgt_if_regulatory_stop_11d_scan; 407 408 reg_ops->is_there_serv_ready_extn = 409 tgt_if_regulatory_is_there_serv_ready_extn; 410 411 reg_ops->set_user_country_code = 412 tgt_if_regulatory_set_user_country_code; 413 414 reg_ops->register_ch_avoid_event_handler = 415 tgt_if_regulatory_register_ch_avoid_event_handler; 416 417 reg_ops->unregister_ch_avoid_event_handler = 418 tgt_if_regulatory_unregister_ch_avoid_event_handler; 419 420 reg_ops->send_ctl_info = tgt_if_regulatory_send_ctl_info; 421 422 return QDF_STATUS_SUCCESS; 423 } 424