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 target_if_btcoex_cfg_enable(psoc, tgt_hdl, event); 164 165 exit: 166 return err_code; 167 } 168 169 static int init_deinit_service_ext_ready_event_handler(ol_scn_t scn_handle, 170 uint8_t *event, 171 uint32_t data_len) 172 { 173 int err_code; 174 struct wlan_objmgr_psoc *psoc; 175 struct target_psoc_info *tgt_hdl; 176 void *wmi_handle; 177 struct tgt_info *info; 178 wmi_legacy_service_ready_callback legacy_callback; 179 180 if (!scn_handle) { 181 target_if_err("scn handle NULL in service ready handler"); 182 return -EINVAL; 183 } 184 185 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 186 if (!psoc) { 187 target_if_err("psoc is null in service ready handler"); 188 return -EINVAL; 189 } 190 191 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 192 psoc); 193 if (!tgt_hdl) { 194 target_if_err("target_psoc_info is null in service ready ev"); 195 return -EINVAL; 196 } 197 198 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 199 info = (&tgt_hdl->info); 200 201 err_code = init_deinit_populate_service_ready_ext_param(wmi_handle, 202 event, &(info->service_ext_param)); 203 if (err_code) 204 goto exit; 205 206 target_psoc_set_num_radios(tgt_hdl, 0); 207 err_code = init_deinit_populate_hw_mode_capability(wmi_handle, 208 event, tgt_hdl); 209 if (err_code) 210 goto exit; 211 212 if (init_deinit_is_preferred_hw_mode_supported(psoc, tgt_hdl) 213 == FALSE) 214 return -EINVAL; 215 216 target_if_print_service_ready_ext_param(psoc, tgt_hdl); 217 218 err_code = init_deinit_populate_phy_reg_cap(psoc, wmi_handle, 219 event, info, false); 220 if (err_code) 221 goto exit; 222 223 target_if_add_11ax_modes(psoc, tgt_hdl); 224 225 if (init_deinit_chainmask_table_alloc( 226 &(info->service_ext_param)) == 227 QDF_STATUS_SUCCESS) { 228 err_code = init_deinit_populate_chainmask_tables(wmi_handle, 229 event, 230 &(info->service_ext_param.chainmask_table[0])); 231 if (err_code) 232 goto exit; 233 } 234 235 err_code = init_deinit_populate_dbr_ring_cap(psoc, wmi_handle, 236 event, info); 237 if (err_code) 238 goto exit; 239 240 legacy_callback = target_if_get_psoc_legacy_service_ready_cb(); 241 if (legacy_callback) 242 legacy_callback(wmi_service_ready_ext_event_id, 243 scn_handle, event, data_len); 244 245 info->wlan_res_cfg.num_vdevs = (target_psoc_get_num_radios(tgt_hdl) * 246 info->wlan_res_cfg.num_vdevs); 247 info->wlan_res_cfg.beacon_tx_offload_max_vdev = 248 (target_psoc_get_num_radios(tgt_hdl) * 249 info->wlan_res_cfg.beacon_tx_offload_max_vdev); 250 251 info->wmi_service_ready = TRUE; 252 253 init_deinit_prepare_send_init_cmd(psoc, tgt_hdl); 254 255 exit: 256 return err_code; 257 } 258 259 static int init_deinit_service_available_handler(ol_scn_t scn_handle, 260 uint8_t *event, 261 uint32_t data_len) 262 { 263 struct wlan_objmgr_psoc *psoc; 264 struct target_psoc_info *tgt_hdl; 265 void *wmi_handle; 266 267 if (!scn_handle) { 268 target_if_err("scn handle NULL"); 269 return -EINVAL; 270 } 271 272 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 273 if (!psoc) { 274 target_if_err("psoc is null"); 275 return -EINVAL; 276 } 277 278 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 279 psoc); 280 if (!tgt_hdl) { 281 target_if_err("target_psoc_info is null"); 282 return -EINVAL; 283 } 284 285 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 286 287 if (wmi_save_ext_service_bitmap(wmi_handle, event, NULL) != 288 QDF_STATUS_SUCCESS) { 289 target_if_err("Failed to save ext service bitmap"); 290 return -EINVAL; 291 } 292 293 return 0; 294 } 295 296 /* MAC address fourth byte index */ 297 #define MAC_BYTE_4 4 298 299 static int init_deinit_ready_event_handler(ol_scn_t scn_handle, 300 uint8_t *event, 301 uint32_t data_len) 302 { 303 struct wlan_objmgr_psoc *psoc; 304 struct wlan_objmgr_pdev *pdev; 305 struct target_psoc_info *tgt_hdl; 306 void *wmi_handle; 307 struct wmi_host_fw_abi_ver fw_ver; 308 uint8_t myaddr[QDF_MAC_ADDR_SIZE]; 309 struct tgt_info *info; 310 struct wmi_host_ready_ev_param ready_ev; 311 wmi_legacy_service_ready_callback legacy_callback; 312 uint8_t num_radios, i; 313 314 if (!scn_handle) { 315 target_if_err("scn handle NULL"); 316 return -EINVAL; 317 } 318 319 psoc = target_if_get_psoc_from_scn_hdl(scn_handle); 320 if (!psoc) { 321 target_if_err("psoc is null"); 322 return -EINVAL; 323 } 324 325 tgt_hdl = (struct target_psoc_info *)wlan_psoc_get_tgt_if_handle( 326 psoc); 327 if (!tgt_hdl) { 328 target_if_err("target_psoc_info is null"); 329 return -EINVAL; 330 } 331 332 wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl); 333 info = (&tgt_hdl->info); 334 335 if (wmi_extract_fw_abi_version(wmi_handle, event, &fw_ver) == 336 QDF_STATUS_SUCCESS) { 337 info->version.wlan_ver = fw_ver.sw_version; 338 info->version.wlan_ver = fw_ver.abi_version; 339 } 340 341 if (wmi_check_and_update_fw_version(wmi_handle, event) < 0) { 342 target_if_err("Version mismatch with FW"); 343 return -EINVAL; 344 } 345 346 if (wmi_extract_ready_event_params(wmi_handle, event, &ready_ev) != 347 QDF_STATUS_SUCCESS) { 348 target_if_err("Failed to extract ready event"); 349 return -EINVAL; 350 } 351 352 if ((ready_ev.num_total_peer != 0) && 353 (info->wlan_res_cfg.num_peers != ready_ev.num_total_peer)) { 354 /* FW allocated number of peers is different than host 355 * requested. Update host max with FW reported value. 356 */ 357 target_if_info("Host Requested %d peers. FW Supports %d peers", 358 info->wlan_res_cfg.num_peers, 359 ready_ev.num_total_peer); 360 info->wlan_res_cfg.num_peers = ready_ev.num_total_peer; 361 } 362 363 /* Indicate to the waiting thread that the ready 364 * event was received 365 */ 366 info->wlan_init_status = wmi_ready_extract_init_status( 367 wmi_handle, event); 368 369 legacy_callback = target_if_get_psoc_legacy_service_ready_cb(); 370 if (legacy_callback) 371 legacy_callback(wmi_ready_event_id, 372 scn_handle, event, data_len); 373 374 num_radios = target_psoc_get_num_radios(tgt_hdl); 375 /* 376 * For non-legacy HW, MAC addr list is extracted. 377 */ 378 if (num_radios > 1) { 379 uint8_t num_mac_addr; 380 wmi_host_mac_addr *addr_list; 381 int i; 382 383 addr_list = wmi_ready_extract_mac_addr_list(wmi_handle, event, 384 &num_mac_addr); 385 if ((num_mac_addr >= num_radios) && (addr_list)) { 386 for (i = 0; i < num_radios; i++) { 387 WMI_HOST_MAC_ADDR_TO_CHAR_ARRAY(&addr_list[i], 388 myaddr); 389 pdev = wlan_objmgr_get_pdev_by_id(psoc, i, 390 WLAN_INIT_DEINIT_ID); 391 if (!pdev) { 392 target_if_err(" PDEV %d is NULL", i); 393 return -EINVAL; 394 } 395 wlan_pdev_set_hw_macaddr(pdev, myaddr); 396 wlan_objmgr_pdev_release_ref(pdev, 397 WLAN_INIT_DEINIT_ID); 398 399 /* assign 1st radio addr to psoc */ 400 if (i == 0) 401 wlan_psoc_set_hw_macaddr(psoc, myaddr); 402 } 403 goto out; 404 } else { 405 target_if_err("Using default MAC addr for all radios.."); 406 } 407 } 408 409 /* 410 * We extract single MAC address in two scenarios: 411 * 1. In non-legacy case, if addr list is NULL or num_mac_addr < num_radios 412 * 2. In all legacy cases 413 */ 414 for (i = 0; i < num_radios; i++) { 415 wmi_ready_extract_mac_addr(wmi_handle, event, myaddr); 416 myaddr[MAC_BYTE_4] += i; 417 pdev = wlan_objmgr_get_pdev_by_id(psoc, i, 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, WLAN_INIT_DEINIT_ID); 424 /* assign 1st radio addr to psoc */ 425 if (i == 0) 426 wlan_psoc_set_hw_macaddr(psoc, myaddr); 427 } 428 429 out: 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