1 /* 2 * Copyright (c) 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 /** 20 * DOC: init_event_handler.c 21 * 22 * WMI common event handler implementation source file 23 */ 24 25 #include <qdf_status.h> 26 #include <wlan_objmgr_psoc_obj.h> 27 #include <wlan_objmgr_pdev_obj.h> 28 #include <target_if.h> 29 #include <target_if_reg.h> 30 #include <init_event_handler.h> 31 #include <service_ready_util.h> 32 #include <service_ready_param.h> 33 #include <init_cmd_api.h> 34 #include <cdp_txrx_cmn.h> 35 36 static int init_deinit_service_ready_event_handler(ol_scn_t scn_handle, 37 uint8_t *event, 38 uint32_t data_len) 39 { 40 int err_code; 41 struct wlan_objmgr_psoc *psoc; 42 struct target_psoc_info *tgt_hdl; 43 wmi_legacy_service_ready_callback legacy_callback; 44 struct common_wmi_handle *wmi_handle; 45 QDF_STATUS ret_val; 46 47 if (!scn_handle) { 48 target_if_err("scn handle NULL in service ready handler"); 49 return -EINVAL; 50 } 51 52 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 53 if (!psoc) { 54 target_if_err("psoc is null in service ready handler"); 55 return -EINVAL; 56 } 57 58 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 59 psoc); 60 if (!tgt_hdl) { 61 target_if_err("target_psoc_info is null in service ready ev"); 62 return -EINVAL; 63 } 64 65 ret_val = target_if_sw_version_check(psoc, tgt_hdl, event); 66 67 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 68 69 err_code = init_deinit_populate_service_bitmap(wmi_handle, event, 70 tgt_hdl->info.service_bitmap); 71 if (err_code) 72 goto exit; 73 74 err_code = init_deinit_populate_fw_version_cmd(wmi_handle, event); 75 if (err_code) 76 goto exit; 77 78 err_code = init_deinit_populate_target_cap(wmi_handle, event, 79 &(tgt_hdl->info.target_caps)); 80 if (err_code) 81 goto exit; 82 83 err_code = init_deinit_populate_phy_reg_cap(psoc, wmi_handle, event, 84 &(tgt_hdl->info), true); 85 if (err_code) 86 goto exit; 87 88 if (init_deinit_validate_160_80p80_fw_caps(psoc, tgt_hdl) != 89 QDF_STATUS_SUCCESS) { 90 wlan_psoc_nif_op_flag_set(psoc, WLAN_SOC_OP_VHT_INVALID_CAP); 91 } 92 93 target_if_ext_res_cfg_enable(psoc, tgt_hdl, event); 94 95 if (wmi_service_enabled(wmi_handle, wmi_service_tt)) 96 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_TT_SUPPORT); 97 98 if (wmi_service_enabled(wmi_handle, wmi_service_widebw_scan)) 99 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_WIDEBAND_SCAN); 100 101 if (wmi_service_enabled(wmi_handle, wmi_service_check_cal_version)) 102 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_SW_CAL); 103 104 if (wmi_service_enabled(wmi_handle, wmi_service_twt_requestor)) 105 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_TWT_REQUESTER); 106 107 if (wmi_service_enabled(wmi_handle, wmi_service_twt_responder)) 108 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_TWT_RESPONDER); 109 110 target_if_debug(" TT support %d, Wide BW Scan %d, SW cal %d", 111 wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_CEXT_TT_SUPPORT), 112 wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_CEXT_WIDEBAND_SCAN), 113 wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_CEXT_SW_CAL)); 114 115 target_if_mesh_support_enable(psoc, tgt_hdl, event); 116 117 target_if_smart_antenna_enable(psoc, tgt_hdl, event); 118 119 target_if_peer_cfg_enable(psoc, tgt_hdl, event); 120 121 target_if_atf_cfg_enable(psoc, tgt_hdl, event); 122 123 target_if_qwrap_cfg_enable(psoc, tgt_hdl, event); 124 125 target_if_lteu_cfg_enable(psoc, tgt_hdl, event); 126 127 /* override derived value, if it exceeds max peer count */ 128 if ((wlan_psoc_get_max_peer_count(psoc) > 129 tgt_hdl->info.wlan_res_cfg.num_active_peers) && 130 (wlan_psoc_get_max_peer_count(psoc) < 131 (tgt_hdl->info.wlan_res_cfg.num_peers - 132 tgt_hdl->info.wlan_res_cfg.num_vdevs))) { 133 tgt_hdl->info.wlan_res_cfg.num_peers = 134 wlan_psoc_get_max_peer_count(psoc) + 135 tgt_hdl->info.wlan_res_cfg.num_vdevs; 136 } 137 legacy_callback = target_if_get_psoc_legacy_service_ready_cb(); 138 if (!legacy_callback) { 139 err_code = -EINVAL; 140 goto exit; 141 } 142 143 err_code = legacy_callback(wmi_service_ready_event_id, 144 scn_handle, event, data_len); 145 init_deinit_chainmask_config(psoc, tgt_hdl); 146 147 if (wmi_service_enabled(wmi_handle, wmi_service_mgmt_tx_wmi)) { 148 wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_WMI_MGMT_REF); 149 target_if_debug("WMI mgmt service enabled"); 150 } else { 151 wlan_psoc_nif_fw_ext_cap_clear(psoc, 152 WLAN_SOC_CEXT_WMI_MGMT_REF); 153 target_if_debug("WMI mgmt service disabled"); 154 } 155 156 err_code = init_deinit_handle_host_mem_req(psoc, tgt_hdl, event); 157 if (err_code != QDF_STATUS_SUCCESS) 158 goto exit; 159 160 target_if_reg_set_offloaded_info(psoc); 161 if (!wmi_service_enabled(wmi_handle, wmi_service_ext_msg)) { 162 target_if_debug("No EXT message, send init command"); 163 tgt_hdl->info.wmi_service_ready = TRUE; 164 target_psoc_set_num_radios(tgt_hdl, 1); 165 /* send init command */ 166 init_deinit_prepare_send_init_cmd(psoc, tgt_hdl); 167 } else { 168 target_if_debug("Wait for EXT message"); 169 } 170 171 target_if_smart_log_enable(psoc, tgt_hdl, event); 172 exit: 173 return err_code; 174 } 175 176 static int init_deinit_service_ext_ready_event_handler(ol_scn_t scn_handle, 177 uint8_t *event, 178 uint32_t data_len) 179 { 180 int err_code; 181 struct wlan_objmgr_psoc *psoc; 182 struct target_psoc_info *tgt_hdl; 183 struct common_wmi_handle *wmi_handle; 184 struct tgt_info *info; 185 wmi_legacy_service_ready_callback legacy_callback; 186 187 if (!scn_handle) { 188 target_if_err("scn handle NULL in service ready handler"); 189 return -EINVAL; 190 } 191 192 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 193 if (!psoc) { 194 target_if_err("psoc is null in service ready handler"); 195 return -EINVAL; 196 } 197 198 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 199 psoc); 200 if (!tgt_hdl) { 201 target_if_err("target_psoc_info is null in service ready ev"); 202 return -EINVAL; 203 } 204 205 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 206 info = (&tgt_hdl->info); 207 208 err_code = init_deinit_populate_service_ready_ext_param(wmi_handle, 209 event, &(info->service_ext_param)); 210 if (err_code) 211 goto exit; 212 213 target_psoc_set_num_radios(tgt_hdl, 0); 214 err_code = init_deinit_populate_hw_mode_capability(wmi_handle, 215 event, tgt_hdl); 216 if (err_code) 217 goto exit; 218 219 if (init_deinit_is_preferred_hw_mode_supported(psoc, tgt_hdl) 220 == FALSE) 221 return -EINVAL; 222 223 target_if_print_service_ready_ext_param(psoc, tgt_hdl); 224 225 err_code = init_deinit_populate_phy_reg_cap(psoc, wmi_handle, 226 event, info, false); 227 if (err_code) 228 goto exit; 229 230 target_if_add_11ax_modes(psoc, tgt_hdl); 231 232 if (init_deinit_chainmask_table_alloc( 233 &(info->service_ext_param)) == 234 QDF_STATUS_SUCCESS) { 235 err_code = init_deinit_populate_chainmask_tables(wmi_handle, 236 event, 237 &(info->service_ext_param.chainmask_table[0])); 238 if (err_code) 239 goto exit; 240 } 241 242 err_code = init_deinit_populate_dbr_ring_cap(psoc, wmi_handle, 243 event, info); 244 if (err_code) 245 goto exit; 246 247 legacy_callback = target_if_get_psoc_legacy_service_ready_cb(); 248 if (legacy_callback) 249 legacy_callback(wmi_service_ready_ext_event_id, 250 scn_handle, event, data_len); 251 252 info->wlan_res_cfg.num_vdevs = (target_psoc_get_num_radios(tgt_hdl) * 253 info->wlan_res_cfg.num_vdevs); 254 info->wlan_res_cfg.beacon_tx_offload_max_vdev = 255 (target_psoc_get_num_radios(tgt_hdl) * 256 info->wlan_res_cfg.beacon_tx_offload_max_vdev); 257 258 info->wmi_service_ready = TRUE; 259 260 init_deinit_prepare_send_init_cmd(psoc, tgt_hdl); 261 262 exit: 263 return err_code; 264 } 265 266 static int init_deinit_service_available_handler(ol_scn_t scn_handle, 267 uint8_t *event, 268 uint32_t data_len) 269 { 270 struct wlan_objmgr_psoc *psoc; 271 struct target_psoc_info *tgt_hdl; 272 struct common_wmi_handle *wmi_handle; 273 274 if (!scn_handle) { 275 target_if_err("scn handle NULL"); 276 return -EINVAL; 277 } 278 279 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 280 if (!psoc) { 281 target_if_err("psoc is null"); 282 return -EINVAL; 283 } 284 285 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 286 psoc); 287 if (!tgt_hdl) { 288 target_if_err("target_psoc_info is null"); 289 return -EINVAL; 290 } 291 292 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 293 294 if (wmi_save_ext_service_bitmap(wmi_handle, event, NULL) != 295 QDF_STATUS_SUCCESS) { 296 target_if_err("Failed to save ext service bitmap"); 297 return -EINVAL; 298 } 299 300 return 0; 301 } 302 303 /* MAC address fourth byte index */ 304 #define MAC_BYTE_4 4 305 306 static int init_deinit_ready_event_handler(ol_scn_t scn_handle, 307 uint8_t *event, 308 uint32_t data_len) 309 { 310 struct wlan_objmgr_psoc *psoc; 311 struct wlan_objmgr_pdev *pdev; 312 struct target_psoc_info *tgt_hdl; 313 struct common_wmi_handle *wmi_handle; 314 struct wmi_host_fw_abi_ver fw_ver; 315 uint8_t myaddr[QDF_MAC_ADDR_SIZE]; 316 struct tgt_info *info; 317 struct wmi_host_ready_ev_param ready_ev; 318 wmi_legacy_service_ready_callback legacy_callback; 319 uint8_t num_radios, i; 320 uint32_t max_peers; 321 322 if (!scn_handle) { 323 target_if_err("scn handle NULL"); 324 return -EINVAL; 325 } 326 327 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 328 if (!psoc) { 329 target_if_err("psoc is null"); 330 return -EINVAL; 331 } 332 333 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 334 psoc); 335 if (!tgt_hdl) { 336 target_if_err("target_psoc_info is null"); 337 return -EINVAL; 338 } 339 340 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 341 info = (&tgt_hdl->info); 342 343 if (wmi_extract_fw_abi_version(wmi_handle, event, &fw_ver) == 344 QDF_STATUS_SUCCESS) { 345 info->version.wlan_ver = fw_ver.sw_version; 346 info->version.wlan_ver = fw_ver.abi_version; 347 } 348 349 if (wmi_check_and_update_fw_version(wmi_handle, event) < 0) { 350 target_if_err("Version mismatch with FW"); 351 return -EINVAL; 352 } 353 354 if (wmi_extract_ready_event_params(wmi_handle, event, &ready_ev) != 355 QDF_STATUS_SUCCESS) { 356 target_if_err("Failed to extract ready event"); 357 return -EINVAL; 358 } 359 360 if ((ready_ev.num_total_peer != 0) && 361 (info->wlan_res_cfg.num_peers != ready_ev.num_total_peer)) { 362 /* FW allocated number of peers is different than host 363 * requested. Update host max with FW reported value. 364 */ 365 target_if_err("Host Requested %d peers. FW Supports %d peers", 366 info->wlan_res_cfg.num_peers, 367 ready_ev.num_total_peer); 368 info->wlan_res_cfg.num_peers = ready_ev.num_total_peer; 369 } 370 371 /* for non legacy num_total_peer will be non zero 372 * allocate peer memory in this case 373 */ 374 if (ready_ev.num_total_peer != 0) { 375 max_peers = info->wlan_res_cfg.num_peers + 376 ready_ev.num_extra_peer + 1; 377 378 cdp_peer_map_attach(wlan_psoc_get_dp_handle(psoc), max_peers); 379 } 380 381 /* Indicate to the waiting thread that the ready 382 * event was received 383 */ 384 info->wlan_init_status = wmi_ready_extract_init_status( 385 wmi_handle, event); 386 387 legacy_callback = target_if_get_psoc_legacy_service_ready_cb(); 388 if (legacy_callback) 389 legacy_callback(wmi_ready_event_id, 390 scn_handle, event, data_len); 391 392 num_radios = target_psoc_get_num_radios(tgt_hdl); 393 /* 394 * For non-legacy HW, MAC addr list is extracted. 395 */ 396 if (num_radios > 1) { 397 uint8_t num_mac_addr; 398 wmi_host_mac_addr *addr_list; 399 int i; 400 401 addr_list = wmi_ready_extract_mac_addr_list(wmi_handle, event, 402 &num_mac_addr); 403 if ((num_mac_addr >= num_radios) && (addr_list)) { 404 for (i = 0; i < num_radios; i++) { 405 WMI_HOST_MAC_ADDR_TO_CHAR_ARRAY(&addr_list[i], 406 myaddr); 407 pdev = wlan_objmgr_get_pdev_by_id(psoc, i, 408 WLAN_INIT_DEINIT_ID); 409 if (!pdev) { 410 target_if_err(" PDEV %d is NULL", i); 411 return -EINVAL; 412 } 413 wlan_pdev_set_hw_macaddr(pdev, myaddr); 414 wlan_objmgr_pdev_release_ref(pdev, 415 WLAN_INIT_DEINIT_ID); 416 417 /* assign 1st radio addr to psoc */ 418 if (i == 0) 419 wlan_psoc_set_hw_macaddr(psoc, myaddr); 420 } 421 goto out; 422 } else { 423 target_if_err("Using default MAC addr for all radios.."); 424 } 425 } 426 427 /* 428 * We extract single MAC address in two scenarios: 429 * 1. In non-legacy case, if addr list is NULL or num_mac_addr < num_radios 430 * 2. In all legacy cases 431 */ 432 for (i = 0; i < num_radios; i++) { 433 wmi_ready_extract_mac_addr(wmi_handle, event, myaddr); 434 myaddr[MAC_BYTE_4] += i; 435 pdev = wlan_objmgr_get_pdev_by_id(psoc, i, WLAN_INIT_DEINIT_ID); 436 if (!pdev) { 437 target_if_err(" PDEV %d is NULL", i); 438 return -EINVAL; 439 } 440 wlan_pdev_set_hw_macaddr(pdev, myaddr); 441 wlan_objmgr_pdev_release_ref(pdev, WLAN_INIT_DEINIT_ID); 442 /* assign 1st radio addr to psoc */ 443 if (i == 0) 444 wlan_psoc_set_hw_macaddr(psoc, myaddr); 445 } 446 447 out: 448 target_if_btcoex_cfg_enable(psoc, tgt_hdl, event); 449 tgt_hdl->info.wmi_ready = TRUE; 450 init_deinit_wakeup_host_wait(psoc, tgt_hdl); 451 452 return 0; 453 } 454 455 456 QDF_STATUS init_deinit_register_tgt_psoc_ev_handlers( 457 struct wlan_objmgr_psoc *psoc) 458 { 459 struct target_psoc_info *tgt_hdl; 460 wmi_unified_t wmi_handle; 461 QDF_STATUS retval = QDF_STATUS_SUCCESS; 462 463 if (!psoc) { 464 target_if_err("psoc is null in register wmi handler"); 465 return QDF_STATUS_E_FAILURE; 466 } 467 468 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 469 psoc); 470 if (!tgt_hdl) { 471 target_if_err("target_psoc_info null in register wmi hadler"); 472 return QDF_STATUS_E_FAILURE; 473 } 474 475 wmi_handle = (wmi_unified_t)target_psoc_get_wmi_hdl(tgt_hdl); 476 477 retval = wmi_unified_register_event_handler(wmi_handle, 478 wmi_service_ready_event_id, 479 init_deinit_service_ready_event_handler, 480 WMI_RX_WORK_CTX); 481 retval = wmi_unified_register_event_handler(wmi_handle, 482 wmi_service_ready_ext_event_id, 483 init_deinit_service_ext_ready_event_handler, 484 WMI_RX_WORK_CTX); 485 retval = wmi_unified_register_event_handler(wmi_handle, 486 wmi_service_available_event_id, 487 init_deinit_service_available_handler, 488 WMI_RX_UMAC_CTX); 489 retval = wmi_unified_register_event_handler(wmi_handle, 490 wmi_ready_event_id, 491 init_deinit_ready_event_handler, 492 WMI_RX_WORK_CTX); 493 494 return retval; 495 } 496 497