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