18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018 The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/completion.h> 78c2ecf20Sopenharmony_ci#include <linux/device.h> 88c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 98c2ecf20Sopenharmony_ci#include <linux/idr.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_address.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/net.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/qcom_scm.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <net/sock.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "debug.h" 218c2ecf20Sopenharmony_ci#include "snoc.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define ATH10K_QMI_CLIENT_ID 0x4b4e454c 248c2ecf20Sopenharmony_ci#define ATH10K_QMI_TIMEOUT 30 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi, 278c2ecf20Sopenharmony_ci struct ath10k_msa_mem_info *mem_info) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct qcom_scm_vmperm dst_perms[3]; 308c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 318c2ecf20Sopenharmony_ci unsigned int src_perms; 328c2ecf20Sopenharmony_ci u32 perm_count; 338c2ecf20Sopenharmony_ci int ret; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci src_perms = BIT(QCOM_SCM_VMID_HLOS); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA; 388c2ecf20Sopenharmony_ci dst_perms[0].perm = QCOM_SCM_PERM_RW; 398c2ecf20Sopenharmony_ci dst_perms[1].vmid = QCOM_SCM_VMID_WLAN; 408c2ecf20Sopenharmony_ci dst_perms[1].perm = QCOM_SCM_PERM_RW; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (mem_info->secure) { 438c2ecf20Sopenharmony_ci perm_count = 2; 448c2ecf20Sopenharmony_ci } else { 458c2ecf20Sopenharmony_ci dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE; 468c2ecf20Sopenharmony_ci dst_perms[2].perm = QCOM_SCM_PERM_RW; 478c2ecf20Sopenharmony_ci perm_count = 3; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, 518c2ecf20Sopenharmony_ci &src_perms, dst_perms, perm_count); 528c2ecf20Sopenharmony_ci if (ret < 0) 538c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return ret; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi, 598c2ecf20Sopenharmony_ci struct ath10k_msa_mem_info *mem_info) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct qcom_scm_vmperm dst_perms; 628c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 638c2ecf20Sopenharmony_ci unsigned int src_perms; 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!mem_info->secure) 698c2ecf20Sopenharmony_ci src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci dst_perms.vmid = QCOM_SCM_VMID_HLOS; 728c2ecf20Sopenharmony_ci dst_perms.perm = QCOM_SCM_PERM_RW; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, 758c2ecf20Sopenharmony_ci &src_perms, &dst_perms, 1); 768c2ecf20Sopenharmony_ci if (ret < 0) 778c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci int ret; 858c2ecf20Sopenharmony_ci int i; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (qmi->msa_fixed_perm) 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (i = 0; i < qmi->nr_mem_region; i++) { 918c2ecf20Sopenharmony_ci ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]); 928c2ecf20Sopenharmony_ci if (ret) 938c2ecf20Sopenharmony_ci goto err_unmap; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cierr_unmap: 998c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 1008c2ecf20Sopenharmony_ci ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int i; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (qmi->msa_fixed_perm) 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0; i < qmi->nr_mem_region; i++) 1128c2ecf20Sopenharmony_ci ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct wlfw_msa_info_resp_msg_v01 resp = {}; 1188c2ecf20Sopenharmony_ci struct wlfw_msa_info_req_msg_v01 req = {}; 1198c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 1208c2ecf20Sopenharmony_ci phys_addr_t max_mapped_addr; 1218c2ecf20Sopenharmony_ci struct qmi_txn txn; 1228c2ecf20Sopenharmony_ci int ret; 1238c2ecf20Sopenharmony_ci int i; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci req.msa_addr = ar->msa.paddr; 1268c2ecf20Sopenharmony_ci req.size = ar->msa.mem_size; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 1298c2ecf20Sopenharmony_ci wlfw_msa_info_resp_msg_v01_ei, &resp); 1308c2ecf20Sopenharmony_ci if (ret < 0) 1318c2ecf20Sopenharmony_ci goto out; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 1348c2ecf20Sopenharmony_ci QMI_WLFW_MSA_INFO_REQ_V01, 1358c2ecf20Sopenharmony_ci WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN, 1368c2ecf20Sopenharmony_ci wlfw_msa_info_req_msg_v01_ei, &req); 1378c2ecf20Sopenharmony_ci if (ret < 0) { 1388c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 1398c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send msa mem info req: %d\n", ret); 1408c2ecf20Sopenharmony_ci goto out; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 1448c2ecf20Sopenharmony_ci if (ret < 0) 1458c2ecf20Sopenharmony_ci goto out; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 1488c2ecf20Sopenharmony_ci ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error); 1498c2ecf20Sopenharmony_ci ret = -EINVAL; 1508c2ecf20Sopenharmony_ci goto out; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) { 1548c2ecf20Sopenharmony_ci ath10k_err(ar, "invalid memory region length received: %d\n", 1558c2ecf20Sopenharmony_ci resp.mem_region_info_len); 1568c2ecf20Sopenharmony_ci ret = -EINVAL; 1578c2ecf20Sopenharmony_ci goto out; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci max_mapped_addr = ar->msa.paddr + ar->msa.mem_size; 1618c2ecf20Sopenharmony_ci qmi->nr_mem_region = resp.mem_region_info_len; 1628c2ecf20Sopenharmony_ci for (i = 0; i < resp.mem_region_info_len; i++) { 1638c2ecf20Sopenharmony_ci if (resp.mem_region_info[i].size > ar->msa.mem_size || 1648c2ecf20Sopenharmony_ci resp.mem_region_info[i].region_addr > max_mapped_addr || 1658c2ecf20Sopenharmony_ci resp.mem_region_info[i].region_addr < ar->msa.paddr || 1668c2ecf20Sopenharmony_ci resp.mem_region_info[i].size + 1678c2ecf20Sopenharmony_ci resp.mem_region_info[i].region_addr > max_mapped_addr) { 1688c2ecf20Sopenharmony_ci ath10k_err(ar, "received out of range memory region address 0x%llx with size 0x%x, aborting\n", 1698c2ecf20Sopenharmony_ci resp.mem_region_info[i].region_addr, 1708c2ecf20Sopenharmony_ci resp.mem_region_info[i].size); 1718c2ecf20Sopenharmony_ci ret = -EINVAL; 1728c2ecf20Sopenharmony_ci goto fail_unwind; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr; 1758c2ecf20Sopenharmony_ci qmi->mem_region[i].size = resp.mem_region_info[i].size; 1768c2ecf20Sopenharmony_ci qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag; 1778c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, 1788c2ecf20Sopenharmony_ci "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n", 1798c2ecf20Sopenharmony_ci i, &qmi->mem_region[i].addr, 1808c2ecf20Sopenharmony_ci qmi->mem_region[i].size, 1818c2ecf20Sopenharmony_ci qmi->mem_region[i].secure); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n"); 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cifail_unwind: 1888c2ecf20Sopenharmony_ci memset(&qmi->mem_region[0], 0, sizeof(qmi->mem_region[0]) * i); 1898c2ecf20Sopenharmony_ciout: 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct wlfw_msa_ready_resp_msg_v01 resp = {}; 1968c2ecf20Sopenharmony_ci struct wlfw_msa_ready_req_msg_v01 req = {}; 1978c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 1988c2ecf20Sopenharmony_ci struct qmi_txn txn; 1998c2ecf20Sopenharmony_ci int ret; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 2028c2ecf20Sopenharmony_ci wlfw_msa_ready_resp_msg_v01_ei, &resp); 2038c2ecf20Sopenharmony_ci if (ret < 0) 2048c2ecf20Sopenharmony_ci goto out; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 2078c2ecf20Sopenharmony_ci QMI_WLFW_MSA_READY_REQ_V01, 2088c2ecf20Sopenharmony_ci WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN, 2098c2ecf20Sopenharmony_ci wlfw_msa_ready_req_msg_v01_ei, &req); 2108c2ecf20Sopenharmony_ci if (ret < 0) { 2118c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 2128c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret); 2138c2ecf20Sopenharmony_ci goto out; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 2178c2ecf20Sopenharmony_ci if (ret < 0) 2188c2ecf20Sopenharmony_ci goto out; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 2218c2ecf20Sopenharmony_ci ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error); 2228c2ecf20Sopenharmony_ci ret = -EINVAL; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n"); 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciout: 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct wlfw_bdf_download_resp_msg_v01 resp = {}; 2358c2ecf20Sopenharmony_ci struct wlfw_bdf_download_req_msg_v01 *req; 2368c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 2378c2ecf20Sopenharmony_ci unsigned int remaining; 2388c2ecf20Sopenharmony_ci struct qmi_txn txn; 2398c2ecf20Sopenharmony_ci const u8 *temp; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci req = kzalloc(sizeof(*req), GFP_KERNEL); 2438c2ecf20Sopenharmony_ci if (!req) 2448c2ecf20Sopenharmony_ci return -ENOMEM; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci temp = ar->normal_mode_fw.board_data; 2478c2ecf20Sopenharmony_ci remaining = ar->normal_mode_fw.board_len; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci while (remaining) { 2508c2ecf20Sopenharmony_ci req->valid = 1; 2518c2ecf20Sopenharmony_ci req->file_id_valid = 1; 2528c2ecf20Sopenharmony_ci req->file_id = 0; 2538c2ecf20Sopenharmony_ci req->total_size_valid = 1; 2548c2ecf20Sopenharmony_ci req->total_size = ar->normal_mode_fw.board_len; 2558c2ecf20Sopenharmony_ci req->seg_id_valid = 1; 2568c2ecf20Sopenharmony_ci req->data_valid = 1; 2578c2ecf20Sopenharmony_ci req->end_valid = 1; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 2608c2ecf20Sopenharmony_ci req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci req->data_len = remaining; 2638c2ecf20Sopenharmony_ci req->end = 1; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci memcpy(req->data, temp, req->data_len); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 2698c2ecf20Sopenharmony_ci wlfw_bdf_download_resp_msg_v01_ei, 2708c2ecf20Sopenharmony_ci &resp); 2718c2ecf20Sopenharmony_ci if (ret < 0) 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 2758c2ecf20Sopenharmony_ci QMI_WLFW_BDF_DOWNLOAD_REQ_V01, 2768c2ecf20Sopenharmony_ci WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 2778c2ecf20Sopenharmony_ci wlfw_bdf_download_req_msg_v01_ei, req); 2788c2ecf20Sopenharmony_ci if (ret < 0) { 2798c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 2808c2ecf20Sopenharmony_ci goto out; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (ret < 0) 2868c2ecf20Sopenharmony_ci goto out; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* end = 1 triggers a CRC check on the BDF. If this fails, we 2898c2ecf20Sopenharmony_ci * get a QMI_ERR_MALFORMED_MSG_V01 error, but the FW is still 2908c2ecf20Sopenharmony_ci * willing to use the BDF. For some platforms, all the valid 2918c2ecf20Sopenharmony_ci * released BDFs fail this CRC check, so attempt to detect this 2928c2ecf20Sopenharmony_ci * scenario and treat it as non-fatal. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01 && 2958c2ecf20Sopenharmony_ci !(req->end == 1 && 2968c2ecf20Sopenharmony_ci resp.resp.result == QMI_ERR_MALFORMED_MSG_V01)) { 2978c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to download board data file: %d\n", 2988c2ecf20Sopenharmony_ci resp.resp.error); 2998c2ecf20Sopenharmony_ci ret = -EINVAL; 3008c2ecf20Sopenharmony_ci goto out; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci remaining -= req->data_len; 3048c2ecf20Sopenharmony_ci temp += req->data_len; 3058c2ecf20Sopenharmony_ci req->seg_id++; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n"); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci kfree(req); 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciout: 3148c2ecf20Sopenharmony_ci kfree(req); 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct wlfw_cal_report_resp_msg_v01 resp = {}; 3218c2ecf20Sopenharmony_ci struct wlfw_cal_report_req_msg_v01 req = {}; 3228c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 3238c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 3248c2ecf20Sopenharmony_ci struct qmi_txn txn; 3258c2ecf20Sopenharmony_ci int i, j = 0; 3268c2ecf20Sopenharmony_ci int ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (ar_snoc->xo_cal_supported) { 3298c2ecf20Sopenharmony_ci req.xo_cal_data_valid = 1; 3308c2ecf20Sopenharmony_ci req.xo_cal_data = ar_snoc->xo_cal_data; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, 3348c2ecf20Sopenharmony_ci &resp); 3358c2ecf20Sopenharmony_ci if (ret < 0) 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) { 3398c2ecf20Sopenharmony_ci if (qmi->cal_data[i].total_size && 3408c2ecf20Sopenharmony_ci qmi->cal_data[i].data) { 3418c2ecf20Sopenharmony_ci req.meta_data[j] = qmi->cal_data[i].cal_id; 3428c2ecf20Sopenharmony_ci j++; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci req.meta_data_len = j; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 3488c2ecf20Sopenharmony_ci QMI_WLFW_CAL_REPORT_REQ_V01, 3498c2ecf20Sopenharmony_ci WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN, 3508c2ecf20Sopenharmony_ci wlfw_cal_report_req_msg_v01_ei, &req); 3518c2ecf20Sopenharmony_ci if (ret < 0) { 3528c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 3538c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send calibration request: %d\n", ret); 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 3588c2ecf20Sopenharmony_ci if (ret < 0) 3598c2ecf20Sopenharmony_ci goto out; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 3628c2ecf20Sopenharmony_ci ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error); 3638c2ecf20Sopenharmony_ci ret = -EINVAL; 3648c2ecf20Sopenharmony_ci goto out; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n"); 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciout: 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int 3758c2ecf20Sopenharmony_ciath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 3788c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = ar_snoc->qmi; 3798c2ecf20Sopenharmony_ci struct wlfw_wlan_mode_resp_msg_v01 resp = {}; 3808c2ecf20Sopenharmony_ci struct wlfw_wlan_mode_req_msg_v01 req = {}; 3818c2ecf20Sopenharmony_ci struct qmi_txn txn; 3828c2ecf20Sopenharmony_ci int ret; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 3858c2ecf20Sopenharmony_ci wlfw_wlan_mode_resp_msg_v01_ei, 3868c2ecf20Sopenharmony_ci &resp); 3878c2ecf20Sopenharmony_ci if (ret < 0) 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci req.mode = mode; 3918c2ecf20Sopenharmony_ci req.hw_debug_valid = 1; 3928c2ecf20Sopenharmony_ci req.hw_debug = 0; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 3958c2ecf20Sopenharmony_ci QMI_WLFW_WLAN_MODE_REQ_V01, 3968c2ecf20Sopenharmony_ci WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN, 3978c2ecf20Sopenharmony_ci wlfw_wlan_mode_req_msg_v01_ei, &req); 3988c2ecf20Sopenharmony_ci if (ret < 0) { 3998c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 4008c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret); 4018c2ecf20Sopenharmony_ci goto out; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 4058c2ecf20Sopenharmony_ci if (ret < 0) 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 4098c2ecf20Sopenharmony_ci ath10k_err(ar, "more request rejected: %d\n", resp.resp.error); 4108c2ecf20Sopenharmony_ci ret = -EINVAL; 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode); 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciout: 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int 4228c2ecf20Sopenharmony_ciath10k_qmi_cfg_send_sync_msg(struct ath10k *ar, 4238c2ecf20Sopenharmony_ci struct ath10k_qmi_wlan_enable_cfg *config, 4248c2ecf20Sopenharmony_ci const char *version) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 4278c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = ar_snoc->qmi; 4288c2ecf20Sopenharmony_ci struct wlfw_wlan_cfg_resp_msg_v01 resp = {}; 4298c2ecf20Sopenharmony_ci struct wlfw_wlan_cfg_req_msg_v01 *req; 4308c2ecf20Sopenharmony_ci struct qmi_txn txn; 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci u32 i; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci req = kzalloc(sizeof(*req), GFP_KERNEL); 4358c2ecf20Sopenharmony_ci if (!req) 4368c2ecf20Sopenharmony_ci return -ENOMEM; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 4398c2ecf20Sopenharmony_ci wlfw_wlan_cfg_resp_msg_v01_ei, 4408c2ecf20Sopenharmony_ci &resp); 4418c2ecf20Sopenharmony_ci if (ret < 0) 4428c2ecf20Sopenharmony_ci goto out; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci req->host_version_valid = 0; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci req->tgt_cfg_valid = 1; 4478c2ecf20Sopenharmony_ci if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) 4488c2ecf20Sopenharmony_ci req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; 4498c2ecf20Sopenharmony_ci else 4508c2ecf20Sopenharmony_ci req->tgt_cfg_len = config->num_ce_tgt_cfg; 4518c2ecf20Sopenharmony_ci for (i = 0; i < req->tgt_cfg_len; i++) { 4528c2ecf20Sopenharmony_ci req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; 4538c2ecf20Sopenharmony_ci req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; 4548c2ecf20Sopenharmony_ci req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; 4558c2ecf20Sopenharmony_ci req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; 4568c2ecf20Sopenharmony_ci req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci req->svc_cfg_valid = 1; 4608c2ecf20Sopenharmony_ci if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) 4618c2ecf20Sopenharmony_ci req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; 4628c2ecf20Sopenharmony_ci else 4638c2ecf20Sopenharmony_ci req->svc_cfg_len = config->num_ce_svc_pipe_cfg; 4648c2ecf20Sopenharmony_ci for (i = 0; i < req->svc_cfg_len; i++) { 4658c2ecf20Sopenharmony_ci req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; 4668c2ecf20Sopenharmony_ci req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; 4678c2ecf20Sopenharmony_ci req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci req->shadow_reg_valid = 1; 4718c2ecf20Sopenharmony_ci if (config->num_shadow_reg_cfg > 4728c2ecf20Sopenharmony_ci QMI_WLFW_MAX_NUM_SHADOW_REG_V01) 4738c2ecf20Sopenharmony_ci req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; 4748c2ecf20Sopenharmony_ci else 4758c2ecf20Sopenharmony_ci req->shadow_reg_len = config->num_shadow_reg_cfg; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci memcpy(req->shadow_reg, config->shadow_reg_cfg, 4788c2ecf20Sopenharmony_ci sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 4818c2ecf20Sopenharmony_ci QMI_WLFW_WLAN_CFG_REQ_V01, 4828c2ecf20Sopenharmony_ci WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN, 4838c2ecf20Sopenharmony_ci wlfw_wlan_cfg_req_msg_v01_ei, req); 4848c2ecf20Sopenharmony_ci if (ret < 0) { 4858c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 4868c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send config request: %d\n", ret); 4878c2ecf20Sopenharmony_ci goto out; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 4918c2ecf20Sopenharmony_ci if (ret < 0) 4928c2ecf20Sopenharmony_ci goto out; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 4958c2ecf20Sopenharmony_ci ath10k_err(ar, "config request rejected: %d\n", resp.resp.error); 4968c2ecf20Sopenharmony_ci ret = -EINVAL; 4978c2ecf20Sopenharmony_ci goto out; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n"); 5018c2ecf20Sopenharmony_ci kfree(req); 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ciout: 5058c2ecf20Sopenharmony_ci kfree(req); 5068c2ecf20Sopenharmony_ci return ret; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciint ath10k_qmi_wlan_enable(struct ath10k *ar, 5108c2ecf20Sopenharmony_ci struct ath10k_qmi_wlan_enable_cfg *config, 5118c2ecf20Sopenharmony_ci enum wlfw_driver_mode_enum_v01 mode, 5128c2ecf20Sopenharmony_ci const char *version) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci int ret; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n", 5178c2ecf20Sopenharmony_ci mode, config); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version); 5208c2ecf20Sopenharmony_ci if (ret) { 5218c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send qmi config: %d\n", ret); 5228c2ecf20Sopenharmony_ci return ret; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci ret = ath10k_qmi_mode_send_sync_msg(ar, mode); 5268c2ecf20Sopenharmony_ci if (ret) { 5278c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send qmi mode: %d\n", ret); 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciint ath10k_qmi_wlan_disable(struct ath10k *ar) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct wlfw_cap_resp_msg_v01 *resp; 5428c2ecf20Sopenharmony_ci struct wlfw_cap_req_msg_v01 req = {}; 5438c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 5448c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 5458c2ecf20Sopenharmony_ci struct qmi_txn txn; 5468c2ecf20Sopenharmony_ci int ret; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci resp = kzalloc(sizeof(*resp), GFP_KERNEL); 5498c2ecf20Sopenharmony_ci if (!resp) 5508c2ecf20Sopenharmony_ci return -ENOMEM; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp); 5538c2ecf20Sopenharmony_ci if (ret < 0) 5548c2ecf20Sopenharmony_ci goto out; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 5578c2ecf20Sopenharmony_ci QMI_WLFW_CAP_REQ_V01, 5588c2ecf20Sopenharmony_ci WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN, 5598c2ecf20Sopenharmony_ci wlfw_cap_req_msg_v01_ei, &req); 5608c2ecf20Sopenharmony_ci if (ret < 0) { 5618c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 5628c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send capability request: %d\n", ret); 5638c2ecf20Sopenharmony_ci goto out; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 5678c2ecf20Sopenharmony_ci if (ret < 0) 5688c2ecf20Sopenharmony_ci goto out; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 5718c2ecf20Sopenharmony_ci ath10k_err(ar, "capability req rejected: %d\n", resp->resp.error); 5728c2ecf20Sopenharmony_ci ret = -EINVAL; 5738c2ecf20Sopenharmony_ci goto out; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (resp->chip_info_valid) { 5778c2ecf20Sopenharmony_ci qmi->chip_info.chip_id = resp->chip_info.chip_id; 5788c2ecf20Sopenharmony_ci qmi->chip_info.chip_family = resp->chip_info.chip_family; 5798c2ecf20Sopenharmony_ci } else { 5808c2ecf20Sopenharmony_ci qmi->chip_info.chip_id = 0xFF; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (resp->board_info_valid) 5848c2ecf20Sopenharmony_ci qmi->board_info.board_id = resp->board_info.board_id; 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci qmi->board_info.board_id = 0xFF; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (resp->soc_info_valid) 5898c2ecf20Sopenharmony_ci qmi->soc_info.soc_id = resp->soc_info.soc_id; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (resp->fw_version_info_valid) { 5928c2ecf20Sopenharmony_ci qmi->fw_version = resp->fw_version_info.fw_version; 5938c2ecf20Sopenharmony_ci strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp, 5948c2ecf20Sopenharmony_ci sizeof(qmi->fw_build_timestamp)); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (resp->fw_build_id_valid) 5988c2ecf20Sopenharmony_ci strlcpy(qmi->fw_build_id, resp->fw_build_id, 5998c2ecf20Sopenharmony_ci MAX_BUILD_ID_LEN + 1); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) { 6028c2ecf20Sopenharmony_ci ath10k_info(ar, "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x", 6038c2ecf20Sopenharmony_ci qmi->chip_info.chip_id, qmi->chip_info.chip_family, 6048c2ecf20Sopenharmony_ci qmi->board_info.board_id, qmi->soc_info.soc_id); 6058c2ecf20Sopenharmony_ci ath10k_info(ar, "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s", 6068c2ecf20Sopenharmony_ci qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci kfree(resp); 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ciout: 6138c2ecf20Sopenharmony_ci kfree(resp); 6148c2ecf20Sopenharmony_ci return ret; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct wlfw_host_cap_resp_msg_v01 resp = {}; 6208c2ecf20Sopenharmony_ci struct wlfw_host_cap_req_msg_v01 req = {}; 6218c2ecf20Sopenharmony_ci struct qmi_elem_info *req_ei; 6228c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 6238c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 6248c2ecf20Sopenharmony_ci struct qmi_txn txn; 6258c2ecf20Sopenharmony_ci int ret; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci req.daemon_support_valid = 1; 6288c2ecf20Sopenharmony_ci req.daemon_support = 0; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei, 6318c2ecf20Sopenharmony_ci &resp); 6328c2ecf20Sopenharmony_ci if (ret < 0) 6338c2ecf20Sopenharmony_ci goto out; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags)) 6368c2ecf20Sopenharmony_ci req_ei = wlfw_host_cap_8bit_req_msg_v01_ei; 6378c2ecf20Sopenharmony_ci else 6388c2ecf20Sopenharmony_ci req_ei = wlfw_host_cap_req_msg_v01_ei; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 6418c2ecf20Sopenharmony_ci QMI_WLFW_HOST_CAP_REQ_V01, 6428c2ecf20Sopenharmony_ci WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, 6438c2ecf20Sopenharmony_ci req_ei, &req); 6448c2ecf20Sopenharmony_ci if (ret < 0) { 6458c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 6468c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send host capability request: %d\n", ret); 6478c2ecf20Sopenharmony_ci goto out; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 6518c2ecf20Sopenharmony_ci if (ret < 0) 6528c2ecf20Sopenharmony_ci goto out; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* older FW didn't support this request, which is not fatal */ 6558c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01 && 6568c2ecf20Sopenharmony_ci resp.resp.error != QMI_ERR_NOT_SUPPORTED_V01) { 6578c2ecf20Sopenharmony_ci ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error); 6588c2ecf20Sopenharmony_ci ret = -EINVAL; 6598c2ecf20Sopenharmony_ci goto out; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capability request completed\n"); 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ciout: 6668c2ecf20Sopenharmony_ci return ret; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ciint ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 6728c2ecf20Sopenharmony_ci struct wlfw_ini_resp_msg_v01 resp = {}; 6738c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = ar_snoc->qmi; 6748c2ecf20Sopenharmony_ci struct wlfw_ini_req_msg_v01 req = {}; 6758c2ecf20Sopenharmony_ci struct qmi_txn txn; 6768c2ecf20Sopenharmony_ci int ret; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci req.enablefwlog_valid = 1; 6798c2ecf20Sopenharmony_ci req.enablefwlog = fw_log_mode; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ini_resp_msg_v01_ei, 6828c2ecf20Sopenharmony_ci &resp); 6838c2ecf20Sopenharmony_ci if (ret < 0) 6848c2ecf20Sopenharmony_ci goto out; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 6878c2ecf20Sopenharmony_ci QMI_WLFW_INI_REQ_V01, 6888c2ecf20Sopenharmony_ci WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN, 6898c2ecf20Sopenharmony_ci wlfw_ini_req_msg_v01_ei, &req); 6908c2ecf20Sopenharmony_ci if (ret < 0) { 6918c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 6928c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send fw log request: %d\n", ret); 6938c2ecf20Sopenharmony_ci goto out; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 6978c2ecf20Sopenharmony_ci if (ret < 0) 6988c2ecf20Sopenharmony_ci goto out; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 7018c2ecf20Sopenharmony_ci ath10k_err(ar, "fw log request rejected: %d\n", 7028c2ecf20Sopenharmony_ci resp.resp.error); 7038c2ecf20Sopenharmony_ci ret = -EINVAL; 7048c2ecf20Sopenharmony_ci goto out; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi fw log request completed, mode: %d\n", 7078c2ecf20Sopenharmony_ci fw_log_mode); 7088c2ecf20Sopenharmony_ci return 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ciout: 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int 7158c2ecf20Sopenharmony_ciath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct wlfw_ind_register_resp_msg_v01 resp = {}; 7188c2ecf20Sopenharmony_ci struct wlfw_ind_register_req_msg_v01 req = {}; 7198c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 7208c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 7218c2ecf20Sopenharmony_ci struct qmi_txn txn; 7228c2ecf20Sopenharmony_ci int ret; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci req.client_id_valid = 1; 7258c2ecf20Sopenharmony_ci req.client_id = ATH10K_QMI_CLIENT_ID; 7268c2ecf20Sopenharmony_ci req.fw_ready_enable_valid = 1; 7278c2ecf20Sopenharmony_ci req.fw_ready_enable = 1; 7288c2ecf20Sopenharmony_ci req.msa_ready_enable_valid = 1; 7298c2ecf20Sopenharmony_ci req.msa_ready_enable = 1; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (ar_snoc->xo_cal_supported) { 7328c2ecf20Sopenharmony_ci req.xo_cal_enable_valid = 1; 7338c2ecf20Sopenharmony_ci req.xo_cal_enable = 1; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 7378c2ecf20Sopenharmony_ci wlfw_ind_register_resp_msg_v01_ei, &resp); 7388c2ecf20Sopenharmony_ci if (ret < 0) 7398c2ecf20Sopenharmony_ci goto out; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 7428c2ecf20Sopenharmony_ci QMI_WLFW_IND_REGISTER_REQ_V01, 7438c2ecf20Sopenharmony_ci WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN, 7448c2ecf20Sopenharmony_ci wlfw_ind_register_req_msg_v01_ei, &req); 7458c2ecf20Sopenharmony_ci if (ret < 0) { 7468c2ecf20Sopenharmony_ci qmi_txn_cancel(&txn); 7478c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to send indication registered request: %d\n", ret); 7488c2ecf20Sopenharmony_ci goto out; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); 7528c2ecf20Sopenharmony_ci if (ret < 0) 7538c2ecf20Sopenharmony_ci goto out; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 7568c2ecf20Sopenharmony_ci ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error); 7578c2ecf20Sopenharmony_ci ret = -EINVAL; 7588c2ecf20Sopenharmony_ci goto out; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (resp.fw_status_valid) { 7628c2ecf20Sopenharmony_ci if (resp.fw_status & QMI_WLFW_FW_READY_V01) 7638c2ecf20Sopenharmony_ci qmi->fw_ready = true; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n"); 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ciout: 7698c2ecf20Sopenharmony_ci return ret; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 7758c2ecf20Sopenharmony_ci int ret; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ret = ath10k_qmi_ind_register_send_sync_msg(qmi); 7788c2ecf20Sopenharmony_ci if (ret) 7798c2ecf20Sopenharmony_ci return; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (qmi->fw_ready) { 7828c2ecf20Sopenharmony_ci ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); 7838c2ecf20Sopenharmony_ci return; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ret = ath10k_qmi_host_cap_send_sync(qmi); 7878c2ecf20Sopenharmony_ci if (ret) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi); 7918c2ecf20Sopenharmony_ci if (ret) 7928c2ecf20Sopenharmony_ci return; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * HACK: sleep for a while inbetween receiving the msa info response 7968c2ecf20Sopenharmony_ci * and the XPU update to prevent SDM845 from crashing due to a security 7978c2ecf20Sopenharmony_ci * violation, when running MPSS.AT.4.0.c2-01184-SDM845_GEN_PACK-1. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci msleep(20); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ret = ath10k_qmi_setup_msa_permissions(qmi); 8028c2ecf20Sopenharmony_ci if (ret) 8038c2ecf20Sopenharmony_ci return; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci ret = ath10k_qmi_msa_ready_send_sync_msg(qmi); 8068c2ecf20Sopenharmony_ci if (ret) 8078c2ecf20Sopenharmony_ci goto err_setup_msa; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ret = ath10k_qmi_cap_send_sync_msg(qmi); 8108c2ecf20Sopenharmony_ci if (ret) 8118c2ecf20Sopenharmony_ci goto err_setup_msa; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cierr_setup_msa: 8168c2ecf20Sopenharmony_ci ath10k_qmi_remove_msa_permission(qmi); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 8228c2ecf20Sopenharmony_ci int ret; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci ar->hif.bus = ATH10K_BUS_SNOC; 8258c2ecf20Sopenharmony_ci ar->id.qmi_ids_valid = true; 8268c2ecf20Sopenharmony_ci ar->id.qmi_board_id = qmi->board_info.board_id; 8278c2ecf20Sopenharmony_ci ar->id.qmi_chip_id = qmi->chip_info.chip_id; 8288c2ecf20Sopenharmony_ci ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci ret = ath10k_core_check_dt(ar); 8318c2ecf20Sopenharmony_ci if (ret) 8328c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "DT bdf variant name not set.\n"); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int 8388c2ecf20Sopenharmony_ciath10k_qmi_driver_event_post(struct ath10k_qmi *qmi, 8398c2ecf20Sopenharmony_ci enum ath10k_qmi_driver_event_type type, 8408c2ecf20Sopenharmony_ci void *data) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct ath10k_qmi_driver_event *event; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci event = kzalloc(sizeof(*event), GFP_ATOMIC); 8458c2ecf20Sopenharmony_ci if (!event) 8468c2ecf20Sopenharmony_ci return -ENOMEM; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci event->type = type; 8498c2ecf20Sopenharmony_ci event->data = data; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci spin_lock(&qmi->event_lock); 8528c2ecf20Sopenharmony_ci list_add_tail(&event->list, &qmi->event_list); 8538c2ecf20Sopenharmony_ci spin_unlock(&qmi->event_lock); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci queue_work(qmi->event_wq, &qmi->event_work); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 8638c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ath10k_qmi_remove_msa_permission(qmi); 8668c2ecf20Sopenharmony_ci ath10k_core_free_board_files(ar); 8678c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags)) 8688c2ecf20Sopenharmony_ci ath10k_snoc_fw_crashed_dump(ar); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND); 8718c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n"); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci int ret; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci ret = ath10k_qmi_fetch_board_file(qmi); 8798c2ecf20Sopenharmony_ci if (ret) 8808c2ecf20Sopenharmony_ci goto out; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ret = ath10k_qmi_bdf_dnld_send_sync(qmi); 8838c2ecf20Sopenharmony_ci if (ret) 8848c2ecf20Sopenharmony_ci goto out; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci ret = ath10k_qmi_send_cal_report_req(qmi); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ciout: 8898c2ecf20Sopenharmony_ci return; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n"); 8978c2ecf20Sopenharmony_ci ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return 0; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl, 9038c2ecf20Sopenharmony_ci struct sockaddr_qrtr *sq, 9048c2ecf20Sopenharmony_ci struct qmi_txn *txn, const void *data) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl, 9128c2ecf20Sopenharmony_ci struct sockaddr_qrtr *sq, 9138c2ecf20Sopenharmony_ci struct qmi_txn *txn, const void *data) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic struct qmi_msg_handler qmi_msg_handler[] = { 9218c2ecf20Sopenharmony_ci { 9228c2ecf20Sopenharmony_ci .type = QMI_INDICATION, 9238c2ecf20Sopenharmony_ci .msg_id = QMI_WLFW_FW_READY_IND_V01, 9248c2ecf20Sopenharmony_ci .ei = wlfw_fw_ready_ind_msg_v01_ei, 9258c2ecf20Sopenharmony_ci .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01), 9268c2ecf20Sopenharmony_ci .fn = ath10k_qmi_fw_ready_ind, 9278c2ecf20Sopenharmony_ci }, 9288c2ecf20Sopenharmony_ci { 9298c2ecf20Sopenharmony_ci .type = QMI_INDICATION, 9308c2ecf20Sopenharmony_ci .msg_id = QMI_WLFW_MSA_READY_IND_V01, 9318c2ecf20Sopenharmony_ci .ei = wlfw_msa_ready_ind_msg_v01_ei, 9328c2ecf20Sopenharmony_ci .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01), 9338c2ecf20Sopenharmony_ci .fn = ath10k_qmi_msa_ready_ind, 9348c2ecf20Sopenharmony_ci }, 9358c2ecf20Sopenharmony_ci {} 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl, 9398c2ecf20Sopenharmony_ci struct qmi_service *service) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); 9428c2ecf20Sopenharmony_ci struct sockaddr_qrtr *sq = &qmi->sq; 9438c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 9448c2ecf20Sopenharmony_ci int ret; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci sq->sq_family = AF_QIPCRTR; 9478c2ecf20Sopenharmony_ci sq->sq_node = service->node; 9488c2ecf20Sopenharmony_ci sq->sq_port = service->port; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n"); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq, 9538c2ecf20Sopenharmony_ci sizeof(qmi->sq), 0); 9548c2ecf20Sopenharmony_ci if (ret) { 9558c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to connect to a remote QMI service port\n"); 9568c2ecf20Sopenharmony_ci return ret; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n"); 9608c2ecf20Sopenharmony_ci ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci return ret; 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl, 9668c2ecf20Sopenharmony_ci struct qmi_service *service) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = 9698c2ecf20Sopenharmony_ci container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci qmi->fw_ready = false; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* 9748c2ecf20Sopenharmony_ci * The del_server event is to be processed only if coming from 9758c2ecf20Sopenharmony_ci * the qmi server. The qmi infrastructure sends del_server, when 9768c2ecf20Sopenharmony_ci * any client releases the qmi handle. In this case do not process 9778c2ecf20Sopenharmony_ci * this del_server event. 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci if (qmi->state == ATH10K_QMI_STATE_INIT_DONE) 9808c2ecf20Sopenharmony_ci ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, 9818c2ecf20Sopenharmony_ci NULL); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic struct qmi_ops ath10k_qmi_ops = { 9858c2ecf20Sopenharmony_ci .new_server = ath10k_qmi_new_server, 9868c2ecf20Sopenharmony_ci .del_server = ath10k_qmi_del_server, 9878c2ecf20Sopenharmony_ci}; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic void ath10k_qmi_driver_event_work(struct work_struct *work) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi, 9928c2ecf20Sopenharmony_ci event_work); 9938c2ecf20Sopenharmony_ci struct ath10k_qmi_driver_event *event; 9948c2ecf20Sopenharmony_ci struct ath10k *ar = qmi->ar; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci spin_lock(&qmi->event_lock); 9978c2ecf20Sopenharmony_ci while (!list_empty(&qmi->event_list)) { 9988c2ecf20Sopenharmony_ci event = list_first_entry(&qmi->event_list, 9998c2ecf20Sopenharmony_ci struct ath10k_qmi_driver_event, list); 10008c2ecf20Sopenharmony_ci list_del(&event->list); 10018c2ecf20Sopenharmony_ci spin_unlock(&qmi->event_lock); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci switch (event->type) { 10048c2ecf20Sopenharmony_ci case ATH10K_QMI_EVENT_SERVER_ARRIVE: 10058c2ecf20Sopenharmony_ci ath10k_qmi_event_server_arrive(qmi); 10068c2ecf20Sopenharmony_ci break; 10078c2ecf20Sopenharmony_ci case ATH10K_QMI_EVENT_SERVER_EXIT: 10088c2ecf20Sopenharmony_ci ath10k_qmi_event_server_exit(qmi); 10098c2ecf20Sopenharmony_ci break; 10108c2ecf20Sopenharmony_ci case ATH10K_QMI_EVENT_FW_READY_IND: 10118c2ecf20Sopenharmony_ci ath10k_qmi_event_fw_ready_ind(qmi); 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci case ATH10K_QMI_EVENT_MSA_READY_IND: 10148c2ecf20Sopenharmony_ci ath10k_qmi_event_msa_ready(qmi); 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci default: 10178c2ecf20Sopenharmony_ci ath10k_warn(ar, "invalid event type: %d", event->type); 10188c2ecf20Sopenharmony_ci break; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci kfree(event); 10218c2ecf20Sopenharmony_ci spin_lock(&qmi->event_lock); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci spin_unlock(&qmi->event_lock); 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ciint ath10k_qmi_init(struct ath10k *ar, u32 msa_size) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 10298c2ecf20Sopenharmony_ci struct device *dev = ar->dev; 10308c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi; 10318c2ecf20Sopenharmony_ci int ret; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci qmi = kzalloc(sizeof(*qmi), GFP_KERNEL); 10348c2ecf20Sopenharmony_ci if (!qmi) 10358c2ecf20Sopenharmony_ci return -ENOMEM; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci qmi->ar = ar; 10388c2ecf20Sopenharmony_ci ar_snoc->qmi = qmi; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (of_property_read_bool(dev->of_node, "qcom,msa-fixed-perm")) 10418c2ecf20Sopenharmony_ci qmi->msa_fixed_perm = true; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci ret = qmi_handle_init(&qmi->qmi_hdl, 10448c2ecf20Sopenharmony_ci WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 10458c2ecf20Sopenharmony_ci &ath10k_qmi_ops, qmi_msg_handler); 10468c2ecf20Sopenharmony_ci if (ret) 10478c2ecf20Sopenharmony_ci goto err; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event", 10508c2ecf20Sopenharmony_ci WQ_UNBOUND, 1); 10518c2ecf20Sopenharmony_ci if (!qmi->event_wq) { 10528c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to allocate workqueue\n"); 10538c2ecf20Sopenharmony_ci ret = -EFAULT; 10548c2ecf20Sopenharmony_ci goto err_release_qmi_handle; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qmi->event_list); 10588c2ecf20Sopenharmony_ci spin_lock_init(&qmi->event_lock); 10598c2ecf20Sopenharmony_ci INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01, 10628c2ecf20Sopenharmony_ci WLFW_SERVICE_VERS_V01, 0); 10638c2ecf20Sopenharmony_ci if (ret) 10648c2ecf20Sopenharmony_ci goto err_qmi_lookup; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci qmi->state = ATH10K_QMI_STATE_INIT_DONE; 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cierr_qmi_lookup: 10708c2ecf20Sopenharmony_ci destroy_workqueue(qmi->event_wq); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cierr_release_qmi_handle: 10738c2ecf20Sopenharmony_ci qmi_handle_release(&qmi->qmi_hdl); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cierr: 10768c2ecf20Sopenharmony_ci kfree(qmi); 10778c2ecf20Sopenharmony_ci return ret; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ciint ath10k_qmi_deinit(struct ath10k *ar) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 10838c2ecf20Sopenharmony_ci struct ath10k_qmi *qmi = ar_snoc->qmi; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci qmi->state = ATH10K_QMI_STATE_DEINIT; 10868c2ecf20Sopenharmony_ci qmi_handle_release(&qmi->qmi_hdl); 10878c2ecf20Sopenharmony_ci cancel_work_sync(&qmi->event_work); 10888c2ecf20Sopenharmony_ci destroy_workqueue(qmi->event_wq); 10898c2ecf20Sopenharmony_ci kfree(qmi); 10908c2ecf20Sopenharmony_ci ar_snoc->qmi = NULL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return 0; 10938c2ecf20Sopenharmony_ci} 1094