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