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