1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 */ 6 7 #include <linux/module.h> 8 #include <linux/soc/qcom/qmi.h> 9 10 #include "bus.h" 11 #include "debug.h" 12 #include "main.h" 13 #include "qmi.h" 14 #include "genl.h" 15 16 #define WLFW_SERVICE_INS_ID_V01 1 17 #define WLFW_CLIENT_ID 0x4b4e454c 18 #define BDF_FILE_NAME_PREFIX "bdwlan" 19 #define ELF_BDF_FILE_NAME "bdwlan.elf" 20 #define ELF_BDF_FILE_NAME_GF "bdwlang.elf" 21 #define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e" 22 #define ELF_BDF_FILE_NAME_GF_PREFIX "bdwlang.e" 23 #define BIN_BDF_FILE_NAME "bdwlan.bin" 24 #define BIN_BDF_FILE_NAME_GF "bdwlang.bin" 25 #define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b" 26 #define BIN_BDF_FILE_NAME_GF_PREFIX "bdwlang.b" 27 #define REGDB_FILE_NAME "regdb.bin" 28 #define HDS_FILE_NAME "hds.bin" 29 #define CHIP_ID_GF_MASK 0x10 30 31 #define CONN_ROAM_FILE_NAME "wlan-connection-roaming" 32 #define INI_EXT ".ini" 33 #define INI_FILE_NAME_LEN 100 34 35 #define QDSS_TRACE_CONFIG_FILE "qdss_trace_config" 36 #ifdef CONFIG_CNSS2_DEBUG 37 #define QDSS_DEBUG_FILE_STR "debug_" 38 #else 39 #define QDSS_DEBUG_FILE_STR "" 40 #endif 41 #define HW_V1_NUMBER "v1" 42 #define HW_V2_NUMBER "v2" 43 44 #define QMI_WLFW_TIMEOUT_MS (plat_priv->ctrl_params.qmi_timeout) 45 #define QMI_WLFW_TIMEOUT_JF msecs_to_jiffies(QMI_WLFW_TIMEOUT_MS) 46 #define COEX_TIMEOUT QMI_WLFW_TIMEOUT_JF 47 #define IMS_TIMEOUT QMI_WLFW_TIMEOUT_JF 48 49 #define QMI_WLFW_MAX_RECV_BUF_SIZE SZ_8K 50 #define IMSPRIVATE_SERVICE_MAX_MSG_LEN SZ_8K 51 #define DMS_QMI_MAX_MSG_LEN SZ_256 52 #define MAX_SHADOW_REG_RESERVED 2 53 #define MAX_NUM_SHADOW_REG_V3 (QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 - \ 54 MAX_SHADOW_REG_RESERVED) 55 56 #define QMI_WLFW_MAC_READY_TIMEOUT_MS 50 57 #define QMI_WLFW_MAC_READY_MAX_RETRY 200 58 59 #ifdef CONFIG_CNSS2_DEBUG 60 static bool ignore_qmi_failure; 61 #define CNSS_QMI_ASSERT() CNSS_ASSERT(ignore_qmi_failure) 62 void cnss_ignore_qmi_failure(bool ignore) 63 { 64 ignore_qmi_failure = ignore; 65 } 66 #else 67 #define CNSS_QMI_ASSERT() do { } while (0) 68 void cnss_ignore_qmi_failure(bool ignore) { } 69 #endif 70 71 static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode) 72 { 73 switch (mode) { 74 case CNSS_MISSION: 75 return "MISSION"; 76 case CNSS_FTM: 77 return "FTM"; 78 case CNSS_EPPING: 79 return "EPPING"; 80 case CNSS_WALTEST: 81 return "WALTEST"; 82 case CNSS_OFF: 83 return "OFF"; 84 case CNSS_CCPM: 85 return "CCPM"; 86 case CNSS_QVIT: 87 return "QVIT"; 88 case CNSS_CALIBRATION: 89 return "CALIBRATION"; 90 default: 91 return "UNKNOWN"; 92 } 93 } 94 95 static int qmi_send_wait(struct qmi_handle *qmi, void *req, void *rsp, 96 struct qmi_elem_info *req_ei, 97 struct qmi_elem_info *rsp_ei, 98 int req_id, size_t req_len, 99 unsigned long timeout) 100 { 101 struct qmi_txn txn; 102 int ret; 103 char *err_msg; 104 struct qmi_response_type_v01 *resp = rsp; 105 106 ret = qmi_txn_init(qmi, &txn, rsp_ei, rsp); 107 if (ret < 0) { 108 err_msg = "Qmi fail: fail to init txn,"; 109 goto out; 110 } 111 112 ret = qmi_send_request(qmi, NULL, &txn, req_id, 113 req_len, req_ei, req); 114 if (ret < 0) { 115 qmi_txn_cancel(&txn); 116 err_msg = "Qmi fail: fail to send req,"; 117 goto out; 118 } 119 120 ret = qmi_txn_wait(&txn, timeout); 121 if (ret < 0) { 122 err_msg = "Qmi fail: wait timeout,"; 123 goto out; 124 } else if (resp->result != QMI_RESULT_SUCCESS_V01) { 125 err_msg = "Qmi fail: request rejected,"; 126 cnss_pr_err("Qmi fail: respons with error:%d\n", 127 resp->error); 128 ret = -resp->result; 129 goto out; 130 } 131 132 cnss_pr_dbg("req %x success\n", req_id); 133 return 0; 134 out: 135 cnss_pr_err("%s req %x, ret %d\n", err_msg, req_id, ret); 136 return ret; 137 } 138 139 static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv) 140 { 141 struct wlfw_ind_register_req_msg_v01 *req; 142 struct wlfw_ind_register_resp_msg_v01 *resp; 143 struct qmi_txn txn; 144 int ret = 0; 145 146 cnss_pr_dbg("Sending indication register message, state: 0x%lx\n", 147 plat_priv->driver_state); 148 149 req = kzalloc(sizeof(*req), GFP_KERNEL); 150 if (!req) 151 return -ENOMEM; 152 153 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 154 if (!resp) { 155 kfree(req); 156 return -ENOMEM; 157 } 158 159 req->client_id_valid = 1; 160 req->client_id = WLFW_CLIENT_ID; 161 req->request_mem_enable_valid = 1; 162 req->request_mem_enable = 1; 163 req->fw_mem_ready_enable_valid = 1; 164 req->fw_mem_ready_enable = 1; 165 /* fw_ready indication is replaced by fw_init_done in HST/HSP */ 166 req->fw_init_done_enable_valid = 1; 167 req->fw_init_done_enable = 1; 168 req->pin_connect_result_enable_valid = 1; 169 req->pin_connect_result_enable = 1; 170 req->cal_done_enable_valid = 1; 171 req->cal_done_enable = 1; 172 req->qdss_trace_req_mem_enable_valid = 1; 173 req->qdss_trace_req_mem_enable = 1; 174 req->qdss_trace_save_enable_valid = 1; 175 req->qdss_trace_save_enable = 1; 176 req->qdss_trace_free_enable_valid = 1; 177 req->qdss_trace_free_enable = 1; 178 req->respond_get_info_enable_valid = 1; 179 req->respond_get_info_enable = 1; 180 req->wfc_call_twt_config_enable_valid = 1; 181 req->wfc_call_twt_config_enable = 1; 182 183 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 184 wlfw_ind_register_resp_msg_v01_ei, resp); 185 if (ret < 0) { 186 cnss_pr_err("Failed to initialize txn for indication register request, err: %d\n", 187 ret); 188 goto out; 189 } 190 191 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 192 QMI_WLFW_IND_REGISTER_REQ_V01, 193 WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN, 194 wlfw_ind_register_req_msg_v01_ei, req); 195 if (ret < 0) { 196 qmi_txn_cancel(&txn); 197 cnss_pr_err("Failed to send indication register request, err: %d\n", 198 ret); 199 goto out; 200 } 201 202 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 203 if (ret < 0) { 204 cnss_pr_err("Failed to wait for response of indication register request, err: %d\n", 205 ret); 206 goto out; 207 } 208 209 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 210 cnss_pr_err("Indication register request failed, result: %d, err: %d\n", 211 resp->resp.result, resp->resp.error); 212 ret = -resp->resp.result; 213 goto out; 214 } 215 216 if (resp->fw_status_valid) { 217 if (resp->fw_status & QMI_WLFW_ALREADY_REGISTERED_V01) { 218 ret = -EALREADY; 219 goto qmi_registered; 220 } 221 } 222 223 kfree(req); 224 kfree(resp); 225 return 0; 226 227 out: 228 CNSS_QMI_ASSERT(); 229 230 qmi_registered: 231 kfree(req); 232 kfree(resp); 233 return ret; 234 } 235 236 static void cnss_wlfw_host_cap_parse_mlo(struct cnss_plat_data *plat_priv, 237 struct wlfw_host_cap_req_msg_v01 *req) 238 { 239 if (plat_priv->device_id == KIWI_DEVICE_ID || 240 plat_priv->device_id == MANGO_DEVICE_ID) { 241 req->mlo_capable_valid = 1; 242 req->mlo_capable = 1; 243 req->mlo_chip_id_valid = 1; 244 req->mlo_chip_id = 0; 245 req->mlo_group_id_valid = 1; 246 req->mlo_group_id = 0; 247 req->max_mlo_peer_valid = 1; 248 /* Max peer number generally won't change for the same device 249 * but needs to be synced with host driver. 250 */ 251 req->max_mlo_peer = 32; 252 req->mlo_num_chips_valid = 1; 253 req->mlo_num_chips = 1; 254 req->mlo_chip_info_valid = 1; 255 req->mlo_chip_info[0].chip_id = 0; 256 req->mlo_chip_info[0].num_local_links = 2; 257 req->mlo_chip_info[0].hw_link_id[0] = 0; 258 req->mlo_chip_info[0].hw_link_id[1] = 1; 259 req->mlo_chip_info[0].valid_mlo_link_id[0] = 1; 260 req->mlo_chip_info[0].valid_mlo_link_id[1] = 1; 261 } 262 } 263 264 static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv) 265 { 266 struct wlfw_host_cap_req_msg_v01 *req; 267 struct wlfw_host_cap_resp_msg_v01 *resp; 268 struct qmi_txn txn; 269 int ret = 0; 270 u64 iova_start = 0, iova_size = 0, 271 iova_ipa_start = 0, iova_ipa_size = 0; 272 u64 feature_list = 0; 273 274 cnss_pr_dbg("Sending host capability message, state: 0x%lx\n", 275 plat_priv->driver_state); 276 277 req = kzalloc(sizeof(*req), GFP_KERNEL); 278 if (!req) 279 return -ENOMEM; 280 281 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 282 if (!resp) { 283 kfree(req); 284 return -ENOMEM; 285 } 286 287 req->num_clients_valid = 1; 288 req->num_clients = 1; 289 cnss_pr_dbg("Number of clients is %d\n", req->num_clients); 290 291 req->wake_msi = cnss_bus_get_wake_irq(plat_priv); 292 if (req->wake_msi) { 293 cnss_pr_dbg("WAKE MSI base data is %d\n", req->wake_msi); 294 req->wake_msi_valid = 1; 295 } 296 297 req->bdf_support_valid = 1; 298 req->bdf_support = 1; 299 300 req->m3_support_valid = 1; 301 req->m3_support = 1; 302 303 req->m3_cache_support_valid = 1; 304 req->m3_cache_support = 1; 305 306 req->cal_done_valid = 1; 307 req->cal_done = plat_priv->cal_done; 308 cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done); 309 310 if (cnss_bus_is_smmu_s1_enabled(plat_priv) && 311 !cnss_bus_get_iova(plat_priv, &iova_start, &iova_size) && 312 !cnss_bus_get_iova_ipa(plat_priv, &iova_ipa_start, 313 &iova_ipa_size)) { 314 req->ddr_range_valid = 1; 315 req->ddr_range[0].start = iova_start; 316 req->ddr_range[0].size = iova_size + iova_ipa_size; 317 cnss_pr_dbg("Sending iova starting 0x%llx with size 0x%llx\n", 318 req->ddr_range[0].start, req->ddr_range[0].size); 319 } 320 321 req->host_build_type_valid = 1; 322 req->host_build_type = cnss_get_host_build_type(); 323 324 cnss_wlfw_host_cap_parse_mlo(plat_priv, req); 325 326 ret = cnss_get_feature_list(plat_priv, &feature_list); 327 if (!ret) { 328 req->feature_list_valid = 1; 329 req->feature_list = feature_list; 330 cnss_pr_dbg("Sending feature list 0x%llx\n", 331 req->feature_list); 332 } 333 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 334 wlfw_host_cap_resp_msg_v01_ei, resp); 335 if (ret < 0) { 336 cnss_pr_err("Failed to initialize txn for host capability request, err: %d\n", 337 ret); 338 goto out; 339 } 340 341 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 342 QMI_WLFW_HOST_CAP_REQ_V01, 343 WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, 344 wlfw_host_cap_req_msg_v01_ei, req); 345 if (ret < 0) { 346 qmi_txn_cancel(&txn); 347 cnss_pr_err("Failed to send host capability request, err: %d\n", 348 ret); 349 goto out; 350 } 351 352 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 353 if (ret < 0) { 354 cnss_pr_err("Failed to wait for response of host capability request, err: %d\n", 355 ret); 356 goto out; 357 } 358 359 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 360 cnss_pr_err("Host capability request failed, result: %d, err: %d\n", 361 resp->resp.result, resp->resp.error); 362 ret = -resp->resp.result; 363 goto out; 364 } 365 366 kfree(req); 367 kfree(resp); 368 return 0; 369 370 out: 371 CNSS_QMI_ASSERT(); 372 kfree(req); 373 kfree(resp); 374 return ret; 375 } 376 377 int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv) 378 { 379 struct wlfw_respond_mem_req_msg_v01 *req; 380 struct wlfw_respond_mem_resp_msg_v01 *resp; 381 struct qmi_txn txn; 382 struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; 383 int ret = 0, i; 384 385 cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n", 386 plat_priv->driver_state); 387 388 req = kzalloc(sizeof(*req), GFP_KERNEL); 389 if (!req) 390 return -ENOMEM; 391 392 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 393 if (!resp) { 394 kfree(req); 395 return -ENOMEM; 396 } 397 398 if (plat_priv->fw_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 399 cnss_pr_err("Invalid seg len %u\n", plat_priv->fw_mem_seg_len); 400 ret = -EINVAL; 401 goto out; 402 } 403 404 req->mem_seg_len = plat_priv->fw_mem_seg_len; 405 for (i = 0; i < req->mem_seg_len; i++) { 406 if (!fw_mem[i].pa || !fw_mem[i].size) { 407 if (fw_mem[i].type == 0) { 408 cnss_pr_err("Invalid memory for FW type, segment = %d\n", 409 i); 410 ret = -EINVAL; 411 goto out; 412 } 413 cnss_pr_err("Memory for FW is not available for type: %u\n", 414 fw_mem[i].type); 415 ret = -ENOMEM; 416 goto out; 417 } 418 419 cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", 420 fw_mem[i].va, &fw_mem[i].pa, 421 fw_mem[i].size, fw_mem[i].type); 422 423 req->mem_seg[i].addr = fw_mem[i].pa; 424 req->mem_seg[i].size = fw_mem[i].size; 425 req->mem_seg[i].type = fw_mem[i].type; 426 } 427 428 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 429 wlfw_respond_mem_resp_msg_v01_ei, resp); 430 if (ret < 0) { 431 cnss_pr_err("Failed to initialize txn for respond memory request, err: %d\n", 432 ret); 433 goto out; 434 } 435 436 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 437 QMI_WLFW_RESPOND_MEM_REQ_V01, 438 WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN, 439 wlfw_respond_mem_req_msg_v01_ei, req); 440 if (ret < 0) { 441 qmi_txn_cancel(&txn); 442 cnss_pr_err("Failed to send respond memory request, err: %d\n", 443 ret); 444 goto out; 445 } 446 447 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 448 if (ret < 0) { 449 cnss_pr_err("Failed to wait for response of respond memory request, err: %d\n", 450 ret); 451 goto out; 452 } 453 454 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 455 cnss_pr_err("Respond memory request failed, result: %d, err: %d\n", 456 resp->resp.result, resp->resp.error); 457 ret = -resp->resp.result; 458 goto out; 459 } 460 461 kfree(req); 462 kfree(resp); 463 return 0; 464 465 out: 466 CNSS_QMI_ASSERT(); 467 kfree(req); 468 kfree(resp); 469 return ret; 470 } 471 472 int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv) 473 { 474 struct wlfw_cap_req_msg_v01 *req; 475 struct wlfw_cap_resp_msg_v01 *resp; 476 struct qmi_txn txn; 477 char *fw_build_timestamp; 478 int ret = 0, i; 479 480 cnss_pr_dbg("Sending target capability message, state: 0x%lx\n", 481 plat_priv->driver_state); 482 483 req = kzalloc(sizeof(*req), GFP_KERNEL); 484 if (!req) 485 return -ENOMEM; 486 487 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 488 if (!resp) { 489 kfree(req); 490 return -ENOMEM; 491 } 492 493 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 494 wlfw_cap_resp_msg_v01_ei, resp); 495 if (ret < 0) { 496 cnss_pr_err("Failed to initialize txn for target capability request, err: %d\n", 497 ret); 498 goto out; 499 } 500 501 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 502 QMI_WLFW_CAP_REQ_V01, 503 WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN, 504 wlfw_cap_req_msg_v01_ei, req); 505 if (ret < 0) { 506 qmi_txn_cancel(&txn); 507 cnss_pr_err("Failed to send respond target capability request, err: %d\n", 508 ret); 509 goto out; 510 } 511 512 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 513 if (ret < 0) { 514 cnss_pr_err("Failed to wait for response of target capability request, err: %d\n", 515 ret); 516 goto out; 517 } 518 519 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 520 cnss_pr_err("Target capability request failed, result: %d, err: %d\n", 521 resp->resp.result, resp->resp.error); 522 ret = -resp->resp.result; 523 goto out; 524 } 525 526 if (resp->chip_info_valid) { 527 plat_priv->chip_info.chip_id = resp->chip_info.chip_id; 528 plat_priv->chip_info.chip_family = resp->chip_info.chip_family; 529 } 530 if (resp->board_info_valid) 531 plat_priv->board_info.board_id = resp->board_info.board_id; 532 else 533 plat_priv->board_info.board_id = 0xFF; 534 if (resp->soc_info_valid) 535 plat_priv->soc_info.soc_id = resp->soc_info.soc_id; 536 if (resp->fw_version_info_valid) { 537 plat_priv->fw_version_info.fw_version = 538 resp->fw_version_info.fw_version; 539 fw_build_timestamp = resp->fw_version_info.fw_build_timestamp; 540 fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN] = '\0'; 541 strlcpy(plat_priv->fw_version_info.fw_build_timestamp, 542 resp->fw_version_info.fw_build_timestamp, 543 QMI_WLFW_MAX_TIMESTAMP_LEN + 1); 544 } 545 if (resp->fw_build_id_valid) { 546 resp->fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN] = '\0'; 547 strlcpy(plat_priv->fw_build_id, resp->fw_build_id, 548 QMI_WLFW_MAX_BUILD_ID_LEN + 1); 549 } 550 /* FW will send aop retention volatage for qca6490 */ 551 if (resp->voltage_mv_valid) { 552 plat_priv->cpr_info.voltage = resp->voltage_mv; 553 cnss_pr_dbg("Voltage for CPR: %dmV\n", 554 plat_priv->cpr_info.voltage); 555 cnss_update_cpr_info(plat_priv); 556 } 557 if (resp->time_freq_hz_valid) { 558 plat_priv->device_freq_hz = resp->time_freq_hz; 559 cnss_pr_dbg("Device frequency is %d HZ\n", 560 plat_priv->device_freq_hz); 561 } 562 if (resp->otp_version_valid) 563 plat_priv->otp_version = resp->otp_version; 564 if (resp->dev_mem_info_valid) { 565 for (i = 0; i < QMI_WLFW_MAX_DEV_MEM_NUM_V01; i++) { 566 plat_priv->dev_mem_info[i].start = 567 resp->dev_mem_info[i].start; 568 plat_priv->dev_mem_info[i].size = 569 resp->dev_mem_info[i].size; 570 cnss_pr_buf("Device memory info[%d]: start = 0x%llx, size = 0x%llx\n", 571 i, plat_priv->dev_mem_info[i].start, 572 plat_priv->dev_mem_info[i].size); 573 } 574 } 575 if (resp->fw_caps_valid) { 576 plat_priv->fw_pcie_gen_switch = 577 !!(resp->fw_caps & QMI_WLFW_HOST_PCIE_GEN_SWITCH_V01); 578 plat_priv->fw_caps = resp->fw_caps; 579 } 580 581 if (resp->hang_data_length_valid && 582 resp->hang_data_length && 583 resp->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE) 584 plat_priv->hang_event_data_len = resp->hang_data_length; 585 else 586 plat_priv->hang_event_data_len = 0; 587 588 if (resp->hang_data_addr_offset_valid) 589 plat_priv->hang_data_addr_offset = resp->hang_data_addr_offset; 590 else 591 plat_priv->hang_data_addr_offset = 0; 592 593 if (resp->hwid_bitmap_valid) 594 plat_priv->hwid_bitmap = resp->hwid_bitmap; 595 596 if (resp->ol_cpr_cfg_valid) 597 cnss_aop_ol_cpr_cfg_setup(plat_priv, &resp->ol_cpr_cfg); 598 599 cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, otp_version: 0x%x\n", 600 plat_priv->chip_info.chip_id, 601 plat_priv->chip_info.chip_family, 602 plat_priv->board_info.board_id, plat_priv->soc_info.soc_id, 603 plat_priv->otp_version); 604 cnss_pr_dbg("fw_version: 0x%x, fw_build_timestamp: %s, fw_build_id: %s, hwid_bitmap:0x%x\n", 605 plat_priv->fw_version_info.fw_version, 606 plat_priv->fw_version_info.fw_build_timestamp, 607 plat_priv->fw_build_id, 608 plat_priv->hwid_bitmap); 609 cnss_pr_dbg("Hang event params, Length: 0x%x, Offset Address: 0x%x\n", 610 plat_priv->hang_event_data_len, 611 plat_priv->hang_data_addr_offset); 612 613 kfree(req); 614 kfree(resp); 615 return 0; 616 617 out: 618 CNSS_QMI_ASSERT(); 619 kfree(req); 620 kfree(resp); 621 return ret; 622 } 623 624 static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv, 625 u32 bdf_type, char *filename, 626 u32 filename_len) 627 { 628 char filename_tmp[MAX_FIRMWARE_NAME_LEN]; 629 int ret = 0; 630 631 switch (bdf_type) { 632 case CNSS_BDF_ELF: 633 /* Board ID will be equal or less than 0xFF in GF mask case */ 634 if (plat_priv->board_info.board_id == 0xFF) { 635 if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK) 636 snprintf(filename_tmp, filename_len, 637 ELF_BDF_FILE_NAME_GF); 638 else 639 snprintf(filename_tmp, filename_len, 640 ELF_BDF_FILE_NAME); 641 } else if (plat_priv->board_info.board_id < 0xFF) { 642 if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK) 643 snprintf(filename_tmp, filename_len, 644 ELF_BDF_FILE_NAME_GF_PREFIX "%02x", 645 plat_priv->board_info.board_id); 646 else 647 snprintf(filename_tmp, filename_len, 648 ELF_BDF_FILE_NAME_PREFIX "%02x", 649 plat_priv->board_info.board_id); 650 } else { 651 snprintf(filename_tmp, filename_len, 652 BDF_FILE_NAME_PREFIX "%02x.e%02x", 653 plat_priv->board_info.board_id >> 8 & 0xFF, 654 plat_priv->board_info.board_id & 0xFF); 655 } 656 break; 657 case CNSS_BDF_BIN: 658 if (plat_priv->board_info.board_id == 0xFF) { 659 if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK) 660 snprintf(filename_tmp, filename_len, 661 BIN_BDF_FILE_NAME_GF); 662 else 663 snprintf(filename_tmp, filename_len, 664 BIN_BDF_FILE_NAME); 665 } else if (plat_priv->board_info.board_id < 0xFF) { 666 if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK) 667 snprintf(filename_tmp, filename_len, 668 BIN_BDF_FILE_NAME_GF_PREFIX "%02x", 669 plat_priv->board_info.board_id); 670 else 671 snprintf(filename_tmp, filename_len, 672 BIN_BDF_FILE_NAME_PREFIX "%02x", 673 plat_priv->board_info.board_id); 674 } else { 675 snprintf(filename_tmp, filename_len, 676 BDF_FILE_NAME_PREFIX "%02x.b%02x", 677 plat_priv->board_info.board_id >> 8 & 0xFF, 678 plat_priv->board_info.board_id & 0xFF); 679 } 680 break; 681 case CNSS_BDF_REGDB: 682 snprintf(filename_tmp, filename_len, REGDB_FILE_NAME); 683 break; 684 case CNSS_BDF_HDS: 685 snprintf(filename_tmp, filename_len, HDS_FILE_NAME); 686 break; 687 default: 688 cnss_pr_err("Invalid BDF type: %d\n", 689 plat_priv->ctrl_params.bdf_type); 690 ret = -EINVAL; 691 break; 692 } 693 694 if (!ret) 695 cnss_bus_add_fw_prefix_name(plat_priv, filename, filename_tmp); 696 697 return ret; 698 } 699 700 int cnss_wlfw_ini_file_send_sync(struct cnss_plat_data *plat_priv, 701 enum wlfw_ini_file_type_v01 file_type) 702 { 703 struct wlfw_ini_file_download_req_msg_v01 *req; 704 struct wlfw_ini_file_download_resp_msg_v01 *resp; 705 struct qmi_txn txn; 706 int ret = 0; 707 const struct firmware *fw; 708 char filename[INI_FILE_NAME_LEN] = {0}; 709 char tmp_filename[INI_FILE_NAME_LEN] = {0}; 710 const u8 *temp; 711 unsigned int remaining; 712 bool backup_supported = false; 713 714 cnss_pr_info("INI File %u download\n", file_type); 715 716 req = kzalloc(sizeof(*req), GFP_KERNEL); 717 if (!req) 718 return -ENOMEM; 719 720 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 721 if (!resp) { 722 kfree(req); 723 return -ENOMEM; 724 } 725 726 switch (file_type) { 727 case WLFW_CONN_ROAM_INI_V01: 728 snprintf(tmp_filename, sizeof(tmp_filename), 729 CONN_ROAM_FILE_NAME); 730 backup_supported = true; 731 break; 732 default: 733 cnss_pr_err("Invalid file type: %u\n", file_type); 734 ret = -EINVAL; 735 goto err_req_fw; 736 } 737 738 snprintf(filename, sizeof(filename), "%s%s", tmp_filename, INI_EXT); 739 /* Fetch the file */ 740 ret = firmware_request_nowarn(&fw, filename, &plat_priv->plat_dev->dev); 741 if (ret) { 742 cnss_pr_err("Failed to get INI file %s (%d), Backup file: %s", 743 filename, ret, 744 backup_supported ? "Supported" : "Not Supported"); 745 746 if (!backup_supported) 747 goto err_req_fw; 748 749 snprintf(filename, sizeof(filename), 750 "%s-%s%s", tmp_filename, "backup", INI_EXT); 751 752 ret = firmware_request_nowarn(&fw, filename, 753 &plat_priv->plat_dev->dev); 754 if (ret) { 755 cnss_pr_err("Failed to get INI file %s (%d)", filename, 756 ret); 757 goto err_req_fw; 758 } 759 } 760 761 temp = fw->data; 762 remaining = fw->size; 763 764 cnss_pr_dbg("Downloading INI file: %s, size: %u\n", filename, 765 remaining); 766 767 while (remaining) { 768 req->file_type_valid = 1; 769 req->file_type = file_type; 770 req->total_size_valid = 1; 771 req->total_size = remaining; 772 req->seg_id_valid = 1; 773 req->data_valid = 1; 774 req->end_valid = 1; 775 776 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 777 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 778 } else { 779 req->data_len = remaining; 780 req->end = 1; 781 } 782 783 memcpy(req->data, temp, req->data_len); 784 785 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 786 wlfw_ini_file_download_resp_msg_v01_ei, 787 resp); 788 if (ret < 0) { 789 cnss_pr_err("Failed to initialize txn for INI file download request, err: %d\n", 790 ret); 791 goto err; 792 } 793 794 ret = qmi_send_request 795 (&plat_priv->qmi_wlfw, NULL, &txn, 796 QMI_WLFW_INI_FILE_DOWNLOAD_REQ_V01, 797 WLFW_INI_FILE_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 798 wlfw_ini_file_download_req_msg_v01_ei, req); 799 if (ret < 0) { 800 qmi_txn_cancel(&txn); 801 cnss_pr_err("Failed to send INI File download request, err: %d\n", 802 ret); 803 goto err; 804 } 805 806 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 807 if (ret < 0) { 808 cnss_pr_err("Failed to wait for response of INI File download request, err: %d\n", 809 ret); 810 goto err; 811 } 812 813 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 814 cnss_pr_err("INI file download request failed, result: %d, err: %d\n", 815 resp->resp.result, resp->resp.error); 816 ret = -resp->resp.result; 817 goto err; 818 } 819 820 remaining -= req->data_len; 821 temp += req->data_len; 822 req->seg_id++; 823 } 824 825 release_firmware(fw); 826 827 kfree(req); 828 kfree(resp); 829 return 0; 830 831 err: 832 release_firmware(fw); 833 err_req_fw: 834 kfree(req); 835 kfree(resp); 836 837 return ret; 838 } 839 840 int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, 841 u32 bdf_type) 842 { 843 struct wlfw_bdf_download_req_msg_v01 *req; 844 struct wlfw_bdf_download_resp_msg_v01 *resp; 845 struct qmi_txn txn; 846 char filename[MAX_FIRMWARE_NAME_LEN]; 847 const struct firmware *fw_entry = NULL; 848 const u8 *temp; 849 unsigned int remaining; 850 int ret = 0; 851 852 cnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n", 853 plat_priv->driver_state, bdf_type); 854 855 req = kzalloc(sizeof(*req), GFP_KERNEL); 856 if (!req) 857 return -ENOMEM; 858 859 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 860 if (!resp) { 861 kfree(req); 862 return -ENOMEM; 863 } 864 865 ret = cnss_get_bdf_file_name(plat_priv, bdf_type, 866 filename, sizeof(filename)); 867 if (ret) 868 goto err_req_fw; 869 870 if (bdf_type == CNSS_BDF_REGDB) 871 ret = cnss_request_firmware_direct(plat_priv, &fw_entry, 872 filename); 873 else 874 ret = firmware_request_nowarn(&fw_entry, filename, 875 &plat_priv->plat_dev->dev); 876 877 if (ret) { 878 cnss_pr_err("Failed to load BDF: %s, ret: %d\n", filename, ret); 879 goto err_req_fw; 880 } 881 882 temp = fw_entry->data; 883 remaining = fw_entry->size; 884 885 cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining); 886 887 while (remaining) { 888 req->valid = 1; 889 req->file_id_valid = 1; 890 req->file_id = plat_priv->board_info.board_id; 891 req->total_size_valid = 1; 892 req->total_size = remaining; 893 req->seg_id_valid = 1; 894 req->data_valid = 1; 895 req->end_valid = 1; 896 req->bdf_type_valid = 1; 897 req->bdf_type = bdf_type; 898 899 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 900 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 901 } else { 902 req->data_len = remaining; 903 req->end = 1; 904 } 905 906 memcpy(req->data, temp, req->data_len); 907 908 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 909 wlfw_bdf_download_resp_msg_v01_ei, resp); 910 if (ret < 0) { 911 cnss_pr_err("Failed to initialize txn for BDF download request, err: %d\n", 912 ret); 913 goto err_send; 914 } 915 916 ret = qmi_send_request 917 (&plat_priv->qmi_wlfw, NULL, &txn, 918 QMI_WLFW_BDF_DOWNLOAD_REQ_V01, 919 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 920 wlfw_bdf_download_req_msg_v01_ei, req); 921 if (ret < 0) { 922 qmi_txn_cancel(&txn); 923 cnss_pr_err("Failed to send respond BDF download request, err: %d\n", 924 ret); 925 goto err_send; 926 } 927 928 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 929 if (ret < 0) { 930 cnss_pr_err("Failed to wait for response of BDF download request, err: %d\n", 931 ret); 932 goto err_send; 933 } 934 935 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 936 cnss_pr_err("BDF download request failed, result: %d, err: %d\n", 937 resp->resp.result, resp->resp.error); 938 ret = -resp->resp.result; 939 goto err_send; 940 } 941 942 remaining -= req->data_len; 943 temp += req->data_len; 944 req->seg_id++; 945 } 946 947 release_firmware(fw_entry); 948 949 if (resp->host_bdf_data_valid) { 950 /* QCA6490 enable S3E regulator for IPA configuration only */ 951 if (!(resp->host_bdf_data & QMI_WLFW_HW_XPA_V01)) 952 cnss_enable_int_pow_amp_vreg(plat_priv); 953 954 plat_priv->cbc_file_download = 955 resp->host_bdf_data & QMI_WLFW_CBC_FILE_DOWNLOAD_V01; 956 cnss_pr_info("Host BDF config: HW_XPA: %d CalDB: %d\n", 957 resp->host_bdf_data & QMI_WLFW_HW_XPA_V01, 958 plat_priv->cbc_file_download); 959 } 960 kfree(req); 961 kfree(resp); 962 return 0; 963 964 err_send: 965 release_firmware(fw_entry); 966 err_req_fw: 967 if (!(bdf_type == CNSS_BDF_REGDB || 968 test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state) || 969 ret == -EAGAIN)) 970 CNSS_QMI_ASSERT(); 971 kfree(req); 972 kfree(resp); 973 return ret; 974 } 975 976 int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv) 977 { 978 struct wlfw_m3_info_req_msg_v01 *req; 979 struct wlfw_m3_info_resp_msg_v01 *resp; 980 struct qmi_txn txn; 981 struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem; 982 int ret = 0; 983 984 cnss_pr_dbg("Sending M3 information message, state: 0x%lx\n", 985 plat_priv->driver_state); 986 987 req = kzalloc(sizeof(*req), GFP_KERNEL); 988 if (!req) 989 return -ENOMEM; 990 991 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 992 if (!resp) { 993 kfree(req); 994 return -ENOMEM; 995 } 996 997 if (!m3_mem->pa || !m3_mem->size) { 998 cnss_pr_err("Memory for M3 is not available\n"); 999 ret = -ENOMEM; 1000 goto out; 1001 } 1002 1003 cnss_pr_dbg("M3 memory, va: 0x%pK, pa: %pa, size: 0x%zx\n", 1004 m3_mem->va, &m3_mem->pa, m3_mem->size); 1005 1006 req->addr = plat_priv->m3_mem.pa; 1007 req->size = plat_priv->m3_mem.size; 1008 1009 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1010 wlfw_m3_info_resp_msg_v01_ei, resp); 1011 if (ret < 0) { 1012 cnss_pr_err("Failed to initialize txn for M3 information request, err: %d\n", 1013 ret); 1014 goto out; 1015 } 1016 1017 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1018 QMI_WLFW_M3_INFO_REQ_V01, 1019 WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, 1020 wlfw_m3_info_req_msg_v01_ei, req); 1021 if (ret < 0) { 1022 qmi_txn_cancel(&txn); 1023 cnss_pr_err("Failed to send M3 information request, err: %d\n", 1024 ret); 1025 goto out; 1026 } 1027 1028 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1029 if (ret < 0) { 1030 cnss_pr_err("Failed to wait for response of M3 information request, err: %d\n", 1031 ret); 1032 goto out; 1033 } 1034 1035 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1036 cnss_pr_err("M3 information request failed, result: %d, err: %d\n", 1037 resp->resp.result, resp->resp.error); 1038 ret = -resp->resp.result; 1039 goto out; 1040 } 1041 1042 kfree(req); 1043 kfree(resp); 1044 return 0; 1045 1046 out: 1047 CNSS_QMI_ASSERT(); 1048 kfree(req); 1049 kfree(resp); 1050 return ret; 1051 } 1052 1053 int cnss_wlfw_wlan_mac_req_send_sync(struct cnss_plat_data *plat_priv, 1054 u8 *mac, u32 mac_len) 1055 { 1056 struct wlfw_mac_addr_req_msg_v01 req; 1057 struct wlfw_mac_addr_resp_msg_v01 resp = {0}; 1058 struct qmi_txn txn; 1059 int ret; 1060 1061 if (!plat_priv || !mac || mac_len != QMI_WLFW_MAC_ADDR_SIZE_V01) 1062 return -EINVAL; 1063 1064 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1065 wlfw_mac_addr_resp_msg_v01_ei, &resp); 1066 if (ret < 0) { 1067 cnss_pr_err("Failed to initialize txn for mac req, err: %d\n", 1068 ret); 1069 ret = -EIO; 1070 goto out; 1071 } 1072 1073 cnss_pr_dbg("Sending WLAN mac req [%pM], state: 0x%lx\n", 1074 mac, plat_priv->driver_state); 1075 memcpy(req.mac_addr, mac, mac_len); 1076 req.mac_addr_valid = 1; 1077 1078 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1079 QMI_WLFW_MAC_ADDR_REQ_V01, 1080 WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN, 1081 wlfw_mac_addr_req_msg_v01_ei, &req); 1082 if (ret < 0) { 1083 qmi_txn_cancel(&txn); 1084 cnss_pr_err("Failed to send mac req, err: %d\n", ret); 1085 ret = -EIO; 1086 goto out; 1087 } 1088 1089 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1090 if (ret < 0) { 1091 cnss_pr_err("Failed to wait for resp of mac req, err: %d\n", 1092 ret); 1093 ret = -EIO; 1094 goto out; 1095 } 1096 1097 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 1098 cnss_pr_err("WLAN mac req failed, result: %d, err: %d\n", 1099 resp.resp.result); 1100 ret = -resp.resp.result; 1101 } 1102 out: 1103 return ret; 1104 } 1105 1106 int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_name, 1107 u32 total_size) 1108 { 1109 int ret = 0; 1110 struct wlfw_qdss_trace_data_req_msg_v01 *req; 1111 struct wlfw_qdss_trace_data_resp_msg_v01 *resp; 1112 unsigned char *p_qdss_trace_data_temp, *p_qdss_trace_data = NULL; 1113 unsigned int remaining; 1114 struct qmi_txn txn; 1115 1116 cnss_pr_dbg("%s\n", __func__); 1117 1118 req = kzalloc(sizeof(*req), GFP_KERNEL); 1119 if (!req) 1120 return -ENOMEM; 1121 1122 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1123 if (!resp) { 1124 kfree(req); 1125 return -ENOMEM; 1126 } 1127 1128 p_qdss_trace_data = kzalloc(total_size, GFP_KERNEL); 1129 if (!p_qdss_trace_data) { 1130 ret = ENOMEM; 1131 goto end; 1132 } 1133 1134 remaining = total_size; 1135 p_qdss_trace_data_temp = p_qdss_trace_data; 1136 while (remaining && resp->end == 0) { 1137 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1138 wlfw_qdss_trace_data_resp_msg_v01_ei, resp); 1139 1140 if (ret < 0) { 1141 cnss_pr_err("Fail to init txn for QDSS trace resp %d\n", 1142 ret); 1143 goto fail; 1144 } 1145 1146 ret = qmi_send_request 1147 (&plat_priv->qmi_wlfw, NULL, &txn, 1148 QMI_WLFW_QDSS_TRACE_DATA_REQ_V01, 1149 WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN, 1150 wlfw_qdss_trace_data_req_msg_v01_ei, req); 1151 1152 if (ret < 0) { 1153 qmi_txn_cancel(&txn); 1154 cnss_pr_err("Fail to send QDSS trace data req %d\n", 1155 ret); 1156 goto fail; 1157 } 1158 1159 ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout); 1160 1161 if (ret < 0) { 1162 cnss_pr_err("QDSS trace resp wait failed with rc %d\n", 1163 ret); 1164 goto fail; 1165 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1166 cnss_pr_err("QMI QDSS trace request rejected, result:%d error:%d\n", 1167 resp->resp.result, resp->resp.error); 1168 ret = -resp->resp.result; 1169 goto fail; 1170 } else { 1171 ret = 0; 1172 } 1173 1174 cnss_pr_dbg("%s: response total size %d data len %d", 1175 __func__, resp->total_size, resp->data_len); 1176 1177 if ((resp->total_size_valid == 1 && 1178 resp->total_size == total_size) && 1179 (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && 1180 (resp->data_valid == 1 && 1181 resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && 1182 resp->data_len <= remaining) { 1183 memcpy(p_qdss_trace_data_temp, 1184 resp->data, resp->data_len); 1185 } else { 1186 cnss_pr_err("%s: Unmatched qdss trace data, Expect total_size %u, seg_id %u, Recv total_size_valid %u, total_size %u, seg_id_valid %u, seg_id %u, data_len_valid %u, data_len %u", 1187 __func__, 1188 total_size, req->seg_id, 1189 resp->total_size_valid, 1190 resp->total_size, 1191 resp->seg_id_valid, 1192 resp->seg_id, 1193 resp->data_valid, 1194 resp->data_len); 1195 ret = -1; 1196 goto fail; 1197 } 1198 1199 remaining -= resp->data_len; 1200 p_qdss_trace_data_temp += resp->data_len; 1201 req->seg_id++; 1202 } 1203 1204 if (remaining == 0 && (resp->end_valid && resp->end)) { 1205 ret = cnss_genl_send_msg(p_qdss_trace_data, 1206 CNSS_GENL_MSG_TYPE_QDSS, file_name, 1207 total_size); 1208 if (ret < 0) { 1209 cnss_pr_err("Fail to save QDSS trace data: %d\n", 1210 ret); 1211 ret = -1; 1212 goto fail; 1213 } 1214 } else { 1215 cnss_pr_err("%s: QDSS trace file corrupted: remaining %u, end_valid %u, end %u", 1216 __func__, 1217 remaining, resp->end_valid, resp->end); 1218 ret = -1; 1219 goto fail; 1220 } 1221 1222 fail: 1223 kfree(p_qdss_trace_data); 1224 1225 end: 1226 kfree(req); 1227 kfree(resp); 1228 return ret; 1229 } 1230 1231 void cnss_get_qdss_cfg_filename(struct cnss_plat_data *plat_priv, 1232 char *filename, u32 filename_len) 1233 { 1234 char filename_tmp[MAX_FIRMWARE_NAME_LEN]; 1235 char *debug_str = QDSS_DEBUG_FILE_STR; 1236 1237 if (plat_priv->device_id == KIWI_DEVICE_ID || 1238 plat_priv->device_id == MANGO_DEVICE_ID) 1239 debug_str = ""; 1240 1241 if (plat_priv->device_version.major_version == FW_V2_NUMBER) 1242 snprintf(filename_tmp, filename_len, QDSS_TRACE_CONFIG_FILE 1243 "_%s%s.cfg", debug_str, HW_V2_NUMBER); 1244 else 1245 snprintf(filename_tmp, filename_len, QDSS_TRACE_CONFIG_FILE 1246 "_%s%s.cfg", debug_str, HW_V1_NUMBER); 1247 1248 cnss_bus_add_fw_prefix_name(plat_priv, filename, filename_tmp); 1249 } 1250 1251 int cnss_wlfw_qdss_dnld_send_sync(struct cnss_plat_data *plat_priv) 1252 { 1253 struct wlfw_qdss_trace_config_download_req_msg_v01 *req; 1254 struct wlfw_qdss_trace_config_download_resp_msg_v01 *resp; 1255 struct qmi_txn txn; 1256 const struct firmware *fw_entry = NULL; 1257 const u8 *temp; 1258 char qdss_cfg_filename[MAX_FIRMWARE_NAME_LEN]; 1259 unsigned int remaining; 1260 int ret = 0; 1261 1262 cnss_pr_dbg("Sending QDSS config download message, state: 0x%lx\n", 1263 plat_priv->driver_state); 1264 1265 req = kzalloc(sizeof(*req), GFP_KERNEL); 1266 if (!req) 1267 return -ENOMEM; 1268 1269 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1270 if (!resp) { 1271 kfree(req); 1272 return -ENOMEM; 1273 } 1274 1275 cnss_get_qdss_cfg_filename(plat_priv, qdss_cfg_filename, sizeof(qdss_cfg_filename)); 1276 ret = cnss_request_firmware_direct(plat_priv, &fw_entry, 1277 qdss_cfg_filename); 1278 if (ret) { 1279 cnss_pr_dbg("Unable to load %s\n", 1280 qdss_cfg_filename); 1281 goto err_req_fw; 1282 } 1283 1284 temp = fw_entry->data; 1285 remaining = fw_entry->size; 1286 1287 cnss_pr_dbg("Downloading QDSS: %s, size: %u\n", 1288 qdss_cfg_filename, remaining); 1289 1290 while (remaining) { 1291 req->total_size_valid = 1; 1292 req->total_size = remaining; 1293 req->seg_id_valid = 1; 1294 req->data_valid = 1; 1295 req->end_valid = 1; 1296 1297 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 1298 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 1299 } else { 1300 req->data_len = remaining; 1301 req->end = 1; 1302 } 1303 1304 memcpy(req->data, temp, req->data_len); 1305 1306 ret = qmi_txn_init 1307 (&plat_priv->qmi_wlfw, &txn, 1308 wlfw_qdss_trace_config_download_resp_msg_v01_ei, 1309 resp); 1310 if (ret < 0) { 1311 cnss_pr_err("Failed to initialize txn for QDSS download request, err: %d\n", 1312 ret); 1313 goto err_send; 1314 } 1315 1316 ret = qmi_send_request 1317 (&plat_priv->qmi_wlfw, NULL, &txn, 1318 QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01, 1319 WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 1320 wlfw_qdss_trace_config_download_req_msg_v01_ei, req); 1321 if (ret < 0) { 1322 qmi_txn_cancel(&txn); 1323 cnss_pr_err("Failed to send respond QDSS download request, err: %d\n", 1324 ret); 1325 goto err_send; 1326 } 1327 1328 ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout); 1329 if (ret < 0) { 1330 cnss_pr_err("Failed to wait for response of QDSS download request, err: %d\n", 1331 ret); 1332 goto err_send; 1333 } 1334 1335 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1336 cnss_pr_err("QDSS download request failed, result: %d, err: %d\n", 1337 resp->resp.result, resp->resp.error); 1338 ret = -resp->resp.result; 1339 goto err_send; 1340 } 1341 1342 remaining -= req->data_len; 1343 temp += req->data_len; 1344 req->seg_id++; 1345 } 1346 1347 release_firmware(fw_entry); 1348 kfree(req); 1349 kfree(resp); 1350 return 0; 1351 1352 err_send: 1353 release_firmware(fw_entry); 1354 err_req_fw: 1355 1356 kfree(req); 1357 kfree(resp); 1358 return ret; 1359 } 1360 1361 static int wlfw_send_qdss_trace_mode_req 1362 (struct cnss_plat_data *plat_priv, 1363 enum wlfw_qdss_trace_mode_enum_v01 mode, 1364 unsigned long long option) 1365 { 1366 int rc = 0; 1367 int tmp = 0; 1368 struct wlfw_qdss_trace_mode_req_msg_v01 *req; 1369 struct wlfw_qdss_trace_mode_resp_msg_v01 *resp; 1370 struct qmi_txn txn; 1371 1372 if (!plat_priv) 1373 return -ENODEV; 1374 1375 req = kzalloc(sizeof(*req), GFP_KERNEL); 1376 if (!req) 1377 return -ENOMEM; 1378 1379 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1380 if (!resp) { 1381 kfree(req); 1382 return -ENOMEM; 1383 } 1384 1385 req->mode_valid = 1; 1386 req->mode = mode; 1387 req->option_valid = 1; 1388 req->option = option; 1389 1390 tmp = plat_priv->hw_trc_override; 1391 1392 req->hw_trc_disable_override_valid = 1; 1393 req->hw_trc_disable_override = 1394 (tmp > QMI_PARAM_DISABLE_V01 ? QMI_PARAM_DISABLE_V01 : 1395 (tmp < 0 ? QMI_PARAM_INVALID_V01 : tmp)); 1396 1397 cnss_pr_dbg("%s: mode %u, option %llu, hw_trc_disable_override: %u", 1398 __func__, mode, option, req->hw_trc_disable_override); 1399 1400 rc = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1401 wlfw_qdss_trace_mode_resp_msg_v01_ei, resp); 1402 if (rc < 0) { 1403 cnss_pr_err("Fail to init txn for QDSS Mode resp %d\n", 1404 rc); 1405 goto out; 1406 } 1407 1408 rc = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1409 QMI_WLFW_QDSS_TRACE_MODE_REQ_V01, 1410 WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN, 1411 wlfw_qdss_trace_mode_req_msg_v01_ei, req); 1412 if (rc < 0) { 1413 qmi_txn_cancel(&txn); 1414 cnss_pr_err("Fail to send QDSS Mode req %d\n", rc); 1415 goto out; 1416 } 1417 1418 rc = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout); 1419 if (rc < 0) { 1420 cnss_pr_err("QDSS Mode resp wait failed with rc %d\n", 1421 rc); 1422 goto out; 1423 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1424 cnss_pr_err("QMI QDSS Mode request rejected, result:%d error:%d\n", 1425 resp->resp.result, resp->resp.error); 1426 rc = -resp->resp.result; 1427 goto out; 1428 } 1429 1430 kfree(resp); 1431 kfree(req); 1432 return rc; 1433 out: 1434 kfree(resp); 1435 kfree(req); 1436 CNSS_QMI_ASSERT(); 1437 return rc; 1438 } 1439 1440 int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv) 1441 { 1442 return wlfw_send_qdss_trace_mode_req(plat_priv, 1443 QMI_WLFW_QDSS_TRACE_ON_V01, 0); 1444 } 1445 1446 int wlfw_qdss_trace_stop(struct cnss_plat_data *plat_priv, unsigned long long option) 1447 { 1448 return wlfw_send_qdss_trace_mode_req(plat_priv, QMI_WLFW_QDSS_TRACE_OFF_V01, 1449 option); 1450 } 1451 1452 int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv, 1453 enum cnss_driver_mode mode) 1454 { 1455 struct wlfw_wlan_mode_req_msg_v01 *req; 1456 struct wlfw_wlan_mode_resp_msg_v01 *resp; 1457 struct qmi_txn txn; 1458 int ret = 0; 1459 1460 if (!plat_priv) 1461 return -ENODEV; 1462 1463 cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n", 1464 cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state); 1465 1466 if (mode == CNSS_OFF && 1467 test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { 1468 cnss_pr_dbg("Recovery is in progress, ignore mode off request\n"); 1469 return 0; 1470 } 1471 1472 req = kzalloc(sizeof(*req), GFP_KERNEL); 1473 if (!req) 1474 return -ENOMEM; 1475 1476 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1477 if (!resp) { 1478 kfree(req); 1479 return -ENOMEM; 1480 } 1481 1482 req->mode = (enum wlfw_driver_mode_enum_v01)mode; 1483 req->hw_debug_valid = 1; 1484 req->hw_debug = 0; 1485 1486 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1487 wlfw_wlan_mode_resp_msg_v01_ei, resp); 1488 if (ret < 0) { 1489 cnss_pr_err("Failed to initialize txn for mode request, mode: %s(%d), err: %d\n", 1490 cnss_qmi_mode_to_str(mode), mode, ret); 1491 goto out; 1492 } 1493 1494 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1495 QMI_WLFW_WLAN_MODE_REQ_V01, 1496 WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN, 1497 wlfw_wlan_mode_req_msg_v01_ei, req); 1498 if (ret < 0) { 1499 qmi_txn_cancel(&txn); 1500 cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n", 1501 cnss_qmi_mode_to_str(mode), mode, ret); 1502 goto out; 1503 } 1504 1505 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1506 if (ret < 0) { 1507 cnss_pr_err("Failed to wait for response of mode request, mode: %s(%d), err: %d\n", 1508 cnss_qmi_mode_to_str(mode), mode, ret); 1509 goto out; 1510 } 1511 1512 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1513 cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n", 1514 cnss_qmi_mode_to_str(mode), mode, resp->resp.result, 1515 resp->resp.error); 1516 ret = -resp->resp.result; 1517 goto out; 1518 } 1519 1520 kfree(req); 1521 kfree(resp); 1522 return 0; 1523 1524 out: 1525 if (mode == CNSS_OFF) { 1526 cnss_pr_dbg("WLFW service is disconnected while sending mode off request\n"); 1527 ret = 0; 1528 } else { 1529 CNSS_QMI_ASSERT(); 1530 } 1531 kfree(req); 1532 kfree(resp); 1533 return ret; 1534 } 1535 1536 int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv, 1537 struct cnss_wlan_enable_cfg *config, 1538 const char *host_version) 1539 { 1540 struct wlfw_wlan_cfg_req_msg_v01 *req; 1541 struct wlfw_wlan_cfg_resp_msg_v01 *resp; 1542 struct qmi_txn txn; 1543 u32 i; 1544 int ret = 0; 1545 1546 if (!plat_priv) 1547 return -ENODEV; 1548 1549 cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n", 1550 plat_priv->driver_state); 1551 1552 req = kzalloc(sizeof(*req), GFP_KERNEL); 1553 if (!req) 1554 return -ENOMEM; 1555 1556 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1557 if (!resp) { 1558 kfree(req); 1559 return -ENOMEM; 1560 } 1561 1562 req->host_version_valid = 1; 1563 strlcpy(req->host_version, host_version, 1564 QMI_WLFW_MAX_STR_LEN_V01 + 1); 1565 1566 req->tgt_cfg_valid = 1; 1567 if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) 1568 req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; 1569 else 1570 req->tgt_cfg_len = config->num_ce_tgt_cfg; 1571 for (i = 0; i < req->tgt_cfg_len; i++) { 1572 req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; 1573 req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; 1574 req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; 1575 req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; 1576 req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; 1577 } 1578 1579 req->svc_cfg_valid = 1; 1580 if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) 1581 req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; 1582 else 1583 req->svc_cfg_len = config->num_ce_svc_pipe_cfg; 1584 for (i = 0; i < req->svc_cfg_len; i++) { 1585 req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; 1586 req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; 1587 req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; 1588 } 1589 1590 if (plat_priv->device_id != KIWI_DEVICE_ID && 1591 plat_priv->device_id != MANGO_DEVICE_ID) { 1592 req->shadow_reg_v2_valid = 1; 1593 if (config->num_shadow_reg_v2_cfg > 1594 QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01) 1595 req->shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01; 1596 else 1597 req->shadow_reg_v2_len = config->num_shadow_reg_v2_cfg; 1598 1599 memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg, 1600 sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) 1601 * req->shadow_reg_v2_len); 1602 } else { 1603 req->shadow_reg_v3_valid = 1; 1604 if (config->num_shadow_reg_v3_cfg > 1605 MAX_NUM_SHADOW_REG_V3) 1606 req->shadow_reg_v3_len = MAX_NUM_SHADOW_REG_V3; 1607 else 1608 req->shadow_reg_v3_len = config->num_shadow_reg_v3_cfg; 1609 1610 plat_priv->num_shadow_regs_v3 = req->shadow_reg_v3_len; 1611 1612 cnss_pr_dbg("Shadow reg v3 len: %d\n", 1613 plat_priv->num_shadow_regs_v3); 1614 1615 memcpy(req->shadow_reg_v3, config->shadow_reg_v3_cfg, 1616 sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01) 1617 * req->shadow_reg_v3_len); 1618 } 1619 1620 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1621 wlfw_wlan_cfg_resp_msg_v01_ei, resp); 1622 if (ret < 0) { 1623 cnss_pr_err("Failed to initialize txn for WLAN config request, err: %d\n", 1624 ret); 1625 goto out; 1626 } 1627 1628 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1629 QMI_WLFW_WLAN_CFG_REQ_V01, 1630 WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN, 1631 wlfw_wlan_cfg_req_msg_v01_ei, req); 1632 if (ret < 0) { 1633 qmi_txn_cancel(&txn); 1634 cnss_pr_err("Failed to send WLAN config request, err: %d\n", 1635 ret); 1636 goto out; 1637 } 1638 1639 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1640 if (ret < 0) { 1641 cnss_pr_err("Failed to wait for response of WLAN config request, err: %d\n", 1642 ret); 1643 goto out; 1644 } 1645 1646 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1647 cnss_pr_err("WLAN config request failed, result: %d, err: %d\n", 1648 resp->resp.result, resp->resp.error); 1649 ret = -resp->resp.result; 1650 goto out; 1651 } 1652 1653 kfree(req); 1654 kfree(resp); 1655 return 0; 1656 1657 out: 1658 CNSS_QMI_ASSERT(); 1659 kfree(req); 1660 kfree(resp); 1661 return ret; 1662 } 1663 1664 int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv, 1665 u32 offset, u32 mem_type, 1666 u32 data_len, u8 *data) 1667 { 1668 struct wlfw_athdiag_read_req_msg_v01 *req; 1669 struct wlfw_athdiag_read_resp_msg_v01 *resp; 1670 struct qmi_txn txn; 1671 int ret = 0; 1672 1673 if (!plat_priv) 1674 return -ENODEV; 1675 1676 if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) { 1677 cnss_pr_err("Invalid parameters for athdiag read: data %pK, data_len %u\n", 1678 data, data_len); 1679 return -EINVAL; 1680 } 1681 1682 cnss_pr_dbg("athdiag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n", 1683 plat_priv->driver_state, offset, mem_type, data_len); 1684 1685 req = kzalloc(sizeof(*req), GFP_KERNEL); 1686 if (!req) 1687 return -ENOMEM; 1688 1689 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1690 if (!resp) { 1691 kfree(req); 1692 return -ENOMEM; 1693 } 1694 1695 req->offset = offset; 1696 req->mem_type = mem_type; 1697 req->data_len = data_len; 1698 1699 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1700 wlfw_athdiag_read_resp_msg_v01_ei, resp); 1701 if (ret < 0) { 1702 cnss_pr_err("Failed to initialize txn for athdiag read request, err: %d\n", 1703 ret); 1704 goto out; 1705 } 1706 1707 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1708 QMI_WLFW_ATHDIAG_READ_REQ_V01, 1709 WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN, 1710 wlfw_athdiag_read_req_msg_v01_ei, req); 1711 if (ret < 0) { 1712 qmi_txn_cancel(&txn); 1713 cnss_pr_err("Failed to send athdiag read request, err: %d\n", 1714 ret); 1715 goto out; 1716 } 1717 1718 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1719 if (ret < 0) { 1720 cnss_pr_err("Failed to wait for response of athdiag read request, err: %d\n", 1721 ret); 1722 goto out; 1723 } 1724 1725 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1726 cnss_pr_err("Athdiag read request failed, result: %d, err: %d\n", 1727 resp->resp.result, resp->resp.error); 1728 ret = -resp->resp.result; 1729 goto out; 1730 } 1731 1732 if (!resp->data_valid || resp->data_len != data_len) { 1733 cnss_pr_err("athdiag read data is invalid, data_valid = %u, data_len = %u\n", 1734 resp->data_valid, resp->data_len); 1735 ret = -EINVAL; 1736 goto out; 1737 } 1738 1739 memcpy(data, resp->data, resp->data_len); 1740 1741 kfree(req); 1742 kfree(resp); 1743 return 0; 1744 1745 out: 1746 kfree(req); 1747 kfree(resp); 1748 return ret; 1749 } 1750 1751 int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv, 1752 u32 offset, u32 mem_type, 1753 u32 data_len, u8 *data) 1754 { 1755 struct wlfw_athdiag_write_req_msg_v01 *req; 1756 struct wlfw_athdiag_write_resp_msg_v01 *resp; 1757 struct qmi_txn txn; 1758 int ret = 0; 1759 1760 if (!plat_priv) 1761 return -ENODEV; 1762 1763 if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) { 1764 cnss_pr_err("Invalid parameters for athdiag write: data %pK, data_len %u\n", 1765 data, data_len); 1766 return -EINVAL; 1767 } 1768 1769 cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %pK\n", 1770 plat_priv->driver_state, offset, mem_type, data_len, data); 1771 1772 req = kzalloc(sizeof(*req), GFP_KERNEL); 1773 if (!req) 1774 return -ENOMEM; 1775 1776 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1777 if (!resp) { 1778 kfree(req); 1779 return -ENOMEM; 1780 } 1781 1782 req->offset = offset; 1783 req->mem_type = mem_type; 1784 req->data_len = data_len; 1785 memcpy(req->data, data, data_len); 1786 1787 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1788 wlfw_athdiag_write_resp_msg_v01_ei, resp); 1789 if (ret < 0) { 1790 cnss_pr_err("Failed to initialize txn for athdiag write request, err: %d\n", 1791 ret); 1792 goto out; 1793 } 1794 1795 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1796 QMI_WLFW_ATHDIAG_WRITE_REQ_V01, 1797 WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN, 1798 wlfw_athdiag_write_req_msg_v01_ei, req); 1799 if (ret < 0) { 1800 qmi_txn_cancel(&txn); 1801 cnss_pr_err("Failed to send athdiag write request, err: %d\n", 1802 ret); 1803 goto out; 1804 } 1805 1806 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1807 if (ret < 0) { 1808 cnss_pr_err("Failed to wait for response of athdiag write request, err: %d\n", 1809 ret); 1810 goto out; 1811 } 1812 1813 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1814 cnss_pr_err("Athdiag write request failed, result: %d, err: %d\n", 1815 resp->resp.result, resp->resp.error); 1816 ret = -resp->resp.result; 1817 goto out; 1818 } 1819 1820 kfree(req); 1821 kfree(resp); 1822 return 0; 1823 1824 out: 1825 kfree(req); 1826 kfree(resp); 1827 return ret; 1828 } 1829 1830 int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv, 1831 u8 fw_log_mode) 1832 { 1833 struct wlfw_ini_req_msg_v01 *req; 1834 struct wlfw_ini_resp_msg_v01 *resp; 1835 struct qmi_txn txn; 1836 int ret = 0; 1837 1838 if (!plat_priv) 1839 return -ENODEV; 1840 1841 cnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n", 1842 plat_priv->driver_state, fw_log_mode); 1843 1844 req = kzalloc(sizeof(*req), GFP_KERNEL); 1845 if (!req) 1846 return -ENOMEM; 1847 1848 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1849 if (!resp) { 1850 kfree(req); 1851 return -ENOMEM; 1852 } 1853 1854 req->enablefwlog_valid = 1; 1855 req->enablefwlog = fw_log_mode; 1856 1857 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1858 wlfw_ini_resp_msg_v01_ei, resp); 1859 if (ret < 0) { 1860 cnss_pr_err("Failed to initialize txn for ini request, fw_log_mode: %d, err: %d\n", 1861 fw_log_mode, ret); 1862 goto out; 1863 } 1864 1865 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1866 QMI_WLFW_INI_REQ_V01, 1867 WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN, 1868 wlfw_ini_req_msg_v01_ei, req); 1869 if (ret < 0) { 1870 qmi_txn_cancel(&txn); 1871 cnss_pr_err("Failed to send ini request, fw_log_mode: %d, err: %d\n", 1872 fw_log_mode, ret); 1873 goto out; 1874 } 1875 1876 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1877 if (ret < 0) { 1878 cnss_pr_err("Failed to wait for response of ini request, fw_log_mode: %d, err: %d\n", 1879 fw_log_mode, ret); 1880 goto out; 1881 } 1882 1883 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1884 cnss_pr_err("Ini request failed, fw_log_mode: %d, result: %d, err: %d\n", 1885 fw_log_mode, resp->resp.result, resp->resp.error); 1886 ret = -resp->resp.result; 1887 goto out; 1888 } 1889 1890 kfree(req); 1891 kfree(resp); 1892 return 0; 1893 1894 out: 1895 kfree(req); 1896 kfree(resp); 1897 return ret; 1898 } 1899 1900 int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv) 1901 { 1902 struct wlfw_pcie_gen_switch_req_msg_v01 req; 1903 struct wlfw_pcie_gen_switch_resp_msg_v01 resp = {0}; 1904 struct qmi_txn txn; 1905 int ret = 0; 1906 1907 if (!plat_priv) 1908 return -ENODEV; 1909 1910 if (plat_priv->pcie_gen_speed == QMI_PCIE_GEN_SPEED_INVALID_V01 || 1911 !plat_priv->fw_pcie_gen_switch) { 1912 cnss_pr_dbg("PCIE Gen speed not setup\n"); 1913 return 0; 1914 } 1915 1916 cnss_pr_dbg("Sending PCIE Gen speed: %d state: 0x%lx\n", 1917 plat_priv->pcie_gen_speed, plat_priv->driver_state); 1918 req.pcie_speed = (enum wlfw_pcie_gen_speed_v01) 1919 plat_priv->pcie_gen_speed; 1920 1921 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1922 wlfw_pcie_gen_switch_resp_msg_v01_ei, &resp); 1923 if (ret < 0) { 1924 cnss_pr_err("Failed to initialize txn for PCIE speed switch err: %d\n", 1925 ret); 1926 goto out; 1927 } 1928 1929 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1930 QMI_WLFW_PCIE_GEN_SWITCH_REQ_V01, 1931 WLFW_PCIE_GEN_SWITCH_REQ_MSG_V01_MAX_MSG_LEN, 1932 wlfw_pcie_gen_switch_req_msg_v01_ei, &req); 1933 if (ret < 0) { 1934 qmi_txn_cancel(&txn); 1935 cnss_pr_err("Failed to send PCIE speed switch, err: %d\n", ret); 1936 goto out; 1937 } 1938 1939 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 1940 if (ret < 0) { 1941 cnss_pr_err("Failed to wait for PCIE Gen switch resp, err: %d\n", 1942 ret); 1943 goto out; 1944 } 1945 1946 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 1947 cnss_pr_err("PCIE Gen Switch req failed, Speed: %d, result: %d, err: %d\n", 1948 plat_priv->pcie_gen_speed, resp.resp.result, 1949 resp.resp.error); 1950 ret = -resp.resp.result; 1951 } 1952 out: 1953 /* Reset PCIE Gen speed after one time use */ 1954 plat_priv->pcie_gen_speed = QMI_PCIE_GEN_SPEED_INVALID_V01; 1955 return ret; 1956 } 1957 1958 int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv) 1959 { 1960 struct wlfw_antenna_switch_req_msg_v01 *req; 1961 struct wlfw_antenna_switch_resp_msg_v01 *resp; 1962 struct qmi_txn txn; 1963 int ret = 0; 1964 1965 if (!plat_priv) 1966 return -ENODEV; 1967 1968 cnss_pr_dbg("Sending antenna switch sync request, state: 0x%lx\n", 1969 plat_priv->driver_state); 1970 1971 req = kzalloc(sizeof(*req), GFP_KERNEL); 1972 if (!req) 1973 return -ENOMEM; 1974 1975 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1976 if (!resp) { 1977 kfree(req); 1978 return -ENOMEM; 1979 } 1980 1981 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 1982 wlfw_antenna_switch_resp_msg_v01_ei, resp); 1983 if (ret < 0) { 1984 cnss_pr_err("Failed to initialize txn for antenna switch request, err: %d\n", 1985 ret); 1986 goto out; 1987 } 1988 1989 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 1990 QMI_WLFW_ANTENNA_SWITCH_REQ_V01, 1991 WLFW_ANTENNA_SWITCH_REQ_MSG_V01_MAX_MSG_LEN, 1992 wlfw_antenna_switch_req_msg_v01_ei, req); 1993 if (ret < 0) { 1994 qmi_txn_cancel(&txn); 1995 cnss_pr_err("Failed to send antenna switch request, err: %d\n", 1996 ret); 1997 goto out; 1998 } 1999 2000 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2001 if (ret < 0) { 2002 cnss_pr_err("Failed to wait for response of antenna switch request, err: %d\n", 2003 ret); 2004 goto out; 2005 } 2006 2007 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2008 cnss_pr_dbg("Antenna switch request failed, result: %d, err: %d\n", 2009 resp->resp.result, resp->resp.error); 2010 ret = -resp->resp.result; 2011 goto out; 2012 } 2013 2014 if (resp->antenna_valid) 2015 plat_priv->antenna = resp->antenna; 2016 2017 cnss_pr_dbg("Antenna valid: %u, antenna 0x%llx\n", 2018 resp->antenna_valid, resp->antenna); 2019 2020 kfree(req); 2021 kfree(resp); 2022 return 0; 2023 2024 out: 2025 kfree(req); 2026 kfree(resp); 2027 return ret; 2028 } 2029 2030 int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv) 2031 { 2032 struct wlfw_antenna_grant_req_msg_v01 *req; 2033 struct wlfw_antenna_grant_resp_msg_v01 *resp; 2034 struct qmi_txn txn; 2035 int ret = 0; 2036 2037 if (!plat_priv) 2038 return -ENODEV; 2039 2040 cnss_pr_dbg("Sending antenna grant sync request, state: 0x%lx, grant 0x%llx\n", 2041 plat_priv->driver_state, plat_priv->grant); 2042 2043 req = kzalloc(sizeof(*req), GFP_KERNEL); 2044 if (!req) 2045 return -ENOMEM; 2046 2047 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2048 if (!resp) { 2049 kfree(req); 2050 return -ENOMEM; 2051 } 2052 2053 req->grant_valid = 1; 2054 req->grant = plat_priv->grant; 2055 2056 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2057 wlfw_antenna_grant_resp_msg_v01_ei, resp); 2058 if (ret < 0) { 2059 cnss_pr_err("Failed to initialize txn for antenna grant request, err: %d\n", 2060 ret); 2061 goto out; 2062 } 2063 2064 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2065 QMI_WLFW_ANTENNA_GRANT_REQ_V01, 2066 WLFW_ANTENNA_GRANT_REQ_MSG_V01_MAX_MSG_LEN, 2067 wlfw_antenna_grant_req_msg_v01_ei, req); 2068 if (ret < 0) { 2069 qmi_txn_cancel(&txn); 2070 cnss_pr_err("Failed to send antenna grant request, err: %d\n", 2071 ret); 2072 goto out; 2073 } 2074 2075 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2076 if (ret < 0) { 2077 cnss_pr_err("Failed to wait for response of antenna grant request, err: %d\n", 2078 ret); 2079 goto out; 2080 } 2081 2082 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2083 cnss_pr_err("Antenna grant request failed, result: %d, err: %d\n", 2084 resp->resp.result, resp->resp.error); 2085 ret = -resp->resp.result; 2086 goto out; 2087 } 2088 2089 kfree(req); 2090 kfree(resp); 2091 return 0; 2092 2093 out: 2094 kfree(req); 2095 kfree(resp); 2096 return ret; 2097 } 2098 2099 int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv) 2100 { 2101 struct wlfw_qdss_trace_mem_info_req_msg_v01 *req; 2102 struct wlfw_qdss_trace_mem_info_resp_msg_v01 *resp; 2103 struct qmi_txn txn; 2104 struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; 2105 int ret = 0; 2106 int i; 2107 2108 cnss_pr_dbg("Sending QDSS trace mem info, state: 0x%lx\n", 2109 plat_priv->driver_state); 2110 2111 req = kzalloc(sizeof(*req), GFP_KERNEL); 2112 if (!req) 2113 return -ENOMEM; 2114 2115 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2116 if (!resp) { 2117 kfree(req); 2118 return -ENOMEM; 2119 } 2120 2121 if (plat_priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 2122 cnss_pr_err("Invalid seg len %u\n", plat_priv->qdss_mem_seg_len); 2123 ret = -EINVAL; 2124 goto out; 2125 } 2126 2127 req->mem_seg_len = plat_priv->qdss_mem_seg_len; 2128 for (i = 0; i < req->mem_seg_len; i++) { 2129 cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", 2130 qdss_mem[i].va, &qdss_mem[i].pa, 2131 qdss_mem[i].size, qdss_mem[i].type); 2132 2133 req->mem_seg[i].addr = qdss_mem[i].pa; 2134 req->mem_seg[i].size = qdss_mem[i].size; 2135 req->mem_seg[i].type = qdss_mem[i].type; 2136 } 2137 2138 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2139 wlfw_qdss_trace_mem_info_resp_msg_v01_ei, resp); 2140 if (ret < 0) { 2141 cnss_pr_err("Fail to initialize txn for QDSS trace mem request: err %d\n", 2142 ret); 2143 goto out; 2144 } 2145 2146 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2147 QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01, 2148 WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN, 2149 wlfw_qdss_trace_mem_info_req_msg_v01_ei, req); 2150 if (ret < 0) { 2151 qmi_txn_cancel(&txn); 2152 cnss_pr_err("Fail to send QDSS trace mem info request: err %d\n", 2153 ret); 2154 goto out; 2155 } 2156 2157 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2158 if (ret < 0) { 2159 cnss_pr_err("Fail to wait for response of QDSS trace mem info request, err %d\n", 2160 ret); 2161 goto out; 2162 } 2163 2164 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2165 cnss_pr_err("QDSS trace mem info request failed, result: %d, err: %d\n", 2166 resp->resp.result, resp->resp.error); 2167 ret = -resp->resp.result; 2168 goto out; 2169 } 2170 2171 kfree(req); 2172 kfree(resp); 2173 return 0; 2174 2175 out: 2176 kfree(req); 2177 kfree(resp); 2178 return ret; 2179 } 2180 2181 int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, 2182 struct cnss_wfc_cfg cfg) 2183 { 2184 struct wlfw_wfc_call_status_req_msg_v01 *req; 2185 struct wlfw_wfc_call_status_resp_msg_v01 *resp; 2186 struct qmi_txn txn; 2187 int ret = 0; 2188 2189 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { 2190 cnss_pr_err("Drop host WFC indication as FW not initialized\n"); 2191 return -EINVAL; 2192 } 2193 req = kzalloc(sizeof(*req), GFP_KERNEL); 2194 if (!req) 2195 return -ENOMEM; 2196 2197 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2198 if (!resp) { 2199 kfree(req); 2200 return -ENOMEM; 2201 } 2202 2203 req->wfc_call_active_valid = 1; 2204 req->wfc_call_active = cfg.mode; 2205 2206 cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n", 2207 plat_priv->driver_state); 2208 2209 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2210 wlfw_wfc_call_status_resp_msg_v01_ei, resp); 2211 if (ret < 0) { 2212 cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n", 2213 ret); 2214 goto out; 2215 } 2216 2217 cnss_pr_dbg("Send WFC Mode: %d\n", cfg.mode); 2218 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2219 QMI_WLFW_WFC_CALL_STATUS_REQ_V01, 2220 WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN, 2221 wlfw_wfc_call_status_req_msg_v01_ei, req); 2222 if (ret < 0) { 2223 qmi_txn_cancel(&txn); 2224 cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n", 2225 ret); 2226 goto out; 2227 } 2228 2229 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2230 if (ret < 0) { 2231 cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n", 2232 ret); 2233 goto out; 2234 } 2235 2236 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2237 cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n", 2238 resp->resp.result, resp->resp.error); 2239 ret = -EINVAL; 2240 goto out; 2241 } 2242 ret = 0; 2243 out: 2244 kfree(req); 2245 kfree(resp); 2246 return ret; 2247 2248 } 2249 static int cnss_wlfw_wfc_call_status_send_sync 2250 (struct cnss_plat_data *plat_priv, 2251 const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg) 2252 { 2253 struct wlfw_wfc_call_status_req_msg_v01 *req; 2254 struct wlfw_wfc_call_status_resp_msg_v01 *resp; 2255 struct qmi_txn txn; 2256 int ret = 0; 2257 2258 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { 2259 cnss_pr_err("Drop IMS WFC indication as FW not initialized\n"); 2260 return -EINVAL; 2261 } 2262 req = kzalloc(sizeof(*req), GFP_KERNEL); 2263 if (!req) 2264 return -ENOMEM; 2265 2266 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2267 if (!resp) { 2268 kfree(req); 2269 return -ENOMEM; 2270 } 2271 2272 /** 2273 * WFC Call r1 design has CNSS as pass thru using opaque hex buffer. 2274 * But in r2 update QMI structure is expanded and as an effect qmi 2275 * decoded structures have padding. Thus we cannot use buffer design. 2276 * For backward compatibility for r1 design copy only wfc_call_active 2277 * value in hex buffer. 2278 */ 2279 req->wfc_call_status_len = sizeof(ind_msg->wfc_call_active); 2280 req->wfc_call_status[0] = ind_msg->wfc_call_active; 2281 2282 /* wfc_call_active is mandatory in IMS indication */ 2283 req->wfc_call_active_valid = 1; 2284 req->wfc_call_active = ind_msg->wfc_call_active; 2285 req->all_wfc_calls_held_valid = ind_msg->all_wfc_calls_held_valid; 2286 req->all_wfc_calls_held = ind_msg->all_wfc_calls_held; 2287 req->is_wfc_emergency_valid = ind_msg->is_wfc_emergency_valid; 2288 req->is_wfc_emergency = ind_msg->is_wfc_emergency; 2289 req->twt_ims_start_valid = ind_msg->twt_ims_start_valid; 2290 req->twt_ims_start = ind_msg->twt_ims_start; 2291 req->twt_ims_int_valid = ind_msg->twt_ims_int_valid; 2292 req->twt_ims_int = ind_msg->twt_ims_int; 2293 req->media_quality_valid = ind_msg->media_quality_valid; 2294 req->media_quality = 2295 (enum wlfw_wfc_media_quality_v01)ind_msg->media_quality; 2296 2297 cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n", 2298 plat_priv->driver_state); 2299 2300 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2301 wlfw_wfc_call_status_resp_msg_v01_ei, resp); 2302 if (ret < 0) { 2303 cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n", 2304 ret); 2305 goto out; 2306 } 2307 2308 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2309 QMI_WLFW_WFC_CALL_STATUS_REQ_V01, 2310 WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN, 2311 wlfw_wfc_call_status_req_msg_v01_ei, req); 2312 if (ret < 0) { 2313 qmi_txn_cancel(&txn); 2314 cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n", 2315 ret); 2316 goto out; 2317 } 2318 2319 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2320 if (ret < 0) { 2321 cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n", 2322 ret); 2323 goto out; 2324 } 2325 2326 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2327 cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n", 2328 resp->resp.result, resp->resp.error); 2329 ret = -resp->resp.result; 2330 goto out; 2331 } 2332 ret = 0; 2333 out: 2334 kfree(req); 2335 kfree(resp); 2336 return ret; 2337 } 2338 2339 int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv) 2340 { 2341 struct wlfw_dynamic_feature_mask_req_msg_v01 *req; 2342 struct wlfw_dynamic_feature_mask_resp_msg_v01 *resp; 2343 struct qmi_txn txn; 2344 int ret = 0; 2345 2346 cnss_pr_dbg("Sending dynamic feature mask 0x%llx, state: 0x%lx\n", 2347 plat_priv->dynamic_feature, 2348 plat_priv->driver_state); 2349 2350 req = kzalloc(sizeof(*req), GFP_KERNEL); 2351 if (!req) 2352 return -ENOMEM; 2353 2354 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2355 if (!resp) { 2356 kfree(req); 2357 return -ENOMEM; 2358 } 2359 2360 req->mask_valid = 1; 2361 req->mask = plat_priv->dynamic_feature; 2362 2363 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2364 wlfw_dynamic_feature_mask_resp_msg_v01_ei, resp); 2365 if (ret < 0) { 2366 cnss_pr_err("Fail to initialize txn for dynamic feature mask request: err %d\n", 2367 ret); 2368 goto out; 2369 } 2370 2371 ret = qmi_send_request 2372 (&plat_priv->qmi_wlfw, NULL, &txn, 2373 QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01, 2374 WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN, 2375 wlfw_dynamic_feature_mask_req_msg_v01_ei, req); 2376 if (ret < 0) { 2377 qmi_txn_cancel(&txn); 2378 cnss_pr_err("Fail to send dynamic feature mask request: err %d\n", 2379 ret); 2380 goto out; 2381 } 2382 2383 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2384 if (ret < 0) { 2385 cnss_pr_err("Fail to wait for response of dynamic feature mask request, err %d\n", 2386 ret); 2387 goto out; 2388 } 2389 2390 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2391 cnss_pr_err("Dynamic feature mask request failed, result: %d, err: %d\n", 2392 resp->resp.result, resp->resp.error); 2393 ret = -resp->resp.result; 2394 goto out; 2395 } 2396 2397 out: 2398 kfree(req); 2399 kfree(resp); 2400 return ret; 2401 } 2402 2403 int cnss_wlfw_get_info_send_sync(struct cnss_plat_data *plat_priv, int type, 2404 void *cmd, int cmd_len) 2405 { 2406 struct wlfw_get_info_req_msg_v01 *req; 2407 struct wlfw_get_info_resp_msg_v01 *resp; 2408 struct qmi_txn txn; 2409 int ret = 0; 2410 2411 cnss_pr_buf("Sending get info message, type: %d, cmd length: %d, state: 0x%lx\n", 2412 type, cmd_len, plat_priv->driver_state); 2413 2414 if (cmd_len > QMI_WLFW_MAX_DATA_SIZE_V01) 2415 return -EINVAL; 2416 2417 req = kzalloc(sizeof(*req), GFP_KERNEL); 2418 if (!req) 2419 return -ENOMEM; 2420 2421 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2422 if (!resp) { 2423 kfree(req); 2424 return -ENOMEM; 2425 } 2426 2427 req->type = type; 2428 req->data_len = cmd_len; 2429 memcpy(req->data, cmd, req->data_len); 2430 2431 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2432 wlfw_get_info_resp_msg_v01_ei, resp); 2433 if (ret < 0) { 2434 cnss_pr_err("Failed to initialize txn for get info request, err: %d\n", 2435 ret); 2436 goto out; 2437 } 2438 2439 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2440 QMI_WLFW_GET_INFO_REQ_V01, 2441 WLFW_GET_INFO_REQ_MSG_V01_MAX_MSG_LEN, 2442 wlfw_get_info_req_msg_v01_ei, req); 2443 if (ret < 0) { 2444 qmi_txn_cancel(&txn); 2445 cnss_pr_err("Failed to send get info request, err: %d\n", 2446 ret); 2447 goto out; 2448 } 2449 2450 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2451 if (ret < 0) { 2452 cnss_pr_err("Failed to wait for response of get info request, err: %d\n", 2453 ret); 2454 goto out; 2455 } 2456 2457 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2458 cnss_pr_err("Get info request failed, result: %d, err: %d\n", 2459 resp->resp.result, resp->resp.error); 2460 ret = -resp->resp.result; 2461 goto out; 2462 } 2463 2464 kfree(req); 2465 kfree(resp); 2466 return 0; 2467 2468 out: 2469 kfree(req); 2470 kfree(resp); 2471 return ret; 2472 } 2473 2474 unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv) 2475 { 2476 return QMI_WLFW_TIMEOUT_MS; 2477 } 2478 2479 static void cnss_wlfw_request_mem_ind_cb(struct qmi_handle *qmi_wlfw, 2480 struct sockaddr_qrtr *sq, 2481 struct qmi_txn *txn, const void *data) 2482 { 2483 struct cnss_plat_data *plat_priv = 2484 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2485 const struct wlfw_request_mem_ind_msg_v01 *ind_msg = data; 2486 int i; 2487 2488 cnss_pr_dbg("Received QMI WLFW request memory indication\n"); 2489 2490 if (!txn) { 2491 cnss_pr_err("Spurious indication\n"); 2492 return; 2493 } 2494 2495 if (ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 2496 cnss_pr_err("Invalid seg len %u\n", ind_msg->mem_seg_len); 2497 return; 2498 } 2499 2500 plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len; 2501 for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { 2502 cnss_pr_dbg("FW requests for memory, size: 0x%x, type: %u\n", 2503 ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type); 2504 plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type; 2505 plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size; 2506 if (!plat_priv->fw_mem[i].va && 2507 plat_priv->fw_mem[i].type == CNSS_MEM_TYPE_DDR) 2508 plat_priv->fw_mem[i].attrs |= 2509 DMA_ATTR_FORCE_CONTIGUOUS; 2510 if (plat_priv->fw_mem[i].type == CNSS_MEM_CAL_V01) 2511 plat_priv->cal_mem = &plat_priv->fw_mem[i]; 2512 } 2513 2514 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM, 2515 0, NULL); 2516 } 2517 2518 static void cnss_wlfw_fw_mem_ready_ind_cb(struct qmi_handle *qmi_wlfw, 2519 struct sockaddr_qrtr *sq, 2520 struct qmi_txn *txn, const void *data) 2521 { 2522 struct cnss_plat_data *plat_priv = 2523 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2524 2525 cnss_pr_dbg("Received QMI WLFW FW memory ready indication\n"); 2526 2527 if (!txn) { 2528 cnss_pr_err("Spurious indication\n"); 2529 return; 2530 } 2531 2532 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_MEM_READY, 2533 0, NULL); 2534 } 2535 2536 /** 2537 * cnss_wlfw_fw_ready_ind_cb: FW ready indication handler (Helium arch) 2538 * 2539 * This event is not required for HST/ HSP as FW calibration done is 2540 * provided in QMI_WLFW_CAL_DONE_IND_V01 2541 */ 2542 static void cnss_wlfw_fw_ready_ind_cb(struct qmi_handle *qmi_wlfw, 2543 struct sockaddr_qrtr *sq, 2544 struct qmi_txn *txn, const void *data) 2545 { 2546 struct cnss_plat_data *plat_priv = 2547 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2548 struct cnss_cal_info *cal_info; 2549 2550 if (!txn) { 2551 cnss_pr_err("Spurious indication\n"); 2552 return; 2553 } 2554 2555 if (plat_priv->device_id == QCA6390_DEVICE_ID || 2556 plat_priv->device_id == QCA6490_DEVICE_ID) { 2557 cnss_pr_dbg("Ignore FW Ready Indication for HST/HSP"); 2558 return; 2559 } 2560 2561 cnss_pr_dbg("Received QMI WLFW FW ready indication.\n"); 2562 cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL); 2563 if (!cal_info) 2564 return; 2565 2566 cal_info->cal_status = CNSS_CAL_DONE; 2567 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE, 2568 0, cal_info); 2569 } 2570 2571 static void cnss_wlfw_fw_init_done_ind_cb(struct qmi_handle *qmi_wlfw, 2572 struct sockaddr_qrtr *sq, 2573 struct qmi_txn *txn, const void *data) 2574 { 2575 struct cnss_plat_data *plat_priv = 2576 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2577 2578 cnss_pr_dbg("Received QMI WLFW FW initialization done indication\n"); 2579 2580 if (!txn) { 2581 cnss_pr_err("Spurious indication\n"); 2582 return; 2583 } 2584 2585 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_READY, 0, NULL); 2586 } 2587 2588 static void cnss_wlfw_pin_result_ind_cb(struct qmi_handle *qmi_wlfw, 2589 struct sockaddr_qrtr *sq, 2590 struct qmi_txn *txn, const void *data) 2591 { 2592 struct cnss_plat_data *plat_priv = 2593 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2594 const struct wlfw_pin_connect_result_ind_msg_v01 *ind_msg = data; 2595 2596 cnss_pr_dbg("Received QMI WLFW pin connect result indication\n"); 2597 2598 if (!txn) { 2599 cnss_pr_err("Spurious indication\n"); 2600 return; 2601 } 2602 2603 if (ind_msg->pwr_pin_result_valid) 2604 plat_priv->pin_result.fw_pwr_pin_result = 2605 ind_msg->pwr_pin_result; 2606 if (ind_msg->phy_io_pin_result_valid) 2607 plat_priv->pin_result.fw_phy_io_pin_result = 2608 ind_msg->phy_io_pin_result; 2609 if (ind_msg->rf_pin_result_valid) 2610 plat_priv->pin_result.fw_rf_pin_result = ind_msg->rf_pin_result; 2611 2612 cnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n", 2613 ind_msg->pwr_pin_result, ind_msg->phy_io_pin_result, 2614 ind_msg->rf_pin_result); 2615 } 2616 2617 int cnss_wlfw_cal_report_req_send_sync(struct cnss_plat_data *plat_priv, 2618 u32 cal_file_download_size) 2619 { 2620 struct wlfw_cal_report_req_msg_v01 req = {0}; 2621 struct wlfw_cal_report_resp_msg_v01 resp = {0}; 2622 struct qmi_txn txn; 2623 int ret = 0; 2624 2625 cnss_pr_dbg("Sending cal file report request. File size: %d, state: 0x%lx\n", 2626 cal_file_download_size, plat_priv->driver_state); 2627 req.cal_file_download_size_valid = 1; 2628 req.cal_file_download_size = cal_file_download_size; 2629 2630 ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, 2631 wlfw_cal_report_resp_msg_v01_ei, &resp); 2632 if (ret < 0) { 2633 cnss_pr_err("Failed to initialize txn for Cal Report request, err: %d\n", 2634 ret); 2635 goto out; 2636 } 2637 ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, 2638 QMI_WLFW_CAL_REPORT_REQ_V01, 2639 WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN, 2640 wlfw_cal_report_req_msg_v01_ei, &req); 2641 if (ret < 0) { 2642 qmi_txn_cancel(&txn); 2643 cnss_pr_err("Failed to send Cal Report request, err: %d\n", 2644 ret); 2645 goto out; 2646 } 2647 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2648 if (ret < 0) { 2649 cnss_pr_err("Failed to wait for response of Cal Report request, err: %d\n", 2650 ret); 2651 goto out; 2652 } 2653 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 2654 cnss_pr_err("Cal Report request failed, result: %d, err: %d\n", 2655 resp.resp.result, resp.resp.error); 2656 ret = -resp.resp.result; 2657 goto out; 2658 } 2659 out: 2660 return ret; 2661 } 2662 2663 static void cnss_wlfw_cal_done_ind_cb(struct qmi_handle *qmi_wlfw, 2664 struct sockaddr_qrtr *sq, 2665 struct qmi_txn *txn, const void *data) 2666 { 2667 struct cnss_plat_data *plat_priv = 2668 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2669 const struct wlfw_cal_done_ind_msg_v01 *ind = data; 2670 struct cnss_cal_info *cal_info; 2671 2672 cnss_pr_dbg("Received Cal done indication. File size: %d\n", 2673 ind->cal_file_upload_size); 2674 cnss_pr_info("Calibration took %d ms\n", 2675 jiffies_to_msecs(jiffies - plat_priv->cal_time)); 2676 if (!txn) { 2677 cnss_pr_err("Spurious indication\n"); 2678 return; 2679 } 2680 if (ind->cal_file_upload_size_valid) 2681 plat_priv->cal_file_size = ind->cal_file_upload_size; 2682 cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL); 2683 if (!cal_info) 2684 return; 2685 2686 cal_info->cal_status = CNSS_CAL_DONE; 2687 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE, 2688 0, cal_info); 2689 } 2690 2691 static void cnss_wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi_wlfw, 2692 struct sockaddr_qrtr *sq, 2693 struct qmi_txn *txn, 2694 const void *data) 2695 { 2696 struct cnss_plat_data *plat_priv = 2697 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2698 const struct wlfw_qdss_trace_req_mem_ind_msg_v01 *ind_msg = data; 2699 int i; 2700 2701 cnss_pr_dbg("Received QMI WLFW QDSS trace request mem indication\n"); 2702 2703 if (!txn) { 2704 cnss_pr_err("Spurious indication\n"); 2705 return; 2706 } 2707 2708 if (plat_priv->qdss_mem_seg_len) { 2709 cnss_pr_err("Ignore double allocation for QDSS trace, current len %u\n", 2710 plat_priv->qdss_mem_seg_len); 2711 return; 2712 } 2713 2714 if (ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 2715 cnss_pr_err("Invalid seg len %u\n", ind_msg->mem_seg_len); 2716 return; 2717 } 2718 2719 plat_priv->qdss_mem_seg_len = ind_msg->mem_seg_len; 2720 for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { 2721 cnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n", 2722 ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type); 2723 plat_priv->qdss_mem[i].type = ind_msg->mem_seg[i].type; 2724 plat_priv->qdss_mem[i].size = ind_msg->mem_seg[i].size; 2725 } 2726 2727 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM, 2728 0, NULL); 2729 } 2730 2731 /** 2732 * cnss_wlfw_fw_mem_file_save_ind_cb: Save given FW mem to filesystem 2733 * 2734 * QDSS_TRACE_SAVE_IND feature is overloaded to provide any host allocated 2735 * fw memory segment for dumping to file system. Only one type of mem can be 2736 * saved per indication and is provided in mem seg index 0. 2737 * 2738 * Return: None 2739 */ 2740 static void cnss_wlfw_fw_mem_file_save_ind_cb(struct qmi_handle *qmi_wlfw, 2741 struct sockaddr_qrtr *sq, 2742 struct qmi_txn *txn, 2743 const void *data) 2744 { 2745 struct cnss_plat_data *plat_priv = 2746 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2747 const struct wlfw_qdss_trace_save_ind_msg_v01 *ind_msg = data; 2748 struct cnss_qmi_event_fw_mem_file_save_data *event_data; 2749 int i = 0; 2750 2751 if (!txn || !data) { 2752 cnss_pr_err("Spurious indication\n"); 2753 return; 2754 } 2755 cnss_pr_dbg("QMI fw_mem_file_save: source: %d mem_seg: %d type: %u len: %u\n", 2756 ind_msg->source, ind_msg->mem_seg_valid, 2757 ind_msg->mem_seg[0].type, ind_msg->mem_seg_len); 2758 2759 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 2760 if (!event_data) 2761 return; 2762 2763 event_data->mem_type = ind_msg->mem_seg[0].type; 2764 event_data->mem_seg_len = ind_msg->mem_seg_len; 2765 event_data->total_size = ind_msg->total_size; 2766 2767 if (ind_msg->mem_seg_valid) { 2768 if (ind_msg->mem_seg_len > QMI_WLFW_MAX_STR_LEN_V01) { 2769 cnss_pr_err("Invalid seg len indication\n"); 2770 goto free_event_data; 2771 } 2772 for (i = 0; i < ind_msg->mem_seg_len; i++) { 2773 event_data->mem_seg[i].addr = ind_msg->mem_seg[i].addr; 2774 event_data->mem_seg[i].size = ind_msg->mem_seg[i].size; 2775 if (event_data->mem_type != ind_msg->mem_seg[i].type) { 2776 cnss_pr_err("FW Mem file save ind cannot have multiple mem types\n"); 2777 goto free_event_data; 2778 } 2779 cnss_pr_dbg("seg-%d: addr 0x%llx size 0x%x\n", 2780 i, ind_msg->mem_seg[i].addr, 2781 ind_msg->mem_seg[i].size); 2782 } 2783 } 2784 2785 if (ind_msg->file_name_valid) 2786 strlcpy(event_data->file_name, ind_msg->file_name, 2787 QMI_WLFW_MAX_STR_LEN_V01 + 1); 2788 if (ind_msg->source == 1) { 2789 if (!ind_msg->file_name_valid) 2790 strlcpy(event_data->file_name, "qdss_trace_wcss_etb", 2791 QMI_WLFW_MAX_STR_LEN_V01 + 1); 2792 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA, 2793 0, event_data); 2794 } else { 2795 if (event_data->mem_type == QMI_WLFW_MEM_QDSS_V01) { 2796 if (!ind_msg->file_name_valid) 2797 strlcpy(event_data->file_name, "qdss_trace_ddr", 2798 QMI_WLFW_MAX_STR_LEN_V01 + 1); 2799 } else { 2800 if (!ind_msg->file_name_valid) 2801 strlcpy(event_data->file_name, "fw_mem_dump", 2802 QMI_WLFW_MAX_STR_LEN_V01 + 1); 2803 } 2804 2805 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE, 2806 0, event_data); 2807 } 2808 2809 return; 2810 2811 free_event_data: 2812 kfree(event_data); 2813 } 2814 2815 static void cnss_wlfw_qdss_trace_free_ind_cb(struct qmi_handle *qmi_wlfw, 2816 struct sockaddr_qrtr *sq, 2817 struct qmi_txn *txn, 2818 const void *data) 2819 { 2820 struct cnss_plat_data *plat_priv = 2821 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2822 2823 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_FREE, 2824 0, NULL); 2825 } 2826 2827 static void cnss_wlfw_respond_get_info_ind_cb(struct qmi_handle *qmi_wlfw, 2828 struct sockaddr_qrtr *sq, 2829 struct qmi_txn *txn, 2830 const void *data) 2831 { 2832 struct cnss_plat_data *plat_priv = 2833 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2834 const struct wlfw_respond_get_info_ind_msg_v01 *ind_msg = data; 2835 2836 cnss_pr_buf("Received QMI WLFW respond get info indication\n"); 2837 2838 if (!txn) { 2839 cnss_pr_err("Spurious indication\n"); 2840 return; 2841 } 2842 2843 cnss_pr_buf("Extract message with event length: %d, type: %d, is last: %d, seq no: %d\n", 2844 ind_msg->data_len, ind_msg->type, 2845 ind_msg->is_last, ind_msg->seq_no); 2846 2847 if (plat_priv->get_info_cb_ctx && plat_priv->get_info_cb) 2848 plat_priv->get_info_cb(plat_priv->get_info_cb_ctx, 2849 (void *)ind_msg->data, 2850 ind_msg->data_len); 2851 } 2852 2853 static int cnss_ims_wfc_call_twt_cfg_send_sync 2854 (struct cnss_plat_data *plat_priv, 2855 const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg) 2856 { 2857 struct ims_private_service_wfc_call_twt_config_req_msg_v01 *req; 2858 struct ims_private_service_wfc_call_twt_config_rsp_msg_v01 *resp; 2859 struct qmi_txn txn; 2860 int ret = 0; 2861 2862 if (!test_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state)) { 2863 cnss_pr_err("Drop FW WFC indication as IMS QMI not connected\n"); 2864 return -EINVAL; 2865 } 2866 2867 req = kzalloc(sizeof(*req), GFP_KERNEL); 2868 if (!req) 2869 return -ENOMEM; 2870 2871 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2872 if (!resp) { 2873 kfree(req); 2874 return -ENOMEM; 2875 } 2876 2877 req->twt_sta_start_valid = ind_msg->twt_sta_start_valid; 2878 req->twt_sta_start = ind_msg->twt_sta_start; 2879 req->twt_sta_int_valid = ind_msg->twt_sta_int_valid; 2880 req->twt_sta_int = ind_msg->twt_sta_int; 2881 req->twt_sta_upo_valid = ind_msg->twt_sta_upo_valid; 2882 req->twt_sta_upo = ind_msg->twt_sta_upo; 2883 req->twt_sta_sp_valid = ind_msg->twt_sta_sp_valid; 2884 req->twt_sta_sp = ind_msg->twt_sta_sp; 2885 req->twt_sta_dl_valid = req->twt_sta_dl_valid; 2886 req->twt_sta_dl = req->twt_sta_dl; 2887 req->twt_sta_config_changed_valid = 2888 ind_msg->twt_sta_config_changed_valid; 2889 req->twt_sta_config_changed = ind_msg->twt_sta_config_changed; 2890 2891 cnss_pr_dbg("CNSS->IMS: TWT_CFG_REQ: state: 0x%lx\n", 2892 plat_priv->driver_state); 2893 2894 ret = 2895 qmi_txn_init(&plat_priv->ims_qmi, &txn, 2896 ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei, 2897 resp); 2898 if (ret < 0) { 2899 cnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Txn Init Err: %d\n", 2900 ret); 2901 goto out; 2902 } 2903 2904 ret = 2905 qmi_send_request(&plat_priv->ims_qmi, NULL, &txn, 2906 QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_V01, 2907 IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_MSG_V01_MAX_MSG_LEN, 2908 ims_private_service_wfc_call_twt_config_req_msg_v01_ei, req); 2909 if (ret < 0) { 2910 qmi_txn_cancel(&txn); 2911 cnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Send Err: %d\n", ret); 2912 goto out; 2913 } 2914 2915 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 2916 if (ret < 0) { 2917 cnss_pr_err("IMS->CNSS: TWT_CFG_RSP: QMI Wait Err: %d\n", ret); 2918 goto out; 2919 } 2920 2921 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2922 cnss_pr_err("IMS->CNSS: TWT_CFG_RSP: Result: %d Err: %d\n", 2923 resp->resp.result, resp->resp.error); 2924 ret = -resp->resp.result; 2925 goto out; 2926 } 2927 ret = 0; 2928 out: 2929 kfree(req); 2930 kfree(resp); 2931 return ret; 2932 } 2933 2934 int cnss_process_twt_cfg_ind_event(struct cnss_plat_data *plat_priv, 2935 void *data) 2936 { 2937 int ret; 2938 struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data; 2939 2940 ret = cnss_ims_wfc_call_twt_cfg_send_sync(plat_priv, ind_msg); 2941 kfree(data); 2942 return ret; 2943 } 2944 2945 static void cnss_wlfw_process_twt_cfg_ind(struct qmi_handle *qmi_wlfw, 2946 struct sockaddr_qrtr *sq, 2947 struct qmi_txn *txn, 2948 const void *data) 2949 { 2950 struct cnss_plat_data *plat_priv = 2951 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 2952 const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data; 2953 struct wlfw_wfc_call_twt_config_ind_msg_v01 *event_data; 2954 2955 if (!txn) { 2956 cnss_pr_err("FW->CNSS: TWT_CFG_IND: Spurious indication\n"); 2957 return; 2958 } 2959 2960 if (!ind_msg) { 2961 cnss_pr_err("FW->CNSS: TWT_CFG_IND: Invalid indication\n"); 2962 return; 2963 } 2964 cnss_pr_dbg("FW->CNSS: TWT_CFG_IND: %x %llx, %x %x, %x %x, %x %x, %x %x, %x %x\n", 2965 ind_msg->twt_sta_start_valid, ind_msg->twt_sta_start, 2966 ind_msg->twt_sta_int_valid, ind_msg->twt_sta_int, 2967 ind_msg->twt_sta_upo_valid, ind_msg->twt_sta_upo, 2968 ind_msg->twt_sta_sp_valid, ind_msg->twt_sta_sp, 2969 ind_msg->twt_sta_dl_valid, ind_msg->twt_sta_dl, 2970 ind_msg->twt_sta_config_changed_valid, 2971 ind_msg->twt_sta_config_changed); 2972 2973 event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL); 2974 if (!event_data) 2975 return; 2976 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND, 0, 2977 event_data); 2978 } 2979 2980 static struct qmi_msg_handler qmi_wlfw_msg_handlers[] = { 2981 { 2982 .type = QMI_INDICATION, 2983 .msg_id = QMI_WLFW_REQUEST_MEM_IND_V01, 2984 .ei = wlfw_request_mem_ind_msg_v01_ei, 2985 .decoded_size = sizeof(struct wlfw_request_mem_ind_msg_v01), 2986 .fn = cnss_wlfw_request_mem_ind_cb 2987 }, 2988 { 2989 .type = QMI_INDICATION, 2990 .msg_id = QMI_WLFW_FW_MEM_READY_IND_V01, 2991 .ei = wlfw_fw_mem_ready_ind_msg_v01_ei, 2992 .decoded_size = sizeof(struct wlfw_fw_mem_ready_ind_msg_v01), 2993 .fn = cnss_wlfw_fw_mem_ready_ind_cb 2994 }, 2995 { 2996 .type = QMI_INDICATION, 2997 .msg_id = QMI_WLFW_FW_READY_IND_V01, 2998 .ei = wlfw_fw_ready_ind_msg_v01_ei, 2999 .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01), 3000 .fn = cnss_wlfw_fw_ready_ind_cb 3001 }, 3002 { 3003 .type = QMI_INDICATION, 3004 .msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01, 3005 .ei = wlfw_fw_init_done_ind_msg_v01_ei, 3006 .decoded_size = sizeof(struct wlfw_fw_init_done_ind_msg_v01), 3007 .fn = cnss_wlfw_fw_init_done_ind_cb 3008 }, 3009 { 3010 .type = QMI_INDICATION, 3011 .msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01, 3012 .ei = wlfw_pin_connect_result_ind_msg_v01_ei, 3013 .decoded_size = 3014 sizeof(struct wlfw_pin_connect_result_ind_msg_v01), 3015 .fn = cnss_wlfw_pin_result_ind_cb 3016 }, 3017 { 3018 .type = QMI_INDICATION, 3019 .msg_id = QMI_WLFW_CAL_DONE_IND_V01, 3020 .ei = wlfw_cal_done_ind_msg_v01_ei, 3021 .decoded_size = sizeof(struct wlfw_cal_done_ind_msg_v01), 3022 .fn = cnss_wlfw_cal_done_ind_cb 3023 }, 3024 { 3025 .type = QMI_INDICATION, 3026 .msg_id = QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01, 3027 .ei = wlfw_qdss_trace_req_mem_ind_msg_v01_ei, 3028 .decoded_size = 3029 sizeof(struct wlfw_qdss_trace_req_mem_ind_msg_v01), 3030 .fn = cnss_wlfw_qdss_trace_req_mem_ind_cb 3031 }, 3032 { 3033 .type = QMI_INDICATION, 3034 .msg_id = QMI_WLFW_QDSS_TRACE_SAVE_IND_V01, 3035 .ei = wlfw_qdss_trace_save_ind_msg_v01_ei, 3036 .decoded_size = 3037 sizeof(struct wlfw_qdss_trace_save_ind_msg_v01), 3038 .fn = cnss_wlfw_fw_mem_file_save_ind_cb 3039 }, 3040 { 3041 .type = QMI_INDICATION, 3042 .msg_id = QMI_WLFW_QDSS_TRACE_FREE_IND_V01, 3043 .ei = wlfw_qdss_trace_free_ind_msg_v01_ei, 3044 .decoded_size = 3045 sizeof(struct wlfw_qdss_trace_free_ind_msg_v01), 3046 .fn = cnss_wlfw_qdss_trace_free_ind_cb 3047 }, 3048 { 3049 .type = QMI_INDICATION, 3050 .msg_id = QMI_WLFW_RESPOND_GET_INFO_IND_V01, 3051 .ei = wlfw_respond_get_info_ind_msg_v01_ei, 3052 .decoded_size = 3053 sizeof(struct wlfw_respond_get_info_ind_msg_v01), 3054 .fn = cnss_wlfw_respond_get_info_ind_cb 3055 }, 3056 { 3057 .type = QMI_INDICATION, 3058 .msg_id = QMI_WLFW_WFC_CALL_TWT_CONFIG_IND_V01, 3059 .ei = wlfw_wfc_call_twt_config_ind_msg_v01_ei, 3060 .decoded_size = 3061 sizeof(struct wlfw_wfc_call_twt_config_ind_msg_v01), 3062 .fn = cnss_wlfw_process_twt_cfg_ind 3063 }, 3064 {} 3065 }; 3066 3067 static int cnss_wlfw_connect_to_server(struct cnss_plat_data *plat_priv, 3068 void *data) 3069 { 3070 struct cnss_qmi_event_server_arrive_data *event_data = data; 3071 struct qmi_handle *qmi_wlfw = &plat_priv->qmi_wlfw; 3072 struct sockaddr_qrtr sq = { 0 }; 3073 int ret = 0; 3074 3075 if (!event_data) 3076 return -EINVAL; 3077 3078 sq.sq_family = AF_QIPCRTR; 3079 sq.sq_node = event_data->node; 3080 sq.sq_port = event_data->port; 3081 3082 ret = kernel_connect(qmi_wlfw->sock, (struct sockaddr *)&sq, 3083 sizeof(sq), 0); 3084 if (ret < 0) { 3085 cnss_pr_err("Failed to connect to QMI WLFW remote service port\n"); 3086 goto out; 3087 } 3088 3089 set_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state); 3090 3091 cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n", 3092 plat_priv->driver_state); 3093 3094 kfree(data); 3095 return 0; 3096 3097 out: 3098 CNSS_QMI_ASSERT(); 3099 kfree(data); 3100 return ret; 3101 } 3102 3103 int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv, void *data) 3104 { 3105 int ret = 0; 3106 3107 if (!plat_priv) 3108 return -ENODEV; 3109 3110 if (test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state)) { 3111 cnss_pr_err("Unexpected WLFW server arrive\n"); 3112 CNSS_ASSERT(0); 3113 return -EINVAL; 3114 } 3115 3116 cnss_ignore_qmi_failure(false); 3117 3118 ret = cnss_wlfw_connect_to_server(plat_priv, data); 3119 if (ret < 0) 3120 goto out; 3121 3122 ret = cnss_wlfw_ind_register_send_sync(plat_priv); 3123 if (ret < 0) { 3124 if (ret == -EALREADY) 3125 ret = 0; 3126 goto out; 3127 } 3128 3129 ret = cnss_wlfw_host_cap_send_sync(plat_priv); 3130 if (ret < 0) 3131 goto out; 3132 3133 return 0; 3134 3135 out: 3136 return ret; 3137 } 3138 3139 int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv) 3140 { 3141 int ret; 3142 3143 if (!plat_priv) 3144 return -ENODEV; 3145 3146 clear_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state); 3147 3148 cnss_pr_info("QMI WLFW service disconnected, state: 0x%lx\n", 3149 plat_priv->driver_state); 3150 3151 cnss_qmi_deinit(plat_priv); 3152 3153 clear_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state); 3154 3155 ret = cnss_qmi_init(plat_priv); 3156 if (ret < 0) { 3157 cnss_pr_err("QMI WLFW service registraton failed, ret\n", ret); 3158 CNSS_ASSERT(0); 3159 } 3160 return 0; 3161 } 3162 3163 static int wlfw_new_server(struct qmi_handle *qmi_wlfw, 3164 struct qmi_service *service) 3165 { 3166 struct cnss_plat_data *plat_priv = 3167 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 3168 struct cnss_qmi_event_server_arrive_data *event_data; 3169 3170 if (plat_priv && test_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state)) { 3171 cnss_pr_info("WLFW server delete in progress, Ignore server arrive, state: 0x%lx\n", 3172 plat_priv->driver_state); 3173 return 0; 3174 } 3175 3176 cnss_pr_dbg("WLFW server arriving: node %u port %u\n", 3177 service->node, service->port); 3178 3179 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 3180 if (!event_data) 3181 return -ENOMEM; 3182 3183 event_data->node = service->node; 3184 event_data->port = service->port; 3185 3186 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_SERVER_ARRIVE, 3187 0, event_data); 3188 3189 return 0; 3190 } 3191 3192 static void wlfw_del_server(struct qmi_handle *qmi_wlfw, 3193 struct qmi_service *service) 3194 { 3195 struct cnss_plat_data *plat_priv = 3196 container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); 3197 3198 if (plat_priv && test_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state)) { 3199 cnss_pr_info("WLFW server delete in progress, Ignore server delete, state: 0x%lx\n", 3200 plat_priv->driver_state); 3201 return; 3202 } 3203 3204 cnss_pr_dbg("WLFW server exiting\n"); 3205 3206 if (plat_priv) { 3207 cnss_ignore_qmi_failure(true); 3208 set_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state); 3209 } 3210 3211 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_SERVER_EXIT, 3212 0, NULL); 3213 } 3214 3215 static struct qmi_ops qmi_wlfw_ops = { 3216 .new_server = wlfw_new_server, 3217 .del_server = wlfw_del_server, 3218 }; 3219 3220 int cnss_qmi_init(struct cnss_plat_data *plat_priv) 3221 { 3222 int ret = 0; 3223 3224 ret = qmi_handle_init(&plat_priv->qmi_wlfw, 3225 QMI_WLFW_MAX_RECV_BUF_SIZE, 3226 &qmi_wlfw_ops, qmi_wlfw_msg_handlers); 3227 if (ret < 0) { 3228 cnss_pr_err("Failed to initialize WLFW QMI handle, err: %d\n", 3229 ret); 3230 goto out; 3231 } 3232 3233 ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01, 3234 WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01); 3235 if (ret < 0) 3236 cnss_pr_err("Failed to add WLFW QMI lookup, err: %d\n", ret); 3237 3238 out: 3239 return ret; 3240 } 3241 3242 void cnss_qmi_deinit(struct cnss_plat_data *plat_priv) 3243 { 3244 qmi_handle_release(&plat_priv->qmi_wlfw); 3245 } 3246 3247 int cnss_qmi_get_dms_mac(struct cnss_plat_data *plat_priv) 3248 { 3249 struct dms_get_mac_address_req_msg_v01 req; 3250 struct dms_get_mac_address_resp_msg_v01 resp; 3251 struct qmi_txn txn; 3252 int ret = 0; 3253 3254 if (!test_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state)) { 3255 cnss_pr_err("DMS QMI connection not established\n"); 3256 return -EINVAL; 3257 } 3258 cnss_pr_dbg("Requesting DMS MAC address"); 3259 3260 memset(&resp, 0, sizeof(resp)); 3261 ret = qmi_txn_init(&plat_priv->qmi_dms, &txn, 3262 dms_get_mac_address_resp_msg_v01_ei, &resp); 3263 if (ret < 0) { 3264 cnss_pr_err("Failed to initialize txn for dms, err: %d\n", 3265 ret); 3266 goto out; 3267 } 3268 req.device = DMS_DEVICE_MAC_WLAN_V01; 3269 ret = qmi_send_request(&plat_priv->qmi_dms, NULL, &txn, 3270 QMI_DMS_GET_MAC_ADDRESS_REQ_V01, 3271 DMS_GET_MAC_ADDRESS_REQ_MSG_V01_MAX_MSG_LEN, 3272 dms_get_mac_address_req_msg_v01_ei, &req); 3273 if (ret < 0) { 3274 qmi_txn_cancel(&txn); 3275 cnss_pr_err("Failed to send QMI_DMS_GET_MAC_ADDRESS_REQ_V01, err: %d\n", 3276 ret); 3277 goto out; 3278 } 3279 ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); 3280 if (ret < 0) { 3281 cnss_pr_err("Failed to wait for QMI_DMS_GET_MAC_ADDRESS_RESP_V01, err: %d\n", 3282 ret); 3283 goto out; 3284 } 3285 3286 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 3287 cnss_pr_err("QMI_DMS_GET_MAC_ADDRESS_REQ_V01 failed, result: %d, err: %d\n", 3288 resp.resp.result, resp.resp.error); 3289 ret = -resp.resp.result; 3290 goto out; 3291 } 3292 if (!resp.mac_address_valid || 3293 resp.mac_address_len != QMI_WLFW_MAC_ADDR_SIZE_V01) { 3294 cnss_pr_err("Invalid MAC address received from DMS\n"); 3295 plat_priv->dms.mac_valid = false; 3296 goto out; 3297 } 3298 plat_priv->dms.mac_valid = true; 3299 memcpy(plat_priv->dms.mac, resp.mac_address, QMI_WLFW_MAC_ADDR_SIZE_V01); 3300 cnss_pr_info("Received DMS MAC: [%pM]\n", plat_priv->dms.mac); 3301 out: 3302 return ret; 3303 } 3304 3305 static int cnss_dms_connect_to_server(struct cnss_plat_data *plat_priv, 3306 unsigned int node, unsigned int port) 3307 { 3308 struct qmi_handle *qmi_dms = &plat_priv->qmi_dms; 3309 struct sockaddr_qrtr sq = {0}; 3310 int ret = 0; 3311 3312 sq.sq_family = AF_QIPCRTR; 3313 sq.sq_node = node; 3314 sq.sq_port = port; 3315 3316 ret = kernel_connect(qmi_dms->sock, (struct sockaddr *)&sq, 3317 sizeof(sq), 0); 3318 if (ret < 0) { 3319 cnss_pr_err("Failed to connect to QMI DMS remote service Node: %d Port: %d\n", 3320 node, port); 3321 goto out; 3322 } 3323 3324 set_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state); 3325 cnss_pr_info("QMI DMS service connected, state: 0x%lx\n", 3326 plat_priv->driver_state); 3327 out: 3328 return ret; 3329 } 3330 3331 static int dms_new_server(struct qmi_handle *qmi_dms, 3332 struct qmi_service *service) 3333 { 3334 struct cnss_plat_data *plat_priv = 3335 container_of(qmi_dms, struct cnss_plat_data, qmi_dms); 3336 3337 if (!service) 3338 return -EINVAL; 3339 3340 return cnss_dms_connect_to_server(plat_priv, service->node, 3341 service->port); 3342 } 3343 3344 static void cnss_dms_server_exit_work(struct work_struct *work) 3345 { 3346 int ret; 3347 struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL); 3348 3349 cnss_dms_deinit(plat_priv); 3350 3351 cnss_pr_info("QMI DMS Server Exit"); 3352 clear_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state); 3353 3354 ret = cnss_dms_init(plat_priv); 3355 if (ret < 0) 3356 cnss_pr_err("QMI DMS service registraton failed, ret\n", ret); 3357 } 3358 3359 static DECLARE_WORK(cnss_dms_del_work, cnss_dms_server_exit_work); 3360 3361 static void dms_del_server(struct qmi_handle *qmi_dms, 3362 struct qmi_service *service) 3363 { 3364 struct cnss_plat_data *plat_priv = 3365 container_of(qmi_dms, struct cnss_plat_data, qmi_dms); 3366 3367 if (!plat_priv) 3368 return; 3369 3370 if (test_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state)) { 3371 cnss_pr_info("DMS server delete or cnss remove in progress, Ignore server delete: 0x%lx\n", 3372 plat_priv->driver_state); 3373 return; 3374 } 3375 3376 set_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state); 3377 clear_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state); 3378 cnss_pr_info("QMI DMS service disconnected, state: 0x%lx\n", 3379 plat_priv->driver_state); 3380 schedule_work(&cnss_dms_del_work); 3381 } 3382 3383 void cnss_cancel_dms_work(void) 3384 { 3385 cancel_work_sync(&cnss_dms_del_work); 3386 } 3387 3388 static struct qmi_ops qmi_dms_ops = { 3389 .new_server = dms_new_server, 3390 .del_server = dms_del_server, 3391 }; 3392 3393 int cnss_dms_init(struct cnss_plat_data *plat_priv) 3394 { 3395 int ret = 0; 3396 3397 ret = qmi_handle_init(&plat_priv->qmi_dms, DMS_QMI_MAX_MSG_LEN, 3398 &qmi_dms_ops, NULL); 3399 if (ret < 0) { 3400 cnss_pr_err("Failed to initialize DMS handle, err: %d\n", ret); 3401 goto out; 3402 } 3403 3404 ret = qmi_add_lookup(&plat_priv->qmi_dms, DMS_SERVICE_ID_V01, 3405 DMS_SERVICE_VERS_V01, 0); 3406 if (ret < 0) 3407 cnss_pr_err("Failed to add DMS lookup, err: %d\n", ret); 3408 out: 3409 return ret; 3410 } 3411 3412 void cnss_dms_deinit(struct cnss_plat_data *plat_priv) 3413 { 3414 set_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state); 3415 qmi_handle_release(&plat_priv->qmi_dms); 3416 } 3417 3418 int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv) 3419 { 3420 int ret; 3421 struct coex_antenna_switch_to_wlan_req_msg_v01 *req; 3422 struct coex_antenna_switch_to_wlan_resp_msg_v01 *resp; 3423 struct qmi_txn txn; 3424 3425 if (!plat_priv) 3426 return -ENODEV; 3427 3428 cnss_pr_dbg("Sending coex antenna switch_to_wlan\n"); 3429 3430 req = kzalloc(sizeof(*req), GFP_KERNEL); 3431 if (!req) 3432 return -ENOMEM; 3433 3434 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 3435 if (!resp) { 3436 kfree(req); 3437 return -ENOMEM; 3438 } 3439 3440 req->antenna = plat_priv->antenna; 3441 3442 ret = qmi_txn_init(&plat_priv->coex_qmi, &txn, 3443 coex_antenna_switch_to_wlan_resp_msg_v01_ei, resp); 3444 if (ret < 0) { 3445 cnss_pr_err("Fail to init txn for coex antenna switch_to_wlan resp %d\n", 3446 ret); 3447 goto out; 3448 } 3449 3450 ret = qmi_send_request 3451 (&plat_priv->coex_qmi, NULL, &txn, 3452 QMI_COEX_SWITCH_ANTENNA_TO_WLAN_REQ_V01, 3453 COEX_ANTENNA_SWITCH_TO_WLAN_REQ_MSG_V01_MAX_MSG_LEN, 3454 coex_antenna_switch_to_wlan_req_msg_v01_ei, req); 3455 if (ret < 0) { 3456 qmi_txn_cancel(&txn); 3457 cnss_pr_err("Fail to send coex antenna switch_to_wlan req %d\n", 3458 ret); 3459 goto out; 3460 } 3461 3462 ret = qmi_txn_wait(&txn, COEX_TIMEOUT); 3463 if (ret < 0) { 3464 cnss_pr_err("Coex antenna switch_to_wlan resp wait failed with ret %d\n", 3465 ret); 3466 goto out; 3467 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 3468 cnss_pr_err("Coex antenna switch_to_wlan request rejected, result:%d error:%d\n", 3469 resp->resp.result, resp->resp.error); 3470 ret = -resp->resp.result; 3471 goto out; 3472 } 3473 3474 if (resp->grant_valid) 3475 plat_priv->grant = resp->grant; 3476 3477 cnss_pr_dbg("Coex antenna grant: 0x%llx\n", resp->grant); 3478 3479 kfree(resp); 3480 kfree(req); 3481 return 0; 3482 3483 out: 3484 kfree(resp); 3485 kfree(req); 3486 return ret; 3487 } 3488 3489 int coex_antenna_switch_to_mdm_send_sync_msg(struct cnss_plat_data *plat_priv) 3490 { 3491 int ret; 3492 struct coex_antenna_switch_to_mdm_req_msg_v01 *req; 3493 struct coex_antenna_switch_to_mdm_resp_msg_v01 *resp; 3494 struct qmi_txn txn; 3495 3496 if (!plat_priv) 3497 return -ENODEV; 3498 3499 cnss_pr_dbg("Sending coex antenna switch_to_mdm\n"); 3500 3501 req = kzalloc(sizeof(*req), GFP_KERNEL); 3502 if (!req) 3503 return -ENOMEM; 3504 3505 resp = kzalloc(sizeof(*resp), GFP_KERNEL); 3506 if (!resp) { 3507 kfree(req); 3508 return -ENOMEM; 3509 } 3510 3511 req->antenna = plat_priv->antenna; 3512 3513 ret = qmi_txn_init(&plat_priv->coex_qmi, &txn, 3514 coex_antenna_switch_to_mdm_resp_msg_v01_ei, resp); 3515 if (ret < 0) { 3516 cnss_pr_err("Fail to init txn for coex antenna switch_to_mdm resp %d\n", 3517 ret); 3518 goto out; 3519 } 3520 3521 ret = qmi_send_request 3522 (&plat_priv->coex_qmi, NULL, &txn, 3523 QMI_COEX_SWITCH_ANTENNA_TO_MDM_REQ_V01, 3524 COEX_ANTENNA_SWITCH_TO_MDM_REQ_MSG_V01_MAX_MSG_LEN, 3525 coex_antenna_switch_to_mdm_req_msg_v01_ei, req); 3526 if (ret < 0) { 3527 qmi_txn_cancel(&txn); 3528 cnss_pr_err("Fail to send coex antenna switch_to_mdm req %d\n", 3529 ret); 3530 goto out; 3531 } 3532 3533 ret = qmi_txn_wait(&txn, COEX_TIMEOUT); 3534 if (ret < 0) { 3535 cnss_pr_err("Coex antenna switch_to_mdm resp wait failed with ret %d\n", 3536 ret); 3537 goto out; 3538 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 3539 cnss_pr_err("Coex antenna switch_to_mdm request rejected, result:%d error:%d\n", 3540 resp->resp.result, resp->resp.error); 3541 ret = -resp->resp.result; 3542 goto out; 3543 } 3544 3545 kfree(resp); 3546 kfree(req); 3547 return 0; 3548 3549 out: 3550 kfree(resp); 3551 kfree(req); 3552 return ret; 3553 } 3554 3555 int cnss_send_subsys_restart_level_msg(struct cnss_plat_data *plat_priv) 3556 { 3557 int ret; 3558 struct wlfw_subsys_restart_level_req_msg_v01 req; 3559 struct wlfw_subsys_restart_level_resp_msg_v01 resp; 3560 u8 pcss_enabled; 3561 3562 if (!plat_priv) 3563 return -ENODEV; 3564 3565 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { 3566 cnss_pr_dbg("Can't send pcss cmd before fw ready\n"); 3567 return 0; 3568 } 3569 3570 pcss_enabled = plat_priv->recovery_pcss_enabled; 3571 cnss_pr_dbg("Sending pcss recovery status: %d\n", pcss_enabled); 3572 3573 req.restart_level_type_valid = 1; 3574 req.restart_level_type = pcss_enabled; 3575 3576 ret = qmi_send_wait(&plat_priv->qmi_wlfw, &req, &resp, 3577 wlfw_subsys_restart_level_req_msg_v01_ei, 3578 wlfw_subsys_restart_level_resp_msg_v01_ei, 3579 QMI_WLFW_SUBSYS_RESTART_LEVEL_REQ_V01, 3580 WLFW_SUBSYS_RESTART_LEVEL_REQ_MSG_V01_MAX_MSG_LEN, 3581 QMI_WLFW_TIMEOUT_JF); 3582 3583 if (ret < 0) 3584 cnss_pr_err("pcss recovery setting failed with ret %d\n", ret); 3585 return ret; 3586 } 3587 3588 static int coex_new_server(struct qmi_handle *qmi, 3589 struct qmi_service *service) 3590 { 3591 struct cnss_plat_data *plat_priv = 3592 container_of(qmi, struct cnss_plat_data, coex_qmi); 3593 struct sockaddr_qrtr sq = { 0 }; 3594 int ret = 0; 3595 3596 cnss_pr_dbg("COEX server arrive: node %u port %u\n", 3597 service->node, service->port); 3598 3599 sq.sq_family = AF_QIPCRTR; 3600 sq.sq_node = service->node; 3601 sq.sq_port = service->port; 3602 ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); 3603 if (ret < 0) { 3604 cnss_pr_err("Fail to connect to remote service port\n"); 3605 return ret; 3606 } 3607 3608 set_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state); 3609 cnss_pr_dbg("COEX Server Connected: 0x%lx\n", 3610 plat_priv->driver_state); 3611 return 0; 3612 } 3613 3614 static void coex_del_server(struct qmi_handle *qmi, 3615 struct qmi_service *service) 3616 { 3617 struct cnss_plat_data *plat_priv = 3618 container_of(qmi, struct cnss_plat_data, coex_qmi); 3619 3620 cnss_pr_dbg("COEX server exit\n"); 3621 3622 clear_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state); 3623 } 3624 3625 static struct qmi_ops coex_qmi_ops = { 3626 .new_server = coex_new_server, 3627 .del_server = coex_del_server, 3628 }; 3629 3630 int cnss_register_coex_service(struct cnss_plat_data *plat_priv) 3631 { int ret; 3632 3633 ret = qmi_handle_init(&plat_priv->coex_qmi, 3634 COEX_SERVICE_MAX_MSG_LEN, 3635 &coex_qmi_ops, NULL); 3636 if (ret < 0) 3637 return ret; 3638 3639 ret = qmi_add_lookup(&plat_priv->coex_qmi, COEX_SERVICE_ID_V01, 3640 COEX_SERVICE_VERS_V01, 0); 3641 return ret; 3642 } 3643 3644 void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv) 3645 { 3646 qmi_handle_release(&plat_priv->coex_qmi); 3647 } 3648 3649 /* IMS Service */ 3650 int ims_subscribe_for_indication_send_async(struct cnss_plat_data *plat_priv) 3651 { 3652 int ret; 3653 struct ims_private_service_subscribe_for_indications_req_msg_v01 *req; 3654 struct qmi_txn *txn; 3655 3656 if (!plat_priv) 3657 return -ENODEV; 3658 3659 cnss_pr_dbg("Sending ASYNC ims subscribe for indication\n"); 3660 3661 req = kzalloc(sizeof(*req), GFP_KERNEL); 3662 if (!req) 3663 return -ENOMEM; 3664 3665 req->wfc_call_status_valid = 1; 3666 req->wfc_call_status = 1; 3667 3668 txn = &plat_priv->txn; 3669 ret = qmi_txn_init(&plat_priv->ims_qmi, txn, NULL, NULL); 3670 if (ret < 0) { 3671 cnss_pr_err("Fail to init txn for ims subscribe for indication resp %d\n", 3672 ret); 3673 goto out; 3674 } 3675 3676 ret = qmi_send_request 3677 (&plat_priv->ims_qmi, NULL, txn, 3678 QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01, 3679 IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_MSG_V01_MAX_MSG_LEN, 3680 ims_private_service_subscribe_for_indications_req_msg_v01_ei, req); 3681 if (ret < 0) { 3682 qmi_txn_cancel(txn); 3683 cnss_pr_err("Fail to send ims subscribe for indication req %d\n", 3684 ret); 3685 goto out; 3686 } 3687 3688 kfree(req); 3689 return 0; 3690 3691 out: 3692 kfree(req); 3693 return ret; 3694 } 3695 3696 static void ims_subscribe_for_indication_resp_cb(struct qmi_handle *qmi, 3697 struct sockaddr_qrtr *sq, 3698 struct qmi_txn *txn, 3699 const void *data) 3700 { 3701 const 3702 struct ims_private_service_subscribe_for_indications_rsp_msg_v01 *resp = 3703 data; 3704 3705 cnss_pr_dbg("Received IMS subscribe indication response\n"); 3706 3707 if (!txn) { 3708 cnss_pr_err("spurious response\n"); 3709 return; 3710 } 3711 3712 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 3713 cnss_pr_err("IMS subscribe for indication request rejected, result:%d error:%d\n", 3714 resp->resp.result, resp->resp.error); 3715 txn->result = -resp->resp.result; 3716 } 3717 } 3718 3719 int cnss_process_wfc_call_ind_event(struct cnss_plat_data *plat_priv, 3720 void *data) 3721 { 3722 int ret; 3723 struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data; 3724 3725 ret = cnss_wlfw_wfc_call_status_send_sync(plat_priv, ind_msg); 3726 kfree(data); 3727 return ret; 3728 } 3729 3730 static void 3731 cnss_ims_process_wfc_call_ind_cb(struct qmi_handle *ims_qmi, 3732 struct sockaddr_qrtr *sq, 3733 struct qmi_txn *txn, const void *data) 3734 { 3735 struct cnss_plat_data *plat_priv = 3736 container_of(ims_qmi, struct cnss_plat_data, ims_qmi); 3737 const 3738 struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data; 3739 struct ims_private_service_wfc_call_status_ind_msg_v01 *event_data; 3740 3741 if (!txn) { 3742 cnss_pr_err("IMS->CNSS: WFC_CALL_IND: Spurious indication\n"); 3743 return; 3744 } 3745 3746 if (!ind_msg) { 3747 cnss_pr_err("IMS->CNSS: WFC_CALL_IND: Invalid indication\n"); 3748 return; 3749 } 3750 cnss_pr_dbg("IMS->CNSS: WFC_CALL_IND: %x, %x %x, %x %x, %x %llx, %x %x, %x %x\n", 3751 ind_msg->wfc_call_active, ind_msg->all_wfc_calls_held_valid, 3752 ind_msg->all_wfc_calls_held, 3753 ind_msg->is_wfc_emergency_valid, ind_msg->is_wfc_emergency, 3754 ind_msg->twt_ims_start_valid, ind_msg->twt_ims_start, 3755 ind_msg->twt_ims_int_valid, ind_msg->twt_ims_int, 3756 ind_msg->media_quality_valid, ind_msg->media_quality); 3757 3758 event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL); 3759 if (!event_data) 3760 return; 3761 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND, 3762 0, event_data); 3763 } 3764 3765 static struct qmi_msg_handler qmi_ims_msg_handlers[] = { 3766 { 3767 .type = QMI_RESPONSE, 3768 .msg_id = 3769 QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01, 3770 .ei = 3771 ims_private_service_subscribe_for_indications_rsp_msg_v01_ei, 3772 .decoded_size = sizeof(struct 3773 ims_private_service_subscribe_for_indications_rsp_msg_v01), 3774 .fn = ims_subscribe_for_indication_resp_cb 3775 }, 3776 { 3777 .type = QMI_INDICATION, 3778 .msg_id = QMI_IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_V01, 3779 .ei = ims_private_service_wfc_call_status_ind_msg_v01_ei, 3780 .decoded_size = 3781 sizeof(struct ims_private_service_wfc_call_status_ind_msg_v01), 3782 .fn = cnss_ims_process_wfc_call_ind_cb 3783 }, 3784 {} 3785 }; 3786 3787 static int ims_new_server(struct qmi_handle *qmi, 3788 struct qmi_service *service) 3789 { 3790 struct cnss_plat_data *plat_priv = 3791 container_of(qmi, struct cnss_plat_data, ims_qmi); 3792 struct sockaddr_qrtr sq = { 0 }; 3793 int ret = 0; 3794 3795 cnss_pr_dbg("IMS server arrive: node %u port %u\n", 3796 service->node, service->port); 3797 3798 sq.sq_family = AF_QIPCRTR; 3799 sq.sq_node = service->node; 3800 sq.sq_port = service->port; 3801 ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); 3802 if (ret < 0) { 3803 cnss_pr_err("Fail to connect to remote service port\n"); 3804 return ret; 3805 } 3806 3807 set_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state); 3808 cnss_pr_dbg("IMS Server Connected: 0x%lx\n", 3809 plat_priv->driver_state); 3810 3811 ret = ims_subscribe_for_indication_send_async(plat_priv); 3812 return ret; 3813 } 3814 3815 static void ims_del_server(struct qmi_handle *qmi, 3816 struct qmi_service *service) 3817 { 3818 struct cnss_plat_data *plat_priv = 3819 container_of(qmi, struct cnss_plat_data, ims_qmi); 3820 3821 cnss_pr_dbg("IMS server exit\n"); 3822 3823 clear_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state); 3824 } 3825 3826 static struct qmi_ops ims_qmi_ops = { 3827 .new_server = ims_new_server, 3828 .del_server = ims_del_server, 3829 }; 3830 3831 int cnss_register_ims_service(struct cnss_plat_data *plat_priv) 3832 { int ret; 3833 3834 ret = qmi_handle_init(&plat_priv->ims_qmi, 3835 IMSPRIVATE_SERVICE_MAX_MSG_LEN, 3836 &ims_qmi_ops, qmi_ims_msg_handlers); 3837 if (ret < 0) 3838 return ret; 3839 3840 ret = qmi_add_lookup(&plat_priv->ims_qmi, IMSPRIVATE_SERVICE_ID_V01, 3841 IMSPRIVATE_SERVICE_VERS_V01, 0); 3842 return ret; 3843 } 3844 3845 void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv) 3846 { 3847 qmi_handle_release(&plat_priv->ims_qmi); 3848 } 3849