1 /* 2 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 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: init_cmd_api.c 22 * 23 * WMI Init command prepare & send APIs 24 */ 25 #include <qdf_status.h> 26 #include <qdf_types.h> 27 #include <wlan_objmgr_psoc_obj.h> 28 #include <wlan_objmgr_pdev_obj.h> 29 #include <target_if.h> 30 #include <service_ready_util.h> 31 #include <wlan_tgt_def_config.h> 32 #include <wlan_reg_ucfg_api.h> 33 #include <init_cmd_api.h> 34 #include <target_if_scan.h> 35 #include <target_if_reg.h> 36 #include <target_if_twt.h> 37 38 /** 39 * init_deinit_alloc_host_mem_chunk() - allocates chunk of memory requested 40 * by FW. 41 * @psoc: PSOC object 42 * @tgt_hdl: Target PSOC info 43 * @req_id: request id 44 * @idx: chunk id 45 * @num_units: Number of units 46 * @unit_len: Unit length 47 * @num_unit_info: Num unit info 48 * 49 * API to allocate host memory chunk requested by FW 50 * 51 * Return: num_units on successful allocation 52 * 0 on failure 53 */ 54 static uint32_t init_deinit_alloc_host_mem_chunk(struct wlan_objmgr_psoc *psoc, 55 struct target_psoc_info *tgt_hdl, 56 u_int32_t req_id, u_int32_t idx, u_int32_t num_units, 57 u_int32_t unit_len, u_int32_t num_unit_info) 58 { 59 qdf_dma_addr_t paddr; 60 uint32_t ichunk = 0; 61 struct tgt_info *info; 62 qdf_device_t qdf_dev; 63 64 info = (&tgt_hdl->info); 65 66 if (!num_units || !unit_len) 67 return 0; 68 69 qdf_dev = wlan_psoc_get_qdf_dev(psoc); 70 if (!qdf_dev) 71 return 0; 72 73 /* 74 * We have skip smaller chunks memory allocation for TXBF_CV and 75 * CFR_CAPTURE buffer as Firmware is expecting continuous memory 76 */ 77 if (!((num_unit_info & HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) && 78 (req_id == TXBF_CV_POOL0 || req_id == TXBF_CV_POOL1 || 79 req_id == TXBF_CV_POOL2 || 80 req_id == CFR_CAPTURE_HOST_MEM_REQ_ID))) { 81 ichunk = ((num_units * unit_len) >> 82 HOST_MEM_CHUNK_MAX_SIZE_POWER2); 83 if (ichunk) 84 num_units = num_units / (ichunk + 1); 85 } 86 87 info->mem_chunks[idx].vaddr = NULL; 88 /* reduce the requested allocation by half until allocation succeeds */ 89 while (!info->mem_chunks[idx].vaddr && num_units) { 90 info->mem_chunks[idx].vaddr = qdf_mem_alloc_consistent(qdf_dev, 91 qdf_dev->dev, num_units * unit_len, &paddr); 92 if (!info->mem_chunks[idx].vaddr) { 93 if (num_unit_info & 94 HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) { 95 num_units = 0; 96 target_if_err("mem chink alloc failed for %d", 97 idx); 98 break; 99 } 100 /* reduce length by half */ 101 num_units = (num_units >> 1); 102 } else { 103 info->mem_chunks[idx].paddr = paddr; 104 info->mem_chunks[idx].len = num_units*unit_len; 105 info->mem_chunks[idx].req_id = req_id; 106 } 107 } 108 target_if_debug("req_id %d idx %d num_units %d unit_len %d", 109 req_id, idx, num_units, unit_len); 110 111 return num_units; 112 } 113 114 /* Host mem size units, it is used for round-off */ 115 #define HOST_MEM_SIZE_UNIT 4 116 117 /** 118 * init_deinit_alloc_host_mem() - allocates amount of memory requested by FW. 119 * @psoc: PSOC object 120 * @tgt_hdl: Target PSOC info 121 * @req_id: request id 122 * @num_units: Number of units 123 * @unit_len: Unit length 124 * @num_unit_info: Num unit info 125 * 126 * API to allocate host memory requested by FW 127 * 128 * Return: QDF_STATUS_SUCCESS on successful allocation 129 * QDF_STATUS_E_FAILURE on failure 130 */ 131 static QDF_STATUS init_deinit_alloc_host_mem(struct wlan_objmgr_psoc *psoc, 132 struct target_psoc_info *tgt_hdl, u_int32_t req_id, 133 u_int32_t num_units, u_int32_t unit_len, 134 u_int32_t num_unit_info) 135 { 136 struct tgt_info *info; 137 uint32_t remaining_units; 138 uint32_t allocated_units = 0; 139 uint32_t idx; 140 141 info = (&tgt_hdl->info); 142 /* adjust the length to nearest multiple of unit size */ 143 unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) & 144 (~(HOST_MEM_SIZE_UNIT - 1)); 145 idx = info->num_mem_chunks; 146 remaining_units = num_units; 147 148 while (remaining_units) { 149 if (idx == MAX_MEM_CHUNKS) { 150 target_if_err( 151 "REACHED MAX CHUNK LIMIT for mem units %d", 152 num_units); 153 target_if_err( 154 "unit len %d requested by FW, only allocated %d", 155 unit_len, (num_units - remaining_units)); 156 info->num_mem_chunks = idx; 157 return QDF_STATUS_E_FAILURE; 158 } 159 160 if ((tgt_hdl->tif_ops) && 161 (tgt_hdl->tif_ops->mem_mgr_alloc_chunk)) 162 allocated_units = tgt_hdl->tif_ops->mem_mgr_alloc_chunk( 163 psoc, tgt_hdl, req_id, idx, 164 remaining_units, 165 unit_len, num_unit_info); 166 else 167 allocated_units = init_deinit_alloc_host_mem_chunk( 168 psoc, tgt_hdl, req_id, idx, 169 remaining_units, 170 unit_len, num_unit_info); 171 if (allocated_units == 0) { 172 target_if_err("FAILED TO ALLOC mem unit len %d", 173 unit_len); 174 target_if_err("units requested %d units allocated %d", 175 num_units, (num_units - remaining_units)); 176 info->num_mem_chunks = idx; 177 return QDF_STATUS_E_NOMEM; 178 } 179 remaining_units -= allocated_units; 180 ++idx; 181 } 182 info->num_mem_chunks = idx; 183 184 return QDF_STATUS_SUCCESS; 185 } 186 187 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc, 188 struct target_psoc_info *tgt_hdl) 189 { 190 struct tgt_info *info; 191 qdf_device_t qdf_dev; 192 uint32_t idx; 193 QDF_STATUS status; 194 195 if (!tgt_hdl) { 196 target_if_err("target_psoc_info is null"); 197 return QDF_STATUS_E_INVAL; 198 } 199 200 if ((tgt_hdl->tif_ops) && 201 (tgt_hdl->tif_ops->mem_mgr_free_chunks)) { 202 status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl); 203 } else { 204 qdf_dev = wlan_psoc_get_qdf_dev(psoc); 205 if (!qdf_dev) { 206 target_if_err("qdf_dev is null"); 207 QDF_BUG(0); 208 return QDF_STATUS_E_INVAL; 209 } 210 info = (&tgt_hdl->info); 211 for (idx = 0; idx < info->num_mem_chunks; idx++) { 212 qdf_mem_free_consistent( 213 qdf_dev, qdf_dev->dev, 214 info->mem_chunks[idx].len, 215 info->mem_chunks[idx].vaddr, 216 info->mem_chunks[idx].paddr, 217 qdf_get_dma_mem_context( 218 (&info->mem_chunks[idx]), memctx)); 219 220 info->mem_chunks[idx].vaddr = NULL; 221 info->mem_chunks[idx].paddr = 0; 222 info->mem_chunks[idx].len = 0; 223 } 224 info->num_mem_chunks = 0; 225 status = QDF_STATUS_SUCCESS; 226 } 227 228 return status; 229 } 230 231 QDF_STATUS init_deinit_handle_host_mem_req( 232 struct wlan_objmgr_psoc *psoc, 233 struct target_psoc_info *tgt_hdl, uint8_t *event) 234 { 235 uint32_t num_mem_reqs; 236 host_mem_req mem_reqs; 237 uint32_t i; 238 uint32_t idx; 239 QDF_STATUS status = QDF_STATUS_SUCCESS; 240 struct wmi_unified *wmi_handle; 241 struct tgt_info *info; 242 243 if (!tgt_hdl) { 244 target_if_err("target_psoc_info is null"); 245 return QDF_STATUS_E_INVAL; 246 } 247 248 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 249 info = (&tgt_hdl->info); 250 251 num_mem_reqs = wmi_extract_num_mem_reqs_from_service_ready( 252 wmi_handle, event); 253 if (!num_mem_reqs) 254 return QDF_STATUS_SUCCESS; 255 256 if (num_mem_reqs > MAX_MEM_CHUNKS) { 257 target_if_err_rl("num_mem_reqs:%u is out of bounds", 258 num_mem_reqs); 259 return QDF_STATUS_E_FAILURE; 260 } 261 262 for (i = 0; i < WMI_FW_PRIORITY_MAX; i++) { 263 for (idx = 0; idx < num_mem_reqs; idx++) { 264 status = wmi_extract_host_mem_req_from_service_ready( 265 wmi_handle, event, &mem_reqs, 266 info->wlan_res_cfg.num_active_peers, 267 info->wlan_res_cfg.num_peers, i, idx); 268 if (mem_reqs.tgt_num_units) { 269 status = init_deinit_alloc_host_mem( 270 psoc, 271 tgt_hdl, 272 mem_reqs.req_id, 273 mem_reqs.tgt_num_units, 274 mem_reqs.unit_size, 275 mem_reqs.num_unit_info); 276 if (status == QDF_STATUS_E_FAILURE) { 277 target_if_err("num_mem_chunk exceeds supp number"); 278 } else if (status == QDF_STATUS_E_NOMEM) { 279 target_if_err("mem alloc failure"); 280 } 281 } 282 283 if (status != QDF_STATUS_SUCCESS) 284 return status; 285 } 286 } 287 288 return status; 289 } 290 291 #ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT 292 /** 293 * is_num_band_to_mac_required() - host needs to configure MACs or not. 294 * @tgt_hdl: Pointer to target handle 295 * 296 * if num of mac per band is sent by host then FW will not initialize 297 * its data structure with its default value. Host either have to set 298 * these value as per current HW mode or else these variable should be 299 * initialized to 0. 300 * Ex - If host is sending default HW mode as DBS in INIT_CMDID and FW 301 * doesn't advertise wmi_service_dual_band_simultaneous_support then host 302 * must not configure MACs and FW should configure with default values. 303 * 304 * @return: true if host needs to configure MACs else false 305 */ 306 static bool is_num_band_to_mac_required(struct target_psoc_info *tgt_hdl) 307 { 308 struct tgt_info *info; 309 struct wmi_unified *wmi_handle; 310 311 if (!tgt_hdl) 312 return true; 313 314 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 315 info = (&tgt_hdl->info); 316 317 if ((info->hw_modes.num_modes == 1) && 318 (info->hw_modes.hw_mode_ids[0] == WMI_HOST_HW_MODE_DBS) && 319 !wmi_service_enabled(wmi_handle, 320 wmi_service_dual_band_simultaneous_support)) 321 return false; 322 323 return true; 324 } 325 #else 326 static bool is_num_band_to_mac_required(struct target_psoc_info *tgt_hdl) 327 { 328 return true; 329 } 330 #endif 331 332 void init_deinit_derive_band_to_mac_param( 333 struct wlan_objmgr_psoc *psoc, 334 struct target_psoc_info *tgt_hdl, 335 struct wmi_init_cmd_param *init_param) 336 { 337 uint8_t i; 338 struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; 339 struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap; 340 struct wmi_host_pdev_band_to_mac *band_to_mac = init_param->band_to_mac; 341 342 if (!tgt_hdl) { 343 target_if_err("target_psoc_info is null "); 344 return; 345 } 346 347 reg_cap = ucfg_reg_get_hal_reg_cap(psoc); 348 if (!reg_cap) { 349 target_if_err("reg cap is NULL"); 350 return; 351 } 352 353 mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); 354 if (!mac_phy_cap) { 355 target_if_err("mac_phy_cap is NULL"); 356 return; 357 } 358 if (is_num_band_to_mac_required(tgt_hdl)) 359 init_param->num_band_to_mac = 360 target_psoc_get_num_radios(tgt_hdl); 361 362 for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) { 363 if (mac_phy_cap->supported_bands == 364 (WMI_HOST_WLAN_5G_CAPABILITY | 365 WMI_HOST_WLAN_2G_CAPABILITY)) { 366 /*Supports both 5G and 2G. Use freq from both radios*/ 367 target_if_debug("Supports both 2G and 5G"); 368 band_to_mac[i].pdev_id = mac_phy_cap->pdev_id; 369 band_to_mac[i].start_freq = 370 reg_cap[i].low_2ghz_chan; 371 band_to_mac[i].end_freq = 372 reg_cap[i].high_5ghz_chan; 373 374 } else if (mac_phy_cap->supported_bands == 375 WMI_HOST_WLAN_2G_CAPABILITY) { 376 reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0; 377 reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0; 378 379 if (!init_param->num_band_to_mac) 380 goto next_mac_phy_cap; 381 382 band_to_mac[i].pdev_id = mac_phy_cap->pdev_id; 383 band_to_mac[i].start_freq = 384 reg_cap[i].low_2ghz_chan; 385 band_to_mac[i].end_freq = 386 reg_cap[i].high_2ghz_chan; 387 target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d", 388 band_to_mac[i].pdev_id, 389 band_to_mac[i].start_freq, 390 band_to_mac[i].end_freq); 391 392 } else if (mac_phy_cap->supported_bands == 393 WMI_HOST_WLAN_5G_CAPABILITY) { 394 reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0; 395 reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0; 396 397 if (!init_param->num_band_to_mac) 398 goto next_mac_phy_cap; 399 400 band_to_mac[i].pdev_id = mac_phy_cap->pdev_id; 401 band_to_mac[i].start_freq = 402 reg_cap[i].low_5ghz_chan; 403 band_to_mac[i].end_freq = 404 reg_cap[i].high_5ghz_chan; 405 406 target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n", 407 band_to_mac[i].pdev_id, 408 band_to_mac[i].start_freq, 409 band_to_mac[i].end_freq); 410 } 411 412 next_mac_phy_cap: 413 mac_phy_cap++; 414 } 415 } 416 417 #if defined(CONFIG_AFC_SUPPORT) 418 /** 419 * init_deinit_derive_afc_dev_type_param() - Derive AFC init deployment param 420 * 421 * @psoc: PSOC object 422 * @init_param: Pointer to init param 423 * 424 * Return: void 425 */ 426 static void init_deinit_derive_afc_dev_type_param( 427 struct wlan_objmgr_psoc *psoc, 428 struct wmi_init_cmd_param *init_param) 429 { 430 enum reg_afc_dev_deploy_type reg_afc_dev_type; 431 target_resource_config *tgt_cfg; 432 QDF_STATUS ret_val; 433 434 tgt_cfg = init_param->res_cfg; 435 436 ret_val = target_if_reg_get_afc_dev_type(psoc, 437 ®_afc_dev_type); 438 439 if (QDF_IS_STATUS_ERROR(ret_val)) { 440 target_if_err("get afc dev type failed"); 441 return; 442 } 443 tgt_cfg->afc_indoor_support = false; 444 tgt_cfg->afc_outdoor_support = false; 445 if (reg_afc_dev_type == AFC_DEPLOYMENT_INDOOR) 446 tgt_cfg->afc_indoor_support = true; 447 else if (reg_afc_dev_type == AFC_DEPLOYMENT_OUTDOOR) 448 tgt_cfg->afc_outdoor_support = true; 449 } 450 #else 451 static inline void init_deinit_derive_afc_dev_type_param( 452 struct wlan_objmgr_psoc *psoc, 453 struct wmi_init_cmd_param *init_param) 454 { 455 } 456 #endif 457 458 void init_deinit_prepare_send_init_cmd( 459 struct wlan_objmgr_psoc *psoc, 460 struct target_psoc_info *tgt_hdl) 461 { 462 struct wmi_init_cmd_param init_param = {0}; 463 struct tgt_info *info; 464 struct wmi_unified *wmi_handle; 465 QDF_STATUS ret_val; 466 uint32_t fw_build_vers_ext; 467 468 if (!tgt_hdl) { 469 target_if_err("target_psoc_info is null"); 470 return; 471 } 472 473 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 474 info = (&tgt_hdl->info); 475 476 init_param.res_cfg = &info->wlan_res_cfg; 477 init_param.num_mem_chunks = info->num_mem_chunks; 478 init_param.mem_chunks = info->mem_chunks; 479 480 if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == 481 QDF_STATUS_SUCCESS) { 482 init_param.hw_mode_id = info->preferred_hw_mode; 483 /* Temp change, until FW submits support for handling this TLV 484 * For single mode, skip sending hw_mode 485 */ 486 if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE) 487 init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX; 488 489 init_deinit_derive_band_to_mac_param(psoc, tgt_hdl, 490 &init_param); 491 } else { 492 ret_val = tgt_if_regulatory_modify_freq_range(psoc); 493 if (QDF_IS_STATUS_ERROR(ret_val)) { 494 target_if_err("Modify freq range is failed"); 495 return; 496 } 497 } 498 499 ret_val = target_if_alloc_pdevs(psoc, tgt_hdl); 500 if (ret_val != QDF_STATUS_SUCCESS) 501 return; 502 503 ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl); 504 if (ret_val != QDF_STATUS_SUCCESS) 505 return; 506 507 info->wlan_res_cfg.max_ndp_sessions = 508 QDF_MIN(info->wlan_res_cfg.max_ndp_sessions, 509 info->service_ext2_param.max_ndp_sessions); 510 511 if (info->service_ext2_param.twt_ack_support_cap) { 512 info->wlan_res_cfg.twt_ack_support_cap = true; 513 target_if_twt_set_twt_ack_support(psoc, true); 514 } 515 516 info->wlan_res_cfg.target_cap_flags = 517 target_psoc_get_target_cap_flags(tgt_hdl); 518 519 target_if_debug("FW version 0x%x ", info->target_caps.fw_version); 520 if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == 521 QDF_STATUS_SUCCESS) { 522 fw_build_vers_ext = info->service_ext_param.fw_build_vers_ext; 523 target_if_debug("fw_build_vers_ext:0x%x HDL version info:0x%0x, CRM sub ID:0x%x\n", 524 fw_build_vers_ext, fw_build_vers_ext & 0x3FF, 525 (fw_build_vers_ext >> 25) & 0x7F); 526 } else { 527 target_if_debug("0x%x\n", info->target_caps.fw_version_1); 528 } 529 530 if (wmi_service_enabled(wmi_handle, wmi_service_ext2_msg)) 531 init_deinit_derive_afc_dev_type_param(psoc, &init_param); 532 533 target_if_ext_res_cfg_enable(psoc, tgt_hdl, NULL); 534 535 target_if_set_reo_shared_qref_feature(psoc, info); 536 537 wmi_unified_init_cmd_send(wmi_handle, &init_param); 538 539 /* Set Max scans allowed */ 540 target_if_scan_set_max_active_scans(psoc, 541 WLAN_MAX_ACTIVE_SCANS_ALLOWED); 542 543 if (wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support)) 544 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_HW_DB2DBM); 545 } 546