1 /* 2 * Copyright (c) 2017-2020 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_EXIT(); 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 /** 382 * tgt_if_regulatory_get_phy_id_from_pdev_id() - Get phy_id from pdev_id 383 * @psoc: Pointer to psoc 384 * @pdev_id: Pdev id 385 * @phy_id: phy_id 386 * 387 * Return: QDF_STATUS 388 */ 389 static QDF_STATUS tgt_if_regulatory_get_phy_id_from_pdev_id( 390 struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, uint8_t *phy_id) 391 { 392 struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle; 393 uint8_t ret; 394 395 if (pdev_id >= WLAN_UMAC_MAX_PDEVS) { 396 target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS"); 397 return QDF_STATUS_E_FAILURE; 398 } 399 400 /* By default pdev_id and phy_id have one to one mapping */ 401 *phy_id = pdev_id; 402 403 if (!(tgt_if_handle && 404 tgt_if_handle->info.is_pdevid_to_phyid_map)) 405 return QDF_STATUS_SUCCESS; 406 407 ret = tgt_if_handle->info.pdev_id_to_phy_id_map[pdev_id]; 408 409 if (ret < PSOC_MAX_PHY_REG_CAP) { 410 *phy_id = ret; 411 } else { 412 target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP"); 413 return QDF_STATUS_E_FAILURE; 414 } 415 416 return QDF_STATUS_SUCCESS; 417 } 418 419 /** 420 * tgt_if_regulatory_get_pdev_id_from_phy_id() - Get pdev_id for phy_id 421 * @psoc: Pointer to psoc 422 * @phy_id: Phy id 423 * @pdev_id: Pdev id 424 * 425 * Return: QDF_STATUS 426 */ 427 static QDF_STATUS tgt_if_regulatory_get_pdev_id_from_phy_id( 428 struct wlan_objmgr_psoc *psoc, uint8_t phy_id, uint8_t *pdev_id) 429 { 430 struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle; 431 uint8_t i; 432 433 if (phy_id >= PSOC_MAX_PHY_REG_CAP) { 434 target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP"); 435 return QDF_STATUS_E_FAILURE; 436 } 437 438 /* By default pdev_id and phy_id have one to one mapping */ 439 *pdev_id = phy_id; 440 441 if (!(tgt_if_handle && 442 tgt_if_handle->info.is_pdevid_to_phyid_map)) 443 return QDF_STATUS_SUCCESS; 444 445 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 446 if (tgt_if_handle->info.pdev_id_to_phy_id_map[i] == phy_id) 447 break; 448 } 449 450 if (i < WLAN_UMAC_MAX_PDEVS) { 451 *pdev_id = i; 452 } else { 453 target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS"); 454 return QDF_STATUS_E_FAILURE; 455 } 456 457 return QDF_STATUS_SUCCESS; 458 } 459 460 QDF_STATUS target_if_register_regulatory_tx_ops( 461 struct wlan_lmac_if_tx_ops *tx_ops) 462 { 463 struct wlan_lmac_if_reg_tx_ops *reg_ops = &tx_ops->reg_ops; 464 465 reg_ops->register_master_handler = 466 tgt_if_regulatory_register_master_list_handler; 467 468 reg_ops->unregister_master_handler = 469 tgt_if_regulatory_unregister_master_list_handler; 470 471 reg_ops->set_country_code = tgt_if_regulatory_set_country_code; 472 473 reg_ops->fill_umac_legacy_chanlist = NULL; 474 475 reg_ops->set_country_failed = NULL; 476 477 reg_ops->register_11d_new_cc_handler = 478 tgt_if_regulatory_register_11d_new_cc_handler; 479 480 reg_ops->unregister_11d_new_cc_handler = 481 tgt_if_regulatory_unregister_11d_new_cc_handler; 482 483 reg_ops->start_11d_scan = tgt_if_regulatory_start_11d_scan; 484 485 reg_ops->stop_11d_scan = tgt_if_regulatory_stop_11d_scan; 486 487 reg_ops->is_there_serv_ready_extn = 488 tgt_if_regulatory_is_there_serv_ready_extn; 489 490 reg_ops->set_user_country_code = 491 tgt_if_regulatory_set_user_country_code; 492 493 reg_ops->register_ch_avoid_event_handler = 494 tgt_if_regulatory_register_ch_avoid_event_handler; 495 496 reg_ops->unregister_ch_avoid_event_handler = 497 tgt_if_regulatory_unregister_ch_avoid_event_handler; 498 499 reg_ops->send_ctl_info = tgt_if_regulatory_send_ctl_info; 500 501 reg_ops->get_phy_id_from_pdev_id = 502 tgt_if_regulatory_get_phy_id_from_pdev_id; 503 504 reg_ops->get_pdev_id_from_phy_id = 505 tgt_if_regulatory_get_pdev_id_from_phy_id; 506 507 return QDF_STATUS_SUCCESS; 508 } 509