1 /* 2 * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /** 19 * DOC: service_ready_util.c 20 * 21 * Public APIs implementation source file for accessing (ext)service ready 22 * data from psoc object 23 */ 24 #include "service_ready_util.h" 25 #include <wlan_reg_ucfg_api.h> 26 #include <target_type.h> 27 #include <qdf_module.h> 28 29 QDF_STATUS init_deinit_chainmask_table_alloc( 30 struct wlan_psoc_host_service_ext_param *ser_ext_par) 31 { 32 int i; 33 uint32_t alloc_size; 34 QDF_STATUS status; 35 36 if (ser_ext_par->num_chainmask_tables > 0) { 37 status = QDF_STATUS_SUCCESS; 38 for (i = 0; i < ser_ext_par->num_chainmask_tables; i++) { 39 alloc_size = 40 (sizeof(struct wlan_psoc_host_chainmask_capabilities) * 41 ser_ext_par->chainmask_table[i].num_valid_chainmasks); 42 43 ser_ext_par->chainmask_table[i].cap_list = 44 qdf_mem_alloc_outline(NULL, alloc_size); 45 if (!ser_ext_par->chainmask_table[i].cap_list) { 46 init_deinit_chainmask_table_free(ser_ext_par); 47 status = QDF_STATUS_E_NOMEM; 48 break; 49 } 50 } 51 } else { 52 status = QDF_STATUS_E_NOSUPPORT; 53 } 54 55 return status; 56 } 57 58 qdf_export_symbol(init_deinit_chainmask_table_alloc); 59 60 QDF_STATUS init_deinit_chainmask_table_free( 61 struct wlan_psoc_host_service_ext_param *ser_ext_par) 62 { 63 struct wlan_psoc_host_chainmask_table *table; 64 int i; 65 66 for (i = 0; i < ser_ext_par->num_chainmask_tables; i++) { 67 table = &(ser_ext_par->chainmask_table[i]); 68 if (table->cap_list) { 69 qdf_mem_free(table->cap_list); 70 table->cap_list = NULL; 71 } 72 } 73 74 return QDF_STATUS_SUCCESS; 75 } 76 77 qdf_export_symbol(init_deinit_chainmask_table_free); 78 79 int init_deinit_populate_service_bitmap(void *wmi_handle, uint8_t *event, 80 uint32_t *service_bitmap) 81 { 82 QDF_STATUS status; 83 84 status = wmi_save_service_bitmap(wmi_handle, event, service_bitmap); 85 if (QDF_IS_STATUS_ERROR(status)) { 86 target_if_err("failed to parse service bitmap"); 87 return qdf_status_to_os_return(status); 88 } 89 90 return 0; 91 } 92 93 int init_deinit_populate_fw_version_cmd(void *wmi_handle, uint8_t *event) 94 { 95 QDF_STATUS status; 96 97 status = wmi_unified_save_fw_version_cmd(wmi_handle, event); 98 if (QDF_IS_STATUS_ERROR(status)) 99 target_if_err("failed to save fw version"); 100 101 return 0; 102 } 103 104 int init_deinit_populate_target_cap(void *wmi_handle, uint8_t *event, 105 struct wlan_psoc_target_capability_info *cap) 106 { 107 QDF_STATUS status; 108 109 status = wmi_get_target_cap_from_service_ready(wmi_handle, event, cap); 110 if (QDF_IS_STATUS_ERROR(status)) { 111 target_if_err("failed to parse target cap"); 112 return qdf_status_to_os_return(status); 113 } 114 115 return 0; 116 } 117 118 int init_deinit_populate_service_ready_ext_param(void *handle, uint8_t *evt, 119 struct wlan_psoc_host_service_ext_param *param) 120 { 121 QDF_STATUS status; 122 123 status = wmi_extract_service_ready_ext(handle, evt, param); 124 if (QDF_IS_STATUS_ERROR(status)) { 125 target_if_err("failed to parse wmi service ready ext param"); 126 return qdf_status_to_os_return(status); 127 } 128 129 return 0; 130 } 131 132 int init_deinit_populate_chainmask_tables(void *handle, uint8_t *evt, 133 struct wlan_psoc_host_chainmask_table *param) 134 { 135 QDF_STATUS status; 136 137 status = wmi_extract_chainmask_tables(handle, evt, param); 138 if (QDF_IS_STATUS_ERROR(status)) { 139 target_if_err("failed to parse wmi service ready ext param"); 140 return qdf_status_to_os_return(status); 141 } 142 143 return 0; 144 } 145 146 int init_deinit_populate_mac_phy_capability(void *handle, uint8_t *evt, 147 struct wlan_psoc_host_hw_mode_caps *hw_cap, struct tgt_info *info) 148 { 149 QDF_STATUS status; 150 uint32_t hw_mode_id; 151 uint32_t phy_bit_map; 152 uint8_t mac_phy_id; 153 154 hw_mode_id = hw_cap->hw_mode_id; 155 phy_bit_map = hw_cap->phy_id_map; 156 target_if_debug("hw_mode_id %d phy_bit_map 0x%x", 157 hw_mode_id, phy_bit_map); 158 159 mac_phy_id = 0; 160 while (phy_bit_map) { 161 if (info->total_mac_phy_cnt >= PSOC_MAX_MAC_PHY_CAP) { 162 target_if_err("total mac phy exceeds max limit %d", 163 info->total_mac_phy_cnt); 164 return -EINVAL; 165 } 166 167 status = wmi_extract_mac_phy_cap_service_ready_ext(handle, 168 evt, hw_mode_id, mac_phy_id, 169 &(info->mac_phy_cap[info->total_mac_phy_cnt])); 170 if (QDF_IS_STATUS_ERROR(status)) { 171 target_if_err("failed to parse mac phy capability"); 172 return qdf_status_to_os_return(status); 173 } 174 info->mac_phy_cap[info->total_mac_phy_cnt].hw_mode_config_type 175 = hw_cap->hw_mode_config_type; 176 info->total_mac_phy_cnt++; 177 phy_bit_map &= (phy_bit_map - 1); 178 mac_phy_id++; 179 } 180 target_if_debug("total_mac_phy_cnt %d", info->total_mac_phy_cnt); 181 182 return 0; 183 } 184 185 static int get_hw_mode(void *handle, uint8_t *evt, uint8_t hw_idx, 186 struct wlan_psoc_host_hw_mode_caps *cap) 187 { 188 QDF_STATUS status; 189 190 status = wmi_extract_hw_mode_cap_service_ready_ext(handle, evt, 191 hw_idx, cap); 192 if (QDF_IS_STATUS_ERROR(status)) { 193 target_if_err("failed to parse hw mode capability"); 194 return qdf_status_to_os_return(status); 195 } 196 197 return 0; 198 } 199 200 static int get_sar_version(void *handle, uint8_t *evt, 201 struct wlan_psoc_host_service_ext_param *ext_param) 202 { 203 QDF_STATUS status; 204 205 status = wmi_extract_sar_cap_service_ready_ext(handle, evt, ext_param); 206 if (QDF_IS_STATUS_ERROR(status)) { 207 target_if_err("failed to parse sar capability"); 208 return qdf_status_to_os_return(status); 209 } 210 211 return 0; 212 } 213 214 int init_deinit_populate_hw_mode_capability(void *wmi_handle, 215 uint8_t *event, struct target_psoc_info *tgt_hdl) 216 { 217 QDF_STATUS status = QDF_STATUS_SUCCESS; 218 uint8_t hw_idx; 219 uint32_t num_hw_modes; 220 struct wlan_psoc_host_hw_mode_caps hw_mode_caps[PSOC_MAX_HW_MODE]; 221 uint32_t preferred_mode; 222 struct tgt_info *info; 223 224 info = &tgt_hdl->info; 225 num_hw_modes = info->service_ext_param.num_hw_modes; 226 if (num_hw_modes > PSOC_MAX_HW_MODE) { 227 target_if_err("invalid num_hw_modes %d", num_hw_modes); 228 return -EINVAL; 229 } 230 target_if_debug("num_hw_modes %d", num_hw_modes); 231 232 qdf_mem_zero(&hw_mode_caps, sizeof(hw_mode_caps)); 233 234 preferred_mode = target_psoc_get_preferred_hw_mode(tgt_hdl); 235 for (hw_idx = 0; hw_idx < num_hw_modes; hw_idx++) { 236 status = get_hw_mode(wmi_handle, event, hw_idx, 237 &hw_mode_caps[hw_idx]); 238 if (status) 239 goto return_exit; 240 241 if ((preferred_mode != WMI_HOST_HW_MODE_MAX) && 242 (hw_mode_caps[hw_idx].hw_mode_id != preferred_mode)) 243 continue; 244 245 status = init_deinit_populate_mac_phy_capability(wmi_handle, 246 event, &hw_mode_caps[hw_idx], info); 247 if (status) 248 goto return_exit; 249 250 if ((preferred_mode != WMI_HOST_HW_MODE_MAX) && 251 (hw_mode_caps[hw_idx].hw_mode_id == preferred_mode)) { 252 info->num_radios = info->total_mac_phy_cnt; 253 target_if_debug("num radios is %d\n", info->num_radios); 254 } 255 } 256 status = get_sar_version(wmi_handle, event, &info->service_ext_param); 257 target_if_debug("sar version %d", info->service_ext_param.sar_version); 258 259 return_exit: 260 return qdf_status_to_os_return(status); 261 } 262 263 int init_deinit_populate_dbr_ring_cap(struct wlan_objmgr_psoc *psoc, 264 void *handle, uint8_t *event, struct tgt_info *info) 265 266 { 267 uint8_t cap_idx; 268 uint32_t num_dbr_ring_caps; 269 QDF_STATUS status = QDF_STATUS_SUCCESS; 270 271 num_dbr_ring_caps = info->service_ext_param.num_dbr_ring_caps; 272 273 target_if_debug("Num DMA Capabilities = %d", num_dbr_ring_caps); 274 275 if (!num_dbr_ring_caps) 276 return 0; 277 278 info->dbr_ring_cap = qdf_mem_malloc( 279 sizeof(struct wlan_psoc_host_dbr_ring_caps) * 280 num_dbr_ring_caps); 281 282 if (!info->dbr_ring_cap) { 283 target_if_err("Mem alloc for DMA cap failed"); 284 return -EINVAL; 285 } 286 287 for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) { 288 status = wmi_extract_dbr_ring_cap_service_ready_ext(handle, 289 event, cap_idx, 290 &(info->dbr_ring_cap[cap_idx])); 291 if (QDF_IS_STATUS_ERROR(status)) { 292 target_if_err("Extraction of DMA cap failed"); 293 goto free_and_return; 294 } 295 } 296 297 return 0; 298 299 free_and_return: 300 qdf_mem_free(info->dbr_ring_cap); 301 info->dbr_ring_cap = NULL; 302 303 return qdf_status_to_os_return(status); 304 } 305 306 QDF_STATUS init_deinit_dbr_ring_cap_free( 307 struct target_psoc_info *tgt_psoc_info) 308 { 309 QDF_STATUS status = QDF_STATUS_SUCCESS; 310 311 if (tgt_psoc_info->info.dbr_ring_cap) { 312 qdf_mem_free(tgt_psoc_info->info.dbr_ring_cap); 313 tgt_psoc_info->info.dbr_ring_cap = NULL; 314 } 315 316 return status; 317 } 318 qdf_export_symbol(init_deinit_dbr_ring_cap_free); 319 320 int init_deinit_populate_phy_reg_cap(struct wlan_objmgr_psoc *psoc, 321 void *handle, uint8_t *event, 322 struct tgt_info *info, bool service_ready) 323 { 324 uint8_t reg_idx; 325 uint32_t num_phy_reg_cap; 326 QDF_STATUS status = QDF_STATUS_SUCCESS; 327 struct wlan_psoc_hal_reg_capability cap; 328 struct wlan_psoc_host_hal_reg_capabilities_ext 329 reg_cap[PSOC_MAX_PHY_REG_CAP] = {{0} }; 330 331 if (service_ready) { 332 status = wmi_extract_hal_reg_cap(handle, event, &cap); 333 if (QDF_IS_STATUS_ERROR(status)) { 334 target_if_err("failed to parse hal reg cap"); 335 return qdf_status_to_os_return(status); 336 } 337 info->service_ext_param.num_phy = 1; 338 num_phy_reg_cap = 1; 339 reg_cap[0].phy_id = 0; 340 qdf_mem_copy(&(reg_cap[0].eeprom_reg_domain), &cap, 341 sizeof(struct wlan_psoc_hal_reg_capability)); 342 target_if_debug("FW wireless modes 0x%x", 343 reg_cap[0].wireless_modes); 344 } else { 345 num_phy_reg_cap = info->service_ext_param.num_phy; 346 if (num_phy_reg_cap > PSOC_MAX_PHY_REG_CAP) { 347 target_if_err("Invalid num_phy_reg_cap %d", 348 num_phy_reg_cap); 349 return -EINVAL; 350 } 351 target_if_debug("num_phy_reg_cap %d", num_phy_reg_cap); 352 353 for (reg_idx = 0; reg_idx < num_phy_reg_cap; reg_idx++) { 354 status = wmi_extract_reg_cap_service_ready_ext(handle, 355 event, reg_idx, &(reg_cap[reg_idx])); 356 if (QDF_IS_STATUS_ERROR(status)) { 357 target_if_err("failed to parse reg cap"); 358 return qdf_status_to_os_return(status); 359 } 360 } 361 } 362 363 status = ucfg_reg_set_hal_reg_cap(psoc, reg_cap, num_phy_reg_cap); 364 365 return qdf_status_to_os_return(status); 366 } 367 368 static bool init_deinit_regdmn_160mhz_support( 369 struct wlan_psoc_host_hal_reg_capabilities_ext *hal_cap) 370 { 371 return ((hal_cap->wireless_modes & 372 WMI_HOST_REGDMN_MODE_11AC_VHT160) != 0); 373 } 374 375 static bool init_deinit_regdmn_80p80mhz_support( 376 struct wlan_psoc_host_hal_reg_capabilities_ext *hal_cap) 377 { 378 return ((hal_cap->wireless_modes & 379 WMI_HOST_REGDMN_MODE_11AC_VHT80_80) != 0); 380 } 381 382 static bool init_deinit_vht_160mhz_is_supported(uint32_t vhtcap) 383 { 384 return ((vhtcap & WLAN_VHTCAP_SUP_CHAN_WIDTH_160) != 0); 385 } 386 387 static bool init_deinit_vht_80p80mhz_is_supported(uint32_t vhtcap) 388 { 389 return ((vhtcap & WLAN_VHTCAP_SUP_CHAN_WIDTH_80_160) != 0); 390 } 391 392 static bool init_deinit_vht_160mhz_shortgi_is_supported(uint32_t vhtcap) 393 { 394 return ((vhtcap & WLAN_VHTCAP_SHORTGI_160) != 0); 395 } 396 397 QDF_STATUS init_deinit_validate_160_80p80_fw_caps( 398 struct wlan_objmgr_psoc *psoc, 399 struct target_psoc_info *tgt_hdl) 400 { 401 bool wireless_mode_160mhz = false; 402 bool wireless_mode_80p80mhz = false; 403 bool vhtcap_160mhz = false; 404 bool vhtcap_80p80_160mhz = false; 405 bool vhtcap_160mhz_sgi = false; 406 bool valid = false; 407 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap; 408 struct common_wmi_handle *wmi_handle; 409 410 if (!tgt_hdl) { 411 target_if_err( 412 "target_psoc_info is null in validate 160n80p80 cap check"); 413 return QDF_STATUS_E_INVAL; 414 } 415 416 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 417 418 if ((tgt_hdl->info.target_type == TARGET_TYPE_QCA8074) || 419 (tgt_hdl->info.target_type == TARGET_TYPE_QCA8074V2) || 420 (tgt_hdl->info.target_type == TARGET_TYPE_QCA6290)) { 421 /** 422 * Return true for now. This is not available in 423 * qca8074 fw yet 424 */ 425 return QDF_STATUS_SUCCESS; 426 } 427 428 reg_cap = ucfg_reg_get_hal_reg_cap(psoc); 429 if (reg_cap == NULL) { 430 target_if_err("reg cap is NULL"); 431 return QDF_STATUS_E_FAILURE; 432 } 433 434 /* NOTE: Host driver gets vht capability and supported channel 435 * width / channel frequency range from FW/HALPHY and obeys it. 436 * Host driver is unaware of any physical filters or any other 437 * hardware factors that can impact these capabilities. 438 * These need to be correctly determined by firmware. 439 */ 440 441 /*This table lists all valid and invalid combinations 442 * WMODE160 WMODE80_80 VHTCAP_160 VHTCAP_80+80_160 IsCombinationvalid? 443 * 0 0 0 0 YES 444 * 0 0 0 1 NO 445 * 0 0 1 0 NO 446 * 0 0 1 1 NO 447 * 0 1 0 0 NO 448 * 0 1 0 1 NO 449 * 0 1 1 0 NO 450 * 0 1 1 1 NO 451 * 1 0 0 0 NO 452 * 1 0 0 1 NO 453 * 1 0 1 0 YES 454 * 1 0 1 1 NO 455 * 1 1 0 0 NO 456 * 1 1 0 1 YES 457 * 1 1 1 0 NO 458 * 1 1 1 1 NO 459 */ 460 461 /* NOTE: Last row in above table is invalid because value corresponding 462 * to both VHTCAP_160 and VHTCAP_80+80_160 being set is reserved as per 463 * 802.11ac. Only one of them can be set at a time. 464 */ 465 466 wireless_mode_160mhz = init_deinit_regdmn_160mhz_support(reg_cap); 467 wireless_mode_80p80mhz = init_deinit_regdmn_80p80mhz_support(reg_cap); 468 vhtcap_160mhz = init_deinit_vht_160mhz_is_supported( 469 tgt_hdl->info.target_caps.vht_cap_info); 470 vhtcap_80p80_160mhz = init_deinit_vht_80p80mhz_is_supported( 471 tgt_hdl->info.target_caps.vht_cap_info); 472 vhtcap_160mhz_sgi = init_deinit_vht_160mhz_shortgi_is_supported( 473 tgt_hdl->info.target_caps.vht_cap_info); 474 475 if (!(wireless_mode_160mhz || wireless_mode_80p80mhz || 476 vhtcap_160mhz || vhtcap_80p80_160mhz)) { 477 valid = QDF_STATUS_SUCCESS; 478 } else if (wireless_mode_160mhz && !wireless_mode_80p80mhz && 479 vhtcap_160mhz && !vhtcap_80p80_160mhz) { 480 valid = QDF_STATUS_SUCCESS; 481 } else if (wireless_mode_160mhz && wireless_mode_80p80mhz && 482 !vhtcap_160mhz && vhtcap_160mhz_sgi) { 483 valid = QDF_STATUS_SUCCESS; 484 } 485 486 if (valid == QDF_STATUS_SUCCESS) { 487 /* 488 * Ensure short GI for 160 MHz is enabled 489 * only if 160/80+80 is supported. 490 */ 491 if (vhtcap_160mhz_sgi && 492 !(vhtcap_160mhz || vhtcap_80p80_160mhz)) { 493 valid = QDF_STATUS_E_FAILURE; 494 } 495 } 496 497 /* Invalid config specified by FW */ 498 if (valid != QDF_STATUS_SUCCESS) { 499 target_if_err("Invalid 160/80+80 MHz config specified by FW. Take care of it first"); 500 target_if_err("wireless_mode_160mhz: %d, wireless_mode_80p80mhz: %d", 501 wireless_mode_160mhz, wireless_mode_80p80mhz); 502 target_if_err("vhtcap_160mhz: %d, vhtcap_80p80_160mhz: %d,vhtcap_160mhz_sgi: %d", 503 vhtcap_160mhz, vhtcap_80p80_160mhz, 504 vhtcap_160mhz_sgi); 505 } 506 return valid; 507 } 508 509 void init_deinit_chainmask_config( 510 struct wlan_objmgr_psoc *psoc, 511 struct target_psoc_info *tgt_hdl) 512 { 513 tgt_hdl->info.wlan_res_cfg.tx_chain_mask = 514 ((1 << tgt_hdl->info.target_caps.num_rf_chains) - 1); 515 tgt_hdl->info.wlan_res_cfg.rx_chain_mask = 516 ((1 << tgt_hdl->info.target_caps.num_rf_chains) - 1); 517 } 518 519 QDF_STATUS init_deinit_is_service_ext_msg( 520 struct wlan_objmgr_psoc *psoc, 521 struct target_psoc_info *tgt_hdl) 522 { 523 struct common_wmi_handle *wmi_handle; 524 525 if (!tgt_hdl) { 526 target_if_err( 527 "psoc target_psoc_info is null in service ext msg"); 528 return QDF_STATUS_E_INVAL; 529 } 530 531 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 532 533 if (wmi_service_enabled(wmi_handle, wmi_service_ext_msg)) 534 return QDF_STATUS_SUCCESS; 535 else 536 return QDF_STATUS_E_FAILURE; 537 } 538 539 bool init_deinit_is_preferred_hw_mode_supported( 540 struct wlan_objmgr_psoc *psoc, 541 struct target_psoc_info *tgt_hdl) 542 { 543 uint16_t i; 544 struct tgt_info *info; 545 546 if (!tgt_hdl) { 547 target_if_err( 548 "psoc target_psoc_info is null in service ext msg"); 549 return FALSE; 550 } 551 552 info = &tgt_hdl->info; 553 554 if (info->preferred_hw_mode == WMI_HOST_HW_MODE_MAX) 555 return TRUE; 556 557 for (i = 0; i < target_psoc_get_total_mac_phy_cnt(tgt_hdl); i++) { 558 if (info->mac_phy_cap[i].hw_mode_id == info->preferred_hw_mode) 559 return TRUE; 560 } 561 562 return FALSE; 563 } 564 565 void init_deinit_wakeup_host_wait( 566 struct wlan_objmgr_psoc *psoc, 567 struct target_psoc_info *tgt_hdl) 568 { 569 if (!tgt_hdl) { 570 target_if_err("psoc target_psoc_info is null in target ready"); 571 return; 572 } 573 qdf_event_set(&tgt_hdl->info.event); 574 } 575