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