13983bc45SNaman Padhiar // SPDX-License-Identifier: GPL-2.0-only 23983bc45SNaman Padhiar /* 33983bc45SNaman Padhiar * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. 487ab436eSNaman Padhiar * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 53983bc45SNaman Padhiar */ 63983bc45SNaman Padhiar 73983bc45SNaman Padhiar #define pr_fmt(fmt) "icnss2_qmi: " fmt 83983bc45SNaman Padhiar 93983bc45SNaman Padhiar #include <linux/export.h> 103983bc45SNaman Padhiar #include <linux/err.h> 113983bc45SNaman Padhiar #include <linux/of.h> 123983bc45SNaman Padhiar #include <linux/init.h> 133983bc45SNaman Padhiar #include <linux/io.h> 143983bc45SNaman Padhiar #include <linux/module.h> 153983bc45SNaman Padhiar #include <linux/kernel.h> 163983bc45SNaman Padhiar #include <linux/etherdevice.h> 173983bc45SNaman Padhiar #include <linux/seq_file.h> 183983bc45SNaman Padhiar #include <linux/slab.h> 193983bc45SNaman Padhiar #include <linux/delay.h> 203983bc45SNaman Padhiar #include <linux/ipc_logging.h> 213983bc45SNaman Padhiar #include <linux/thread_info.h> 223983bc45SNaman Padhiar #include <linux/firmware.h> 233983bc45SNaman Padhiar #include <linux/soc/qcom/qmi.h> 243983bc45SNaman Padhiar #include <linux/platform_device.h> 2523e8cd33SNaman Padhiar #ifdef CONFIG_CNSS_OUT_OF_TREE 2623e8cd33SNaman Padhiar #include "icnss2.h" 2723e8cd33SNaman Padhiar #else 283983bc45SNaman Padhiar #include <soc/qcom/icnss2.h> 2923e8cd33SNaman Padhiar #endif 303983bc45SNaman Padhiar #include <soc/qcom/of_common.h> 313983bc45SNaman Padhiar #include "wlan_firmware_service_v01.h" 323983bc45SNaman Padhiar #include "main.h" 333983bc45SNaman Padhiar #include "qmi.h" 343983bc45SNaman Padhiar #include "debug.h" 353983bc45SNaman Padhiar #include "genl.h" 363983bc45SNaman Padhiar 373983bc45SNaman Padhiar #define WLFW_SERVICE_WCN_INS_ID_V01 3 383983bc45SNaman Padhiar #define WLFW_SERVICE_INS_ID_V01 0 393983bc45SNaman Padhiar #define WLFW_CLIENT_ID 0x4b4e454c 403983bc45SNaman Padhiar #define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77 413983bc45SNaman Padhiar 423983bc45SNaman Padhiar #define BDF_FILE_NAME_PREFIX "bdwlan" 433983bc45SNaman Padhiar #define ELF_BDF_FILE_NAME "bdwlan.elf" 443983bc45SNaman Padhiar #define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e" 453983bc45SNaman Padhiar #define BIN_BDF_FILE_NAME "bdwlan.bin" 463983bc45SNaman Padhiar #define BIN_BDF_FILE_NAME_PREFIX "bdwlan." 473983bc45SNaman Padhiar #define REGDB_FILE_NAME "regdb.bin" 483983bc45SNaman Padhiar 493983bc45SNaman Padhiar #define QDSS_TRACE_CONFIG_FILE "qdss_trace_config.cfg" 503983bc45SNaman Padhiar 513983bc45SNaman Padhiar #define WLAN_BOARD_ID_INDEX 0x100 523983bc45SNaman Padhiar #define DEVICE_BAR_SIZE 0x200000 533983bc45SNaman Padhiar #define M3_SEGMENT_ADDR_MASK 0xFFFFFFFF 543983bc45SNaman Padhiar #define DMS_QMI_MAX_MSG_LEN SZ_256 553983bc45SNaman Padhiar #define DMS_MAC_NOT_PROVISIONED 16 563983bc45SNaman Padhiar #define BDWLAN_SIZE 6 573983bc45SNaman Padhiar #define UMC_CHIP_ID 0x4320 58aec346c6SSandeep Singh #define MAX_SHADOW_REG_RESERVED 2 59aec346c6SSandeep Singh #define MAX_NUM_SHADOW_REG_V3 (QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 - \ 60aec346c6SSandeep Singh MAX_SHADOW_REG_RESERVED) 6187ab436eSNaman Padhiar #define IMSPRIVATE_SERVICE_MAX_MSG_LEN SZ_8K 623983bc45SNaman Padhiar 633983bc45SNaman Padhiar #ifdef CONFIG_ICNSS2_DEBUG 643983bc45SNaman Padhiar bool ignore_fw_timeout; 653983bc45SNaman Padhiar #define ICNSS_QMI_ASSERT() ICNSS_ASSERT(ignore_fw_timeout) 663983bc45SNaman Padhiar #else 673983bc45SNaman Padhiar #define ICNSS_QMI_ASSERT() do { } while (0) 683983bc45SNaman Padhiar #endif 693983bc45SNaman Padhiar 703983bc45SNaman Padhiar #ifdef CONFIG_ICNSS2_DEBUG 713983bc45SNaman Padhiar void icnss_ignore_fw_timeout(bool ignore) 723983bc45SNaman Padhiar { 733983bc45SNaman Padhiar ignore_fw_timeout = ignore; 743983bc45SNaman Padhiar } 753983bc45SNaman Padhiar #else 763983bc45SNaman Padhiar void icnss_ignore_fw_timeout(bool ignore) { } 773983bc45SNaman Padhiar #endif 783983bc45SNaman Padhiar 793983bc45SNaman Padhiar #define icnss_qmi_fatal_err(_fmt, ...) do { \ 803983bc45SNaman Padhiar icnss_pr_err("fatal: "_fmt, ##__VA_ARGS__); \ 813983bc45SNaman Padhiar ICNSS_QMI_ASSERT(); \ 823983bc45SNaman Padhiar } while (0) 833983bc45SNaman Padhiar 843983bc45SNaman Padhiar int wlfw_msa_mem_info_send_sync_msg(struct icnss_priv *priv) 853983bc45SNaman Padhiar { 863983bc45SNaman Padhiar int ret; 873983bc45SNaman Padhiar int i; 883983bc45SNaman Padhiar struct wlfw_msa_info_req_msg_v01 *req; 893983bc45SNaman Padhiar struct wlfw_msa_info_resp_msg_v01 *resp; 903983bc45SNaman Padhiar struct qmi_txn txn; 913983bc45SNaman Padhiar uint64_t max_mapped_addr; 923983bc45SNaman Padhiar 933983bc45SNaman Padhiar if (!priv) 943983bc45SNaman Padhiar return -ENODEV; 953983bc45SNaman Padhiar 963983bc45SNaman Padhiar icnss_pr_dbg("Sending MSA mem info, state: 0x%lx\n", priv->state); 973983bc45SNaman Padhiar 983983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 993983bc45SNaman Padhiar if (!req) 1003983bc45SNaman Padhiar return -ENOMEM; 1013983bc45SNaman Padhiar 1023983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 1033983bc45SNaman Padhiar if (!resp) { 1043983bc45SNaman Padhiar kfree(req); 1053983bc45SNaman Padhiar return -ENOMEM; 1063983bc45SNaman Padhiar } 1073983bc45SNaman Padhiar 1083983bc45SNaman Padhiar req->msa_addr = priv->msa_pa; 1093983bc45SNaman Padhiar req->size = priv->msa_mem_size; 1103983bc45SNaman Padhiar 1113983bc45SNaman Padhiar priv->stats.msa_info_req++; 1123983bc45SNaman Padhiar 1133983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 1143983bc45SNaman Padhiar wlfw_msa_info_resp_msg_v01_ei, resp); 1153983bc45SNaman Padhiar if (ret < 0) { 1163983bc45SNaman Padhiar icnss_qmi_fatal_err( 1173983bc45SNaman Padhiar "Fail to init txn for MSA Mem info resp %d\n", 1183983bc45SNaman Padhiar ret); 1193983bc45SNaman Padhiar goto out; 1203983bc45SNaman Padhiar } 1213983bc45SNaman Padhiar 1223983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 1233983bc45SNaman Padhiar QMI_WLFW_MSA_INFO_REQ_V01, 1243983bc45SNaman Padhiar WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN, 1253983bc45SNaman Padhiar wlfw_msa_info_req_msg_v01_ei, req); 1263983bc45SNaman Padhiar if (ret < 0) { 1273983bc45SNaman Padhiar qmi_txn_cancel(&txn); 1283983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send MSA Mem info req %d\n", ret); 1293983bc45SNaman Padhiar goto out; 1303983bc45SNaman Padhiar } 1313983bc45SNaman Padhiar 1323983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 1333983bc45SNaman Padhiar if (ret < 0) { 1343983bc45SNaman Padhiar icnss_qmi_fatal_err("MSA Mem info resp wait failed ret %d\n", 1353983bc45SNaman Padhiar ret); 1363983bc45SNaman Padhiar goto out; 1373983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 1383983bc45SNaman Padhiar icnss_qmi_fatal_err( 1393983bc45SNaman Padhiar "QMI MSA Mem info request rejected, result:%d error:%d\n", 1403983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 1413983bc45SNaman Padhiar ret = -resp->resp.result; 1423983bc45SNaman Padhiar goto out; 1433983bc45SNaman Padhiar } 1443983bc45SNaman Padhiar 1453983bc45SNaman Padhiar icnss_pr_dbg("Receive mem_region_info_len: %d\n", 1463983bc45SNaman Padhiar resp->mem_region_info_len); 1473983bc45SNaman Padhiar 1483983bc45SNaman Padhiar if (resp->mem_region_info_len > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) { 1493983bc45SNaman Padhiar icnss_qmi_fatal_err( 1503983bc45SNaman Padhiar "Invalid memory region length received: %d\n", 1513983bc45SNaman Padhiar resp->mem_region_info_len); 1523983bc45SNaman Padhiar ret = -EINVAL; 1533983bc45SNaman Padhiar goto out; 1543983bc45SNaman Padhiar } 1553983bc45SNaman Padhiar 1563983bc45SNaman Padhiar max_mapped_addr = priv->msa_pa + priv->msa_mem_size; 1573983bc45SNaman Padhiar priv->stats.msa_info_resp++; 1583983bc45SNaman Padhiar priv->nr_mem_region = resp->mem_region_info_len; 1593983bc45SNaman Padhiar for (i = 0; i < resp->mem_region_info_len; i++) { 1603983bc45SNaman Padhiar 1613983bc45SNaman Padhiar if (resp->mem_region_info[i].size > priv->msa_mem_size || 1623983bc45SNaman Padhiar resp->mem_region_info[i].region_addr >= max_mapped_addr || 1633983bc45SNaman Padhiar resp->mem_region_info[i].region_addr < priv->msa_pa || 1643983bc45SNaman Padhiar resp->mem_region_info[i].size + 1653983bc45SNaman Padhiar resp->mem_region_info[i].region_addr > max_mapped_addr) { 1663983bc45SNaman Padhiar icnss_pr_dbg("Received out of range Addr: 0x%llx Size: 0x%x\n", 1673983bc45SNaman Padhiar resp->mem_region_info[i].region_addr, 1683983bc45SNaman Padhiar resp->mem_region_info[i].size); 1693983bc45SNaman Padhiar ret = -EINVAL; 1703983bc45SNaman Padhiar goto fail_unwind; 1713983bc45SNaman Padhiar } 1723983bc45SNaman Padhiar 1733983bc45SNaman Padhiar priv->mem_region[i].reg_addr = 1743983bc45SNaman Padhiar resp->mem_region_info[i].region_addr; 1753983bc45SNaman Padhiar priv->mem_region[i].size = 1763983bc45SNaman Padhiar resp->mem_region_info[i].size; 1773983bc45SNaman Padhiar priv->mem_region[i].secure_flag = 1783983bc45SNaman Padhiar resp->mem_region_info[i].secure_flag; 1793983bc45SNaman Padhiar icnss_pr_dbg("Memory Region: %d Addr: 0x%llx Size: 0x%x Flag: 0x%08x\n", 1803983bc45SNaman Padhiar i, priv->mem_region[i].reg_addr, 1813983bc45SNaman Padhiar priv->mem_region[i].size, 1823983bc45SNaman Padhiar priv->mem_region[i].secure_flag); 1833983bc45SNaman Padhiar } 1843983bc45SNaman Padhiar 1853983bc45SNaman Padhiar kfree(resp); 1863983bc45SNaman Padhiar kfree(req); 1873983bc45SNaman Padhiar return 0; 1883983bc45SNaman Padhiar 1893983bc45SNaman Padhiar fail_unwind: 1903983bc45SNaman Padhiar memset(&priv->mem_region[0], 0, sizeof(priv->mem_region[0]) * i); 1913983bc45SNaman Padhiar out: 1923983bc45SNaman Padhiar kfree(resp); 1933983bc45SNaman Padhiar kfree(req); 1943983bc45SNaman Padhiar priv->stats.msa_info_err++; 1953983bc45SNaman Padhiar return ret; 1963983bc45SNaman Padhiar } 1973983bc45SNaman Padhiar 1983983bc45SNaman Padhiar int wlfw_msa_ready_send_sync_msg(struct icnss_priv *priv) 1993983bc45SNaman Padhiar { 2003983bc45SNaman Padhiar int ret; 2013983bc45SNaman Padhiar struct wlfw_msa_ready_req_msg_v01 *req; 2023983bc45SNaman Padhiar struct wlfw_msa_ready_resp_msg_v01 *resp; 2033983bc45SNaman Padhiar struct qmi_txn txn; 2043983bc45SNaman Padhiar 2053983bc45SNaman Padhiar if (!priv) 2063983bc45SNaman Padhiar return -ENODEV; 2073983bc45SNaman Padhiar 2083983bc45SNaman Padhiar icnss_pr_dbg("Sending MSA ready request message, state: 0x%lx\n", 2093983bc45SNaman Padhiar priv->state); 2103983bc45SNaman Padhiar 2113983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 2123983bc45SNaman Padhiar if (!req) 2133983bc45SNaman Padhiar return -ENOMEM; 2143983bc45SNaman Padhiar 2153983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2163983bc45SNaman Padhiar if (!resp) { 2173983bc45SNaman Padhiar kfree(req); 2183983bc45SNaman Padhiar return -ENOMEM; 2193983bc45SNaman Padhiar } 2203983bc45SNaman Padhiar 2213983bc45SNaman Padhiar priv->stats.msa_ready_req++; 2223983bc45SNaman Padhiar 2233983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 2243983bc45SNaman Padhiar wlfw_msa_ready_resp_msg_v01_ei, resp); 2253983bc45SNaman Padhiar if (ret < 0) { 2263983bc45SNaman Padhiar icnss_qmi_fatal_err( 2273983bc45SNaman Padhiar "Fail to init txn for MSA Mem Ready resp %d\n", 2283983bc45SNaman Padhiar ret); 2293983bc45SNaman Padhiar goto out; 2303983bc45SNaman Padhiar } 2313983bc45SNaman Padhiar 2323983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 2333983bc45SNaman Padhiar QMI_WLFW_MSA_READY_REQ_V01, 2343983bc45SNaman Padhiar WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN, 2353983bc45SNaman Padhiar wlfw_msa_ready_req_msg_v01_ei, req); 2363983bc45SNaman Padhiar if (ret < 0) { 2373983bc45SNaman Padhiar qmi_txn_cancel(&txn); 2383983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send MSA Mem Ready req %d\n", ret); 2393983bc45SNaman Padhiar goto out; 2403983bc45SNaman Padhiar } 2413983bc45SNaman Padhiar 2423983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 2433983bc45SNaman Padhiar if (ret < 0) { 2443983bc45SNaman Padhiar icnss_qmi_fatal_err( 2453983bc45SNaman Padhiar "MSA Mem Ready resp wait failed with ret %d\n", 2463983bc45SNaman Padhiar ret); 2473983bc45SNaman Padhiar goto out; 2483983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 2493983bc45SNaman Padhiar icnss_qmi_fatal_err( 2503983bc45SNaman Padhiar "QMI MSA Mem Ready request rejected, result:%d error:%d\n", 2513983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 2523983bc45SNaman Padhiar ret = -resp->resp.result; 2533983bc45SNaman Padhiar goto out; 2543983bc45SNaman Padhiar } 2553983bc45SNaman Padhiar 2563983bc45SNaman Padhiar priv->stats.msa_ready_resp++; 2573983bc45SNaman Padhiar 2583983bc45SNaman Padhiar kfree(resp); 2593983bc45SNaman Padhiar kfree(req); 2603983bc45SNaman Padhiar return 0; 2613983bc45SNaman Padhiar 2623983bc45SNaman Padhiar out: 2633983bc45SNaman Padhiar kfree(resp); 2643983bc45SNaman Padhiar kfree(req); 2653983bc45SNaman Padhiar priv->stats.msa_ready_err++; 2663983bc45SNaman Padhiar return ret; 2673983bc45SNaman Padhiar } 2683983bc45SNaman Padhiar 2693983bc45SNaman Padhiar int wlfw_device_info_send_msg(struct icnss_priv *priv) 2703983bc45SNaman Padhiar { 2713983bc45SNaman Padhiar int ret; 2723983bc45SNaman Padhiar struct wlfw_device_info_req_msg_v01 *req; 2733983bc45SNaman Padhiar struct wlfw_device_info_resp_msg_v01 *resp; 2743983bc45SNaman Padhiar struct qmi_txn txn; 2753983bc45SNaman Padhiar 2763983bc45SNaman Padhiar if (!priv) 2773983bc45SNaman Padhiar return -ENODEV; 2783983bc45SNaman Padhiar 2793983bc45SNaman Padhiar icnss_pr_dbg("Sending Device Info request message, state: 0x%lx\n", 2803983bc45SNaman Padhiar priv->state); 2813983bc45SNaman Padhiar 2823983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 2833983bc45SNaman Padhiar if (!req) 2843983bc45SNaman Padhiar return -ENOMEM; 2853983bc45SNaman Padhiar 2863983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 2873983bc45SNaman Padhiar if (!resp) { 2883983bc45SNaman Padhiar kfree(req); 2893983bc45SNaman Padhiar return -ENOMEM; 2903983bc45SNaman Padhiar } 2913983bc45SNaman Padhiar 2923983bc45SNaman Padhiar priv->stats.device_info_req++; 2933983bc45SNaman Padhiar 2943983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 2953983bc45SNaman Padhiar wlfw_device_info_resp_msg_v01_ei, resp); 2963983bc45SNaman Padhiar if (ret < 0) { 2973983bc45SNaman Padhiar icnss_qmi_fatal_err( 2983983bc45SNaman Padhiar "Fail to init txn for Device Info resp %d\n", 2993983bc45SNaman Padhiar ret); 3003983bc45SNaman Padhiar goto out; 3013983bc45SNaman Padhiar } 3023983bc45SNaman Padhiar 3033983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 3043983bc45SNaman Padhiar QMI_WLFW_DEVICE_INFO_REQ_V01, 3053983bc45SNaman Padhiar WLFW_DEVICE_INFO_REQ_MSG_V01_MAX_MSG_LEN, 3063983bc45SNaman Padhiar wlfw_device_info_req_msg_v01_ei, req); 3073983bc45SNaman Padhiar if (ret < 0) { 3083983bc45SNaman Padhiar qmi_txn_cancel(&txn); 3093983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send device info req %d\n", ret); 3103983bc45SNaman Padhiar goto out; 3113983bc45SNaman Padhiar } 3123983bc45SNaman Padhiar 3133983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 3143983bc45SNaman Padhiar if (ret < 0) { 3153983bc45SNaman Padhiar icnss_qmi_fatal_err( 3163983bc45SNaman Padhiar "Device Info resp wait failed with ret %d\n", 3173983bc45SNaman Padhiar ret); 3183983bc45SNaman Padhiar goto out; 3193983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 3203983bc45SNaman Padhiar icnss_qmi_fatal_err( 3213983bc45SNaman Padhiar "QMI Device info request rejected, result:%d error:%d\n", 3223983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 3233983bc45SNaman Padhiar ret = -resp->resp.result; 3243983bc45SNaman Padhiar goto out; 3253983bc45SNaman Padhiar } 3263983bc45SNaman Padhiar 3273983bc45SNaman Padhiar priv->stats.device_info_resp++; 3283983bc45SNaman Padhiar 3293983bc45SNaman Padhiar if (resp->bar_addr_valid) 3303983bc45SNaman Padhiar priv->mem_base_pa = resp->bar_addr; 3313983bc45SNaman Padhiar 3323983bc45SNaman Padhiar if (resp->bar_size_valid) 3333983bc45SNaman Padhiar priv->mem_base_size = resp->bar_size; 3343983bc45SNaman Padhiar 3353983bc45SNaman Padhiar if (!priv->mem_base_pa) { 3363983bc45SNaman Padhiar ret = -EINVAL; 3373983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to get bar address\n"); 3383983bc45SNaman Padhiar goto out; 3393983bc45SNaman Padhiar } 3403983bc45SNaman Padhiar 3413983bc45SNaman Padhiar if (priv->mem_base_size < DEVICE_BAR_SIZE) { 3423983bc45SNaman Padhiar ret = -EINVAL; 3433983bc45SNaman Padhiar icnss_qmi_fatal_err("Bar size is not proper 0x%x\n", 3443983bc45SNaman Padhiar priv->mem_base_size); 3453983bc45SNaman Padhiar goto out; 3463983bc45SNaman Padhiar } 3473983bc45SNaman Padhiar 3483983bc45SNaman Padhiar if (resp->mhi_state_info_addr_valid) 3493983bc45SNaman Padhiar priv->mhi_state_info_pa = resp->mhi_state_info_addr; 3503983bc45SNaman Padhiar 3513983bc45SNaman Padhiar if (resp->mhi_state_info_size_valid) 3523983bc45SNaman Padhiar priv->mhi_state_info_size = resp->mhi_state_info_size; 3533983bc45SNaman Padhiar 3543983bc45SNaman Padhiar if (!priv->mhi_state_info_pa) 3553983bc45SNaman Padhiar icnss_pr_err("Fail to get MHI info address\n"); 3563983bc45SNaman Padhiar 3573983bc45SNaman Padhiar kfree(resp); 3583983bc45SNaman Padhiar kfree(req); 3593983bc45SNaman Padhiar return 0; 3603983bc45SNaman Padhiar 3613983bc45SNaman Padhiar out: 3623983bc45SNaman Padhiar kfree(resp); 3633983bc45SNaman Padhiar kfree(req); 3643983bc45SNaman Padhiar priv->stats.device_info_err++; 3653983bc45SNaman Padhiar return ret; 3663983bc45SNaman Padhiar } 3673983bc45SNaman Padhiar 3683983bc45SNaman Padhiar int wlfw_power_save_send_msg(struct icnss_priv *priv, 3693983bc45SNaman Padhiar enum wlfw_power_save_mode_v01 mode) 3703983bc45SNaman Padhiar { 3713983bc45SNaman Padhiar int ret; 3723983bc45SNaman Padhiar struct wlfw_power_save_req_msg_v01 *req; 3733983bc45SNaman Padhiar struct qmi_txn txn; 3743983bc45SNaman Padhiar 3753983bc45SNaman Padhiar if (!priv) 3763983bc45SNaman Padhiar return -ENODEV; 3773983bc45SNaman Padhiar 3783983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &priv->state)) 3793983bc45SNaman Padhiar return -EINVAL; 3803983bc45SNaman Padhiar 3813983bc45SNaman Padhiar if (test_bit(ICNSS_PD_RESTART, &priv->state) || 3823983bc45SNaman Padhiar !test_bit(ICNSS_MODE_ON, &priv->state)) 3833983bc45SNaman Padhiar return 0; 3843983bc45SNaman Padhiar 3853983bc45SNaman Padhiar icnss_pr_dbg("Sending power save mode: %d, state: 0x%lx\n", 3863983bc45SNaman Padhiar mode, priv->state); 3873983bc45SNaman Padhiar 3883983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 3893983bc45SNaman Padhiar if (!req) 3903983bc45SNaman Padhiar return -ENOMEM; 3913983bc45SNaman Padhiar 3923983bc45SNaman Padhiar req->power_save_mode_valid = 1; 3933983bc45SNaman Padhiar req->power_save_mode = mode; 3943983bc45SNaman Padhiar 3953983bc45SNaman Padhiar if (mode == WLFW_POWER_SAVE_EXIT_V01) 3963983bc45SNaman Padhiar priv->stats.exit_power_save_req++; 3973983bc45SNaman Padhiar else 3983983bc45SNaman Padhiar priv->stats.enter_power_save_req++; 3993983bc45SNaman Padhiar 4003983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 4013983bc45SNaman Padhiar NULL, NULL); 4023983bc45SNaman Padhiar if (ret < 0) { 4033983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for exit power save%d\n", 4043983bc45SNaman Padhiar ret); 4053983bc45SNaman Padhiar goto out; 4063983bc45SNaman Padhiar } 4073983bc45SNaman Padhiar 4083983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 4093983bc45SNaman Padhiar QMI_WLFW_POWER_SAVE_REQ_V01, 4103983bc45SNaman Padhiar WLFW_POWER_SAVE_REQ_MSG_V01_MAX_MSG_LEN, 4113983bc45SNaman Padhiar wlfw_power_save_req_msg_v01_ei, req); 4123983bc45SNaman Padhiar if (ret < 0) { 4133983bc45SNaman Padhiar qmi_txn_cancel(&txn); 4143983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send exit power save req %d\n", 4153983bc45SNaman Padhiar ret); 4163983bc45SNaman Padhiar goto out; 4173983bc45SNaman Padhiar } 4183983bc45SNaman Padhiar 4193983bc45SNaman Padhiar qmi_txn_cancel(&txn); 4203983bc45SNaman Padhiar 4213983bc45SNaman Padhiar if (mode == WLFW_POWER_SAVE_EXIT_V01) 4223983bc45SNaman Padhiar priv->stats.exit_power_save_resp++; 4233983bc45SNaman Padhiar else 4243983bc45SNaman Padhiar priv->stats.enter_power_save_resp++; 4253983bc45SNaman Padhiar 4263983bc45SNaman Padhiar kfree(req); 4273983bc45SNaman Padhiar return 0; 4283983bc45SNaman Padhiar 4293983bc45SNaman Padhiar out: 4303983bc45SNaman Padhiar kfree(req); 4313983bc45SNaman Padhiar 4323983bc45SNaman Padhiar if (mode == WLFW_POWER_SAVE_EXIT_V01) 4333983bc45SNaman Padhiar priv->stats.exit_power_save_err++; 4343983bc45SNaman Padhiar else 4353983bc45SNaman Padhiar priv->stats.enter_power_save_err++; 4363983bc45SNaman Padhiar return ret; 4373983bc45SNaman Padhiar } 4383983bc45SNaman Padhiar 4393983bc45SNaman Padhiar int wlfw_send_soc_wake_msg(struct icnss_priv *priv, 4403983bc45SNaman Padhiar enum wlfw_soc_wake_enum_v01 type) 4413983bc45SNaman Padhiar { 4423983bc45SNaman Padhiar int ret; 4433983bc45SNaman Padhiar struct wlfw_soc_wake_req_msg_v01 *req; 4443983bc45SNaman Padhiar struct wlfw_soc_wake_resp_msg_v01 *resp; 4453983bc45SNaman Padhiar struct qmi_txn txn; 4463983bc45SNaman Padhiar 4473983bc45SNaman Padhiar if (!priv) 4483983bc45SNaman Padhiar return -ENODEV; 4493983bc45SNaman Padhiar 4503983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &priv->state)) 4513983bc45SNaman Padhiar return -EINVAL; 4523983bc45SNaman Padhiar 4533983bc45SNaman Padhiar icnss_pr_soc_wake("Sending soc wake msg, type: 0x%x\n", 4543983bc45SNaman Padhiar type); 4553983bc45SNaman Padhiar 4563983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 4573983bc45SNaman Padhiar if (!req) 4583983bc45SNaman Padhiar return -ENOMEM; 4593983bc45SNaman Padhiar 4603983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 4613983bc45SNaman Padhiar if (!resp) { 4623983bc45SNaman Padhiar kfree(req); 4633983bc45SNaman Padhiar return -ENOMEM; 4643983bc45SNaman Padhiar } 4653983bc45SNaman Padhiar req->wake_valid = 1; 4663983bc45SNaman Padhiar req->wake = type; 4673983bc45SNaman Padhiar 4683983bc45SNaman Padhiar priv->stats.soc_wake_req++; 4693983bc45SNaman Padhiar 4703983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 4713983bc45SNaman Padhiar wlfw_soc_wake_resp_msg_v01_ei, resp); 4723983bc45SNaman Padhiar 4733983bc45SNaman Padhiar if (ret < 0) { 4743983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for wake msg resp %d\n", 4753983bc45SNaman Padhiar ret); 4763983bc45SNaman Padhiar goto out; 4773983bc45SNaman Padhiar } 4783983bc45SNaman Padhiar 4793983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 4803983bc45SNaman Padhiar QMI_WLFW_SOC_WAKE_REQ_V01, 4813983bc45SNaman Padhiar WLFW_SOC_WAKE_REQ_MSG_V01_MAX_MSG_LEN, 4823983bc45SNaman Padhiar wlfw_soc_wake_req_msg_v01_ei, req); 4833983bc45SNaman Padhiar if (ret < 0) { 4843983bc45SNaman Padhiar qmi_txn_cancel(&txn); 4853983bc45SNaman Padhiar icnss_pr_err("Fail to send soc wake msg %d\n", ret); 4863983bc45SNaman Padhiar goto out; 4873983bc45SNaman Padhiar } 4883983bc45SNaman Padhiar 4893983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 4903983bc45SNaman Padhiar if (ret < 0) { 4913983bc45SNaman Padhiar icnss_qmi_fatal_err("SOC wake timed out with ret %d\n", 4923983bc45SNaman Padhiar ret); 4933983bc45SNaman Padhiar goto out; 4943983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 4953983bc45SNaman Padhiar icnss_qmi_fatal_err( 4963983bc45SNaman Padhiar "SOC wake request rejected,result:%d error:%d\n", 4973983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 4983983bc45SNaman Padhiar ret = -resp->resp.result; 4993983bc45SNaman Padhiar goto out; 5003983bc45SNaman Padhiar } 5013983bc45SNaman Padhiar 5023983bc45SNaman Padhiar priv->stats.soc_wake_resp++; 5033983bc45SNaman Padhiar 5043983bc45SNaman Padhiar kfree(resp); 5053983bc45SNaman Padhiar kfree(req); 5063983bc45SNaman Padhiar return 0; 5073983bc45SNaman Padhiar 5083983bc45SNaman Padhiar out: 5093983bc45SNaman Padhiar kfree(req); 5103983bc45SNaman Padhiar kfree(resp); 5113983bc45SNaman Padhiar priv->stats.soc_wake_err++; 5123983bc45SNaman Padhiar return ret; 5133983bc45SNaman Padhiar } 5143983bc45SNaman Padhiar 5153983bc45SNaman Padhiar int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv) 5163983bc45SNaman Padhiar { 5173983bc45SNaman Padhiar int ret; 5183983bc45SNaman Padhiar struct wlfw_ind_register_req_msg_v01 *req; 5193983bc45SNaman Padhiar struct wlfw_ind_register_resp_msg_v01 *resp; 5203983bc45SNaman Padhiar struct qmi_txn txn; 5213983bc45SNaman Padhiar 5223983bc45SNaman Padhiar if (!priv) 5233983bc45SNaman Padhiar return -ENODEV; 5243983bc45SNaman Padhiar 5253983bc45SNaman Padhiar icnss_pr_dbg("Sending indication register message, state: 0x%lx\n", 5263983bc45SNaman Padhiar priv->state); 5273983bc45SNaman Padhiar 5283983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 5293983bc45SNaman Padhiar if (!req) 5303983bc45SNaman Padhiar return -ENOMEM; 5313983bc45SNaman Padhiar 5323983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 5333983bc45SNaman Padhiar if (!resp) { 5343983bc45SNaman Padhiar kfree(req); 5353983bc45SNaman Padhiar return -ENOMEM; 5363983bc45SNaman Padhiar } 5373983bc45SNaman Padhiar 5383983bc45SNaman Padhiar req->client_id_valid = 1; 5393983bc45SNaman Padhiar req->client_id = WLFW_CLIENT_ID; 5403983bc45SNaman Padhiar req->fw_ready_enable_valid = 1; 5413983bc45SNaman Padhiar req->fw_ready_enable = 1; 5423983bc45SNaman Padhiar req->pin_connect_result_enable_valid = 1; 5433983bc45SNaman Padhiar req->pin_connect_result_enable = 1; 5443983bc45SNaman Padhiar 5453983bc45SNaman Padhiar if (priv->device_id == ADRASTEA_DEVICE_ID) { 5463983bc45SNaman Padhiar req->msa_ready_enable_valid = 1; 5473983bc45SNaman Padhiar req->msa_ready_enable = 1; 5483983bc45SNaman Padhiar if (test_bit(FW_REJUVENATE_ENABLE, 5493983bc45SNaman Padhiar &priv->ctrl_params.quirks)) { 5503983bc45SNaman Padhiar req->rejuvenate_enable_valid = 1; 5513983bc45SNaman Padhiar req->rejuvenate_enable = 1; 5523983bc45SNaman Padhiar } 553aec346c6SSandeep Singh } else if (priv->device_id == WCN6750_DEVICE_ID || 554aec346c6SSandeep Singh priv->device_id == WCN6450_DEVICE_ID) { 5553983bc45SNaman Padhiar req->fw_init_done_enable_valid = 1; 5563983bc45SNaman Padhiar req->fw_init_done_enable = 1; 5573983bc45SNaman Padhiar req->cal_done_enable_valid = 1; 5583983bc45SNaman Padhiar req->cal_done_enable = 1; 5593983bc45SNaman Padhiar req->qdss_trace_req_mem_enable_valid = 1; 5603983bc45SNaman Padhiar req->qdss_trace_req_mem_enable = 1; 5613983bc45SNaman Padhiar req->qdss_trace_save_enable_valid = 1; 5623983bc45SNaman Padhiar req->qdss_trace_save_enable = 1; 5633983bc45SNaman Padhiar req->qdss_trace_free_enable_valid = 1; 5643983bc45SNaman Padhiar req->qdss_trace_free_enable = 1; 5653983bc45SNaman Padhiar req->respond_get_info_enable_valid = 1; 5663983bc45SNaman Padhiar req->respond_get_info_enable = 1; 5673983bc45SNaman Padhiar req->m3_dump_upload_segments_req_enable_valid = 1; 5683983bc45SNaman Padhiar req->m3_dump_upload_segments_req_enable = 1; 5693983bc45SNaman Padhiar } 5703983bc45SNaman Padhiar 5713983bc45SNaman Padhiar priv->stats.ind_register_req++; 5723983bc45SNaman Padhiar 5733983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 5743983bc45SNaman Padhiar wlfw_ind_register_resp_msg_v01_ei, resp); 5753983bc45SNaman Padhiar if (ret < 0) { 5763983bc45SNaman Padhiar icnss_qmi_fatal_err( 5773983bc45SNaman Padhiar "Fail to init txn for Ind Register resp %d\n", 5783983bc45SNaman Padhiar ret); 5793983bc45SNaman Padhiar goto out; 5803983bc45SNaman Padhiar } 5813983bc45SNaman Padhiar 5823983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 5833983bc45SNaman Padhiar QMI_WLFW_IND_REGISTER_REQ_V01, 5843983bc45SNaman Padhiar WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN, 5853983bc45SNaman Padhiar wlfw_ind_register_req_msg_v01_ei, req); 5863983bc45SNaman Padhiar if (ret < 0) { 5873983bc45SNaman Padhiar qmi_txn_cancel(&txn); 5883983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send Ind Register req %d\n", ret); 5893983bc45SNaman Padhiar goto out; 5903983bc45SNaman Padhiar } 5913983bc45SNaman Padhiar 5923983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 5933983bc45SNaman Padhiar if (ret < 0) { 5943983bc45SNaman Padhiar icnss_qmi_fatal_err( 5953983bc45SNaman Padhiar "Ind Register resp wait failed with ret %d\n", 5963983bc45SNaman Padhiar ret); 5973983bc45SNaman Padhiar goto out; 5983983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 5993983bc45SNaman Padhiar icnss_qmi_fatal_err( 6003983bc45SNaman Padhiar "QMI Ind Register request rejected, result:%d error:%d\n", 6013983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 6023983bc45SNaman Padhiar ret = -resp->resp.result; 6033983bc45SNaman Padhiar goto out; 6043983bc45SNaman Padhiar } 6053983bc45SNaman Padhiar 6063983bc45SNaman Padhiar priv->stats.ind_register_resp++; 6073983bc45SNaman Padhiar 6083983bc45SNaman Padhiar if (resp->fw_status_valid && 6093983bc45SNaman Padhiar (resp->fw_status & QMI_WLFW_ALREADY_REGISTERED_V01)) { 6103983bc45SNaman Padhiar ret = -EALREADY; 6113983bc45SNaman Padhiar icnss_pr_dbg("WLFW already registered\n"); 6123983bc45SNaman Padhiar goto qmi_registered; 6133983bc45SNaman Padhiar } 6143983bc45SNaman Padhiar 6153983bc45SNaman Padhiar kfree(resp); 6163983bc45SNaman Padhiar kfree(req); 6173983bc45SNaman Padhiar 6183983bc45SNaman Padhiar return 0; 6193983bc45SNaman Padhiar 6203983bc45SNaman Padhiar out: 6213983bc45SNaman Padhiar priv->stats.ind_register_err++; 6223983bc45SNaman Padhiar qmi_registered: 6233983bc45SNaman Padhiar kfree(resp); 6243983bc45SNaman Padhiar kfree(req); 6253983bc45SNaman Padhiar return ret; 6263983bc45SNaman Padhiar } 6273983bc45SNaman Padhiar 6283983bc45SNaman Padhiar int wlfw_cal_report_req(struct icnss_priv *priv) 6293983bc45SNaman Padhiar { 6303983bc45SNaman Padhiar int ret; 6313983bc45SNaman Padhiar struct wlfw_cal_report_req_msg_v01 *req; 6323983bc45SNaman Padhiar struct wlfw_cal_report_resp_msg_v01 *resp; 6333983bc45SNaman Padhiar struct qmi_txn txn; 6343983bc45SNaman Padhiar 6353983bc45SNaman Padhiar if (!priv) 6363983bc45SNaman Padhiar return -ENODEV; 6373983bc45SNaman Padhiar 6383983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &priv->state)) 6393983bc45SNaman Padhiar return -EINVAL; 6403983bc45SNaman Padhiar 6413983bc45SNaman Padhiar icnss_pr_info("Sending cal report request, state: 0x%lx\n", 6423983bc45SNaman Padhiar priv->state); 6433983bc45SNaman Padhiar 6443983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 6453983bc45SNaman Padhiar if (!req) 6463983bc45SNaman Padhiar return -ENOMEM; 6473983bc45SNaman Padhiar 6483983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 6493983bc45SNaman Padhiar if (!resp) { 6503983bc45SNaman Padhiar kfree(req); 6513983bc45SNaman Padhiar return -ENOMEM; 6523983bc45SNaman Padhiar } 6533983bc45SNaman Padhiar req->meta_data_len = 0; 6543983bc45SNaman Padhiar 6553983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 6563983bc45SNaman Padhiar wlfw_cal_report_resp_msg_v01_ei, resp); 6573983bc45SNaman Padhiar if (ret < 0) { 6583983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for cal report req %d\n", 6593983bc45SNaman Padhiar ret); 6603983bc45SNaman Padhiar goto out; 6613983bc45SNaman Padhiar } 6623983bc45SNaman Padhiar 6633983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 6643983bc45SNaman Padhiar QMI_WLFW_CAL_REPORT_REQ_V01, 6653983bc45SNaman Padhiar WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN, 6663983bc45SNaman Padhiar wlfw_cal_report_req_msg_v01_ei, req); 6673983bc45SNaman Padhiar if (ret < 0) { 6683983bc45SNaman Padhiar qmi_txn_cancel(&txn); 6693983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send cal report req %d\n", ret); 6703983bc45SNaman Padhiar goto out; 6713983bc45SNaman Padhiar } 6723983bc45SNaman Padhiar 6733983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, 6743983bc45SNaman Padhiar priv->ctrl_params.qmi_timeout); 6753983bc45SNaman Padhiar 6763983bc45SNaman Padhiar if (ret < 0) { 6773983bc45SNaman Padhiar icnss_qmi_fatal_err("Cal report wait failed with ret %d\n", 6783983bc45SNaman Padhiar ret); 6793983bc45SNaman Padhiar goto out; 6803983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 6813983bc45SNaman Padhiar icnss_qmi_fatal_err("QMI cal report request rejected, result:%d error:%d\n", 6823983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 6833983bc45SNaman Padhiar ret = -resp->resp.result; 6843983bc45SNaman Padhiar goto out; 6853983bc45SNaman Padhiar } 6863983bc45SNaman Padhiar 6873983bc45SNaman Padhiar kfree(resp); 6883983bc45SNaman Padhiar kfree(req); 6893983bc45SNaman Padhiar 6903983bc45SNaman Padhiar return 0; 6913983bc45SNaman Padhiar 6923983bc45SNaman Padhiar out: 6933983bc45SNaman Padhiar return ret; 6943983bc45SNaman Padhiar } 6953983bc45SNaman Padhiar 6963983bc45SNaman Padhiar int wlfw_cap_send_sync_msg(struct icnss_priv *priv) 6973983bc45SNaman Padhiar { 698f6e67cd9SSandeep Singh int ret = 0, i = 0; 6993983bc45SNaman Padhiar struct wlfw_cap_req_msg_v01 *req; 7003983bc45SNaman Padhiar struct wlfw_cap_resp_msg_v01 *resp; 7013983bc45SNaman Padhiar struct qmi_txn txn; 7023983bc45SNaman Padhiar 7033983bc45SNaman Padhiar if (!priv) 7043983bc45SNaman Padhiar return -ENODEV; 7053983bc45SNaman Padhiar 7063983bc45SNaman Padhiar icnss_pr_dbg("Sending target capability message, state: 0x%lx\n", 7073983bc45SNaman Padhiar priv->state); 7083983bc45SNaman Padhiar 7093983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 7103983bc45SNaman Padhiar if (!req) 7113983bc45SNaman Padhiar return -ENOMEM; 7123983bc45SNaman Padhiar 7133983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 7143983bc45SNaman Padhiar if (!resp) { 7153983bc45SNaman Padhiar kfree(req); 7163983bc45SNaman Padhiar return -ENOMEM; 7173983bc45SNaman Padhiar } 7183983bc45SNaman Padhiar 7193983bc45SNaman Padhiar priv->stats.cap_req++; 7203983bc45SNaman Padhiar 7213983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, wlfw_cap_resp_msg_v01_ei, resp); 7223983bc45SNaman Padhiar if (ret < 0) { 7233983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for Capability resp %d\n", 7243983bc45SNaman Padhiar ret); 7253983bc45SNaman Padhiar goto out; 7263983bc45SNaman Padhiar } 7273983bc45SNaman Padhiar 7283983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 7293983bc45SNaman Padhiar QMI_WLFW_CAP_REQ_V01, 7303983bc45SNaman Padhiar WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN, 7313983bc45SNaman Padhiar wlfw_cap_req_msg_v01_ei, req); 7323983bc45SNaman Padhiar if (ret < 0) { 7333983bc45SNaman Padhiar qmi_txn_cancel(&txn); 7343983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send Capability req %d\n", ret); 7353983bc45SNaman Padhiar goto out; 7363983bc45SNaman Padhiar } 7373983bc45SNaman Padhiar 7383983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, 7393983bc45SNaman Padhiar priv->ctrl_params.qmi_timeout + 7403983bc45SNaman Padhiar msecs_to_jiffies(priv->wlan_en_delay_ms)); 7413983bc45SNaman Padhiar if (ret < 0) { 7423983bc45SNaman Padhiar icnss_qmi_fatal_err("Capability resp wait failed with ret %d\n", 7433983bc45SNaman Padhiar ret); 7443983bc45SNaman Padhiar goto out; 7453983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 7463983bc45SNaman Padhiar ret = -resp->resp.result; 7473983bc45SNaman Padhiar if (resp->resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED) { 7483983bc45SNaman Padhiar icnss_pr_err("RF card not present\n"); 7493983bc45SNaman Padhiar goto out; 7503983bc45SNaman Padhiar } 7513983bc45SNaman Padhiar icnss_qmi_fatal_err( 7523983bc45SNaman Padhiar "QMI Capability request rejected, result:%d error:%d\n", 7533983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 7543983bc45SNaman Padhiar goto out; 7553983bc45SNaman Padhiar } 7563983bc45SNaman Padhiar 7573983bc45SNaman Padhiar priv->stats.cap_resp++; 7583983bc45SNaman Padhiar 7593983bc45SNaman Padhiar if (resp->chip_info_valid) { 7603983bc45SNaman Padhiar priv->chip_info.chip_id = resp->chip_info.chip_id; 7613983bc45SNaman Padhiar priv->chip_info.chip_family = resp->chip_info.chip_family; 7623983bc45SNaman Padhiar } 7633983bc45SNaman Padhiar if (resp->board_info_valid) 7643983bc45SNaman Padhiar priv->board_id = resp->board_info.board_id; 7653983bc45SNaman Padhiar else 7663983bc45SNaman Padhiar priv->board_id = 0xFF; 7673983bc45SNaman Padhiar if (resp->soc_info_valid) 7683983bc45SNaman Padhiar priv->soc_id = resp->soc_info.soc_id; 7693983bc45SNaman Padhiar if (resp->fw_version_info_valid) { 7703983bc45SNaman Padhiar priv->fw_version_info.fw_version = 7713983bc45SNaman Padhiar resp->fw_version_info.fw_version; 7723983bc45SNaman Padhiar strlcpy(priv->fw_version_info.fw_build_timestamp, 7733983bc45SNaman Padhiar resp->fw_version_info.fw_build_timestamp, 7743983bc45SNaman Padhiar WLFW_MAX_TIMESTAMP_LEN + 1); 7753983bc45SNaman Padhiar } 7763983bc45SNaman Padhiar 777f6e67cd9SSandeep Singh if (resp->dev_mem_info_valid) { 778f6e67cd9SSandeep Singh for (i = 0; i < QMI_WLFW_MAX_DEV_MEM_NUM_V01; i++) { 779f6e67cd9SSandeep Singh priv->dev_mem_info[i].start = 780f6e67cd9SSandeep Singh resp->dev_mem_info[i].start; 781f6e67cd9SSandeep Singh priv->dev_mem_info[i].size = 782f6e67cd9SSandeep Singh resp->dev_mem_info[i].size; 783f6e67cd9SSandeep Singh icnss_pr_info("Device memory info[%d]: start = 0x%llx, size = 0x%llx\n", 784f6e67cd9SSandeep Singh i, priv->dev_mem_info[i].start, 785f6e67cd9SSandeep Singh priv->dev_mem_info[i].size); 786f6e67cd9SSandeep Singh } 787f6e67cd9SSandeep Singh } 788f6e67cd9SSandeep Singh 7893983bc45SNaman Padhiar if (resp->voltage_mv_valid) { 7903983bc45SNaman Padhiar priv->cpr_info.voltage = resp->voltage_mv; 7913983bc45SNaman Padhiar icnss_pr_dbg("Voltage for CPR: %dmV\n", 7923983bc45SNaman Padhiar priv->cpr_info.voltage); 7933983bc45SNaman Padhiar icnss_update_cpr_info(priv); 7943983bc45SNaman Padhiar } 7953983bc45SNaman Padhiar 7963983bc45SNaman Padhiar if (resp->fw_build_id_valid) 7973983bc45SNaman Padhiar strlcpy(priv->fw_build_id, resp->fw_build_id, 7983983bc45SNaman Padhiar QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1); 7993983bc45SNaman Padhiar 800c5b4320dSSandeep Singh if (resp->rd_card_chain_cap_valid) { 801c5b4320dSSandeep Singh priv->rd_card_chain_cap = (enum icnss_rd_card_chain_cap)resp->rd_card_chain_cap; 802c5b4320dSSandeep Singh if (resp->rd_card_chain_cap == WLFW_RD_CARD_CHAIN_CAP_1x1_V01) 8033983bc45SNaman Padhiar priv->is_chain1_supported = false; 804c5b4320dSSandeep Singh } 8053983bc45SNaman Padhiar 8063983bc45SNaman Padhiar if (resp->foundry_name_valid) 8073983bc45SNaman Padhiar priv->foundry_name = resp->foundry_name[0]; 8083983bc45SNaman Padhiar else if (resp->chip_info_valid && priv->chip_info.chip_id == UMC_CHIP_ID) 8093983bc45SNaman Padhiar priv->foundry_name = 'u'; 8103983bc45SNaman Padhiar 811c5b4320dSSandeep Singh if (resp->he_channel_width_cap_valid) 812c5b4320dSSandeep Singh priv->phy_he_channel_width_cap = 813c5b4320dSSandeep Singh (enum icnss_phy_he_channel_width_cap)resp->he_channel_width_cap; 814c5b4320dSSandeep Singh 815c5b4320dSSandeep Singh if (resp->phy_qam_cap_valid) 816c5b4320dSSandeep Singh priv->phy_qam_cap = (enum icnss_phy_qam_cap)resp->phy_qam_cap; 817c5b4320dSSandeep Singh 818e60f6609SLin Bai if (resp->serial_id_valid) { 819e60f6609SLin Bai priv->serial_id = resp->serial_id; 820e60f6609SLin Bai icnss_pr_info("serial id 0x%x 0x%x\n", 821e60f6609SLin Bai resp->serial_id.serial_id_msb, 822e60f6609SLin Bai resp->serial_id.serial_id_lsb); 823e60f6609SLin Bai } 824e60f6609SLin Bai 8253983bc45SNaman Padhiar icnss_pr_dbg("Capability, chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x", 8263983bc45SNaman Padhiar priv->chip_info.chip_id, priv->chip_info.chip_family, 8273983bc45SNaman Padhiar priv->board_id, priv->soc_id); 8283983bc45SNaman Padhiar 8293983bc45SNaman Padhiar icnss_pr_dbg("fw_version: 0x%x, fw_build_timestamp: %s, fw_build_id: %s", 8303983bc45SNaman Padhiar priv->fw_version_info.fw_version, 8313983bc45SNaman Padhiar priv->fw_version_info.fw_build_timestamp, 8323983bc45SNaman Padhiar priv->fw_build_id); 8333983bc45SNaman Padhiar 834c5b4320dSSandeep Singh icnss_pr_dbg("RD card chain cap: %d, PHY HE channel width cap: %d, PHY QAM cap: %d", 835c5b4320dSSandeep Singh priv->rd_card_chain_cap, priv->phy_he_channel_width_cap, 836c5b4320dSSandeep Singh priv->phy_qam_cap); 837c5b4320dSSandeep Singh 8383983bc45SNaman Padhiar kfree(resp); 8393983bc45SNaman Padhiar kfree(req); 8403983bc45SNaman Padhiar return 0; 8413983bc45SNaman Padhiar 8423983bc45SNaman Padhiar out: 8433983bc45SNaman Padhiar kfree(resp); 8443983bc45SNaman Padhiar kfree(req); 8453983bc45SNaman Padhiar priv->stats.cap_err++; 8463983bc45SNaman Padhiar return ret; 8473983bc45SNaman Padhiar } 8483983bc45SNaman Padhiar 8493983bc45SNaman Padhiar int icnss_qmi_get_dms_mac(struct icnss_priv *priv) 8503983bc45SNaman Padhiar { 8513983bc45SNaman Padhiar struct dms_get_mac_address_req_msg_v01 req; 8523983bc45SNaman Padhiar struct dms_get_mac_address_resp_msg_v01 resp; 8533983bc45SNaman Padhiar struct qmi_txn txn; 8543983bc45SNaman Padhiar int ret = 0; 8553983bc45SNaman Padhiar 8563983bc45SNaman Padhiar if (!test_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state)) { 8573983bc45SNaman Padhiar icnss_pr_err("DMS QMI connection not established\n"); 8583983bc45SNaman Padhiar return -EAGAIN; 8593983bc45SNaman Padhiar } 8603983bc45SNaman Padhiar icnss_pr_dbg("Requesting DMS MAC address"); 8613983bc45SNaman Padhiar 8623983bc45SNaman Padhiar memset(&resp, 0, sizeof(resp)); 8633983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi_dms, &txn, 8643983bc45SNaman Padhiar dms_get_mac_address_resp_msg_v01_ei, &resp); 8653983bc45SNaman Padhiar if (ret < 0) { 8663983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for dms, err: %d\n", 8673983bc45SNaman Padhiar ret); 8683983bc45SNaman Padhiar goto out; 8693983bc45SNaman Padhiar } 8703983bc45SNaman Padhiar req.device = DMS_DEVICE_MAC_WLAN_V01; 8713983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi_dms, NULL, &txn, 8723983bc45SNaman Padhiar QMI_DMS_GET_MAC_ADDRESS_REQ_V01, 8733983bc45SNaman Padhiar DMS_GET_MAC_ADDRESS_REQ_MSG_V01_MAX_MSG_LEN, 8743983bc45SNaman Padhiar dms_get_mac_address_req_msg_v01_ei, &req); 8753983bc45SNaman Padhiar if (ret < 0) { 8763983bc45SNaman Padhiar qmi_txn_cancel(&txn); 8773983bc45SNaman Padhiar icnss_pr_err("Failed to send QMI_DMS_GET_MAC_ADDRESS_REQ_V01, err: %d\n", 8783983bc45SNaman Padhiar ret); 8793983bc45SNaman Padhiar goto out; 8803983bc45SNaman Padhiar } 8813983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 8823983bc45SNaman Padhiar if (ret < 0) { 8833983bc45SNaman Padhiar icnss_pr_err("Failed to wait for QMI_DMS_GET_MAC_ADDRESS_RESP_V01, err: %d\n", 8843983bc45SNaman Padhiar ret); 8853983bc45SNaman Padhiar goto out; 8863983bc45SNaman Padhiar } 8873983bc45SNaman Padhiar 8883983bc45SNaman Padhiar if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 8893983bc45SNaman Padhiar if (resp.resp.error == DMS_MAC_NOT_PROVISIONED) { 8903983bc45SNaman Padhiar icnss_pr_err("NV MAC address is not provisioned"); 8913983bc45SNaman Padhiar priv->dms.nv_mac_not_prov = 1; 8923983bc45SNaman Padhiar } else { 8933983bc45SNaman Padhiar icnss_pr_err("QMI_DMS_GET_MAC_ADDRESS_REQ_V01 failed, result: %d, err: %d\n", 8943983bc45SNaman Padhiar resp.resp.result, resp.resp.error); 8953983bc45SNaman Padhiar } 8963983bc45SNaman Padhiar ret = -resp.resp.result; 8973983bc45SNaman Padhiar goto out; 8983983bc45SNaman Padhiar } 8993983bc45SNaman Padhiar if (!resp.mac_address_valid || 9003983bc45SNaman Padhiar resp.mac_address_len != QMI_WLFW_MAC_ADDR_SIZE_V01) { 9013983bc45SNaman Padhiar icnss_pr_err("Invalid MAC address received from DMS\n"); 9023983bc45SNaman Padhiar priv->dms.mac_valid = false; 9033983bc45SNaman Padhiar goto out; 9043983bc45SNaman Padhiar } 9053983bc45SNaman Padhiar priv->dms.mac_valid = true; 9063983bc45SNaman Padhiar memcpy(priv->dms.mac, resp.mac_address, QMI_WLFW_MAC_ADDR_SIZE_V01); 9073983bc45SNaman Padhiar icnss_pr_info("Received DMS MAC: [%pM]\n", priv->dms.mac); 9083983bc45SNaman Padhiar out: 9093983bc45SNaman Padhiar return ret; 9103983bc45SNaman Padhiar } 9113983bc45SNaman Padhiar 9123983bc45SNaman Padhiar int icnss_wlfw_wlan_mac_req_send_sync(struct icnss_priv *priv, 9133983bc45SNaman Padhiar u8 *mac, u32 mac_len) 9143983bc45SNaman Padhiar { 9153983bc45SNaman Padhiar struct wlfw_mac_addr_req_msg_v01 req; 9163983bc45SNaman Padhiar struct wlfw_mac_addr_resp_msg_v01 resp = {0}; 9173983bc45SNaman Padhiar struct qmi_txn txn; 9183983bc45SNaman Padhiar int ret; 9193983bc45SNaman Padhiar 9203983bc45SNaman Padhiar if (!priv || !mac || mac_len != QMI_WLFW_MAC_ADDR_SIZE_V01) 9213983bc45SNaman Padhiar return -EINVAL; 9223983bc45SNaman Padhiar 9233983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 9243983bc45SNaman Padhiar wlfw_mac_addr_resp_msg_v01_ei, &resp); 9253983bc45SNaman Padhiar if (ret < 0) { 9263983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for mac req, err: %d\n", 9273983bc45SNaman Padhiar ret); 9283983bc45SNaman Padhiar ret = -EIO; 9293983bc45SNaman Padhiar goto out; 9303983bc45SNaman Padhiar } 9313983bc45SNaman Padhiar 9323983bc45SNaman Padhiar icnss_pr_dbg("Sending WLAN mac req [%pM], state: 0x%lx\n", 9333983bc45SNaman Padhiar mac, priv->state); 9343983bc45SNaman Padhiar memcpy(req.mac_addr, mac, mac_len); 9353983bc45SNaman Padhiar req.mac_addr_valid = 1; 9363983bc45SNaman Padhiar 9373983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 9383983bc45SNaman Padhiar QMI_WLFW_MAC_ADDR_REQ_V01, 9393983bc45SNaman Padhiar WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN, 9403983bc45SNaman Padhiar wlfw_mac_addr_req_msg_v01_ei, &req); 9413983bc45SNaman Padhiar if (ret < 0) { 9423983bc45SNaman Padhiar qmi_txn_cancel(&txn); 9433983bc45SNaman Padhiar icnss_pr_err("Failed to send mac req, err: %d\n", ret); 9443983bc45SNaman Padhiar ret = -EIO; 9453983bc45SNaman Padhiar goto out; 9463983bc45SNaman Padhiar } 9473983bc45SNaman Padhiar 9483983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 9493983bc45SNaman Padhiar if (ret < 0) { 9503983bc45SNaman Padhiar icnss_pr_err("Failed to wait for resp of mac req, err: %d\n", 9513983bc45SNaman Padhiar ret); 9523983bc45SNaman Padhiar ret = -EIO; 9533983bc45SNaman Padhiar goto out; 9543983bc45SNaman Padhiar } 9553983bc45SNaman Padhiar 9563983bc45SNaman Padhiar if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { 957ecb024f0SRajesh Chauhan icnss_pr_err("WLAN mac req failed, result: %d\n", 9583983bc45SNaman Padhiar resp.resp.result); 9593983bc45SNaman Padhiar ret = -resp.resp.result; 9603983bc45SNaman Padhiar } 9613983bc45SNaman Padhiar out: 9623983bc45SNaman Padhiar return ret; 9633983bc45SNaman Padhiar } 9643983bc45SNaman Padhiar 9653983bc45SNaman Padhiar static int icnss_dms_connect_to_server(struct icnss_priv *priv, 9663983bc45SNaman Padhiar unsigned int node, unsigned int port) 9673983bc45SNaman Padhiar { 9683983bc45SNaman Padhiar struct qmi_handle *qmi_dms = &priv->qmi_dms; 9693983bc45SNaman Padhiar struct sockaddr_qrtr sq = {0}; 9703983bc45SNaman Padhiar int ret = 0; 9713983bc45SNaman Padhiar 9723983bc45SNaman Padhiar sq.sq_family = AF_QIPCRTR; 9733983bc45SNaman Padhiar sq.sq_node = node; 9743983bc45SNaman Padhiar sq.sq_port = port; 9753983bc45SNaman Padhiar 9763983bc45SNaman Padhiar ret = kernel_connect(qmi_dms->sock, (struct sockaddr *)&sq, 9773983bc45SNaman Padhiar sizeof(sq), 0); 9783983bc45SNaman Padhiar if (ret < 0) { 9793983bc45SNaman Padhiar icnss_pr_err("Failed to connect to QMI DMS remote service Node: %d Port: %d\n", 9803983bc45SNaman Padhiar node, port); 9813983bc45SNaman Padhiar goto out; 9823983bc45SNaman Padhiar } 9833983bc45SNaman Padhiar 9843983bc45SNaman Padhiar set_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state); 9853983bc45SNaman Padhiar icnss_pr_info("QMI DMS service connected, state: 0x%lx\n", 9863983bc45SNaman Padhiar priv->state); 9873983bc45SNaman Padhiar out: 9883983bc45SNaman Padhiar return ret; 9893983bc45SNaman Padhiar } 9903983bc45SNaman Padhiar 9913983bc45SNaman Padhiar static int dms_new_server(struct qmi_handle *qmi_dms, 9923983bc45SNaman Padhiar struct qmi_service *service) 9933983bc45SNaman Padhiar { 9943983bc45SNaman Padhiar struct icnss_priv *priv = 9953983bc45SNaman Padhiar container_of(qmi_dms, struct icnss_priv, qmi_dms); 9963983bc45SNaman Padhiar 9973983bc45SNaman Padhiar if (!service) 9983983bc45SNaman Padhiar return -EINVAL; 9993983bc45SNaman Padhiar 10003983bc45SNaman Padhiar return icnss_dms_connect_to_server(priv, service->node, 10013983bc45SNaman Padhiar service->port); 10023983bc45SNaman Padhiar } 10033983bc45SNaman Padhiar 10043983bc45SNaman Padhiar static void dms_del_server(struct qmi_handle *qmi_dms, 10053983bc45SNaman Padhiar struct qmi_service *service) 10063983bc45SNaman Padhiar { 10073983bc45SNaman Padhiar struct icnss_priv *priv = 10083983bc45SNaman Padhiar container_of(qmi_dms, struct icnss_priv, qmi_dms); 10093983bc45SNaman Padhiar 10103983bc45SNaman Padhiar clear_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state); 10113983bc45SNaman Padhiar icnss_pr_info("QMI DMS service disconnected, state: 0x%lx\n", 10123983bc45SNaman Padhiar priv->state); 10133983bc45SNaman Padhiar } 10143983bc45SNaman Padhiar 10153983bc45SNaman Padhiar static struct qmi_ops qmi_dms_ops = { 10163983bc45SNaman Padhiar .new_server = dms_new_server, 10173983bc45SNaman Padhiar .del_server = dms_del_server, 10183983bc45SNaman Padhiar }; 10193983bc45SNaman Padhiar 10203983bc45SNaman Padhiar int icnss_dms_init(struct icnss_priv *priv) 10213983bc45SNaman Padhiar { 10223983bc45SNaman Padhiar int ret = 0; 10233983bc45SNaman Padhiar 10243983bc45SNaman Padhiar ret = qmi_handle_init(&priv->qmi_dms, DMS_QMI_MAX_MSG_LEN, 10253983bc45SNaman Padhiar &qmi_dms_ops, NULL); 10263983bc45SNaman Padhiar if (ret < 0) { 10273983bc45SNaman Padhiar icnss_pr_err("Failed to initialize DMS handle, err: %d\n", ret); 10283983bc45SNaman Padhiar goto out; 10293983bc45SNaman Padhiar } 10303983bc45SNaman Padhiar 10313983bc45SNaman Padhiar ret = qmi_add_lookup(&priv->qmi_dms, DMS_SERVICE_ID_V01, 10323983bc45SNaman Padhiar DMS_SERVICE_VERS_V01, 0); 10333983bc45SNaman Padhiar if (ret < 0) 10343983bc45SNaman Padhiar icnss_pr_err("Failed to add DMS lookup, err: %d\n", ret); 10353983bc45SNaman Padhiar out: 10363983bc45SNaman Padhiar return ret; 10373983bc45SNaman Padhiar } 10383983bc45SNaman Padhiar 10393983bc45SNaman Padhiar void icnss_dms_deinit(struct icnss_priv *priv) 10403983bc45SNaman Padhiar { 10413983bc45SNaman Padhiar qmi_handle_release(&priv->qmi_dms); 10423983bc45SNaman Padhiar } 10433983bc45SNaman Padhiar 10443983bc45SNaman Padhiar static int icnss_get_bdf_file_name(struct icnss_priv *priv, 10453983bc45SNaman Padhiar u32 bdf_type, char *filename, 10463983bc45SNaman Padhiar u32 filename_len) 10473983bc45SNaman Padhiar { 10483983bc45SNaman Padhiar char filename_tmp[ICNSS_MAX_FILE_NAME]; 10493983bc45SNaman Padhiar char foundry_specific_filename[ICNSS_MAX_FILE_NAME]; 10503983bc45SNaman Padhiar int ret = 0; 10513983bc45SNaman Padhiar 10523983bc45SNaman Padhiar switch (bdf_type) { 10533983bc45SNaman Padhiar case ICNSS_BDF_ELF: 10543983bc45SNaman Padhiar if (priv->board_id == 0xFF) 10553983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, ELF_BDF_FILE_NAME); 10563983bc45SNaman Padhiar else if (priv->board_id < 0xFF) 10573983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, 10583983bc45SNaman Padhiar ELF_BDF_FILE_NAME_PREFIX "%02x", 10593983bc45SNaman Padhiar priv->board_id); 10603983bc45SNaman Padhiar else 10613983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, 10623983bc45SNaman Padhiar BDF_FILE_NAME_PREFIX "%02x.e%02x", 10633983bc45SNaman Padhiar priv->board_id >> 8 & 0xFF, 10643983bc45SNaman Padhiar priv->board_id & 0xFF); 10653983bc45SNaman Padhiar break; 10663983bc45SNaman Padhiar case ICNSS_BDF_BIN: 10673983bc45SNaman Padhiar if (priv->board_id == 0xFF) 10683983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, BIN_BDF_FILE_NAME); 10693983bc45SNaman Padhiar else if (priv->board_id >= WLAN_BOARD_ID_INDEX) 10703983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, 10713983bc45SNaman Padhiar BIN_BDF_FILE_NAME_PREFIX "%03x", 10723983bc45SNaman Padhiar priv->board_id); 10733983bc45SNaman Padhiar else 10743983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, 10753983bc45SNaman Padhiar BIN_BDF_FILE_NAME_PREFIX "b%02x", 10763983bc45SNaman Padhiar priv->board_id); 10773983bc45SNaman Padhiar if (priv->foundry_name) { 10783983bc45SNaman Padhiar strlcpy(foundry_specific_filename, filename_tmp, ICNSS_MAX_FILE_NAME); 10793983bc45SNaman Padhiar memmove(foundry_specific_filename + BDWLAN_SIZE + 1, 10803983bc45SNaman Padhiar foundry_specific_filename + BDWLAN_SIZE, 10813983bc45SNaman Padhiar BDWLAN_SIZE - 1); 10823983bc45SNaman Padhiar foundry_specific_filename[BDWLAN_SIZE] = priv->foundry_name; 10833983bc45SNaman Padhiar foundry_specific_filename[ICNSS_MAX_FILE_NAME - 1] = '\0'; 10843983bc45SNaman Padhiar strlcpy(filename_tmp, foundry_specific_filename, ICNSS_MAX_FILE_NAME); 10853983bc45SNaman Padhiar } 10863983bc45SNaman Padhiar break; 10873983bc45SNaman Padhiar case ICNSS_BDF_REGDB: 10883983bc45SNaman Padhiar snprintf(filename_tmp, filename_len, REGDB_FILE_NAME); 10893983bc45SNaman Padhiar break; 10903983bc45SNaman Padhiar default: 10913983bc45SNaman Padhiar icnss_pr_err("Invalid BDF type: %d\n", 10923983bc45SNaman Padhiar priv->ctrl_params.bdf_type); 10933983bc45SNaman Padhiar ret = -EINVAL; 10943983bc45SNaman Padhiar break; 10953983bc45SNaman Padhiar } 10963983bc45SNaman Padhiar 109704d2478bSNaman Padhiar if (!ret) 10983983bc45SNaman Padhiar icnss_add_fw_prefix_name(priv, filename, filename_tmp); 10993983bc45SNaman Padhiar 11003983bc45SNaman Padhiar return ret; 11013983bc45SNaman Padhiar } 11023983bc45SNaman Padhiar 11033983bc45SNaman Padhiar static char *icnss_bdf_type_to_str(enum icnss_bdf_type bdf_type) 11043983bc45SNaman Padhiar { 11053983bc45SNaman Padhiar switch (bdf_type) { 11063983bc45SNaman Padhiar case ICNSS_BDF_BIN: 11073983bc45SNaman Padhiar return "BDF"; 11083983bc45SNaman Padhiar case ICNSS_BDF_ELF: 11093983bc45SNaman Padhiar return "BDF"; 11103983bc45SNaman Padhiar case ICNSS_BDF_REGDB: 11113983bc45SNaman Padhiar return "REGDB"; 11123983bc45SNaman Padhiar default: 11133983bc45SNaman Padhiar return "UNKNOWN"; 11143983bc45SNaman Padhiar } 11153983bc45SNaman Padhiar }; 11163983bc45SNaman Padhiar 11173983bc45SNaman Padhiar int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type) 11183983bc45SNaman Padhiar { 11193983bc45SNaman Padhiar struct wlfw_bdf_download_req_msg_v01 *req; 11203983bc45SNaman Padhiar struct wlfw_bdf_download_resp_msg_v01 *resp; 11213983bc45SNaman Padhiar struct qmi_txn txn; 11223983bc45SNaman Padhiar char filename[ICNSS_MAX_FILE_NAME]; 11233983bc45SNaman Padhiar const struct firmware *fw_entry = NULL; 11243983bc45SNaman Padhiar const u8 *temp; 11253983bc45SNaman Padhiar unsigned int remaining; 11263983bc45SNaman Padhiar int ret = 0; 11273983bc45SNaman Padhiar 11283983bc45SNaman Padhiar icnss_pr_dbg("Sending %s download message, state: 0x%lx, type: %d\n", 11293983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), priv->state, bdf_type); 11303983bc45SNaman Padhiar 11313983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 11323983bc45SNaman Padhiar if (!req) 11333983bc45SNaman Padhiar return -ENOMEM; 11343983bc45SNaman Padhiar 11353983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 11363983bc45SNaman Padhiar if (!resp) { 11373983bc45SNaman Padhiar kfree(req); 11383983bc45SNaman Padhiar return -ENOMEM; 11393983bc45SNaman Padhiar } 11403983bc45SNaman Padhiar 11413983bc45SNaman Padhiar ret = icnss_get_bdf_file_name(priv, bdf_type, 11423983bc45SNaman Padhiar filename, sizeof(filename)); 114304d2478bSNaman Padhiar if (ret) 11443983bc45SNaman Padhiar goto err_req_fw; 11453983bc45SNaman Padhiar 1146328d2fa0SSandeep Singh ret = firmware_request_nowarn(&fw_entry, filename, &priv->pdev->dev); 11473983bc45SNaman Padhiar if (ret) { 11483983bc45SNaman Padhiar icnss_pr_err("Failed to load %s: %s ret:%d\n", 11493983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), filename, ret); 11503983bc45SNaman Padhiar goto err_req_fw; 11513983bc45SNaman Padhiar } 11523983bc45SNaman Padhiar 11533983bc45SNaman Padhiar temp = fw_entry->data; 11543983bc45SNaman Padhiar remaining = fw_entry->size; 11553983bc45SNaman Padhiar 11563983bc45SNaman Padhiar icnss_pr_dbg("Downloading %s: %s, size: %u\n", 11573983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), filename, remaining); 11583983bc45SNaman Padhiar 11593983bc45SNaman Padhiar while (remaining) { 11603983bc45SNaman Padhiar req->valid = 1; 11613983bc45SNaman Padhiar req->file_id_valid = 1; 11623983bc45SNaman Padhiar req->file_id = priv->board_id; 11633983bc45SNaman Padhiar req->total_size_valid = 1; 11643983bc45SNaman Padhiar req->total_size = fw_entry->size; 11653983bc45SNaman Padhiar req->seg_id_valid = 1; 11663983bc45SNaman Padhiar req->data_valid = 1; 11673983bc45SNaman Padhiar req->end_valid = 1; 11683983bc45SNaman Padhiar req->bdf_type_valid = 1; 11693983bc45SNaman Padhiar req->bdf_type = bdf_type; 11703983bc45SNaman Padhiar 11713983bc45SNaman Padhiar if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 11723983bc45SNaman Padhiar req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 11733983bc45SNaman Padhiar } else { 11743983bc45SNaman Padhiar req->data_len = remaining; 11753983bc45SNaman Padhiar req->end = 1; 11763983bc45SNaman Padhiar } 11773983bc45SNaman Padhiar 11783983bc45SNaman Padhiar memcpy(req->data, temp, req->data_len); 11793983bc45SNaman Padhiar 11803983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 11813983bc45SNaman Padhiar wlfw_bdf_download_resp_msg_v01_ei, resp); 11823983bc45SNaman Padhiar if (ret < 0) { 11833983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for %s download request, err: %d\n", 11843983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), ret); 11853983bc45SNaman Padhiar goto err_send; 11863983bc45SNaman Padhiar } 11873983bc45SNaman Padhiar 11883983bc45SNaman Padhiar ret = qmi_send_request 11893983bc45SNaman Padhiar (&priv->qmi, NULL, &txn, 11903983bc45SNaman Padhiar QMI_WLFW_BDF_DOWNLOAD_REQ_V01, 11913983bc45SNaman Padhiar WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 11923983bc45SNaman Padhiar wlfw_bdf_download_req_msg_v01_ei, req); 11933983bc45SNaman Padhiar if (ret < 0) { 11943983bc45SNaman Padhiar qmi_txn_cancel(&txn); 11953983bc45SNaman Padhiar icnss_pr_err("Failed to send respond %s download request, err: %d\n", 11963983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), ret); 11973983bc45SNaman Padhiar goto err_send; 11983983bc45SNaman Padhiar } 11993983bc45SNaman Padhiar 12003983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 12013983bc45SNaman Padhiar if (ret < 0) { 12023983bc45SNaman Padhiar icnss_pr_err("Failed to wait for response of %s download request, err: %d\n", 12033983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), ret); 12043983bc45SNaman Padhiar goto err_send; 12053983bc45SNaman Padhiar } 12063983bc45SNaman Padhiar 12073983bc45SNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 12083983bc45SNaman Padhiar icnss_pr_err("%s download request failed, result: %d, err: %d\n", 12093983bc45SNaman Padhiar icnss_bdf_type_to_str(bdf_type), resp->resp.result, 12103983bc45SNaman Padhiar resp->resp.error); 12113983bc45SNaman Padhiar ret = -resp->resp.result; 12123983bc45SNaman Padhiar goto err_send; 12133983bc45SNaman Padhiar } 12143983bc45SNaman Padhiar 12153983bc45SNaman Padhiar remaining -= req->data_len; 12163983bc45SNaman Padhiar temp += req->data_len; 12173983bc45SNaman Padhiar req->seg_id++; 12183983bc45SNaman Padhiar } 12193983bc45SNaman Padhiar 12203983bc45SNaman Padhiar release_firmware(fw_entry); 12213983bc45SNaman Padhiar 12223983bc45SNaman Padhiar kfree(req); 12233983bc45SNaman Padhiar kfree(resp); 12243983bc45SNaman Padhiar return 0; 12253983bc45SNaman Padhiar 12263983bc45SNaman Padhiar err_send: 12273983bc45SNaman Padhiar release_firmware(fw_entry); 12283983bc45SNaman Padhiar err_req_fw: 12293983bc45SNaman Padhiar if (bdf_type != ICNSS_BDF_REGDB) 12303983bc45SNaman Padhiar ICNSS_QMI_ASSERT(); 12313983bc45SNaman Padhiar kfree(req); 12323983bc45SNaman Padhiar kfree(resp); 12333983bc45SNaman Padhiar return ret; 12343983bc45SNaman Padhiar } 12353983bc45SNaman Padhiar 12363983bc45SNaman Padhiar int icnss_wlfw_qdss_data_send_sync(struct icnss_priv *priv, char *file_name, 12373983bc45SNaman Padhiar u32 total_size) 12383983bc45SNaman Padhiar { 12393983bc45SNaman Padhiar int ret = 0; 12403983bc45SNaman Padhiar struct wlfw_qdss_trace_data_req_msg_v01 *req; 12413983bc45SNaman Padhiar struct wlfw_qdss_trace_data_resp_msg_v01 *resp; 12423983bc45SNaman Padhiar unsigned char *p_qdss_trace_data_temp, *p_qdss_trace_data = NULL; 12433983bc45SNaman Padhiar unsigned int remaining; 12443983bc45SNaman Padhiar struct qmi_txn txn; 12453983bc45SNaman Padhiar 12463983bc45SNaman Padhiar icnss_pr_dbg("%s", __func__); 12473983bc45SNaman Padhiar 12483983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 12493983bc45SNaman Padhiar if (!req) 12503983bc45SNaman Padhiar return -ENOMEM; 12513983bc45SNaman Padhiar 12523983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 12533983bc45SNaman Padhiar if (!resp) { 12543983bc45SNaman Padhiar kfree(req); 12553983bc45SNaman Padhiar return -ENOMEM; 12563983bc45SNaman Padhiar } 12573983bc45SNaman Padhiar 12583983bc45SNaman Padhiar p_qdss_trace_data = kzalloc(total_size, GFP_KERNEL); 12593983bc45SNaman Padhiar if (!p_qdss_trace_data) { 12603983bc45SNaman Padhiar ret = ENOMEM; 12613983bc45SNaman Padhiar goto end; 12623983bc45SNaman Padhiar } 12633983bc45SNaman Padhiar 12643983bc45SNaman Padhiar remaining = total_size; 12653983bc45SNaman Padhiar p_qdss_trace_data_temp = p_qdss_trace_data; 12663983bc45SNaman Padhiar while (remaining && resp->end == 0) { 12673983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 12683983bc45SNaman Padhiar wlfw_qdss_trace_data_resp_msg_v01_ei, resp); 12693983bc45SNaman Padhiar 12703983bc45SNaman Padhiar if (ret < 0) { 12713983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for QDSS trace resp %d\n", 12723983bc45SNaman Padhiar ret); 12733983bc45SNaman Padhiar goto fail; 12743983bc45SNaman Padhiar } 12753983bc45SNaman Padhiar 12763983bc45SNaman Padhiar ret = qmi_send_request 12773983bc45SNaman Padhiar (&priv->qmi, NULL, &txn, 12783983bc45SNaman Padhiar QMI_WLFW_QDSS_TRACE_DATA_REQ_V01, 12793983bc45SNaman Padhiar WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN, 12803983bc45SNaman Padhiar wlfw_qdss_trace_data_req_msg_v01_ei, req); 12813983bc45SNaman Padhiar 12823983bc45SNaman Padhiar if (ret < 0) { 12833983bc45SNaman Padhiar qmi_txn_cancel(&txn); 12843983bc45SNaman Padhiar icnss_pr_err("Fail to send QDSS trace data req %d\n", 12853983bc45SNaman Padhiar ret); 12863983bc45SNaman Padhiar goto fail; 12873983bc45SNaman Padhiar } 12883983bc45SNaman Padhiar 12893983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 12903983bc45SNaman Padhiar 12913983bc45SNaman Padhiar if (ret < 0) { 12923983bc45SNaman Padhiar icnss_pr_err("QDSS trace resp wait failed with rc %d\n", 12933983bc45SNaman Padhiar ret); 12943983bc45SNaman Padhiar goto fail; 12953983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 12963983bc45SNaman Padhiar icnss_pr_err("QMI QDSS trace request rejected, result:%d error:%d\n", 12973983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 12983983bc45SNaman Padhiar ret = -resp->resp.result; 12993983bc45SNaman Padhiar goto fail; 13003983bc45SNaman Padhiar } else { 13013983bc45SNaman Padhiar ret = 0; 13023983bc45SNaman Padhiar } 13033983bc45SNaman Padhiar 13043983bc45SNaman Padhiar icnss_pr_dbg("%s: response total size %d data len %d", 13053983bc45SNaman Padhiar __func__, resp->total_size, resp->data_len); 13063983bc45SNaman Padhiar 13073983bc45SNaman Padhiar if ((resp->total_size_valid == 1 && 13083983bc45SNaman Padhiar resp->total_size == total_size) && 13093983bc45SNaman Padhiar (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && 13103983bc45SNaman Padhiar (resp->data_valid == 1 && 1311ef9321c2SAlan Chen resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && 1312ef9321c2SAlan Chen resp->data_len <= remaining) { 13133983bc45SNaman Padhiar memcpy(p_qdss_trace_data_temp, 13143983bc45SNaman Padhiar resp->data, resp->data_len); 13153983bc45SNaman Padhiar } else { 13163983bc45SNaman Padhiar icnss_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", 13173983bc45SNaman Padhiar __func__, 13183983bc45SNaman Padhiar total_size, req->seg_id, 13193983bc45SNaman Padhiar resp->total_size_valid, 13203983bc45SNaman Padhiar resp->total_size, 13213983bc45SNaman Padhiar resp->seg_id_valid, 13223983bc45SNaman Padhiar resp->seg_id, 13233983bc45SNaman Padhiar resp->data_valid, 13243983bc45SNaman Padhiar resp->data_len); 13253983bc45SNaman Padhiar ret = -EINVAL; 13263983bc45SNaman Padhiar goto fail; 13273983bc45SNaman Padhiar } 13283983bc45SNaman Padhiar 13293983bc45SNaman Padhiar remaining -= resp->data_len; 13303983bc45SNaman Padhiar p_qdss_trace_data_temp += resp->data_len; 13313983bc45SNaman Padhiar req->seg_id++; 13323983bc45SNaman Padhiar } 13333983bc45SNaman Padhiar 13343983bc45SNaman Padhiar if (remaining == 0 && (resp->end_valid && resp->end)) { 13353983bc45SNaman Padhiar ret = icnss_genl_send_msg(p_qdss_trace_data, 13363983bc45SNaman Padhiar ICNSS_GENL_MSG_TYPE_QDSS, file_name, 13373983bc45SNaman Padhiar total_size); 13383983bc45SNaman Padhiar if (ret < 0) { 13393983bc45SNaman Padhiar icnss_pr_err("Fail to save QDSS trace data: %d\n", 13403983bc45SNaman Padhiar ret); 13413983bc45SNaman Padhiar ret = -EINVAL; 13423983bc45SNaman Padhiar } 13433983bc45SNaman Padhiar } else { 13443983bc45SNaman Padhiar icnss_pr_err("%s: QDSS trace file corrupted: remaining %u, end_valid %u, end %u", 13453983bc45SNaman Padhiar __func__, 13463983bc45SNaman Padhiar remaining, resp->end_valid, resp->end); 13473983bc45SNaman Padhiar ret = -EINVAL; 13483983bc45SNaman Padhiar } 13493983bc45SNaman Padhiar 13503983bc45SNaman Padhiar fail: 13513983bc45SNaman Padhiar kfree(p_qdss_trace_data); 13523983bc45SNaman Padhiar 13533983bc45SNaman Padhiar end: 13543983bc45SNaman Padhiar kfree(req); 13553983bc45SNaman Padhiar kfree(resp); 13563983bc45SNaman Padhiar return ret; 13573983bc45SNaman Padhiar } 13583983bc45SNaman Padhiar 13593983bc45SNaman Padhiar int icnss_wlfw_qdss_dnld_send_sync(struct icnss_priv *priv) 13603983bc45SNaman Padhiar { 13613983bc45SNaman Padhiar struct wlfw_qdss_trace_config_download_req_msg_v01 *req; 13623983bc45SNaman Padhiar struct wlfw_qdss_trace_config_download_resp_msg_v01 *resp; 13633983bc45SNaman Padhiar struct qmi_txn txn; 13643983bc45SNaman Padhiar char filename[ICNSS_MAX_FILE_NAME]; 13653983bc45SNaman Padhiar const struct firmware *fw_entry = NULL; 13663983bc45SNaman Padhiar const u8 *temp; 13673983bc45SNaman Padhiar unsigned int remaining; 13683983bc45SNaman Padhiar int ret = 0; 13693983bc45SNaman Padhiar 13703983bc45SNaman Padhiar icnss_pr_dbg("Sending QDSS config download message, state: 0x%lx\n", 13713983bc45SNaman Padhiar priv->state); 13723983bc45SNaman Padhiar 13733983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 13743983bc45SNaman Padhiar if (!req) 13753983bc45SNaman Padhiar return -ENOMEM; 13763983bc45SNaman Padhiar 13773983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 13783983bc45SNaman Padhiar if (!resp) { 13793983bc45SNaman Padhiar kfree(req); 13803983bc45SNaman Padhiar return -ENOMEM; 13813983bc45SNaman Padhiar } 13823983bc45SNaman Padhiar 13833983bc45SNaman Padhiar icnss_add_fw_prefix_name(priv, filename, QDSS_TRACE_CONFIG_FILE); 1384328d2fa0SSandeep Singh ret = firmware_request_nowarn(&fw_entry, filename, 13853983bc45SNaman Padhiar &priv->pdev->dev); 13863983bc45SNaman Padhiar if (ret) { 13873983bc45SNaman Padhiar icnss_pr_err("Failed to load QDSS: %s ret:%d\n", 13883983bc45SNaman Padhiar filename, ret); 13893983bc45SNaman Padhiar goto err_req_fw; 13903983bc45SNaman Padhiar } 13913983bc45SNaman Padhiar 13923983bc45SNaman Padhiar temp = fw_entry->data; 13933983bc45SNaman Padhiar remaining = fw_entry->size; 13943983bc45SNaman Padhiar 13953983bc45SNaman Padhiar icnss_pr_dbg("Downloading QDSS: %s, size: %u\n", 13963983bc45SNaman Padhiar filename, remaining); 13973983bc45SNaman Padhiar 13983983bc45SNaman Padhiar while (remaining) { 13993983bc45SNaman Padhiar req->total_size_valid = 1; 14003983bc45SNaman Padhiar req->total_size = remaining; 14013983bc45SNaman Padhiar req->seg_id_valid = 1; 14023983bc45SNaman Padhiar req->data_valid = 1; 14033983bc45SNaman Padhiar req->end_valid = 1; 14043983bc45SNaman Padhiar 14053983bc45SNaman Padhiar if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { 14063983bc45SNaman Padhiar req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; 14073983bc45SNaman Padhiar } else { 14083983bc45SNaman Padhiar req->data_len = remaining; 14093983bc45SNaman Padhiar req->end = 1; 14103983bc45SNaman Padhiar } 14113983bc45SNaman Padhiar 14123983bc45SNaman Padhiar memcpy(req->data, temp, req->data_len); 14133983bc45SNaman Padhiar 14143983bc45SNaman Padhiar ret = qmi_txn_init 14153983bc45SNaman Padhiar (&priv->qmi, &txn, 14163983bc45SNaman Padhiar wlfw_qdss_trace_config_download_resp_msg_v01_ei, 14173983bc45SNaman Padhiar resp); 14183983bc45SNaman Padhiar if (ret < 0) { 14193983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for QDSS download request, err: %d\n", 14203983bc45SNaman Padhiar ret); 14213983bc45SNaman Padhiar goto err_send; 14223983bc45SNaman Padhiar } 14233983bc45SNaman Padhiar 14243983bc45SNaman Padhiar ret = qmi_send_request 14253983bc45SNaman Padhiar (&priv->qmi, NULL, &txn, 14263983bc45SNaman Padhiar QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01, 14273983bc45SNaman Padhiar WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 14283983bc45SNaman Padhiar wlfw_qdss_trace_config_download_req_msg_v01_ei, req); 14293983bc45SNaman Padhiar if (ret < 0) { 14303983bc45SNaman Padhiar qmi_txn_cancel(&txn); 14313983bc45SNaman Padhiar icnss_pr_err("Failed to send respond QDSS download request, err: %d\n", 14323983bc45SNaman Padhiar ret); 14333983bc45SNaman Padhiar goto err_send; 14343983bc45SNaman Padhiar } 14353983bc45SNaman Padhiar 14363983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 14373983bc45SNaman Padhiar if (ret < 0) { 14383983bc45SNaman Padhiar icnss_pr_err("Failed to wait for response of QDSS download request, err: %d\n", 14393983bc45SNaman Padhiar ret); 14403983bc45SNaman Padhiar goto err_send; 14413983bc45SNaman Padhiar } 14423983bc45SNaman Padhiar 14433983bc45SNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 14443983bc45SNaman Padhiar icnss_pr_err("QDSS download request failed, result: %d, err: %d\n", 14453983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 14463983bc45SNaman Padhiar ret = -resp->resp.result; 14473983bc45SNaman Padhiar goto err_send; 14483983bc45SNaman Padhiar } 14493983bc45SNaman Padhiar 14503983bc45SNaman Padhiar remaining -= req->data_len; 14513983bc45SNaman Padhiar temp += req->data_len; 14523983bc45SNaman Padhiar req->seg_id++; 14533983bc45SNaman Padhiar } 14543983bc45SNaman Padhiar 14553983bc45SNaman Padhiar release_firmware(fw_entry); 14563983bc45SNaman Padhiar kfree(req); 14573983bc45SNaman Padhiar kfree(resp); 14583983bc45SNaman Padhiar return 0; 14593983bc45SNaman Padhiar 14603983bc45SNaman Padhiar err_send: 14613983bc45SNaman Padhiar release_firmware(fw_entry); 14623983bc45SNaman Padhiar err_req_fw: 14633983bc45SNaman Padhiar 14643983bc45SNaman Padhiar kfree(req); 14653983bc45SNaman Padhiar kfree(resp); 14663983bc45SNaman Padhiar return ret; 14673983bc45SNaman Padhiar } 14683983bc45SNaman Padhiar 14693983bc45SNaman Padhiar int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv, 14703983bc45SNaman Padhiar enum wlfw_driver_mode_enum_v01 mode) 14713983bc45SNaman Padhiar { 14723983bc45SNaman Padhiar int ret; 14733983bc45SNaman Padhiar struct wlfw_wlan_mode_req_msg_v01 *req; 14743983bc45SNaman Padhiar struct wlfw_wlan_mode_resp_msg_v01 *resp; 14753983bc45SNaman Padhiar struct qmi_txn txn; 14763983bc45SNaman Padhiar 14773983bc45SNaman Padhiar if (!priv) 14783983bc45SNaman Padhiar return -ENODEV; 14793983bc45SNaman Padhiar 14803983bc45SNaman Padhiar /* During recovery do not send mode request for WLAN OFF as 14813983bc45SNaman Padhiar * FW not able to process it. 14823983bc45SNaman Padhiar */ 14833983bc45SNaman Padhiar if (test_bit(ICNSS_PD_RESTART, &priv->state) && 14843983bc45SNaman Padhiar mode == QMI_WLFW_OFF_V01) 14853983bc45SNaman Padhiar return 0; 14863983bc45SNaman Padhiar 14873983bc45SNaman Padhiar if (!test_bit(ICNSS_MODE_ON, &priv->state) && 14883983bc45SNaman Padhiar mode == QMI_WLFW_OFF_V01) 14893983bc45SNaman Padhiar return 0; 14903983bc45SNaman Padhiar 14913983bc45SNaman Padhiar icnss_pr_dbg("Sending Mode request, state: 0x%lx, mode: %d\n", 14923983bc45SNaman Padhiar priv->state, mode); 14933983bc45SNaman Padhiar 14943983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 14953983bc45SNaman Padhiar if (!req) 14963983bc45SNaman Padhiar return -ENOMEM; 14973983bc45SNaman Padhiar 14983983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 14993983bc45SNaman Padhiar if (!resp) { 15003983bc45SNaman Padhiar kfree(req); 15013983bc45SNaman Padhiar return -ENOMEM; 15023983bc45SNaman Padhiar } 15033983bc45SNaman Padhiar 15043983bc45SNaman Padhiar req->mode = mode; 15053983bc45SNaman Padhiar req->hw_debug_valid = 1; 15063983bc45SNaman Padhiar req->hw_debug = !!test_bit(HW_DEBUG_ENABLE, &priv->ctrl_params.quirks); 15073983bc45SNaman Padhiar 150860f897b6SNaman Padhiar if (priv->wlan_en_delay_ms >= 100) { 150960f897b6SNaman Padhiar icnss_pr_dbg("Setting WLAN_EN delay: %d ms\n", 151060f897b6SNaman Padhiar priv->wlan_en_delay_ms); 151160f897b6SNaman Padhiar req->wlan_en_delay_valid = 1; 151260f897b6SNaman Padhiar req->wlan_en_delay = priv->wlan_en_delay_ms; 151360f897b6SNaman Padhiar } 151460f897b6SNaman Padhiar 15153983bc45SNaman Padhiar priv->stats.mode_req++; 15163983bc45SNaman Padhiar 15173983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 15183983bc45SNaman Padhiar wlfw_wlan_mode_resp_msg_v01_ei, resp); 15193983bc45SNaman Padhiar if (ret < 0) { 15203983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for Mode resp %d\n", ret); 15213983bc45SNaman Padhiar goto out; 15223983bc45SNaman Padhiar } 15233983bc45SNaman Padhiar 15243983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 15253983bc45SNaman Padhiar QMI_WLFW_WLAN_MODE_REQ_V01, 15263983bc45SNaman Padhiar WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN, 15273983bc45SNaman Padhiar wlfw_wlan_mode_req_msg_v01_ei, req); 15283983bc45SNaman Padhiar if (ret < 0) { 15293983bc45SNaman Padhiar qmi_txn_cancel(&txn); 15303983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send Mode req %d\n", ret); 15313983bc45SNaman Padhiar goto out; 15323983bc45SNaman Padhiar } 15333983bc45SNaman Padhiar 15343983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, 15353983bc45SNaman Padhiar priv->ctrl_params.qmi_timeout + 15363983bc45SNaman Padhiar msecs_to_jiffies(priv->wlan_en_delay_ms)); 15373983bc45SNaman Padhiar if (ret < 0) { 15383983bc45SNaman Padhiar icnss_qmi_fatal_err("Mode resp wait failed with ret %d\n", ret); 15393983bc45SNaman Padhiar goto out; 15403983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 15413983bc45SNaman Padhiar icnss_qmi_fatal_err( 15423983bc45SNaman Padhiar "QMI Mode request rejected, result:%d error:%d\n", 15433983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 15443983bc45SNaman Padhiar ret = -resp->resp.result; 15453983bc45SNaman Padhiar goto out; 15463983bc45SNaman Padhiar } 15473983bc45SNaman Padhiar 15483983bc45SNaman Padhiar priv->stats.mode_resp++; 15493983bc45SNaman Padhiar 15503983bc45SNaman Padhiar if (mode == QMI_WLFW_OFF_V01) { 15513983bc45SNaman Padhiar icnss_pr_dbg("Clear mode on 0x%lx, mode: %d\n", 15523983bc45SNaman Padhiar priv->state, mode); 15533983bc45SNaman Padhiar clear_bit(ICNSS_MODE_ON, &priv->state); 15543983bc45SNaman Padhiar } else { 15553983bc45SNaman Padhiar icnss_pr_dbg("Set mode on 0x%lx, mode: %d\n", 15563983bc45SNaman Padhiar priv->state, mode); 15573983bc45SNaman Padhiar set_bit(ICNSS_MODE_ON, &priv->state); 15583983bc45SNaman Padhiar } 15593983bc45SNaman Padhiar 15603983bc45SNaman Padhiar kfree(resp); 15613983bc45SNaman Padhiar kfree(req); 15623983bc45SNaman Padhiar return 0; 15633983bc45SNaman Padhiar 15643983bc45SNaman Padhiar out: 15653983bc45SNaman Padhiar kfree(resp); 15663983bc45SNaman Padhiar kfree(req); 15673983bc45SNaman Padhiar priv->stats.mode_req_err++; 15683983bc45SNaman Padhiar return ret; 15693983bc45SNaman Padhiar } 15703983bc45SNaman Padhiar 15713983bc45SNaman Padhiar static int wlfw_send_qdss_trace_mode_req 15723983bc45SNaman Padhiar (struct icnss_priv *priv, 15733983bc45SNaman Padhiar enum wlfw_qdss_trace_mode_enum_v01 mode, 15743983bc45SNaman Padhiar unsigned long long option) 15753983bc45SNaman Padhiar { 15763983bc45SNaman Padhiar int rc = 0; 15773983bc45SNaman Padhiar int tmp = 0; 15783983bc45SNaman Padhiar struct wlfw_qdss_trace_mode_req_msg_v01 *req; 15793983bc45SNaman Padhiar struct wlfw_qdss_trace_mode_resp_msg_v01 *resp; 15803983bc45SNaman Padhiar struct qmi_txn txn; 15813983bc45SNaman Padhiar 15823983bc45SNaman Padhiar if (!priv) 15833983bc45SNaman Padhiar return -ENODEV; 15843983bc45SNaman Padhiar 15853983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 15863983bc45SNaman Padhiar if (!req) 15873983bc45SNaman Padhiar return -ENOMEM; 15883983bc45SNaman Padhiar 15893983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 15903983bc45SNaman Padhiar if (!resp) { 15913983bc45SNaman Padhiar kfree(req); 15923983bc45SNaman Padhiar return -ENOMEM; 15933983bc45SNaman Padhiar } 15943983bc45SNaman Padhiar 15953983bc45SNaman Padhiar req->mode_valid = 1; 15963983bc45SNaman Padhiar req->mode = mode; 15973983bc45SNaman Padhiar req->option_valid = 1; 15983983bc45SNaman Padhiar req->option = option; 15993983bc45SNaman Padhiar 16003983bc45SNaman Padhiar tmp = priv->hw_trc_override; 16013983bc45SNaman Padhiar 16023983bc45SNaman Padhiar req->hw_trc_disable_override_valid = 1; 16033983bc45SNaman Padhiar req->hw_trc_disable_override = 16043983bc45SNaman Padhiar (tmp > QMI_PARAM_DISABLE_V01 ? QMI_PARAM_DISABLE_V01 : 16053983bc45SNaman Padhiar (tmp < 0 ? QMI_PARAM_INVALID_V01 : tmp)); 16063983bc45SNaman Padhiar 16073983bc45SNaman Padhiar icnss_pr_dbg("%s: mode %u, option %llu, hw_trc_disable_override: %u", 16083983bc45SNaman Padhiar __func__, mode, option, req->hw_trc_disable_override); 16093983bc45SNaman Padhiar 16103983bc45SNaman Padhiar rc = qmi_txn_init(&priv->qmi, &txn, 16113983bc45SNaman Padhiar wlfw_qdss_trace_mode_resp_msg_v01_ei, resp); 16123983bc45SNaman Padhiar if (rc < 0) { 16133983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for QDSS Mode resp %d\n", 16143983bc45SNaman Padhiar rc); 16153983bc45SNaman Padhiar goto out; 16163983bc45SNaman Padhiar } 16173983bc45SNaman Padhiar 16183983bc45SNaman Padhiar rc = qmi_send_request(&priv->qmi, NULL, &txn, 16193983bc45SNaman Padhiar QMI_WLFW_QDSS_TRACE_MODE_REQ_V01, 16203983bc45SNaman Padhiar WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN, 16213983bc45SNaman Padhiar wlfw_qdss_trace_mode_req_msg_v01_ei, req); 16223983bc45SNaman Padhiar if (rc < 0) { 16233983bc45SNaman Padhiar qmi_txn_cancel(&txn); 16243983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send QDSS Mode req %d\n", rc); 16253983bc45SNaman Padhiar goto out; 16263983bc45SNaman Padhiar } 16273983bc45SNaman Padhiar 16283983bc45SNaman Padhiar rc = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 16293983bc45SNaman Padhiar if (rc < 0) { 16303983bc45SNaman Padhiar icnss_qmi_fatal_err("QDSS Mode resp wait failed with rc %d\n", 16313983bc45SNaman Padhiar rc); 16323983bc45SNaman Padhiar goto out; 16333983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 16343983bc45SNaman Padhiar icnss_qmi_fatal_err( 16353983bc45SNaman Padhiar "QMI QDSS Mode request rejected, result:%d error:%d\n", 16363983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 16373983bc45SNaman Padhiar rc = -resp->resp.result; 16383983bc45SNaman Padhiar goto out; 16393983bc45SNaman Padhiar } 16403983bc45SNaman Padhiar 16413983bc45SNaman Padhiar out: 16423983bc45SNaman Padhiar kfree(resp); 16433983bc45SNaman Padhiar kfree(req); 16443983bc45SNaman Padhiar return rc; 16453983bc45SNaman Padhiar } 16463983bc45SNaman Padhiar 16473983bc45SNaman Padhiar int wlfw_qdss_trace_start(struct icnss_priv *priv) 16483983bc45SNaman Padhiar { 16493983bc45SNaman Padhiar return wlfw_send_qdss_trace_mode_req(priv, 16503983bc45SNaman Padhiar QMI_WLFW_QDSS_TRACE_ON_V01, 0); 16513983bc45SNaman Padhiar } 16523983bc45SNaman Padhiar 16533983bc45SNaman Padhiar int wlfw_qdss_trace_stop(struct icnss_priv *priv, unsigned long long option) 16543983bc45SNaman Padhiar { 16553983bc45SNaman Padhiar return wlfw_send_qdss_trace_mode_req(priv, QMI_WLFW_QDSS_TRACE_OFF_V01, 16563983bc45SNaman Padhiar option); 16573983bc45SNaman Padhiar } 16583983bc45SNaman Padhiar 16593983bc45SNaman Padhiar int wlfw_wlan_cfg_send_sync_msg(struct icnss_priv *priv, 16603983bc45SNaman Padhiar struct wlfw_wlan_cfg_req_msg_v01 *data) 16613983bc45SNaman Padhiar { 16623983bc45SNaman Padhiar int ret; 16633983bc45SNaman Padhiar struct wlfw_wlan_cfg_req_msg_v01 *req; 16643983bc45SNaman Padhiar struct wlfw_wlan_cfg_resp_msg_v01 *resp; 16653983bc45SNaman Padhiar struct qmi_txn txn; 16663983bc45SNaman Padhiar 16673983bc45SNaman Padhiar if (!priv) 16683983bc45SNaman Padhiar return -ENODEV; 16693983bc45SNaman Padhiar 16703983bc45SNaman Padhiar icnss_pr_dbg("Sending config request, state: 0x%lx\n", priv->state); 16713983bc45SNaman Padhiar 16723983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 16733983bc45SNaman Padhiar if (!req) 16743983bc45SNaman Padhiar return -ENOMEM; 16753983bc45SNaman Padhiar 16763983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 16773983bc45SNaman Padhiar if (!resp) { 16783983bc45SNaman Padhiar kfree(req); 16793983bc45SNaman Padhiar return -ENOMEM; 16803983bc45SNaman Padhiar } 16813983bc45SNaman Padhiar 16823983bc45SNaman Padhiar memcpy(req, data, sizeof(*req)); 16833983bc45SNaman Padhiar 16843983bc45SNaman Padhiar priv->stats.cfg_req++; 16853983bc45SNaman Padhiar 16863983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 16873983bc45SNaman Padhiar wlfw_wlan_cfg_resp_msg_v01_ei, resp); 16883983bc45SNaman Padhiar if (ret < 0) { 16893983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for Config resp %d\n", 16903983bc45SNaman Padhiar ret); 16913983bc45SNaman Padhiar goto out; 16923983bc45SNaman Padhiar } 16933983bc45SNaman Padhiar 16943983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 16953983bc45SNaman Padhiar QMI_WLFW_WLAN_CFG_REQ_V01, 16963983bc45SNaman Padhiar WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN, 16973983bc45SNaman Padhiar wlfw_wlan_cfg_req_msg_v01_ei, req); 16983983bc45SNaman Padhiar if (ret < 0) { 16993983bc45SNaman Padhiar qmi_txn_cancel(&txn); 17003983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send Config req %d\n", ret); 17013983bc45SNaman Padhiar goto out; 17023983bc45SNaman Padhiar } 17033983bc45SNaman Padhiar 17043983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 17053983bc45SNaman Padhiar if (ret < 0) { 17063983bc45SNaman Padhiar icnss_qmi_fatal_err("Config resp wait failed with ret %d\n", 17073983bc45SNaman Padhiar ret); 17083983bc45SNaman Padhiar goto out; 17093983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 17103983bc45SNaman Padhiar icnss_qmi_fatal_err( 17113983bc45SNaman Padhiar "QMI Config request rejected, result:%d error:%d\n", 17123983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 17133983bc45SNaman Padhiar ret = -resp->resp.result; 17143983bc45SNaman Padhiar goto out; 17153983bc45SNaman Padhiar } 17163983bc45SNaman Padhiar 17173983bc45SNaman Padhiar priv->stats.cfg_resp++; 17183983bc45SNaman Padhiar 17193983bc45SNaman Padhiar kfree(resp); 17203983bc45SNaman Padhiar kfree(req); 17213983bc45SNaman Padhiar return 0; 17223983bc45SNaman Padhiar 17233983bc45SNaman Padhiar out: 17243983bc45SNaman Padhiar kfree(resp); 17253983bc45SNaman Padhiar kfree(req); 17263983bc45SNaman Padhiar priv->stats.cfg_req_err++; 17273983bc45SNaman Padhiar return ret; 17283983bc45SNaman Padhiar } 17293983bc45SNaman Padhiar 17303983bc45SNaman Padhiar int wlfw_send_modem_shutdown_msg(struct icnss_priv *priv) 17313983bc45SNaman Padhiar { 17323983bc45SNaman Padhiar int ret; 17333983bc45SNaman Padhiar struct wlfw_shutdown_req_msg_v01 *req; 17343983bc45SNaman Padhiar struct wlfw_shutdown_resp_msg_v01 *resp; 17353983bc45SNaman Padhiar struct qmi_txn txn; 17363983bc45SNaman Padhiar 17373983bc45SNaman Padhiar if (!priv) 17383983bc45SNaman Padhiar return -ENODEV; 17393983bc45SNaman Padhiar 17403983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &priv->state)) 17413983bc45SNaman Padhiar return -EINVAL; 17423983bc45SNaman Padhiar 17433983bc45SNaman Padhiar icnss_pr_dbg("Sending modem shutdown request, state: 0x%lx\n", 17443983bc45SNaman Padhiar priv->state); 17453983bc45SNaman Padhiar 17463983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 17473983bc45SNaman Padhiar if (!req) 17483983bc45SNaman Padhiar return -ENOMEM; 17493983bc45SNaman Padhiar 17503983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 17513983bc45SNaman Padhiar if (!resp) { 17523983bc45SNaman Padhiar kfree(req); 17533983bc45SNaman Padhiar return -ENOMEM; 17543983bc45SNaman Padhiar } 17553983bc45SNaman Padhiar 17563983bc45SNaman Padhiar req->shutdown_valid = 1; 17573983bc45SNaman Padhiar req->shutdown = 1; 17583983bc45SNaman Padhiar 17593983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 17603983bc45SNaman Padhiar wlfw_shutdown_resp_msg_v01_ei, resp); 17613983bc45SNaman Padhiar 17623983bc45SNaman Padhiar if (ret < 0) { 17633983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for shutdown resp %d\n", 17643983bc45SNaman Padhiar ret); 17653983bc45SNaman Padhiar goto out; 17663983bc45SNaman Padhiar } 17673983bc45SNaman Padhiar 17683983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 17693983bc45SNaman Padhiar QMI_WLFW_SHUTDOWN_REQ_V01, 17703983bc45SNaman Padhiar WLFW_SHUTDOWN_REQ_MSG_V01_MAX_MSG_LEN, 17713983bc45SNaman Padhiar wlfw_shutdown_req_msg_v01_ei, req); 17723983bc45SNaman Padhiar if (ret < 0) { 17733983bc45SNaman Padhiar qmi_txn_cancel(&txn); 17743983bc45SNaman Padhiar icnss_pr_err("Fail to send Shutdown req %d\n", ret); 17753983bc45SNaman Padhiar goto out; 17763983bc45SNaman Padhiar } 17773983bc45SNaman Padhiar 17783983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 17793983bc45SNaman Padhiar if (ret < 0) { 17803983bc45SNaman Padhiar icnss_pr_err("Shutdown resp wait failed with ret %d\n", 17813983bc45SNaman Padhiar ret); 17823983bc45SNaman Padhiar goto out; 17833983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 17843983bc45SNaman Padhiar icnss_pr_err("QMI modem shutdown request rejected result:%d error:%d\n", 17853983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 17863983bc45SNaman Padhiar ret = -resp->resp.result; 17873983bc45SNaman Padhiar goto out; 17883983bc45SNaman Padhiar } 17893983bc45SNaman Padhiar 17903983bc45SNaman Padhiar out: 17913983bc45SNaman Padhiar kfree(resp); 17923983bc45SNaman Padhiar kfree(req); 17933983bc45SNaman Padhiar return ret; 17943983bc45SNaman Padhiar } 17953983bc45SNaman Padhiar 17963983bc45SNaman Padhiar int wlfw_ini_send_sync_msg(struct icnss_priv *priv, uint8_t fw_log_mode) 17973983bc45SNaman Padhiar { 17983983bc45SNaman Padhiar int ret; 17993983bc45SNaman Padhiar struct wlfw_ini_req_msg_v01 *req; 18003983bc45SNaman Padhiar struct wlfw_ini_resp_msg_v01 *resp; 18013983bc45SNaman Padhiar struct qmi_txn txn; 18023983bc45SNaman Padhiar 18033983bc45SNaman Padhiar if (!priv) 18043983bc45SNaman Padhiar return -ENODEV; 18053983bc45SNaman Padhiar 18063983bc45SNaman Padhiar icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n", 18073983bc45SNaman Padhiar priv->state, fw_log_mode); 18083983bc45SNaman Padhiar 18093983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 18103983bc45SNaman Padhiar if (!req) 18113983bc45SNaman Padhiar return -ENOMEM; 18123983bc45SNaman Padhiar 18133983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 18143983bc45SNaman Padhiar if (!resp) { 18153983bc45SNaman Padhiar kfree(req); 18163983bc45SNaman Padhiar return -ENOMEM; 18173983bc45SNaman Padhiar } 18183983bc45SNaman Padhiar 18193983bc45SNaman Padhiar req->enablefwlog_valid = 1; 18203983bc45SNaman Padhiar req->enablefwlog = fw_log_mode; 18213983bc45SNaman Padhiar 18223983bc45SNaman Padhiar priv->stats.ini_req++; 18233983bc45SNaman Padhiar 18243983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, wlfw_ini_resp_msg_v01_ei, resp); 18253983bc45SNaman Padhiar if (ret < 0) { 18263983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to init txn for INI resp %d\n", ret); 18273983bc45SNaman Padhiar goto out; 18283983bc45SNaman Padhiar } 18293983bc45SNaman Padhiar 18303983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 18313983bc45SNaman Padhiar QMI_WLFW_INI_REQ_V01, 18323983bc45SNaman Padhiar WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN, 18333983bc45SNaman Padhiar wlfw_ini_req_msg_v01_ei, req); 18343983bc45SNaman Padhiar if (ret < 0) { 18353983bc45SNaman Padhiar qmi_txn_cancel(&txn); 18363983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send INI req %d\n", ret); 18373983bc45SNaman Padhiar goto out; 18383983bc45SNaman Padhiar } 18393983bc45SNaman Padhiar 18403983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 18413983bc45SNaman Padhiar if (ret < 0) { 18423983bc45SNaman Padhiar icnss_qmi_fatal_err("INI resp wait failed with ret %d\n", ret); 18433983bc45SNaman Padhiar goto out; 18443983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 18453983bc45SNaman Padhiar icnss_qmi_fatal_err( 18463983bc45SNaman Padhiar "QMI INI request rejected, result:%d error:%d\n", 18473983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 18483983bc45SNaman Padhiar ret = -resp->resp.result; 18493983bc45SNaman Padhiar goto out; 18503983bc45SNaman Padhiar } 18513983bc45SNaman Padhiar 18523983bc45SNaman Padhiar priv->stats.ini_resp++; 18533983bc45SNaman Padhiar 18543983bc45SNaman Padhiar kfree(resp); 18553983bc45SNaman Padhiar kfree(req); 18563983bc45SNaman Padhiar return 0; 18573983bc45SNaman Padhiar 18583983bc45SNaman Padhiar out: 18593983bc45SNaman Padhiar kfree(resp); 18603983bc45SNaman Padhiar kfree(req); 18613983bc45SNaman Padhiar priv->stats.ini_req_err++; 18623983bc45SNaman Padhiar return ret; 18633983bc45SNaman Padhiar } 18643983bc45SNaman Padhiar 18653983bc45SNaman Padhiar int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv, 18663983bc45SNaman Padhiar uint32_t offset, uint32_t mem_type, 18673983bc45SNaman Padhiar uint32_t data_len, uint8_t *data) 18683983bc45SNaman Padhiar { 18693983bc45SNaman Padhiar int ret; 18703983bc45SNaman Padhiar struct wlfw_athdiag_read_req_msg_v01 *req; 18713983bc45SNaman Padhiar struct wlfw_athdiag_read_resp_msg_v01 *resp; 18723983bc45SNaman Padhiar struct qmi_txn txn; 18733983bc45SNaman Padhiar 18743983bc45SNaman Padhiar if (!priv) 18753983bc45SNaman Padhiar return -ENODEV; 18763983bc45SNaman Padhiar 18773983bc45SNaman Padhiar icnss_pr_dbg("Diag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n", 18783983bc45SNaman Padhiar priv->state, offset, mem_type, data_len); 18793983bc45SNaman Padhiar 18803983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 18813983bc45SNaman Padhiar if (!req) 18823983bc45SNaman Padhiar return -ENOMEM; 18833983bc45SNaman Padhiar 18843983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 18853983bc45SNaman Padhiar if (!resp) { 18863983bc45SNaman Padhiar kfree(req); 18873983bc45SNaman Padhiar return -ENOMEM; 18883983bc45SNaman Padhiar } 18893983bc45SNaman Padhiar 18903983bc45SNaman Padhiar req->offset = offset; 18913983bc45SNaman Padhiar req->mem_type = mem_type; 18923983bc45SNaman Padhiar req->data_len = data_len; 18933983bc45SNaman Padhiar 18943983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 18953983bc45SNaman Padhiar wlfw_athdiag_read_resp_msg_v01_ei, resp); 18963983bc45SNaman Padhiar if (ret < 0) { 18973983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for Athdiag Read resp %d\n", 18983983bc45SNaman Padhiar ret); 18993983bc45SNaman Padhiar goto out; 19003983bc45SNaman Padhiar } 19013983bc45SNaman Padhiar 19023983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 19033983bc45SNaman Padhiar QMI_WLFW_ATHDIAG_READ_REQ_V01, 19043983bc45SNaman Padhiar WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN, 19053983bc45SNaman Padhiar wlfw_athdiag_read_req_msg_v01_ei, req); 19063983bc45SNaman Padhiar if (ret < 0) { 19073983bc45SNaman Padhiar qmi_txn_cancel(&txn); 19083983bc45SNaman Padhiar icnss_pr_err("Fail to send Athdiag Read req %d\n", ret); 19093983bc45SNaman Padhiar goto out; 19103983bc45SNaman Padhiar } 19113983bc45SNaman Padhiar 19123983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 19133983bc45SNaman Padhiar if (ret < 0) { 19143983bc45SNaman Padhiar icnss_pr_err("Athdaig Read resp wait failed with ret %d\n", 19153983bc45SNaman Padhiar ret); 19163983bc45SNaman Padhiar goto out; 19173983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 19183983bc45SNaman Padhiar icnss_pr_err("QMI Athdiag Read request rejected, result:%d error:%d\n", 19193983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 19203983bc45SNaman Padhiar ret = -resp->resp.result; 19213983bc45SNaman Padhiar goto out; 19223983bc45SNaman Padhiar } else { 19233983bc45SNaman Padhiar ret = 0; 19243983bc45SNaman Padhiar } 19253983bc45SNaman Padhiar 19263983bc45SNaman Padhiar if (!resp->data_valid || resp->data_len < data_len) { 19273983bc45SNaman Padhiar icnss_pr_err("Athdiag read data is invalid, data_valid = %u, data_len = %u\n", 19283983bc45SNaman Padhiar resp->data_valid, resp->data_len); 19293983bc45SNaman Padhiar ret = -EINVAL; 19303983bc45SNaman Padhiar goto out; 19313983bc45SNaman Padhiar } 19323983bc45SNaman Padhiar 19333983bc45SNaman Padhiar memcpy(data, resp->data, resp->data_len); 19343983bc45SNaman Padhiar 19353983bc45SNaman Padhiar out: 19363983bc45SNaman Padhiar kfree(resp); 19373983bc45SNaman Padhiar kfree(req); 19383983bc45SNaman Padhiar return ret; 19393983bc45SNaman Padhiar } 19403983bc45SNaman Padhiar 19413983bc45SNaman Padhiar int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv, 19423983bc45SNaman Padhiar uint32_t offset, uint32_t mem_type, 19433983bc45SNaman Padhiar uint32_t data_len, uint8_t *data) 19443983bc45SNaman Padhiar { 19453983bc45SNaman Padhiar int ret; 19463983bc45SNaman Padhiar struct wlfw_athdiag_write_req_msg_v01 *req; 19473983bc45SNaman Padhiar struct wlfw_athdiag_write_resp_msg_v01 *resp; 19483983bc45SNaman Padhiar struct qmi_txn txn; 19493983bc45SNaman Padhiar 19503983bc45SNaman Padhiar if (!priv) 19513983bc45SNaman Padhiar return -ENODEV; 19523983bc45SNaman Padhiar 19533983bc45SNaman Padhiar icnss_pr_dbg("Diag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %pK\n", 19543983bc45SNaman Padhiar priv->state, offset, mem_type, data_len, data); 19553983bc45SNaman Padhiar 19563983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 19573983bc45SNaman Padhiar if (!req) 19583983bc45SNaman Padhiar return -ENOMEM; 19593983bc45SNaman Padhiar 19603983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 19613983bc45SNaman Padhiar if (!resp) { 19623983bc45SNaman Padhiar kfree(req); 19633983bc45SNaman Padhiar return -ENOMEM; 19643983bc45SNaman Padhiar } 19653983bc45SNaman Padhiar 19663983bc45SNaman Padhiar req->offset = offset; 19673983bc45SNaman Padhiar req->mem_type = mem_type; 19683983bc45SNaman Padhiar req->data_len = data_len; 19693983bc45SNaman Padhiar memcpy(req->data, data, data_len); 19703983bc45SNaman Padhiar 19713983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 19723983bc45SNaman Padhiar wlfw_athdiag_write_resp_msg_v01_ei, resp); 19733983bc45SNaman Padhiar if (ret < 0) { 19743983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for Athdiag Write resp %d\n", 19753983bc45SNaman Padhiar ret); 19763983bc45SNaman Padhiar goto out; 19773983bc45SNaman Padhiar } 19783983bc45SNaman Padhiar 19793983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 19803983bc45SNaman Padhiar QMI_WLFW_ATHDIAG_WRITE_REQ_V01, 19813983bc45SNaman Padhiar WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN, 19823983bc45SNaman Padhiar wlfw_athdiag_write_req_msg_v01_ei, req); 19833983bc45SNaman Padhiar if (ret < 0) { 19843983bc45SNaman Padhiar qmi_txn_cancel(&txn); 19853983bc45SNaman Padhiar icnss_pr_err("Fail to send Athdiag Write req %d\n", ret); 19863983bc45SNaman Padhiar goto out; 19873983bc45SNaman Padhiar } 19883983bc45SNaman Padhiar 19893983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 19903983bc45SNaman Padhiar if (ret < 0) { 19913983bc45SNaman Padhiar icnss_pr_err("Athdiag Write resp wait failed with ret %d\n", 19923983bc45SNaman Padhiar ret); 19933983bc45SNaman Padhiar goto out; 19943983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 19953983bc45SNaman Padhiar icnss_pr_err("QMI Athdiag Write request rejected, result:%d error:%d\n", 19963983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 19973983bc45SNaman Padhiar ret = -resp->resp.result; 19983983bc45SNaman Padhiar goto out; 19993983bc45SNaman Padhiar } else { 20003983bc45SNaman Padhiar ret = 0; 20013983bc45SNaman Padhiar } 20023983bc45SNaman Padhiar 20033983bc45SNaman Padhiar out: 20043983bc45SNaman Padhiar kfree(resp); 20053983bc45SNaman Padhiar kfree(req); 20063983bc45SNaman Padhiar return ret; 20073983bc45SNaman Padhiar } 20083983bc45SNaman Padhiar 20093983bc45SNaman Padhiar int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv) 20103983bc45SNaman Padhiar { 20113983bc45SNaman Padhiar int ret; 20123983bc45SNaman Padhiar struct wlfw_rejuvenate_ack_req_msg_v01 *req; 20133983bc45SNaman Padhiar struct wlfw_rejuvenate_ack_resp_msg_v01 *resp; 20143983bc45SNaman Padhiar struct qmi_txn txn; 20153983bc45SNaman Padhiar 20163983bc45SNaman Padhiar if (!priv) 20173983bc45SNaman Padhiar return -ENODEV; 20183983bc45SNaman Padhiar 20193983bc45SNaman Padhiar icnss_pr_dbg("Sending rejuvenate ack request, state: 0x%lx\n", 20203983bc45SNaman Padhiar priv->state); 20213983bc45SNaman Padhiar 20223983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 20233983bc45SNaman Padhiar if (!req) 20243983bc45SNaman Padhiar return -ENOMEM; 20253983bc45SNaman Padhiar 20263983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 20273983bc45SNaman Padhiar if (!resp) { 20283983bc45SNaman Padhiar kfree(req); 20293983bc45SNaman Padhiar return -ENOMEM; 20303983bc45SNaman Padhiar } 20313983bc45SNaman Padhiar 20323983bc45SNaman Padhiar priv->stats.rejuvenate_ack_req++; 20333983bc45SNaman Padhiar 20343983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 20353983bc45SNaman Padhiar wlfw_rejuvenate_ack_resp_msg_v01_ei, resp); 20363983bc45SNaman Padhiar if (ret < 0) { 20373983bc45SNaman Padhiar icnss_qmi_fatal_err( 20383983bc45SNaman Padhiar "Fail to init txn for Rejuvenate Ack resp %d\n", 20393983bc45SNaman Padhiar ret); 20403983bc45SNaman Padhiar goto out; 20413983bc45SNaman Padhiar } 20423983bc45SNaman Padhiar 20433983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 20443983bc45SNaman Padhiar QMI_WLFW_REJUVENATE_ACK_REQ_V01, 20453983bc45SNaman Padhiar WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN, 20463983bc45SNaman Padhiar wlfw_rejuvenate_ack_req_msg_v01_ei, req); 20473983bc45SNaman Padhiar if (ret < 0) { 20483983bc45SNaman Padhiar qmi_txn_cancel(&txn); 20493983bc45SNaman Padhiar icnss_qmi_fatal_err("Fail to send Rejuvenate Ack req %d\n", 20503983bc45SNaman Padhiar ret); 20513983bc45SNaman Padhiar goto out; 20523983bc45SNaman Padhiar } 20533983bc45SNaman Padhiar 20543983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 20553983bc45SNaman Padhiar if (ret < 0) { 20563983bc45SNaman Padhiar icnss_qmi_fatal_err( 20573983bc45SNaman Padhiar "Rejuvenate Ack resp wait failed with ret %d\n", 20583983bc45SNaman Padhiar ret); 20593983bc45SNaman Padhiar goto out; 20603983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 20613983bc45SNaman Padhiar icnss_qmi_fatal_err( 20623983bc45SNaman Padhiar "QMI Rejuvenate Ack request rejected, result:%d error:%d\n", 20633983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 20643983bc45SNaman Padhiar ret = -resp->resp.result; 20653983bc45SNaman Padhiar goto out; 20663983bc45SNaman Padhiar } 20673983bc45SNaman Padhiar 20683983bc45SNaman Padhiar priv->stats.rejuvenate_ack_resp++; 20693983bc45SNaman Padhiar 20703983bc45SNaman Padhiar kfree(resp); 20713983bc45SNaman Padhiar kfree(req); 20723983bc45SNaman Padhiar return 0; 20733983bc45SNaman Padhiar 20743983bc45SNaman Padhiar out: 20753983bc45SNaman Padhiar kfree(resp); 20763983bc45SNaman Padhiar kfree(req); 20773983bc45SNaman Padhiar priv->stats.rejuvenate_ack_err++; 20783983bc45SNaman Padhiar return ret; 20793983bc45SNaman Padhiar } 20803983bc45SNaman Padhiar 20813983bc45SNaman Padhiar int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv, 20823983bc45SNaman Padhiar uint64_t dynamic_feature_mask) 20833983bc45SNaman Padhiar { 20843983bc45SNaman Padhiar int ret; 20853983bc45SNaman Padhiar struct wlfw_dynamic_feature_mask_req_msg_v01 *req; 20863983bc45SNaman Padhiar struct wlfw_dynamic_feature_mask_resp_msg_v01 *resp; 20873983bc45SNaman Padhiar struct qmi_txn txn; 20883983bc45SNaman Padhiar 20893983bc45SNaman Padhiar if (!priv) 20903983bc45SNaman Padhiar return -ENODEV; 20913983bc45SNaman Padhiar 20923983bc45SNaman Padhiar if (!test_bit(ICNSS_WLFW_CONNECTED, &priv->state)) { 20933983bc45SNaman Padhiar icnss_pr_err("Invalid state for dynamic feature: 0x%lx\n", 20943983bc45SNaman Padhiar priv->state); 20953983bc45SNaman Padhiar return -EINVAL; 20963983bc45SNaman Padhiar } 20973983bc45SNaman Padhiar 20983983bc45SNaman Padhiar if (!test_bit(FW_REJUVENATE_ENABLE, &priv->ctrl_params.quirks)) { 20993983bc45SNaman Padhiar icnss_pr_dbg("FW rejuvenate is disabled from quirks\n"); 21003983bc45SNaman Padhiar return 0; 21013983bc45SNaman Padhiar } 21023983bc45SNaman Padhiar 21033983bc45SNaman Padhiar icnss_pr_dbg("Sending dynamic feature mask request, val 0x%llx, state: 0x%lx\n", 21043983bc45SNaman Padhiar dynamic_feature_mask, priv->state); 21053983bc45SNaman Padhiar 21063983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 21073983bc45SNaman Padhiar if (!req) 21083983bc45SNaman Padhiar return -ENOMEM; 21093983bc45SNaman Padhiar 21103983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 21113983bc45SNaman Padhiar if (!resp) { 21123983bc45SNaman Padhiar kfree(req); 21133983bc45SNaman Padhiar return -ENOMEM; 21143983bc45SNaman Padhiar } 21153983bc45SNaman Padhiar 21163983bc45SNaman Padhiar req->mask_valid = 1; 21173983bc45SNaman Padhiar req->mask = dynamic_feature_mask; 21183983bc45SNaman Padhiar 21193983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 21203983bc45SNaman Padhiar wlfw_dynamic_feature_mask_resp_msg_v01_ei, resp); 21213983bc45SNaman Padhiar if (ret < 0) { 21223983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for Dynamic Feature Mask resp %d\n", 21233983bc45SNaman Padhiar ret); 21243983bc45SNaman Padhiar goto out; 21253983bc45SNaman Padhiar } 21263983bc45SNaman Padhiar 21273983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 21283983bc45SNaman Padhiar QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01, 21293983bc45SNaman Padhiar WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN, 21303983bc45SNaman Padhiar wlfw_dynamic_feature_mask_req_msg_v01_ei, req); 21313983bc45SNaman Padhiar if (ret < 0) { 21323983bc45SNaman Padhiar qmi_txn_cancel(&txn); 21333983bc45SNaman Padhiar icnss_pr_err("Fail to send Dynamic Feature Mask req %d\n", ret); 21343983bc45SNaman Padhiar goto out; 21353983bc45SNaman Padhiar } 21363983bc45SNaman Padhiar 21373983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 21383983bc45SNaman Padhiar if (ret < 0) { 21393983bc45SNaman Padhiar icnss_pr_err("Dynamic Feature Mask resp wait failed with ret %d\n", 21403983bc45SNaman Padhiar ret); 21413983bc45SNaman Padhiar goto out; 21423983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 21433983bc45SNaman Padhiar icnss_pr_err("QMI Dynamic Feature Mask request rejected, result:%d error:%d\n", 21443983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 21453983bc45SNaman Padhiar ret = -resp->resp.result; 21463983bc45SNaman Padhiar goto out; 21473983bc45SNaman Padhiar } 21483983bc45SNaman Padhiar 21493983bc45SNaman Padhiar icnss_pr_dbg("prev_mask_valid %u, prev_mask 0x%llx, curr_maks_valid %u, curr_mask 0x%llx\n", 21503983bc45SNaman Padhiar resp->prev_mask_valid, resp->prev_mask, 21513983bc45SNaman Padhiar resp->curr_mask_valid, resp->curr_mask); 21523983bc45SNaman Padhiar 21533983bc45SNaman Padhiar out: 21543983bc45SNaman Padhiar kfree(resp); 21553983bc45SNaman Padhiar kfree(req); 21563983bc45SNaman Padhiar return ret; 21573983bc45SNaman Padhiar } 21583983bc45SNaman Padhiar 21593983bc45SNaman Padhiar void icnss_handle_rejuvenate(struct icnss_priv *priv) 21603983bc45SNaman Padhiar { 21613983bc45SNaman Padhiar struct icnss_event_pd_service_down_data *event_data; 21623983bc45SNaman Padhiar struct icnss_uevent_fw_down_data fw_down_data = {0}; 21633983bc45SNaman Padhiar 21643983bc45SNaman Padhiar event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 21653983bc45SNaman Padhiar if (event_data == NULL) 21663983bc45SNaman Padhiar return; 21673983bc45SNaman Padhiar 21683983bc45SNaman Padhiar event_data->crashed = true; 21693983bc45SNaman Padhiar event_data->fw_rejuvenate = true; 21703983bc45SNaman Padhiar fw_down_data.crashed = true; 21713983bc45SNaman Padhiar set_bit(ICNSS_REJUVENATE, &priv->state); 21723983bc45SNaman Padhiar 21733983bc45SNaman Padhiar icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, 21743983bc45SNaman Padhiar &fw_down_data); 21753983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, 21763983bc45SNaman Padhiar 0, event_data); 21773983bc45SNaman Padhiar } 21783983bc45SNaman Padhiar 21793983bc45SNaman Padhiar int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv) 21803983bc45SNaman Padhiar { 21813983bc45SNaman Padhiar struct wlfw_qdss_trace_mem_info_req_msg_v01 *req; 21823983bc45SNaman Padhiar struct wlfw_qdss_trace_mem_info_resp_msg_v01 *resp; 21833983bc45SNaman Padhiar struct qmi_txn txn; 21843983bc45SNaman Padhiar struct icnss_fw_mem *qdss_mem = priv->qdss_mem; 21853983bc45SNaman Padhiar int ret = 0; 21863983bc45SNaman Padhiar int i; 21873983bc45SNaman Padhiar 21883983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &priv->state)) 21893983bc45SNaman Padhiar return -EINVAL; 21903983bc45SNaman Padhiar 21913983bc45SNaman Padhiar icnss_pr_dbg("Sending QDSS trace mem info, state: 0x%lx\n", 21923983bc45SNaman Padhiar priv->state); 21933983bc45SNaman Padhiar 21943983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 21953983bc45SNaman Padhiar if (!req) 21963983bc45SNaman Padhiar return -ENOMEM; 21973983bc45SNaman Padhiar 21983983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 21993983bc45SNaman Padhiar if (!resp) { 22003983bc45SNaman Padhiar kfree(req); 22013983bc45SNaman Padhiar return -ENOMEM; 22023983bc45SNaman Padhiar } 22033983bc45SNaman Padhiar 22043983bc45SNaman Padhiar req->mem_seg_len = priv->qdss_mem_seg_len; 22053983bc45SNaman Padhiar 2206219c37b8SSandeep Singh if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 22073983bc45SNaman Padhiar icnss_pr_err("Invalid seg len %u\n", 22083983bc45SNaman Padhiar priv->qdss_mem_seg_len); 22093983bc45SNaman Padhiar ret = -EINVAL; 22103983bc45SNaman Padhiar goto out; 22113983bc45SNaman Padhiar } 22123983bc45SNaman Padhiar 22133983bc45SNaman Padhiar for (i = 0; i < req->mem_seg_len; i++) { 22143983bc45SNaman Padhiar icnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", 22153983bc45SNaman Padhiar qdss_mem[i].va, &qdss_mem[i].pa, 22163983bc45SNaman Padhiar qdss_mem[i].size, qdss_mem[i].type); 22173983bc45SNaman Padhiar 22183983bc45SNaman Padhiar req->mem_seg[i].addr = qdss_mem[i].pa; 22193983bc45SNaman Padhiar req->mem_seg[i].size = qdss_mem[i].size; 22203983bc45SNaman Padhiar req->mem_seg[i].type = qdss_mem[i].type; 22213983bc45SNaman Padhiar } 22223983bc45SNaman Padhiar 22233983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 22243983bc45SNaman Padhiar wlfw_qdss_trace_mem_info_resp_msg_v01_ei, resp); 22253983bc45SNaman Padhiar if (ret < 0) { 22263983bc45SNaman Padhiar icnss_pr_err("Fail to initialize txn for QDSS trace mem request: err %d\n", 22273983bc45SNaman Padhiar ret); 22283983bc45SNaman Padhiar goto out; 22293983bc45SNaman Padhiar } 22303983bc45SNaman Padhiar 22313983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 22323983bc45SNaman Padhiar QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01, 22333983bc45SNaman Padhiar WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN, 22343983bc45SNaman Padhiar wlfw_qdss_trace_mem_info_req_msg_v01_ei, req); 22353983bc45SNaman Padhiar if (ret < 0) { 22363983bc45SNaman Padhiar qmi_txn_cancel(&txn); 22373983bc45SNaman Padhiar icnss_pr_err("Fail to send QDSS trace mem info request: err %d\n", 22383983bc45SNaman Padhiar ret); 22393983bc45SNaman Padhiar goto out; 22403983bc45SNaman Padhiar } 22413983bc45SNaman Padhiar 22423983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 22433983bc45SNaman Padhiar if (ret < 0) { 22443983bc45SNaman Padhiar icnss_pr_err("Fail to wait for response of QDSS trace mem info request, err %d\n", 22453983bc45SNaman Padhiar ret); 22463983bc45SNaman Padhiar goto out; 22473983bc45SNaman Padhiar } 22483983bc45SNaman Padhiar 22493983bc45SNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 22503983bc45SNaman Padhiar icnss_pr_err("QDSS trace mem info request failed, result: %d, err: %d\n", 22513983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 22523983bc45SNaman Padhiar ret = -resp->resp.result; 22533983bc45SNaman Padhiar goto out; 22543983bc45SNaman Padhiar } 22553983bc45SNaman Padhiar 22563983bc45SNaman Padhiar kfree(req); 22573983bc45SNaman Padhiar kfree(resp); 22583983bc45SNaman Padhiar return 0; 22593983bc45SNaman Padhiar 22603983bc45SNaman Padhiar out: 22613983bc45SNaman Padhiar kfree(req); 22623983bc45SNaman Padhiar kfree(resp); 22633983bc45SNaman Padhiar return ret; 22643983bc45SNaman Padhiar } 22653983bc45SNaman Padhiar 22663983bc45SNaman Padhiar int icnss_wlfw_m3_dump_upload_done_send_sync(struct icnss_priv *priv, 22673983bc45SNaman Padhiar u32 pdev_id, int status) 22683983bc45SNaman Padhiar { 22693983bc45SNaman Padhiar struct wlfw_m3_dump_upload_done_req_msg_v01 *req; 22703983bc45SNaman Padhiar struct wlfw_m3_dump_upload_done_resp_msg_v01 *resp; 22713983bc45SNaman Padhiar struct qmi_txn txn; 22723983bc45SNaman Padhiar int ret = 0; 22733983bc45SNaman Padhiar 22743983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 22753983bc45SNaman Padhiar if (!req) 22763983bc45SNaman Padhiar return -ENOMEM; 22773983bc45SNaman Padhiar 22783983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 22793983bc45SNaman Padhiar if (!resp) { 22803983bc45SNaman Padhiar kfree(req); 22813983bc45SNaman Padhiar return -ENOMEM; 22823983bc45SNaman Padhiar } 22833983bc45SNaman Padhiar 22843983bc45SNaman Padhiar icnss_pr_dbg("Sending M3 Upload done req, pdev %d, status %d\n", 22853983bc45SNaman Padhiar pdev_id, status); 22863983bc45SNaman Padhiar 22873983bc45SNaman Padhiar req->pdev_id = pdev_id; 22883983bc45SNaman Padhiar req->status = status; 22893983bc45SNaman Padhiar 22903983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 22913983bc45SNaman Padhiar wlfw_m3_dump_upload_done_resp_msg_v01_ei, resp); 22923983bc45SNaman Padhiar if (ret < 0) { 22933983bc45SNaman Padhiar icnss_pr_err("Fail to initialize txn for M3 dump upload done req: err %d\n", 22943983bc45SNaman Padhiar ret); 22953983bc45SNaman Padhiar goto out; 22963983bc45SNaman Padhiar } 22973983bc45SNaman Padhiar 22983983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 22993983bc45SNaman Padhiar QMI_WLFW_M3_DUMP_UPLOAD_DONE_REQ_V01, 23003983bc45SNaman Padhiar WLFW_M3_DUMP_UPLOAD_DONE_REQ_MSG_V01_MAX_MSG_LEN, 23013983bc45SNaman Padhiar wlfw_m3_dump_upload_done_req_msg_v01_ei, req); 23023983bc45SNaman Padhiar if (ret < 0) { 23033983bc45SNaman Padhiar qmi_txn_cancel(&txn); 23043983bc45SNaman Padhiar icnss_pr_err("Fail to send M3 dump upload done request: err %d\n", 23053983bc45SNaman Padhiar ret); 23063983bc45SNaman Padhiar goto out; 23073983bc45SNaman Padhiar } 23083983bc45SNaman Padhiar 23093983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 23103983bc45SNaman Padhiar if (ret < 0) { 23113983bc45SNaman Padhiar icnss_pr_err("Fail to wait for response of M3 dump upload done request, err %d\n", 23123983bc45SNaman Padhiar ret); 23133983bc45SNaman Padhiar goto out; 23143983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 23153983bc45SNaman Padhiar icnss_pr_err("M3 Dump Upload Done Req failed, result: %d, err: 0x%X\n", 23163983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 23173983bc45SNaman Padhiar ret = -resp->resp.result; 23183983bc45SNaman Padhiar goto out; 23193983bc45SNaman Padhiar } 23203983bc45SNaman Padhiar 23213983bc45SNaman Padhiar out: 23223983bc45SNaman Padhiar kfree(req); 23233983bc45SNaman Padhiar kfree(resp); 23243983bc45SNaman Padhiar return ret; 23253983bc45SNaman Padhiar } 23263983bc45SNaman Padhiar 23273983bc45SNaman Padhiar static void fw_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, 23283983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 23293983bc45SNaman Padhiar { 23303983bc45SNaman Padhiar struct icnss_priv *priv = 23313983bc45SNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 23323983bc45SNaman Padhiar 23333983bc45SNaman Padhiar icnss_pr_dbg("Received FW Ready Indication\n"); 23343983bc45SNaman Padhiar 23353983bc45SNaman Padhiar if (!txn) { 23363983bc45SNaman Padhiar pr_err("spurious indication\n"); 23373983bc45SNaman Padhiar return; 23383983bc45SNaman Padhiar } 23393983bc45SNaman Padhiar 23403983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_FW_READY_IND, 23413983bc45SNaman Padhiar 0, NULL); 23423983bc45SNaman Padhiar } 23433983bc45SNaman Padhiar 23443983bc45SNaman Padhiar static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, 23453983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 23463983bc45SNaman Padhiar { 23473983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 23483983bc45SNaman Padhiar struct device *dev = &priv->pdev->dev; 23493983bc45SNaman Padhiar const struct wlfw_msa_ready_ind_msg_v01 *ind_msg = data; 23503983bc45SNaman Padhiar uint64_t msa_base_addr = priv->msa_pa; 23513983bc45SNaman Padhiar phys_addr_t hang_data_phy_addr; 23523983bc45SNaman Padhiar 23533983bc45SNaman Padhiar icnss_pr_dbg("Received MSA Ready Indication\n"); 23543983bc45SNaman Padhiar 23553983bc45SNaman Padhiar if (!txn) { 23563983bc45SNaman Padhiar pr_err("spurious indication\n"); 23573983bc45SNaman Padhiar return; 23583983bc45SNaman Padhiar } 23593983bc45SNaman Padhiar 23603983bc45SNaman Padhiar priv->stats.msa_ready_ind++; 23613983bc45SNaman Padhiar 23623983bc45SNaman Padhiar /* Check if the length is valid & 23633983bc45SNaman Padhiar * the length should not be 0 and 23643983bc45SNaman Padhiar * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400) 23653983bc45SNaman Padhiar */ 23663983bc45SNaman Padhiar 23673983bc45SNaman Padhiar if (ind_msg->hang_data_length_valid && 23683983bc45SNaman Padhiar ind_msg->hang_data_length && 23693983bc45SNaman Padhiar ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE) 23703983bc45SNaman Padhiar priv->hang_event_data_len = ind_msg->hang_data_length; 23713983bc45SNaman Padhiar else 23723983bc45SNaman Padhiar goto out; 23733983bc45SNaman Padhiar 23743983bc45SNaman Padhiar /* Check if the offset is valid & 23753983bc45SNaman Padhiar * the offset should be in range of 0 to msa_mem_size-hang_data_length 23763983bc45SNaman Padhiar */ 23773983bc45SNaman Padhiar 23783983bc45SNaman Padhiar if (ind_msg->hang_data_addr_offset_valid && 23793983bc45SNaman Padhiar (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size - 23803983bc45SNaman Padhiar ind_msg->hang_data_length))) 23813983bc45SNaman Padhiar hang_data_phy_addr = msa_base_addr + 23823983bc45SNaman Padhiar ind_msg->hang_data_addr_offset; 23833983bc45SNaman Padhiar else 23843983bc45SNaman Padhiar goto out; 23853983bc45SNaman Padhiar 23863983bc45SNaman Padhiar if (priv->hang_event_data_pa == hang_data_phy_addr) 23873983bc45SNaman Padhiar goto exit; 23883983bc45SNaman Padhiar 23893983bc45SNaman Padhiar priv->hang_event_data_pa = hang_data_phy_addr; 23903983bc45SNaman Padhiar priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa, 23913983bc45SNaman Padhiar ind_msg->hang_data_length); 23923983bc45SNaman Padhiar 23933983bc45SNaman Padhiar if (!priv->hang_event_data_va) { 23943983bc45SNaman Padhiar icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n", 23953983bc45SNaman Padhiar &priv->hang_event_data_pa); 23963983bc45SNaman Padhiar goto fail; 23973983bc45SNaman Padhiar } 23983983bc45SNaman Padhiar exit: 23993983bc45SNaman Padhiar icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n", 24003983bc45SNaman Padhiar ind_msg->hang_data_addr_offset, 24013983bc45SNaman Padhiar ind_msg->hang_data_length, 24023983bc45SNaman Padhiar priv->hang_event_data_va); 24033983bc45SNaman Padhiar 24043983bc45SNaman Padhiar return; 24053983bc45SNaman Padhiar 24063983bc45SNaman Padhiar out: 24073983bc45SNaman Padhiar icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x", 24083983bc45SNaman Padhiar ind_msg->hang_data_addr_offset, 24093983bc45SNaman Padhiar ind_msg->hang_data_length); 24103983bc45SNaman Padhiar fail: 24113983bc45SNaman Padhiar priv->hang_event_data_va = NULL; 24123983bc45SNaman Padhiar priv->hang_event_data_pa = 0; 24133983bc45SNaman Padhiar priv->hang_event_data_len = 0; 24143983bc45SNaman Padhiar } 24153983bc45SNaman Padhiar 24163983bc45SNaman Padhiar static void pin_connect_result_ind_cb(struct qmi_handle *qmi, 24173983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 24183983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 24193983bc45SNaman Padhiar { 24203983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 24213983bc45SNaman Padhiar const struct wlfw_pin_connect_result_ind_msg_v01 *ind_msg = data; 24223983bc45SNaman Padhiar 24233983bc45SNaman Padhiar icnss_pr_dbg("Received Pin Connect Result Indication\n"); 24243983bc45SNaman Padhiar 24253983bc45SNaman Padhiar if (!txn) { 24263983bc45SNaman Padhiar pr_err("spurious indication\n"); 24273983bc45SNaman Padhiar return; 24283983bc45SNaman Padhiar } 24293983bc45SNaman Padhiar 24303983bc45SNaman Padhiar if (ind_msg->pwr_pin_result_valid) 24313983bc45SNaman Padhiar priv->pwr_pin_result = ind_msg->pwr_pin_result; 24323983bc45SNaman Padhiar if (ind_msg->phy_io_pin_result_valid) 24333983bc45SNaman Padhiar priv->phy_io_pin_result = ind_msg->phy_io_pin_result; 24343983bc45SNaman Padhiar if (ind_msg->rf_pin_result_valid) 24353983bc45SNaman Padhiar priv->rf_pin_result = ind_msg->rf_pin_result; 24363983bc45SNaman Padhiar 24373983bc45SNaman Padhiar icnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n", 24383983bc45SNaman Padhiar ind_msg->pwr_pin_result, ind_msg->phy_io_pin_result, 24393983bc45SNaman Padhiar ind_msg->rf_pin_result); 24403983bc45SNaman Padhiar priv->stats.pin_connect_result++; 24413983bc45SNaman Padhiar } 24423983bc45SNaman Padhiar 24433983bc45SNaman Padhiar static void rejuvenate_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, 24443983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 24453983bc45SNaman Padhiar { 24463983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 24473983bc45SNaman Padhiar const struct wlfw_rejuvenate_ind_msg_v01 *ind_msg = data; 24483983bc45SNaman Padhiar 24493983bc45SNaman Padhiar icnss_pr_dbg("Received Rejuvenate Indication\n"); 24503983bc45SNaman Padhiar 24513983bc45SNaman Padhiar if (!txn) { 24523983bc45SNaman Padhiar pr_err("spurious indication\n"); 24533983bc45SNaman Padhiar return; 24543983bc45SNaman Padhiar } 24553983bc45SNaman Padhiar 24563983bc45SNaman Padhiar icnss_ignore_fw_timeout(true); 24573983bc45SNaman Padhiar 24583983bc45SNaman Padhiar if (ind_msg->cause_for_rejuvenation_valid) 24593983bc45SNaman Padhiar priv->cause_for_rejuvenation = ind_msg->cause_for_rejuvenation; 24603983bc45SNaman Padhiar else 24613983bc45SNaman Padhiar priv->cause_for_rejuvenation = 0; 24623983bc45SNaman Padhiar if (ind_msg->requesting_sub_system_valid) 24633983bc45SNaman Padhiar priv->requesting_sub_system = ind_msg->requesting_sub_system; 24643983bc45SNaman Padhiar else 24653983bc45SNaman Padhiar priv->requesting_sub_system = 0; 24663983bc45SNaman Padhiar if (ind_msg->line_number_valid) 24673983bc45SNaman Padhiar priv->line_number = ind_msg->line_number; 24683983bc45SNaman Padhiar else 24693983bc45SNaman Padhiar priv->line_number = 0; 24703983bc45SNaman Padhiar if (ind_msg->function_name_valid) 24713983bc45SNaman Padhiar memcpy(priv->function_name, ind_msg->function_name, 24723983bc45SNaman Padhiar QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1); 24733983bc45SNaman Padhiar else 24743983bc45SNaman Padhiar memset(priv->function_name, 0, 24753983bc45SNaman Padhiar QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1); 24763983bc45SNaman Padhiar 24773983bc45SNaman Padhiar icnss_pr_info("Cause for rejuvenation: 0x%x, requesting sub-system: 0x%x, line number: %u, function name: %s\n", 24783983bc45SNaman Padhiar priv->cause_for_rejuvenation, 24793983bc45SNaman Padhiar priv->requesting_sub_system, 24803983bc45SNaman Padhiar priv->line_number, 24813983bc45SNaman Padhiar priv->function_name); 24823983bc45SNaman Padhiar 24833983bc45SNaman Padhiar priv->stats.rejuvenate_ind++; 24843983bc45SNaman Padhiar 24853983bc45SNaman Padhiar icnss_handle_rejuvenate(priv); 24863983bc45SNaman Padhiar } 24873983bc45SNaman Padhiar 24883983bc45SNaman Padhiar static void cal_done_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, 24893983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 24903983bc45SNaman Padhiar { 24913983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 24923983bc45SNaman Padhiar 24933983bc45SNaman Padhiar icnss_pr_dbg("Received QMI WLFW calibration done indication\n"); 24943983bc45SNaman Padhiar 24953983bc45SNaman Padhiar if (!txn) { 24963983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 24973983bc45SNaman Padhiar return; 24983983bc45SNaman Padhiar } 24993983bc45SNaman Padhiar 25003983bc45SNaman Padhiar priv->cal_done = true; 25013983bc45SNaman Padhiar clear_bit(ICNSS_COLD_BOOT_CAL, &priv->state); 25023983bc45SNaman Padhiar } 25033983bc45SNaman Padhiar 25043983bc45SNaman Padhiar static void fw_init_done_ind_cb(struct qmi_handle *qmi, 25053983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 25063983bc45SNaman Padhiar struct qmi_txn *txn, const void *data) 25073983bc45SNaman Padhiar { 25083983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 25093983bc45SNaman Padhiar struct device *dev = &priv->pdev->dev; 25103983bc45SNaman Padhiar const struct wlfw_fw_init_done_ind_msg_v01 *ind_msg = data; 25113983bc45SNaman Padhiar uint64_t msa_base_addr = priv->msa_pa; 25123983bc45SNaman Padhiar phys_addr_t hang_data_phy_addr; 25133983bc45SNaman Padhiar 25143983bc45SNaman Padhiar icnss_pr_dbg("Received QMI WLFW FW initialization done indication\n"); 25153983bc45SNaman Padhiar 25163983bc45SNaman Padhiar if (!txn) { 25173983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 25183983bc45SNaman Padhiar return; 25193983bc45SNaman Padhiar } 25203983bc45SNaman Padhiar 25213983bc45SNaman Padhiar /* Check if the length is valid & 25223983bc45SNaman Padhiar * the length should not be 0 and 25233983bc45SNaman Padhiar * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400) 25243983bc45SNaman Padhiar */ 25253983bc45SNaman Padhiar 25263983bc45SNaman Padhiar if (ind_msg->hang_data_length_valid && 25273983bc45SNaman Padhiar ind_msg->hang_data_length && 25283983bc45SNaman Padhiar ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE) 25293983bc45SNaman Padhiar priv->hang_event_data_len = ind_msg->hang_data_length; 25303983bc45SNaman Padhiar else 25313983bc45SNaman Padhiar goto out; 25323983bc45SNaman Padhiar 25333983bc45SNaman Padhiar /* Check if the offset is valid & 25343983bc45SNaman Padhiar * the offset should be in range of 0 to msa_mem_size-hang_data_length 25353983bc45SNaman Padhiar */ 25363983bc45SNaman Padhiar 25373983bc45SNaman Padhiar if (ind_msg->hang_data_addr_offset_valid && 25383983bc45SNaman Padhiar (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size - 25393983bc45SNaman Padhiar ind_msg->hang_data_length))) 25403983bc45SNaman Padhiar hang_data_phy_addr = msa_base_addr + 25413983bc45SNaman Padhiar ind_msg->hang_data_addr_offset; 25423983bc45SNaman Padhiar else 25433983bc45SNaman Padhiar goto out; 25443983bc45SNaman Padhiar 25453983bc45SNaman Padhiar if (priv->hang_event_data_pa == hang_data_phy_addr) 25463983bc45SNaman Padhiar goto exit; 25473983bc45SNaman Padhiar 25483983bc45SNaman Padhiar priv->hang_event_data_pa = hang_data_phy_addr; 25493983bc45SNaman Padhiar priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa, 25503983bc45SNaman Padhiar ind_msg->hang_data_length); 25513983bc45SNaman Padhiar 25523983bc45SNaman Padhiar if (!priv->hang_event_data_va) { 25533983bc45SNaman Padhiar icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n", 25543983bc45SNaman Padhiar &priv->hang_event_data_pa); 25553983bc45SNaman Padhiar goto fail; 25563983bc45SNaman Padhiar } 25573983bc45SNaman Padhiar 25583983bc45SNaman Padhiar exit: 25593983bc45SNaman Padhiar icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n", 25603983bc45SNaman Padhiar ind_msg->hang_data_addr_offset, 25613983bc45SNaman Padhiar ind_msg->hang_data_length, 25623983bc45SNaman Padhiar priv->hang_event_data_va); 25633983bc45SNaman Padhiar 25643983bc45SNaman Padhiar goto post; 25653983bc45SNaman Padhiar 25663983bc45SNaman Padhiar out: 25673983bc45SNaman Padhiar icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x", 25683983bc45SNaman Padhiar ind_msg->hang_data_addr_offset, 25693983bc45SNaman Padhiar ind_msg->hang_data_length); 25703983bc45SNaman Padhiar fail: 25713983bc45SNaman Padhiar priv->hang_event_data_va = NULL; 25723983bc45SNaman Padhiar priv->hang_event_data_pa = 0; 25733983bc45SNaman Padhiar priv->hang_event_data_len = 0; 25743983bc45SNaman Padhiar post: 25753983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_FW_INIT_DONE_IND, 25763983bc45SNaman Padhiar 0, NULL); 25773983bc45SNaman Padhiar 25783983bc45SNaman Padhiar } 25793983bc45SNaman Padhiar 25803983bc45SNaman Padhiar static void wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi, 25813983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 25823983bc45SNaman Padhiar struct qmi_txn *txn, 25833983bc45SNaman Padhiar const void *data) 25843983bc45SNaman Padhiar { 25853983bc45SNaman Padhiar struct icnss_priv *priv = 25863983bc45SNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 25873983bc45SNaman Padhiar const struct wlfw_qdss_trace_req_mem_ind_msg_v01 *ind_msg = data; 25883983bc45SNaman Padhiar int i; 25893983bc45SNaman Padhiar 25903983bc45SNaman Padhiar icnss_pr_dbg("Received QMI WLFW QDSS trace request mem indication\n"); 25913983bc45SNaman Padhiar 25923983bc45SNaman Padhiar if (!txn) { 25933983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 25943983bc45SNaman Padhiar return; 25953983bc45SNaman Padhiar } 25963983bc45SNaman Padhiar 25973983bc45SNaman Padhiar if (priv->qdss_mem_seg_len) { 25983983bc45SNaman Padhiar icnss_pr_err("Ignore double allocation for QDSS trace, current len %u\n", 25993983bc45SNaman Padhiar priv->qdss_mem_seg_len); 26003983bc45SNaman Padhiar return; 26013983bc45SNaman Padhiar } 26023983bc45SNaman Padhiar 26033983bc45SNaman Padhiar priv->qdss_mem_seg_len = ind_msg->mem_seg_len; 26043983bc45SNaman Padhiar 2605219c37b8SSandeep Singh if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { 26063983bc45SNaman Padhiar icnss_pr_err("Invalid seg len %u\n", 26073983bc45SNaman Padhiar priv->qdss_mem_seg_len); 26083983bc45SNaman Padhiar return; 26093983bc45SNaman Padhiar } 26103983bc45SNaman Padhiar 26113983bc45SNaman Padhiar for (i = 0; i < priv->qdss_mem_seg_len; i++) { 26123983bc45SNaman Padhiar icnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n", 26133983bc45SNaman Padhiar ind_msg->mem_seg[i].size, 26143983bc45SNaman Padhiar ind_msg->mem_seg[i].type); 26153983bc45SNaman Padhiar priv->qdss_mem[i].type = ind_msg->mem_seg[i].type; 26163983bc45SNaman Padhiar priv->qdss_mem[i].size = ind_msg->mem_seg[i].size; 26173983bc45SNaman Padhiar } 26183983bc45SNaman Padhiar 26193983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM, 26203983bc45SNaman Padhiar 0, NULL); 26213983bc45SNaman Padhiar } 26223983bc45SNaman Padhiar 26233983bc45SNaman Padhiar static void wlfw_qdss_trace_save_ind_cb(struct qmi_handle *qmi, 26243983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 26253983bc45SNaman Padhiar struct qmi_txn *txn, 26263983bc45SNaman Padhiar const void *data) 26273983bc45SNaman Padhiar { 26283983bc45SNaman Padhiar struct icnss_priv *priv = 26293983bc45SNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 26303983bc45SNaman Padhiar const struct wlfw_qdss_trace_save_ind_msg_v01 *ind_msg = data; 26313983bc45SNaman Padhiar struct icnss_qmi_event_qdss_trace_save_data *event_data; 26323983bc45SNaman Padhiar int i = 0; 26333983bc45SNaman Padhiar 26343983bc45SNaman Padhiar icnss_pr_dbg("Received QMI WLFW QDSS trace save indication\n"); 26353983bc45SNaman Padhiar 26363983bc45SNaman Padhiar if (!txn) { 26373983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 26383983bc45SNaman Padhiar return; 26393983bc45SNaman Padhiar } 26403983bc45SNaman Padhiar 26413983bc45SNaman Padhiar icnss_pr_dbg("QDSS_trace_save info: source %u, total_size %u, file_name_valid %u, file_name %s\n", 26423983bc45SNaman Padhiar ind_msg->source, ind_msg->total_size, 26433983bc45SNaman Padhiar ind_msg->file_name_valid, ind_msg->file_name); 26443983bc45SNaman Padhiar 26453983bc45SNaman Padhiar event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 26463983bc45SNaman Padhiar if (!event_data) 26473983bc45SNaman Padhiar return; 26483983bc45SNaman Padhiar 26493983bc45SNaman Padhiar if (ind_msg->mem_seg_valid) { 26503983bc45SNaman Padhiar if (ind_msg->mem_seg_len > QDSS_TRACE_SEG_LEN_MAX) { 26513983bc45SNaman Padhiar icnss_pr_err("Invalid seg len %u\n", 26523983bc45SNaman Padhiar ind_msg->mem_seg_len); 26533983bc45SNaman Padhiar goto free_event_data; 26543983bc45SNaman Padhiar } 26553983bc45SNaman Padhiar icnss_pr_dbg("QDSS_trace_save seg len %u\n", 26563983bc45SNaman Padhiar ind_msg->mem_seg_len); 26573983bc45SNaman Padhiar event_data->mem_seg_len = ind_msg->mem_seg_len; 26583983bc45SNaman Padhiar for (i = 0; i < ind_msg->mem_seg_len; i++) { 26593983bc45SNaman Padhiar event_data->mem_seg[i].addr = ind_msg->mem_seg[i].addr; 26603983bc45SNaman Padhiar event_data->mem_seg[i].size = ind_msg->mem_seg[i].size; 26613983bc45SNaman Padhiar icnss_pr_dbg("seg-%d: addr 0x%llx size 0x%x\n", 26623983bc45SNaman Padhiar i, ind_msg->mem_seg[i].addr, 26633983bc45SNaman Padhiar ind_msg->mem_seg[i].size); 26643983bc45SNaman Padhiar } 26653983bc45SNaman Padhiar } 26663983bc45SNaman Padhiar 26673983bc45SNaman Padhiar event_data->total_size = ind_msg->total_size; 26683983bc45SNaman Padhiar 26693983bc45SNaman Padhiar if (ind_msg->file_name_valid) 26703983bc45SNaman Padhiar strlcpy(event_data->file_name, ind_msg->file_name, 26713983bc45SNaman Padhiar QDSS_TRACE_FILE_NAME_MAX + 1); 26723983bc45SNaman Padhiar 26733983bc45SNaman Padhiar if (ind_msg->source == 1) { 26743983bc45SNaman Padhiar if (!ind_msg->file_name_valid) 26753983bc45SNaman Padhiar strlcpy(event_data->file_name, "qdss_trace_wcss_etb", 26763983bc45SNaman Padhiar QDSS_TRACE_FILE_NAME_MAX + 1); 26773983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA, 26783983bc45SNaman Padhiar 0, event_data); 26793983bc45SNaman Padhiar } else { 26803983bc45SNaman Padhiar if (!ind_msg->file_name_valid) 26813983bc45SNaman Padhiar strlcpy(event_data->file_name, "qdss_trace_ddr", 26823983bc45SNaman Padhiar QDSS_TRACE_FILE_NAME_MAX + 1); 26833983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_SAVE, 26843983bc45SNaman Padhiar 0, event_data); 26853983bc45SNaman Padhiar } 26863983bc45SNaman Padhiar 26873983bc45SNaman Padhiar return; 26883983bc45SNaman Padhiar 26893983bc45SNaman Padhiar free_event_data: 26903983bc45SNaman Padhiar kfree(event_data); 26913983bc45SNaman Padhiar } 26923983bc45SNaman Padhiar 26933983bc45SNaman Padhiar static void wlfw_qdss_trace_free_ind_cb(struct qmi_handle *qmi, 26943983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 26953983bc45SNaman Padhiar struct qmi_txn *txn, 26963983bc45SNaman Padhiar const void *data) 26973983bc45SNaman Padhiar { 26983983bc45SNaman Padhiar struct icnss_priv *priv = 26993983bc45SNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 27003983bc45SNaman Padhiar 27013983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_FREE, 27023983bc45SNaman Padhiar 0, NULL); 27033983bc45SNaman Padhiar } 27043983bc45SNaman Padhiar 27053983bc45SNaman Padhiar static void icnss_wlfw_respond_get_info_ind_cb(struct qmi_handle *qmi, 27063983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 27073983bc45SNaman Padhiar struct qmi_txn *txn, 27083983bc45SNaman Padhiar const void *data) 27093983bc45SNaman Padhiar { 27103983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 27113983bc45SNaman Padhiar const struct wlfw_respond_get_info_ind_msg_v01 *ind_msg = data; 27123983bc45SNaman Padhiar 27133983bc45SNaman Padhiar if (!txn) { 27143983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 27153983bc45SNaman Padhiar return; 27163983bc45SNaman Padhiar } 27173983bc45SNaman Padhiar 27183983bc45SNaman Padhiar icnss_pr_vdbg("Extract message with event length: %d, type: %d, is last: %d, seq no: %d\n", 27193983bc45SNaman Padhiar ind_msg->data_len, ind_msg->type, 27203983bc45SNaman Padhiar ind_msg->is_last, ind_msg->seq_no); 27213983bc45SNaman Padhiar 27223983bc45SNaman Padhiar if (priv->get_info_cb_ctx && priv->get_info_cb) 27233983bc45SNaman Padhiar priv->get_info_cb(priv->get_info_cb_ctx, 27243983bc45SNaman Padhiar (void *)ind_msg->data, 27253983bc45SNaman Padhiar ind_msg->data_len); 27263983bc45SNaman Padhiar } 27273983bc45SNaman Padhiar 27283983bc45SNaman Padhiar static void icnss_wlfw_m3_dump_upload_segs_req_ind_cb(struct qmi_handle *qmi, 27293983bc45SNaman Padhiar struct sockaddr_qrtr *sq, 27303983bc45SNaman Padhiar struct qmi_txn *txn, 27313983bc45SNaman Padhiar const void *d) 27323983bc45SNaman Padhiar { 27333983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 27343983bc45SNaman Padhiar const struct wlfw_m3_dump_upload_segments_req_ind_msg_v01 *ind_msg = d; 27353983bc45SNaman Padhiar struct icnss_m3_upload_segments_req_data *event_data = NULL; 27363983bc45SNaman Padhiar u64 max_mapped_addr = 0; 27373983bc45SNaman Padhiar u64 segment_addr = 0; 27383983bc45SNaman Padhiar int i = 0; 27393983bc45SNaman Padhiar 27403983bc45SNaman Padhiar icnss_pr_dbg("Received QMI WLFW M3 dump upload sigments indication\n"); 27413983bc45SNaman Padhiar 27423983bc45SNaman Padhiar if (!txn) { 27433983bc45SNaman Padhiar icnss_pr_err("Spurious indication\n"); 27443983bc45SNaman Padhiar return; 27453983bc45SNaman Padhiar } 27463983bc45SNaman Padhiar 27473983bc45SNaman Padhiar icnss_pr_dbg("M3 Dump upload info: pdev_id: %d no_of_segments: %d\n", 27483983bc45SNaman Padhiar ind_msg->pdev_id, ind_msg->no_of_valid_segments); 27493983bc45SNaman Padhiar 27503983bc45SNaman Padhiar if (ind_msg->no_of_valid_segments > QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01) 27513983bc45SNaman Padhiar return; 27523983bc45SNaman Padhiar 27533983bc45SNaman Padhiar event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 27543983bc45SNaman Padhiar if (!event_data) 27553983bc45SNaman Padhiar return; 27563983bc45SNaman Padhiar 27573983bc45SNaman Padhiar event_data->pdev_id = ind_msg->pdev_id; 27583983bc45SNaman Padhiar event_data->no_of_valid_segments = ind_msg->no_of_valid_segments; 27593983bc45SNaman Padhiar max_mapped_addr = priv->msa_pa + priv->msa_mem_size; 27603983bc45SNaman Padhiar 27613983bc45SNaman Padhiar for (i = 0; i < ind_msg->no_of_valid_segments; i++) { 27623983bc45SNaman Padhiar segment_addr = ind_msg->m3_segment[i].addr & 27633983bc45SNaman Padhiar M3_SEGMENT_ADDR_MASK; 27643983bc45SNaman Padhiar 27653983bc45SNaman Padhiar if (ind_msg->m3_segment[i].size > priv->msa_mem_size || 27663983bc45SNaman Padhiar segment_addr >= max_mapped_addr || 27673983bc45SNaman Padhiar segment_addr < priv->msa_pa || 27683983bc45SNaman Padhiar ind_msg->m3_segment[i].size + 27693983bc45SNaman Padhiar segment_addr > max_mapped_addr) { 27703983bc45SNaman Padhiar icnss_pr_dbg("Received out of range Segment %d Addr: 0x%llx Size: 0x%x, Name: %s, type: %d\n", 27713983bc45SNaman Padhiar (i + 1), segment_addr, 27723983bc45SNaman Padhiar ind_msg->m3_segment[i].size, 27733983bc45SNaman Padhiar ind_msg->m3_segment[i].name, 27743983bc45SNaman Padhiar ind_msg->m3_segment[i].type); 27753983bc45SNaman Padhiar goto out; 27763983bc45SNaman Padhiar } 27773983bc45SNaman Padhiar 27783983bc45SNaman Padhiar event_data->m3_segment[i].addr = segment_addr; 27793983bc45SNaman Padhiar event_data->m3_segment[i].size = ind_msg->m3_segment[i].size; 27803983bc45SNaman Padhiar event_data->m3_segment[i].type = ind_msg->m3_segment[i].type; 27813983bc45SNaman Padhiar strlcpy(event_data->m3_segment[i].name, 27823983bc45SNaman Padhiar ind_msg->m3_segment[i].name, 27833983bc45SNaman Padhiar WLFW_MAX_STR_LEN + 1); 27843983bc45SNaman Padhiar 27853983bc45SNaman Padhiar icnss_pr_dbg("Received Segment %d Addr: 0x%llx Size: 0x%x, Name: %s, type: %d\n", 27863983bc45SNaman Padhiar (i + 1), segment_addr, 27873983bc45SNaman Padhiar ind_msg->m3_segment[i].size, 27883983bc45SNaman Padhiar ind_msg->m3_segment[i].name, 27893983bc45SNaman Padhiar ind_msg->m3_segment[i].type); 27903983bc45SNaman Padhiar } 27913983bc45SNaman Padhiar 27923983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_M3_DUMP_UPLOAD_REQ, 27933983bc45SNaman Padhiar 0, event_data); 27943983bc45SNaman Padhiar 27953983bc45SNaman Padhiar return; 27963983bc45SNaman Padhiar out: 27973983bc45SNaman Padhiar kfree(event_data); 27983983bc45SNaman Padhiar } 27993983bc45SNaman Padhiar 280087ab436eSNaman Padhiar static int icnss_wlfw_wfc_call_status_send_sync 280187ab436eSNaman Padhiar (struct icnss_priv *priv, 280287ab436eSNaman Padhiar const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg) 280387ab436eSNaman Padhiar { 280487ab436eSNaman Padhiar struct wlfw_wfc_call_status_req_msg_v01 *req; 280587ab436eSNaman Padhiar struct wlfw_wfc_call_status_resp_msg_v01 *resp; 280687ab436eSNaman Padhiar struct qmi_txn txn; 280787ab436eSNaman Padhiar int ret = 0; 280887ab436eSNaman Padhiar 2809*ae9e2e6bSPrateek Patil if (!test_bit(ICNSS_FW_READY, &priv->state) || 2810*ae9e2e6bSPrateek Patil !test_bit(ICNSS_MODE_ON, &priv->state)) { 281187ab436eSNaman Padhiar icnss_pr_err("Drop IMS WFC indication as FW not initialized\n"); 281287ab436eSNaman Padhiar return -EINVAL; 281387ab436eSNaman Padhiar } 281487ab436eSNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 281587ab436eSNaman Padhiar if (!req) 281687ab436eSNaman Padhiar return -ENOMEM; 281787ab436eSNaman Padhiar 281887ab436eSNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 281987ab436eSNaman Padhiar if (!resp) { 282087ab436eSNaman Padhiar kfree(req); 282187ab436eSNaman Padhiar return -ENOMEM; 282287ab436eSNaman Padhiar } 282387ab436eSNaman Padhiar 282487ab436eSNaman Padhiar /** 282587ab436eSNaman Padhiar * WFC Call r1 design has CNSS as pass thru using opaque hex buffer. 282687ab436eSNaman Padhiar * But in r2 update QMI structure is expanded and as an effect qmi 282787ab436eSNaman Padhiar * decoded structures have padding. Thus we cannot use buffer design. 282887ab436eSNaman Padhiar * For backward compatibility for r1 design copy only wfc_call_active 282987ab436eSNaman Padhiar * value in hex buffer. 283087ab436eSNaman Padhiar */ 283187ab436eSNaman Padhiar req->wfc_call_status_len = sizeof(ind_msg->wfc_call_active); 283287ab436eSNaman Padhiar req->wfc_call_status[0] = ind_msg->wfc_call_active; 283387ab436eSNaman Padhiar 283487ab436eSNaman Padhiar /* wfc_call_active is mandatory in IMS indication */ 283587ab436eSNaman Padhiar req->wfc_call_active_valid = 1; 283687ab436eSNaman Padhiar req->wfc_call_active = ind_msg->wfc_call_active; 283787ab436eSNaman Padhiar req->all_wfc_calls_held_valid = ind_msg->all_wfc_calls_held_valid; 283887ab436eSNaman Padhiar req->all_wfc_calls_held = ind_msg->all_wfc_calls_held; 283987ab436eSNaman Padhiar req->is_wfc_emergency_valid = ind_msg->is_wfc_emergency_valid; 284087ab436eSNaman Padhiar req->is_wfc_emergency = ind_msg->is_wfc_emergency; 284187ab436eSNaman Padhiar req->twt_ims_start_valid = ind_msg->twt_ims_start_valid; 284287ab436eSNaman Padhiar req->twt_ims_start = ind_msg->twt_ims_start; 284387ab436eSNaman Padhiar req->twt_ims_int_valid = ind_msg->twt_ims_int_valid; 284487ab436eSNaman Padhiar req->twt_ims_int = ind_msg->twt_ims_int; 284587ab436eSNaman Padhiar req->media_quality_valid = ind_msg->media_quality_valid; 284687ab436eSNaman Padhiar req->media_quality = 284787ab436eSNaman Padhiar (enum wlfw_wfc_media_quality_v01)ind_msg->media_quality; 284887ab436eSNaman Padhiar 284987ab436eSNaman Padhiar icnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n", 285087ab436eSNaman Padhiar priv->state); 285187ab436eSNaman Padhiar 285287ab436eSNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 285387ab436eSNaman Padhiar wlfw_wfc_call_status_resp_msg_v01_ei, resp); 285487ab436eSNaman Padhiar if (ret < 0) { 285587ab436eSNaman Padhiar icnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n", 285687ab436eSNaman Padhiar ret); 285787ab436eSNaman Padhiar goto out; 285887ab436eSNaman Padhiar } 285987ab436eSNaman Padhiar 286087ab436eSNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 286187ab436eSNaman Padhiar QMI_WLFW_WFC_CALL_STATUS_REQ_V01, 286287ab436eSNaman Padhiar WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN, 286387ab436eSNaman Padhiar wlfw_wfc_call_status_req_msg_v01_ei, req); 286487ab436eSNaman Padhiar if (ret < 0) { 286587ab436eSNaman Padhiar qmi_txn_cancel(&txn); 286687ab436eSNaman Padhiar icnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n", 286787ab436eSNaman Padhiar ret); 286887ab436eSNaman Padhiar goto out; 286987ab436eSNaman Padhiar } 287087ab436eSNaman Padhiar 287187ab436eSNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 287287ab436eSNaman Padhiar if (ret < 0) { 287387ab436eSNaman Padhiar icnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n", 287487ab436eSNaman Padhiar ret); 287587ab436eSNaman Padhiar goto out; 287687ab436eSNaman Padhiar } 287787ab436eSNaman Padhiar 287887ab436eSNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 287987ab436eSNaman Padhiar icnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n", 288087ab436eSNaman Padhiar resp->resp.result, resp->resp.error); 288187ab436eSNaman Padhiar ret = -resp->resp.result; 288287ab436eSNaman Padhiar goto out; 288387ab436eSNaman Padhiar } 288487ab436eSNaman Padhiar ret = 0; 288587ab436eSNaman Padhiar out: 288687ab436eSNaman Padhiar kfree(req); 288787ab436eSNaman Padhiar kfree(resp); 288887ab436eSNaman Padhiar return ret; 288987ab436eSNaman Padhiar } 289087ab436eSNaman Padhiar 289187ab436eSNaman Padhiar static int icnss_ims_wfc_call_twt_cfg_send_sync 289287ab436eSNaman Padhiar (struct icnss_priv *priv, 289387ab436eSNaman Padhiar const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg) 289487ab436eSNaman Padhiar { 289587ab436eSNaman Padhiar struct ims_private_service_wfc_call_twt_config_req_msg_v01 *req; 289687ab436eSNaman Padhiar struct ims_private_service_wfc_call_twt_config_rsp_msg_v01 *resp; 289787ab436eSNaman Padhiar struct qmi_txn txn; 289887ab436eSNaman Padhiar int ret = 0; 289987ab436eSNaman Padhiar 290087ab436eSNaman Padhiar if (!test_bit(ICNSS_IMS_CONNECTED, &priv->state)) { 290187ab436eSNaman Padhiar icnss_pr_err("Drop FW WFC indication as IMS QMI not connected\n"); 290287ab436eSNaman Padhiar return -EINVAL; 290387ab436eSNaman Padhiar } 290487ab436eSNaman Padhiar 290587ab436eSNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 290687ab436eSNaman Padhiar if (!req) 290787ab436eSNaman Padhiar return -ENOMEM; 290887ab436eSNaman Padhiar 290987ab436eSNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 291087ab436eSNaman Padhiar if (!resp) { 291187ab436eSNaman Padhiar kfree(req); 291287ab436eSNaman Padhiar return -ENOMEM; 291387ab436eSNaman Padhiar } 291487ab436eSNaman Padhiar 291587ab436eSNaman Padhiar req->twt_sta_start_valid = ind_msg->twt_sta_start_valid; 291687ab436eSNaman Padhiar req->twt_sta_start = ind_msg->twt_sta_start; 291787ab436eSNaman Padhiar req->twt_sta_int_valid = ind_msg->twt_sta_int_valid; 291887ab436eSNaman Padhiar req->twt_sta_int = ind_msg->twt_sta_int; 291987ab436eSNaman Padhiar req->twt_sta_upo_valid = ind_msg->twt_sta_upo_valid; 292087ab436eSNaman Padhiar req->twt_sta_upo = ind_msg->twt_sta_upo; 292187ab436eSNaman Padhiar req->twt_sta_sp_valid = ind_msg->twt_sta_sp_valid; 292287ab436eSNaman Padhiar req->twt_sta_sp = ind_msg->twt_sta_sp; 292387ab436eSNaman Padhiar req->twt_sta_dl_valid = req->twt_sta_dl_valid; 292487ab436eSNaman Padhiar req->twt_sta_dl = req->twt_sta_dl; 292587ab436eSNaman Padhiar req->twt_sta_config_changed_valid = 292687ab436eSNaman Padhiar ind_msg->twt_sta_config_changed_valid; 292787ab436eSNaman Padhiar req->twt_sta_config_changed = ind_msg->twt_sta_config_changed; 292887ab436eSNaman Padhiar 292987ab436eSNaman Padhiar icnss_pr_dbg("CNSS->IMS: TWT_CFG_REQ: state: 0x%lx\n", 293087ab436eSNaman Padhiar priv->state); 293187ab436eSNaman Padhiar 293287ab436eSNaman Padhiar ret = 293387ab436eSNaman Padhiar qmi_txn_init(&priv->ims_qmi, &txn, 293487ab436eSNaman Padhiar ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei, 293587ab436eSNaman Padhiar resp); 293687ab436eSNaman Padhiar if (ret < 0) { 293787ab436eSNaman Padhiar icnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Txn Init Err: %d\n", 293887ab436eSNaman Padhiar ret); 293987ab436eSNaman Padhiar goto out; 294087ab436eSNaman Padhiar } 294187ab436eSNaman Padhiar 294287ab436eSNaman Padhiar ret = 294387ab436eSNaman Padhiar qmi_send_request(&priv->ims_qmi, NULL, &txn, 294487ab436eSNaman Padhiar QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_V01, 294587ab436eSNaman Padhiar IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_MSG_V01_MAX_MSG_LEN, 294687ab436eSNaman Padhiar ims_private_service_wfc_call_twt_config_req_msg_v01_ei, req); 294787ab436eSNaman Padhiar if (ret < 0) { 294887ab436eSNaman Padhiar qmi_txn_cancel(&txn); 294987ab436eSNaman Padhiar icnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Send Err: %d\n", ret); 295087ab436eSNaman Padhiar goto out; 295187ab436eSNaman Padhiar } 295287ab436eSNaman Padhiar 295387ab436eSNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 295487ab436eSNaman Padhiar if (ret < 0) { 295587ab436eSNaman Padhiar icnss_pr_err("IMS->CNSS: TWT_CFG_RSP: QMI Wait Err: %d\n", ret); 295687ab436eSNaman Padhiar goto out; 295787ab436eSNaman Padhiar } 295887ab436eSNaman Padhiar 295987ab436eSNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 296087ab436eSNaman Padhiar icnss_pr_err("IMS->CNSS: TWT_CFG_RSP: Result: %d Err: %d\n", 296187ab436eSNaman Padhiar resp->resp.result, resp->resp.error); 296287ab436eSNaman Padhiar ret = -resp->resp.result; 296387ab436eSNaman Padhiar goto out; 296487ab436eSNaman Padhiar } 296587ab436eSNaman Padhiar ret = 0; 296687ab436eSNaman Padhiar out: 296787ab436eSNaman Padhiar kfree(req); 296887ab436eSNaman Padhiar kfree(resp); 296987ab436eSNaman Padhiar return ret; 297087ab436eSNaman Padhiar } 297187ab436eSNaman Padhiar 297287ab436eSNaman Padhiar int icnss_process_twt_cfg_ind_event(struct icnss_priv *priv, 297387ab436eSNaman Padhiar void *data) 297487ab436eSNaman Padhiar { 297587ab436eSNaman Padhiar int ret; 297687ab436eSNaman Padhiar struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data; 297787ab436eSNaman Padhiar 297887ab436eSNaman Padhiar ret = icnss_ims_wfc_call_twt_cfg_send_sync(priv, ind_msg); 297987ab436eSNaman Padhiar kfree(data); 298087ab436eSNaman Padhiar return ret; 298187ab436eSNaman Padhiar } 298287ab436eSNaman Padhiar 298387ab436eSNaman Padhiar static void icnss_wlfw_process_twt_cfg_ind(struct qmi_handle *qmi, 298487ab436eSNaman Padhiar struct sockaddr_qrtr *sq, 298587ab436eSNaman Padhiar struct qmi_txn *txn, 298687ab436eSNaman Padhiar const void *data) 298787ab436eSNaman Padhiar { 298887ab436eSNaman Padhiar struct icnss_priv *priv = 298987ab436eSNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 299087ab436eSNaman Padhiar const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data; 299187ab436eSNaman Padhiar struct wlfw_wfc_call_twt_config_ind_msg_v01 *event_data; 299287ab436eSNaman Padhiar 299387ab436eSNaman Padhiar if (!txn) { 299487ab436eSNaman Padhiar icnss_pr_err("FW->CNSS: TWT_CFG_IND: Spurious indication\n"); 299587ab436eSNaman Padhiar return; 299687ab436eSNaman Padhiar } 299787ab436eSNaman Padhiar 299887ab436eSNaman Padhiar if (!ind_msg) { 299987ab436eSNaman Padhiar icnss_pr_err("FW->CNSS: TWT_CFG_IND: Invalid indication\n"); 300087ab436eSNaman Padhiar return; 300187ab436eSNaman Padhiar } 300287ab436eSNaman Padhiar icnss_pr_dbg("FW->CNSS: TWT_CFG_IND: %x %llx, %x %x, %x %x, %x %x, %x %x, %x %x\n", 300387ab436eSNaman Padhiar ind_msg->twt_sta_start_valid, ind_msg->twt_sta_start, 300487ab436eSNaman Padhiar ind_msg->twt_sta_int_valid, ind_msg->twt_sta_int, 300587ab436eSNaman Padhiar ind_msg->twt_sta_upo_valid, ind_msg->twt_sta_upo, 300687ab436eSNaman Padhiar ind_msg->twt_sta_sp_valid, ind_msg->twt_sta_sp, 300787ab436eSNaman Padhiar ind_msg->twt_sta_dl_valid, ind_msg->twt_sta_dl, 300887ab436eSNaman Padhiar ind_msg->twt_sta_config_changed_valid, 300987ab436eSNaman Padhiar ind_msg->twt_sta_config_changed); 301087ab436eSNaman Padhiar 301187ab436eSNaman Padhiar event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL); 301287ab436eSNaman Padhiar if (!event_data) 301387ab436eSNaman Padhiar return; 301487ab436eSNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND, 0, 301587ab436eSNaman Padhiar event_data); 301687ab436eSNaman Padhiar } 301787ab436eSNaman Padhiar 30183983bc45SNaman Padhiar static struct qmi_msg_handler wlfw_msg_handlers[] = { 30193983bc45SNaman Padhiar { 30203983bc45SNaman Padhiar .type = QMI_INDICATION, 30213983bc45SNaman Padhiar .msg_id = QMI_WLFW_FW_READY_IND_V01, 30223983bc45SNaman Padhiar .ei = wlfw_fw_ready_ind_msg_v01_ei, 30233983bc45SNaman Padhiar .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01), 30243983bc45SNaman Padhiar .fn = fw_ready_ind_cb 30253983bc45SNaman Padhiar }, 30263983bc45SNaman Padhiar { 30273983bc45SNaman Padhiar .type = QMI_INDICATION, 30283983bc45SNaman Padhiar .msg_id = QMI_WLFW_MSA_READY_IND_V01, 30293983bc45SNaman Padhiar .ei = wlfw_msa_ready_ind_msg_v01_ei, 30303983bc45SNaman Padhiar .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01), 30313983bc45SNaman Padhiar .fn = msa_ready_ind_cb 30323983bc45SNaman Padhiar }, 30333983bc45SNaman Padhiar { 30343983bc45SNaman Padhiar .type = QMI_INDICATION, 30353983bc45SNaman Padhiar .msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01, 30363983bc45SNaman Padhiar .ei = wlfw_pin_connect_result_ind_msg_v01_ei, 30373983bc45SNaman Padhiar .decoded_size = 30383983bc45SNaman Padhiar sizeof(struct wlfw_pin_connect_result_ind_msg_v01), 30393983bc45SNaman Padhiar .fn = pin_connect_result_ind_cb 30403983bc45SNaman Padhiar }, 30413983bc45SNaman Padhiar { 30423983bc45SNaman Padhiar .type = QMI_INDICATION, 30433983bc45SNaman Padhiar .msg_id = QMI_WLFW_REJUVENATE_IND_V01, 30443983bc45SNaman Padhiar .ei = wlfw_rejuvenate_ind_msg_v01_ei, 30453983bc45SNaman Padhiar .decoded_size = sizeof(struct wlfw_rejuvenate_ind_msg_v01), 30463983bc45SNaman Padhiar .fn = rejuvenate_ind_cb 30473983bc45SNaman Padhiar }, 30483983bc45SNaman Padhiar { 30493983bc45SNaman Padhiar .type = QMI_INDICATION, 30503983bc45SNaman Padhiar .msg_id = QMI_WLFW_CAL_DONE_IND_V01, 30513983bc45SNaman Padhiar .ei = wlfw_cal_done_ind_msg_v01_ei, 30523983bc45SNaman Padhiar .decoded_size = sizeof(struct wlfw_cal_done_ind_msg_v01), 30533983bc45SNaman Padhiar .fn = cal_done_ind_cb 30543983bc45SNaman Padhiar }, 30553983bc45SNaman Padhiar { 30563983bc45SNaman Padhiar .type = QMI_INDICATION, 30573983bc45SNaman Padhiar .msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01, 30583983bc45SNaman Padhiar .ei = wlfw_fw_init_done_ind_msg_v01_ei, 30593983bc45SNaman Padhiar .decoded_size = sizeof(struct wlfw_fw_init_done_ind_msg_v01), 30603983bc45SNaman Padhiar .fn = fw_init_done_ind_cb 30613983bc45SNaman Padhiar }, 30623983bc45SNaman Padhiar { 30633983bc45SNaman Padhiar .type = QMI_INDICATION, 30643983bc45SNaman Padhiar .msg_id = QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01, 30653983bc45SNaman Padhiar .ei = wlfw_qdss_trace_req_mem_ind_msg_v01_ei, 30663983bc45SNaman Padhiar .decoded_size = 30673983bc45SNaman Padhiar sizeof(struct wlfw_qdss_trace_req_mem_ind_msg_v01), 30683983bc45SNaman Padhiar .fn = wlfw_qdss_trace_req_mem_ind_cb 30693983bc45SNaman Padhiar }, 30703983bc45SNaman Padhiar { 30713983bc45SNaman Padhiar .type = QMI_INDICATION, 30723983bc45SNaman Padhiar .msg_id = QMI_WLFW_QDSS_TRACE_SAVE_IND_V01, 30733983bc45SNaman Padhiar .ei = wlfw_qdss_trace_save_ind_msg_v01_ei, 30743983bc45SNaman Padhiar .decoded_size = 30753983bc45SNaman Padhiar sizeof(struct wlfw_qdss_trace_save_ind_msg_v01), 30763983bc45SNaman Padhiar .fn = wlfw_qdss_trace_save_ind_cb 30773983bc45SNaman Padhiar }, 30783983bc45SNaman Padhiar { 30793983bc45SNaman Padhiar .type = QMI_INDICATION, 30803983bc45SNaman Padhiar .msg_id = QMI_WLFW_QDSS_TRACE_FREE_IND_V01, 30813983bc45SNaman Padhiar .ei = wlfw_qdss_trace_free_ind_msg_v01_ei, 30823983bc45SNaman Padhiar .decoded_size = 30833983bc45SNaman Padhiar sizeof(struct wlfw_qdss_trace_free_ind_msg_v01), 30843983bc45SNaman Padhiar .fn = wlfw_qdss_trace_free_ind_cb 30853983bc45SNaman Padhiar }, 30863983bc45SNaman Padhiar { 30873983bc45SNaman Padhiar .type = QMI_INDICATION, 30883983bc45SNaman Padhiar .msg_id = QMI_WLFW_RESPOND_GET_INFO_IND_V01, 30893983bc45SNaman Padhiar .ei = wlfw_respond_get_info_ind_msg_v01_ei, 30903983bc45SNaman Padhiar .decoded_size = 30913983bc45SNaman Padhiar sizeof(struct wlfw_respond_get_info_ind_msg_v01), 30923983bc45SNaman Padhiar .fn = icnss_wlfw_respond_get_info_ind_cb 30933983bc45SNaman Padhiar }, 30943983bc45SNaman Padhiar { 30953983bc45SNaman Padhiar .type = QMI_INDICATION, 30963983bc45SNaman Padhiar .msg_id = QMI_WLFW_M3_DUMP_UPLOAD_SEGMENTS_REQ_IND_V01, 30973983bc45SNaman Padhiar .ei = wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei, 30983983bc45SNaman Padhiar .decoded_size = 30993983bc45SNaman Padhiar sizeof(struct wlfw_m3_dump_upload_segments_req_ind_msg_v01), 31003983bc45SNaman Padhiar .fn = icnss_wlfw_m3_dump_upload_segs_req_ind_cb 31013983bc45SNaman Padhiar }, 310287ab436eSNaman Padhiar { 310387ab436eSNaman Padhiar .type = QMI_INDICATION, 310487ab436eSNaman Padhiar .msg_id = QMI_WLFW_WFC_CALL_TWT_CONFIG_IND_V01, 310587ab436eSNaman Padhiar .ei = wlfw_wfc_call_twt_config_ind_msg_v01_ei, 310687ab436eSNaman Padhiar .decoded_size = 310787ab436eSNaman Padhiar sizeof(struct wlfw_wfc_call_twt_config_ind_msg_v01), 310887ab436eSNaman Padhiar .fn = icnss_wlfw_process_twt_cfg_ind 310987ab436eSNaman Padhiar }, 31103983bc45SNaman Padhiar {} 31113983bc45SNaman Padhiar }; 31123983bc45SNaman Padhiar 31133983bc45SNaman Padhiar int icnss_connect_to_fw_server(struct icnss_priv *priv, void *data) 31143983bc45SNaman Padhiar { 31153983bc45SNaman Padhiar struct icnss_event_server_arrive_data *event_data = data; 31163983bc45SNaman Padhiar struct qmi_handle *qmi = &priv->qmi; 31173983bc45SNaman Padhiar struct sockaddr_qrtr sq = { 0 }; 31183983bc45SNaman Padhiar int ret = 0; 31193983bc45SNaman Padhiar 31203983bc45SNaman Padhiar if (!priv) { 31213983bc45SNaman Padhiar ret = -ENODEV; 31223983bc45SNaman Padhiar goto out; 31233983bc45SNaman Padhiar } 31243983bc45SNaman Padhiar 31253983bc45SNaman Padhiar sq.sq_family = AF_QIPCRTR; 31263983bc45SNaman Padhiar sq.sq_node = event_data->node; 31273983bc45SNaman Padhiar sq.sq_port = event_data->port; 31283983bc45SNaman Padhiar ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); 31293983bc45SNaman Padhiar if (ret < 0) { 31303983bc45SNaman Padhiar icnss_pr_err("Fail to connect to remote service port\n"); 31313983bc45SNaman Padhiar goto out; 31323983bc45SNaman Padhiar } 31333983bc45SNaman Padhiar 31343983bc45SNaman Padhiar icnss_pr_info("QMI Server Connected: state: 0x%lx\n", priv->state); 31353983bc45SNaman Padhiar 31363983bc45SNaman Padhiar kfree(data); 31373983bc45SNaman Padhiar return 0; 31383983bc45SNaman Padhiar 31393983bc45SNaman Padhiar out: 31403983bc45SNaman Padhiar kfree(data); 31413983bc45SNaman Padhiar ICNSS_ASSERT(0); 31423983bc45SNaman Padhiar return ret; 31433983bc45SNaman Padhiar } 31443983bc45SNaman Padhiar 31453983bc45SNaman Padhiar int icnss_clear_server(struct icnss_priv *priv) 31463983bc45SNaman Padhiar { 31473983bc45SNaman Padhiar int ret; 31483983bc45SNaman Padhiar 31493983bc45SNaman Padhiar if (!priv) 31503983bc45SNaman Padhiar return -ENODEV; 31513983bc45SNaman Padhiar 31523983bc45SNaman Padhiar icnss_pr_info("QMI Service Disconnected: 0x%lx\n", priv->state); 31533983bc45SNaman Padhiar clear_bit(ICNSS_WLFW_CONNECTED, &priv->state); 31543983bc45SNaman Padhiar 31553983bc45SNaman Padhiar icnss_unregister_fw_service(priv); 31563983bc45SNaman Padhiar 31573983bc45SNaman Padhiar clear_bit(ICNSS_DEL_SERVER, &priv->state); 31583983bc45SNaman Padhiar 31593983bc45SNaman Padhiar ret = icnss_register_fw_service(priv); 31603983bc45SNaman Padhiar if (ret < 0) { 31613983bc45SNaman Padhiar icnss_pr_err("WLFW server registration failed\n"); 31623983bc45SNaman Padhiar ICNSS_ASSERT(0); 31633983bc45SNaman Padhiar } 31643983bc45SNaman Padhiar 31653983bc45SNaman Padhiar return 0; 31663983bc45SNaman Padhiar } 31673983bc45SNaman Padhiar 31683983bc45SNaman Padhiar static int wlfw_new_server(struct qmi_handle *qmi, 31693983bc45SNaman Padhiar struct qmi_service *service) 31703983bc45SNaman Padhiar { 31713983bc45SNaman Padhiar struct icnss_priv *priv = 31723983bc45SNaman Padhiar container_of(qmi, struct icnss_priv, qmi); 31733983bc45SNaman Padhiar struct icnss_event_server_arrive_data *event_data; 31743983bc45SNaman Padhiar 31753983bc45SNaman Padhiar if (priv && test_bit(ICNSS_DEL_SERVER, &priv->state)) { 31763983bc45SNaman Padhiar icnss_pr_info("WLFW server delete in progress, Ignore server arrive: 0x%lx\n", 31773983bc45SNaman Padhiar priv->state); 31783983bc45SNaman Padhiar return 0; 31793983bc45SNaman Padhiar } 31803983bc45SNaman Padhiar 31813983bc45SNaman Padhiar icnss_pr_dbg("WLFW server arrive: node %u port %u\n", 31823983bc45SNaman Padhiar service->node, service->port); 31833983bc45SNaman Padhiar 31843983bc45SNaman Padhiar event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); 31853983bc45SNaman Padhiar if (event_data == NULL) 31863983bc45SNaman Padhiar return -ENOMEM; 31873983bc45SNaman Padhiar 31883983bc45SNaman Padhiar event_data->node = service->node; 31893983bc45SNaman Padhiar event_data->port = service->port; 31903983bc45SNaman Padhiar 31913983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_SERVER_ARRIVE, 31923983bc45SNaman Padhiar 0, event_data); 31933983bc45SNaman Padhiar 31943983bc45SNaman Padhiar return 0; 31953983bc45SNaman Padhiar } 31963983bc45SNaman Padhiar 31973983bc45SNaman Padhiar static void wlfw_del_server(struct qmi_handle *qmi, 31983983bc45SNaman Padhiar struct qmi_service *service) 31993983bc45SNaman Padhiar { 32003983bc45SNaman Padhiar struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi); 32013983bc45SNaman Padhiar 32023983bc45SNaman Padhiar if (priv && test_bit(ICNSS_DEL_SERVER, &priv->state)) { 3203c0e7f285SSandeep Singh icnss_pr_info("WLFW server delete / icnss remove in progress, Ignore server delete: 0x%lx\n", 32043983bc45SNaman Padhiar priv->state); 32053983bc45SNaman Padhiar return; 32063983bc45SNaman Padhiar } 32073983bc45SNaman Padhiar 32083983bc45SNaman Padhiar icnss_pr_dbg("WLFW server delete\n"); 32093983bc45SNaman Padhiar 32103983bc45SNaman Padhiar if (priv) { 32113983bc45SNaman Padhiar set_bit(ICNSS_DEL_SERVER, &priv->state); 32123983bc45SNaman Padhiar set_bit(ICNSS_FW_DOWN, &priv->state); 32133983bc45SNaman Padhiar icnss_ignore_fw_timeout(true); 32143983bc45SNaman Padhiar } 32153983bc45SNaman Padhiar 32163983bc45SNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_SERVER_EXIT, 32173983bc45SNaman Padhiar 0, NULL); 32183983bc45SNaman Padhiar } 32193983bc45SNaman Padhiar 32203983bc45SNaman Padhiar static struct qmi_ops wlfw_qmi_ops = { 32213983bc45SNaman Padhiar .new_server = wlfw_new_server, 32223983bc45SNaman Padhiar .del_server = wlfw_del_server, 32233983bc45SNaman Padhiar }; 32243983bc45SNaman Padhiar 32253983bc45SNaman Padhiar int icnss_register_fw_service(struct icnss_priv *priv) 32263983bc45SNaman Padhiar { 32273983bc45SNaman Padhiar int ret; 32283983bc45SNaman Padhiar 32293983bc45SNaman Padhiar ret = qmi_handle_init(&priv->qmi, 32303983bc45SNaman Padhiar WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, 32313983bc45SNaman Padhiar &wlfw_qmi_ops, wlfw_msg_handlers); 32323983bc45SNaman Padhiar if (ret < 0) 32333983bc45SNaman Padhiar return ret; 32343983bc45SNaman Padhiar 3235aec346c6SSandeep Singh if (priv->device_id == WCN6750_DEVICE_ID || 3236aec346c6SSandeep Singh priv->device_id == WCN6450_DEVICE_ID) 32373983bc45SNaman Padhiar ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01, 32383983bc45SNaman Padhiar WLFW_SERVICE_VERS_V01, 32393983bc45SNaman Padhiar WLFW_SERVICE_WCN_INS_ID_V01); 32403983bc45SNaman Padhiar else 32413983bc45SNaman Padhiar ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01, 32423983bc45SNaman Padhiar WLFW_SERVICE_VERS_V01, 32433983bc45SNaman Padhiar WLFW_SERVICE_INS_ID_V01); 32443983bc45SNaman Padhiar return ret; 32453983bc45SNaman Padhiar } 32463983bc45SNaman Padhiar 32473983bc45SNaman Padhiar void icnss_unregister_fw_service(struct icnss_priv *priv) 32483983bc45SNaman Padhiar { 32493f3761e1SSandeep Singh set_bit(ICNSS_DEL_SERVER, &priv->state); 32503983bc45SNaman Padhiar qmi_handle_release(&priv->qmi); 32513983bc45SNaman Padhiar } 32523983bc45SNaman Padhiar 32533983bc45SNaman Padhiar int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv, 32543983bc45SNaman Padhiar struct icnss_wlan_enable_cfg *config, 32553983bc45SNaman Padhiar enum icnss_driver_mode mode, 32563983bc45SNaman Padhiar const char *host_version) 32573983bc45SNaman Padhiar { 32583983bc45SNaman Padhiar struct wlfw_wlan_cfg_req_msg_v01 req; 32593983bc45SNaman Padhiar u32 i; 32603983bc45SNaman Padhiar int ret; 32613983bc45SNaman Padhiar 32623983bc45SNaman Padhiar icnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n", 32633983bc45SNaman Padhiar mode, config, host_version); 32643983bc45SNaman Padhiar 32653983bc45SNaman Padhiar memset(&req, 0, sizeof(req)); 32663983bc45SNaman Padhiar 32673983bc45SNaman Padhiar if (mode == ICNSS_WALTEST || mode == ICNSS_CCPM) 32683983bc45SNaman Padhiar goto skip; 32693983bc45SNaman Padhiar 32703983bc45SNaman Padhiar if (!config || !host_version) { 32713983bc45SNaman Padhiar icnss_pr_err("Invalid cfg pointer, config: %pK, host_version: %pK\n", 32723983bc45SNaman Padhiar config, host_version); 32733983bc45SNaman Padhiar ret = -EINVAL; 32743983bc45SNaman Padhiar goto out; 32753983bc45SNaman Padhiar } 32763983bc45SNaman Padhiar 32773983bc45SNaman Padhiar req.host_version_valid = 1; 32783983bc45SNaman Padhiar strlcpy(req.host_version, host_version, 32793983bc45SNaman Padhiar WLFW_MAX_STR_LEN + 1); 32803983bc45SNaman Padhiar 32813983bc45SNaman Padhiar req.tgt_cfg_valid = 1; 32823983bc45SNaman Padhiar if (config->num_ce_tgt_cfg > WLFW_MAX_NUM_CE) 32833983bc45SNaman Padhiar req.tgt_cfg_len = WLFW_MAX_NUM_CE; 32843983bc45SNaman Padhiar else 32853983bc45SNaman Padhiar req.tgt_cfg_len = config->num_ce_tgt_cfg; 32863983bc45SNaman Padhiar for (i = 0; i < req.tgt_cfg_len; i++) { 32873983bc45SNaman Padhiar req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; 32883983bc45SNaman Padhiar req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; 32893983bc45SNaman Padhiar req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; 32903983bc45SNaman Padhiar req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; 32913983bc45SNaman Padhiar req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; 32923983bc45SNaman Padhiar } 32933983bc45SNaman Padhiar 32943983bc45SNaman Padhiar req.svc_cfg_valid = 1; 32953983bc45SNaman Padhiar if (config->num_ce_svc_pipe_cfg > WLFW_MAX_NUM_SVC) 32963983bc45SNaman Padhiar req.svc_cfg_len = WLFW_MAX_NUM_SVC; 32973983bc45SNaman Padhiar else 32983983bc45SNaman Padhiar req.svc_cfg_len = config->num_ce_svc_pipe_cfg; 32993983bc45SNaman Padhiar for (i = 0; i < req.svc_cfg_len; i++) { 33003983bc45SNaman Padhiar req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; 33013983bc45SNaman Padhiar req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; 33023983bc45SNaman Padhiar req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; 33033983bc45SNaman Padhiar } 33043983bc45SNaman Padhiar 33053983bc45SNaman Padhiar if (priv->device_id == WCN6750_DEVICE_ID) { 33063983bc45SNaman Padhiar req.shadow_reg_v2_valid = 1; 33073983bc45SNaman Padhiar if (config->num_shadow_reg_v2_cfg > 33083983bc45SNaman Padhiar QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01) 33093983bc45SNaman Padhiar req.shadow_reg_v2_len = 33103983bc45SNaman Padhiar QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01; 33113983bc45SNaman Padhiar else 33123983bc45SNaman Padhiar req.shadow_reg_v2_len = config->num_shadow_reg_v2_cfg; 33133983bc45SNaman Padhiar 33143983bc45SNaman Padhiar memcpy(req.shadow_reg_v2, config->shadow_reg_v2_cfg, 33153983bc45SNaman Padhiar sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) * 33163983bc45SNaman Padhiar req.shadow_reg_v2_len); 33173983bc45SNaman Padhiar } else if (priv->device_id == ADRASTEA_DEVICE_ID) { 33183983bc45SNaman Padhiar req.shadow_reg_valid = 1; 33193983bc45SNaman Padhiar if (config->num_shadow_reg_cfg > 33203983bc45SNaman Padhiar QMI_WLFW_MAX_NUM_SHADOW_REG_V01) 33213983bc45SNaman Padhiar req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; 33223983bc45SNaman Padhiar else 33233983bc45SNaman Padhiar req.shadow_reg_len = config->num_shadow_reg_cfg; 33243983bc45SNaman Padhiar 33253983bc45SNaman Padhiar memcpy(req.shadow_reg, config->shadow_reg_cfg, 33263983bc45SNaman Padhiar sizeof(struct wlfw_msi_cfg_s_v01) * req.shadow_reg_len); 3327aec346c6SSandeep Singh } else if (priv->device_id == WCN6450_DEVICE_ID) { 3328aec346c6SSandeep Singh req.shadow_reg_v3_valid = 1; 3329aec346c6SSandeep Singh if (config->num_shadow_reg_v3_cfg > 3330aec346c6SSandeep Singh MAX_NUM_SHADOW_REG_V3) 3331aec346c6SSandeep Singh req.shadow_reg_v3_len = MAX_NUM_SHADOW_REG_V3; 3332aec346c6SSandeep Singh else 3333aec346c6SSandeep Singh req.shadow_reg_v3_len = config->num_shadow_reg_v3_cfg; 3334aec346c6SSandeep Singh 3335aec346c6SSandeep Singh memcpy(req.shadow_reg_v3, config->shadow_reg_v3_cfg, 3336aec346c6SSandeep Singh sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01) 3337aec346c6SSandeep Singh * req.shadow_reg_v3_len); 33383983bc45SNaman Padhiar } 33393983bc45SNaman Padhiar 33403983bc45SNaman Padhiar ret = wlfw_wlan_cfg_send_sync_msg(priv, &req); 33413983bc45SNaman Padhiar if (ret) 33423983bc45SNaman Padhiar goto out; 33433983bc45SNaman Padhiar skip: 33443983bc45SNaman Padhiar ret = wlfw_wlan_mode_send_sync_msg(priv, 33453983bc45SNaman Padhiar (enum wlfw_driver_mode_enum_v01)mode); 33463983bc45SNaman Padhiar out: 33473983bc45SNaman Padhiar if (test_bit(SKIP_QMI, &priv->ctrl_params.quirks)) 33483983bc45SNaman Padhiar ret = 0; 33493983bc45SNaman Padhiar 33503983bc45SNaman Padhiar return ret; 33513983bc45SNaman Padhiar } 33523983bc45SNaman Padhiar 33533983bc45SNaman Padhiar int icnss_send_wlan_disable_to_fw(struct icnss_priv *priv) 33543983bc45SNaman Padhiar { 33553983bc45SNaman Padhiar enum wlfw_driver_mode_enum_v01 mode = QMI_WLFW_OFF_V01; 33563983bc45SNaman Padhiar 33573983bc45SNaman Padhiar return wlfw_wlan_mode_send_sync_msg(priv, mode); 33583983bc45SNaman Padhiar } 33593983bc45SNaman Padhiar 33603983bc45SNaman Padhiar #ifdef CONFIG_ICNSS2_DEBUG 33613983bc45SNaman Padhiar static inline u32 icnss_get_host_build_type(void) 33623983bc45SNaman Padhiar { 33633983bc45SNaman Padhiar return QMI_HOST_BUILD_TYPE_PRIMARY_V01; 33643983bc45SNaman Padhiar } 33653983bc45SNaman Padhiar #else 33663983bc45SNaman Padhiar static inline u32 icnss_get_host_build_type(void) 33673983bc45SNaman Padhiar { 33683983bc45SNaman Padhiar return QMI_HOST_BUILD_TYPE_SECONDARY_V01; 33693983bc45SNaman Padhiar } 33703983bc45SNaman Padhiar #endif 33713983bc45SNaman Padhiar 33723983bc45SNaman Padhiar int wlfw_host_cap_send_sync(struct icnss_priv *priv) 33733983bc45SNaman Padhiar { 33743983bc45SNaman Padhiar struct wlfw_host_cap_req_msg_v01 *req; 33753983bc45SNaman Padhiar struct wlfw_host_cap_resp_msg_v01 *resp; 33763983bc45SNaman Padhiar struct qmi_txn txn; 33773983bc45SNaman Padhiar int ddr_type; 33783983bc45SNaman Padhiar u32 gpio; 33793983bc45SNaman Padhiar int ret = 0; 33803983bc45SNaman Padhiar u64 iova_start = 0, iova_size = 0, 33813983bc45SNaman Padhiar iova_ipa_start = 0, iova_ipa_size = 0; 33823983bc45SNaman Padhiar 33833983bc45SNaman Padhiar icnss_pr_dbg("Sending host capability message, state: 0x%lx\n", 33843983bc45SNaman Padhiar priv->state); 33853983bc45SNaman Padhiar 33863983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 33873983bc45SNaman Padhiar if (!req) 33883983bc45SNaman Padhiar return -ENOMEM; 33893983bc45SNaman Padhiar 33903983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 33913983bc45SNaman Padhiar if (!resp) { 33923983bc45SNaman Padhiar kfree(req); 33933983bc45SNaman Padhiar return -ENOMEM; 33943983bc45SNaman Padhiar } 33953983bc45SNaman Padhiar 33963983bc45SNaman Padhiar req->num_clients_valid = 1; 33973983bc45SNaman Padhiar req->num_clients = 1; 33983983bc45SNaman Padhiar 33993983bc45SNaman Padhiar req->bdf_support_valid = 1; 34003983bc45SNaman Padhiar req->bdf_support = 1; 34013983bc45SNaman Padhiar 34023983bc45SNaman Padhiar req->cal_done_valid = 1; 34033983bc45SNaman Padhiar req->cal_done = priv->cal_done; 34043983bc45SNaman Padhiar icnss_pr_dbg("Calibration done is %d\n", priv->cal_done); 34053983bc45SNaman Padhiar 34063983bc45SNaman Padhiar if (priv->smmu_s1_enable && 34073983bc45SNaman Padhiar !icnss_get_iova(priv, &iova_start, &iova_size) && 34083983bc45SNaman Padhiar !icnss_get_iova_ipa(priv, &iova_ipa_start, 34093983bc45SNaman Padhiar &iova_ipa_size)) { 34103983bc45SNaman Padhiar req->ddr_range_valid = 1; 34113983bc45SNaman Padhiar req->ddr_range[0].start = iova_start; 34123983bc45SNaman Padhiar req->ddr_range[0].size = iova_size + iova_ipa_size; 34133983bc45SNaman Padhiar req->ddr_range[1].start = priv->msa_pa; 34143983bc45SNaman Padhiar req->ddr_range[1].size = priv->msa_mem_size; 34153983bc45SNaman Padhiar icnss_pr_dbg("Sending iova starting 0x%llx with size 0x%llx\n", 34163983bc45SNaman Padhiar req->ddr_range[0].start, req->ddr_range[0].size); 34173983bc45SNaman Padhiar icnss_pr_dbg("Sending msa starting 0x%llx with size 0x%llx\n", 34183983bc45SNaman Padhiar req->ddr_range[1].start, req->ddr_range[1].size); 34193983bc45SNaman Padhiar } 34203983bc45SNaman Padhiar 34213983bc45SNaman Padhiar req->host_build_type_valid = 1; 34223983bc45SNaman Padhiar req->host_build_type = icnss_get_host_build_type(); 34233983bc45SNaman Padhiar 34243983bc45SNaman Padhiar if (priv->wlan_en_delay_ms >= 100) { 34253983bc45SNaman Padhiar icnss_pr_dbg("Setting WLAN_EN delay: %d ms\n", 34263983bc45SNaman Padhiar priv->wlan_en_delay_ms); 34273983bc45SNaman Padhiar req->wlan_enable_delay_valid = 1; 34283983bc45SNaman Padhiar req->wlan_enable_delay = priv->wlan_en_delay_ms; 34293983bc45SNaman Padhiar } 34303983bc45SNaman Padhiar 34313983bc45SNaman Padhiar /* ddr_type = 7(LPDDR4) and 8(LPDDR5) */ 34323983bc45SNaman Padhiar ddr_type = of_fdt_get_ddrtype(); 34333983bc45SNaman Padhiar if (ddr_type > 0) { 34343983bc45SNaman Padhiar icnss_pr_dbg("DDR Type: %d\n", ddr_type); 34353983bc45SNaman Padhiar req->ddr_type_valid = 1; 34363983bc45SNaman Padhiar req->ddr_type = ddr_type; 34373983bc45SNaman Padhiar } 34383983bc45SNaman Padhiar 34393983bc45SNaman Padhiar ret = of_property_read_u32(priv->pdev->dev.of_node, "wlan-en-gpio", 34403983bc45SNaman Padhiar &gpio); 34413983bc45SNaman Padhiar if (!ret) { 34423983bc45SNaman Padhiar icnss_pr_dbg("WLAN_EN_GPIO modified through DT: %d\n", gpio); 34433983bc45SNaman Padhiar req->gpio_info_valid = 1; 34443983bc45SNaman Padhiar req->gpio_info[WLAN_EN_GPIO_V01] = gpio; 34453983bc45SNaman Padhiar } else { 34463983bc45SNaman Padhiar req->gpio_info[WLAN_EN_GPIO_V01] = 0xFFFF; 34473983bc45SNaman Padhiar } 34483983bc45SNaman Padhiar 34493983bc45SNaman Padhiar ret = of_property_read_u32(priv->pdev->dev.of_node, "bt-en-gpio", 34503983bc45SNaman Padhiar &gpio); 34513983bc45SNaman Padhiar if (!ret) { 34523983bc45SNaman Padhiar icnss_pr_dbg("BT_EN_GPIO modified through DT: %d\n", gpio); 34533983bc45SNaman Padhiar req->gpio_info_valid = 1; 34543983bc45SNaman Padhiar req->gpio_info[BT_EN_GPIO_V01] = gpio; 34553983bc45SNaman Padhiar } else { 34563983bc45SNaman Padhiar req->gpio_info[BT_EN_GPIO_V01] = 0xFFFF; 34573983bc45SNaman Padhiar } 34583983bc45SNaman Padhiar 34593983bc45SNaman Padhiar ret = of_property_read_u32(priv->pdev->dev.of_node, "host-sol-gpio", 34603983bc45SNaman Padhiar &gpio); 34613983bc45SNaman Padhiar if (!ret) { 34623983bc45SNaman Padhiar icnss_pr_dbg("HOST_SOL_GPIO modified through DT: %d\n", gpio); 34633983bc45SNaman Padhiar req->gpio_info_valid = 1; 34643983bc45SNaman Padhiar req->gpio_info[HOST_SOL_GPIO_V01] = gpio; 34653983bc45SNaman Padhiar } else { 34663983bc45SNaman Padhiar req->gpio_info[HOST_SOL_GPIO_V01] = 0xFFFF; 34673983bc45SNaman Padhiar } 34683983bc45SNaman Padhiar 34693983bc45SNaman Padhiar ret = of_property_read_u32(priv->pdev->dev.of_node, "target-sol-gpio", 34703983bc45SNaman Padhiar &gpio); 34713983bc45SNaman Padhiar if (!ret) { 34723983bc45SNaman Padhiar icnss_pr_dbg("TARGET_SOL_GPIO modified through DT: %d\n", gpio); 34733983bc45SNaman Padhiar req->gpio_info_valid = 1; 34743983bc45SNaman Padhiar req->gpio_info[TARGET_SOL_GPIO_V01] = gpio; 34753983bc45SNaman Padhiar } else { 34763983bc45SNaman Padhiar req->gpio_info[TARGET_SOL_GPIO_V01] = 0xFFFF; 34773983bc45SNaman Padhiar } 34783983bc45SNaman Padhiar 34793983bc45SNaman Padhiar req->gpio_info_len = GPIO_TYPE_MAX_V01; 34803983bc45SNaman Padhiar 34813983bc45SNaman Padhiar ret = qmi_txn_init(&priv->qmi, &txn, 34823983bc45SNaman Padhiar wlfw_host_cap_resp_msg_v01_ei, resp); 34833983bc45SNaman Padhiar if (ret < 0) { 34843983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for host capability request, err: %d\n", 34853983bc45SNaman Padhiar ret); 34863983bc45SNaman Padhiar goto out; 34873983bc45SNaman Padhiar } 34883983bc45SNaman Padhiar 34893983bc45SNaman Padhiar ret = qmi_send_request(&priv->qmi, NULL, &txn, 34903983bc45SNaman Padhiar QMI_WLFW_HOST_CAP_REQ_V01, 34913983bc45SNaman Padhiar WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, 34923983bc45SNaman Padhiar wlfw_host_cap_req_msg_v01_ei, req); 34933983bc45SNaman Padhiar if (ret < 0) { 34943983bc45SNaman Padhiar qmi_txn_cancel(&txn); 34953983bc45SNaman Padhiar icnss_pr_err("Failed to send host capability request, err: %d\n", 34963983bc45SNaman Padhiar ret); 34973983bc45SNaman Padhiar goto out; 34983983bc45SNaman Padhiar } 34993983bc45SNaman Padhiar 35003983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 35013983bc45SNaman Padhiar if (ret < 0) { 35023983bc45SNaman Padhiar icnss_pr_err("Failed to wait for response of host capability request, err: %d\n", 35033983bc45SNaman Padhiar ret); 35043983bc45SNaman Padhiar goto out; 35053983bc45SNaman Padhiar } 35063983bc45SNaman Padhiar 35073983bc45SNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 35083983bc45SNaman Padhiar icnss_pr_err("Host capability request failed, result: %d, err: %d\n", 35093983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 35103983bc45SNaman Padhiar ret = -resp->resp.result; 35113983bc45SNaman Padhiar goto out; 35123983bc45SNaman Padhiar } 35133983bc45SNaman Padhiar 35143983bc45SNaman Padhiar kfree(req); 35153983bc45SNaman Padhiar kfree(resp); 35163983bc45SNaman Padhiar return 0; 35173983bc45SNaman Padhiar 35183983bc45SNaman Padhiar out: 35193983bc45SNaman Padhiar ICNSS_QMI_ASSERT(); 35203983bc45SNaman Padhiar kfree(req); 35213983bc45SNaman Padhiar kfree(resp); 35223983bc45SNaman Padhiar return ret; 35233983bc45SNaman Padhiar } 35243983bc45SNaman Padhiar 35253983bc45SNaman Padhiar int icnss_wlfw_get_info_send_sync(struct icnss_priv *plat_priv, int type, 35263983bc45SNaman Padhiar void *cmd, int cmd_len) 35273983bc45SNaman Padhiar { 35283983bc45SNaman Padhiar struct wlfw_get_info_req_msg_v01 *req; 35293983bc45SNaman Padhiar struct wlfw_get_info_resp_msg_v01 *resp; 35303983bc45SNaman Padhiar struct qmi_txn txn; 35313983bc45SNaman Padhiar int ret = 0; 3532e409b8c5SPrateek Patil int flags = GFP_KERNEL & ~__GFP_DIRECT_RECLAIM; 35333983bc45SNaman Padhiar 35343983bc45SNaman Padhiar if (cmd_len > QMI_WLFW_MAX_DATA_SIZE_V01) 35353983bc45SNaman Padhiar return -EINVAL; 35363983bc45SNaman Padhiar 35373983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &plat_priv->state)) 35383983bc45SNaman Padhiar return -EINVAL; 35393983bc45SNaman Padhiar 3540e409b8c5SPrateek Patil req = kzalloc(sizeof(*req), flags); 35413983bc45SNaman Padhiar if (!req) 35423983bc45SNaman Padhiar return -ENOMEM; 35433983bc45SNaman Padhiar 3544e409b8c5SPrateek Patil resp = kzalloc(sizeof(*resp), flags); 35453983bc45SNaman Padhiar if (!resp) { 35463983bc45SNaman Padhiar kfree(req); 35473983bc45SNaman Padhiar return -ENOMEM; 35483983bc45SNaman Padhiar } 35493983bc45SNaman Padhiar 35503983bc45SNaman Padhiar req->type = type; 35513983bc45SNaman Padhiar req->data_len = cmd_len; 35523983bc45SNaman Padhiar memcpy(req->data, cmd, req->data_len); 35533983bc45SNaman Padhiar 35543983bc45SNaman Padhiar ret = qmi_txn_init(&plat_priv->qmi, &txn, 35553983bc45SNaman Padhiar wlfw_get_info_resp_msg_v01_ei, resp); 35563983bc45SNaman Padhiar if (ret < 0) { 35573983bc45SNaman Padhiar icnss_pr_err("Failed to initialize txn for get info request, err: %d\n", 35583983bc45SNaman Padhiar ret); 35593983bc45SNaman Padhiar goto out; 35603983bc45SNaman Padhiar } 35613983bc45SNaman Padhiar 35623983bc45SNaman Padhiar ret = qmi_send_request(&plat_priv->qmi, NULL, &txn, 35633983bc45SNaman Padhiar QMI_WLFW_GET_INFO_REQ_V01, 35643983bc45SNaman Padhiar WLFW_GET_INFO_REQ_MSG_V01_MAX_MSG_LEN, 35653983bc45SNaman Padhiar wlfw_get_info_req_msg_v01_ei, req); 35663983bc45SNaman Padhiar if (ret < 0) { 35673983bc45SNaman Padhiar qmi_txn_cancel(&txn); 35683983bc45SNaman Padhiar icnss_pr_err("Failed to send get info request, err: %d\n", 35693983bc45SNaman Padhiar ret); 35703983bc45SNaman Padhiar goto out; 35713983bc45SNaman Padhiar } 35723983bc45SNaman Padhiar 35733983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout); 35743983bc45SNaman Padhiar if (ret < 0) { 35753983bc45SNaman Padhiar icnss_pr_err("Failed to wait for response of get info request, err: %d\n", 35763983bc45SNaman Padhiar ret); 35773983bc45SNaman Padhiar goto out; 35783983bc45SNaman Padhiar } 35793983bc45SNaman Padhiar 35803983bc45SNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 35813983bc45SNaman Padhiar icnss_pr_err("Get info request failed, result: %d, err: %d\n", 35823983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 35833983bc45SNaman Padhiar ret = -resp->resp.result; 35843983bc45SNaman Padhiar goto out; 35853983bc45SNaman Padhiar } 35863983bc45SNaman Padhiar 35873983bc45SNaman Padhiar kfree(req); 35883983bc45SNaman Padhiar kfree(resp); 35893983bc45SNaman Padhiar return 0; 35903983bc45SNaman Padhiar 35913983bc45SNaman Padhiar out: 35923983bc45SNaman Padhiar kfree(req); 35933983bc45SNaman Padhiar kfree(resp); 35943983bc45SNaman Padhiar return ret; 35953983bc45SNaman Padhiar } 35963983bc45SNaman Padhiar 35973983bc45SNaman Padhiar int wlfw_subsys_restart_level_msg(struct icnss_priv *penv, uint8_t restart_level) 35983983bc45SNaman Padhiar { 35993983bc45SNaman Padhiar int ret; 36003983bc45SNaman Padhiar struct wlfw_subsys_restart_level_req_msg_v01 *req; 36013983bc45SNaman Padhiar struct wlfw_subsys_restart_level_resp_msg_v01 *resp; 36023983bc45SNaman Padhiar struct qmi_txn txn; 36033983bc45SNaman Padhiar 36043983bc45SNaman Padhiar if (!penv) 36053983bc45SNaman Padhiar return -ENODEV; 36063983bc45SNaman Padhiar 36073983bc45SNaman Padhiar if (test_bit(ICNSS_FW_DOWN, &penv->state)) 36083983bc45SNaman Padhiar return -EINVAL; 36093983bc45SNaman Padhiar 36103983bc45SNaman Padhiar icnss_pr_dbg("Sending subsystem restart level: 0x%x\n", restart_level); 36113983bc45SNaman Padhiar 36123983bc45SNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 36133983bc45SNaman Padhiar if (!req) 36143983bc45SNaman Padhiar return -ENOMEM; 36153983bc45SNaman Padhiar 36163983bc45SNaman Padhiar resp = kzalloc(sizeof(*resp), GFP_KERNEL); 36173983bc45SNaman Padhiar if (!resp) { 36183983bc45SNaman Padhiar kfree(req); 36193983bc45SNaman Padhiar return -ENOMEM; 36203983bc45SNaman Padhiar } 36213983bc45SNaman Padhiar 36223983bc45SNaman Padhiar req->restart_level_type_valid = 1; 36233983bc45SNaman Padhiar req->restart_level_type = restart_level; 36243983bc45SNaman Padhiar 36253983bc45SNaman Padhiar penv->stats.restart_level_req++; 36263983bc45SNaman Padhiar 36273983bc45SNaman Padhiar ret = qmi_txn_init(&penv->qmi, &txn, 36283983bc45SNaman Padhiar wlfw_subsys_restart_level_resp_msg_v01_ei, resp); 36293983bc45SNaman Padhiar if (ret < 0) { 36303983bc45SNaman Padhiar icnss_pr_err("Fail to init txn for subsystem restart level, resp %d\n", 36313983bc45SNaman Padhiar ret); 36323983bc45SNaman Padhiar goto out; 36333983bc45SNaman Padhiar } 36343983bc45SNaman Padhiar 36353983bc45SNaman Padhiar ret = qmi_send_request(&penv->qmi, NULL, &txn, 36363983bc45SNaman Padhiar QMI_WLFW_SUBSYS_RESTART_LEVEL_REQ_V01, 36373983bc45SNaman Padhiar WLFW_SUBSYS_RESTART_LEVEL_REQ_MSG_V01_MAX_MSG_LEN, 36383983bc45SNaman Padhiar wlfw_subsys_restart_level_req_msg_v01_ei, req); 36393983bc45SNaman Padhiar if (ret < 0) { 36403983bc45SNaman Padhiar qmi_txn_cancel(&txn); 36413983bc45SNaman Padhiar icnss_pr_err("Fail to send subsystem restart level %d\n", 36423983bc45SNaman Padhiar ret); 36433983bc45SNaman Padhiar goto out; 36443983bc45SNaman Padhiar } 36453983bc45SNaman Padhiar 36463983bc45SNaman Padhiar ret = qmi_txn_wait(&txn, penv->ctrl_params.qmi_timeout); 36473983bc45SNaman Padhiar if (ret < 0) { 36483983bc45SNaman Padhiar icnss_pr_err("Subsystem restart level timed out with ret %d\n", 36493983bc45SNaman Padhiar ret); 36503983bc45SNaman Padhiar goto out; 36513983bc45SNaman Padhiar } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 36523983bc45SNaman Padhiar icnss_pr_err("Subsystem restart level request rejected,result:%d error:%d\n", 36533983bc45SNaman Padhiar resp->resp.result, resp->resp.error); 36543983bc45SNaman Padhiar ret = -resp->resp.result; 36553983bc45SNaman Padhiar goto out; 36563983bc45SNaman Padhiar } 36573983bc45SNaman Padhiar 36583983bc45SNaman Padhiar penv->stats.restart_level_resp++; 36593983bc45SNaman Padhiar 36603983bc45SNaman Padhiar kfree(resp); 36613983bc45SNaman Padhiar kfree(req); 36623983bc45SNaman Padhiar return 0; 36633983bc45SNaman Padhiar 36643983bc45SNaman Padhiar out: 36653983bc45SNaman Padhiar kfree(req); 36663983bc45SNaman Padhiar kfree(resp); 36673983bc45SNaman Padhiar penv->stats.restart_level_err++; 36683983bc45SNaman Padhiar return ret; 36693983bc45SNaman Padhiar } 36709be6cc90SSandeep Singh 36719be6cc90SSandeep Singh int icnss_send_vbatt_update(struct icnss_priv *priv, uint64_t voltage_uv) 36729be6cc90SSandeep Singh { 36739be6cc90SSandeep Singh int ret; 36749be6cc90SSandeep Singh struct wlfw_vbatt_req_msg_v01 *req; 36759be6cc90SSandeep Singh struct wlfw_vbatt_resp_msg_v01 *resp; 36769be6cc90SSandeep Singh struct qmi_txn txn; 36779be6cc90SSandeep Singh 36789be6cc90SSandeep Singh if (!priv) 36799be6cc90SSandeep Singh return -ENODEV; 36809be6cc90SSandeep Singh 36819be6cc90SSandeep Singh if (test_bit(ICNSS_FW_DOWN, &priv->state)) 36829be6cc90SSandeep Singh return -EINVAL; 36839be6cc90SSandeep Singh 36849be6cc90SSandeep Singh icnss_pr_dbg("Sending Vbatt message, state: 0x%lx\n", priv->state); 36859be6cc90SSandeep Singh 36869be6cc90SSandeep Singh req = kzalloc(sizeof(*req), GFP_KERNEL); 36879be6cc90SSandeep Singh if (!req) 36889be6cc90SSandeep Singh return -ENOMEM; 36899be6cc90SSandeep Singh 36909be6cc90SSandeep Singh resp = kzalloc(sizeof(*resp), GFP_KERNEL); 36919be6cc90SSandeep Singh if (!resp) { 36929be6cc90SSandeep Singh kfree(req); 36939be6cc90SSandeep Singh return -ENOMEM; 36949be6cc90SSandeep Singh } 36959be6cc90SSandeep Singh 36969be6cc90SSandeep Singh req->voltage_uv = voltage_uv; 36979be6cc90SSandeep Singh 36989be6cc90SSandeep Singh ret = qmi_txn_init(&priv->qmi, &txn, wlfw_vbatt_resp_msg_v01_ei, resp); 36999be6cc90SSandeep Singh if (ret < 0) { 37009be6cc90SSandeep Singh icnss_pr_err("Fail to init txn for Vbatt message resp %d\n", 37019be6cc90SSandeep Singh ret); 37029be6cc90SSandeep Singh goto out; 37039be6cc90SSandeep Singh } 37049be6cc90SSandeep Singh 37059be6cc90SSandeep Singh ret = qmi_send_request(&priv->qmi, NULL, &txn, 37069be6cc90SSandeep Singh QMI_WLFW_VBATT_REQ_V01, 37079be6cc90SSandeep Singh WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN, 37089be6cc90SSandeep Singh wlfw_vbatt_req_msg_v01_ei, req); 37099be6cc90SSandeep Singh if (ret < 0) { 37109be6cc90SSandeep Singh qmi_txn_cancel(&txn); 37119be6cc90SSandeep Singh icnss_pr_err("Fail to send Vbatt message req %d\n", ret); 37129be6cc90SSandeep Singh goto out; 37139be6cc90SSandeep Singh } 37149be6cc90SSandeep Singh 37159be6cc90SSandeep Singh ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); 37169be6cc90SSandeep Singh if (ret < 0) { 37179be6cc90SSandeep Singh icnss_pr_err("VBATT message resp wait failed with ret %d\n", 37189be6cc90SSandeep Singh ret); 37199be6cc90SSandeep Singh goto out; 37209be6cc90SSandeep Singh } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 37219be6cc90SSandeep Singh icnss_pr_err("QMI Vbatt message request rejected, result:%d error:%d\n", 37229be6cc90SSandeep Singh resp->resp.result, resp->resp.error); 37239be6cc90SSandeep Singh ret = -resp->resp.result; 37249be6cc90SSandeep Singh goto out; 37259be6cc90SSandeep Singh } 37269be6cc90SSandeep Singh 37279be6cc90SSandeep Singh kfree(resp); 37289be6cc90SSandeep Singh kfree(req); 37299be6cc90SSandeep Singh return 0; 37309be6cc90SSandeep Singh 37319be6cc90SSandeep Singh out: 37329be6cc90SSandeep Singh kfree(resp); 37339be6cc90SSandeep Singh kfree(req); 37349be6cc90SSandeep Singh return ret; 37359be6cc90SSandeep Singh } 3736075cc964SSurabhi Vishnoi 3737075cc964SSurabhi Vishnoi int wlfw_wlan_hw_init_cfg_msg(struct icnss_priv *penv, 3738075cc964SSurabhi Vishnoi enum wlfw_wlan_rf_subtype_v01 type) 3739075cc964SSurabhi Vishnoi { 3740075cc964SSurabhi Vishnoi int ret; 3741075cc964SSurabhi Vishnoi struct wlfw_wlan_hw_init_cfg_req_msg_v01 *req; 3742075cc964SSurabhi Vishnoi struct wlfw_wlan_hw_init_cfg_resp_msg_v01 *resp; 3743075cc964SSurabhi Vishnoi struct qmi_txn txn; 3744075cc964SSurabhi Vishnoi 3745075cc964SSurabhi Vishnoi if (!penv) 3746075cc964SSurabhi Vishnoi return -ENODEV; 3747075cc964SSurabhi Vishnoi 3748075cc964SSurabhi Vishnoi icnss_pr_dbg("Sending hw init cfg, rf_subtype: 0x%x\n", type); 3749075cc964SSurabhi Vishnoi 3750075cc964SSurabhi Vishnoi req = kzalloc(sizeof(*req), GFP_KERNEL); 3751075cc964SSurabhi Vishnoi if (!req) 3752075cc964SSurabhi Vishnoi return -ENOMEM; 3753075cc964SSurabhi Vishnoi 3754075cc964SSurabhi Vishnoi resp = kzalloc(sizeof(*resp), GFP_KERNEL); 3755075cc964SSurabhi Vishnoi if (!resp) { 3756075cc964SSurabhi Vishnoi kfree(req); 3757075cc964SSurabhi Vishnoi return -ENOMEM; 3758075cc964SSurabhi Vishnoi } 3759075cc964SSurabhi Vishnoi 3760075cc964SSurabhi Vishnoi req->rf_subtype_valid = 1; 3761075cc964SSurabhi Vishnoi req->rf_subtype = type; 3762075cc964SSurabhi Vishnoi 3763075cc964SSurabhi Vishnoi ret = qmi_txn_init(&penv->qmi, &txn, 3764075cc964SSurabhi Vishnoi wlfw_wlan_hw_init_cfg_resp_msg_v01_ei, resp); 3765075cc964SSurabhi Vishnoi if (ret < 0) { 3766075cc964SSurabhi Vishnoi icnss_pr_err("Fail to init txn for hw init cfg, resp %d\n", 3767075cc964SSurabhi Vishnoi ret); 3768075cc964SSurabhi Vishnoi goto out; 3769075cc964SSurabhi Vishnoi } 3770075cc964SSurabhi Vishnoi 3771075cc964SSurabhi Vishnoi ret = qmi_send_request(&penv->qmi, NULL, &txn, 3772075cc964SSurabhi Vishnoi QMI_WLFW_WLAN_HW_INIT_CFG_REQ_V01, 3773075cc964SSurabhi Vishnoi WLFW_WLAN_HW_INIT_CFG_REQ_MSG_V01_MAX_MSG_LEN, 3774075cc964SSurabhi Vishnoi wlfw_wlan_hw_init_cfg_req_msg_v01_ei, req); 3775075cc964SSurabhi Vishnoi if (ret < 0) { 3776075cc964SSurabhi Vishnoi qmi_txn_cancel(&txn); 3777075cc964SSurabhi Vishnoi icnss_pr_err("Fail to send hw init cfg %d\n", ret); 3778075cc964SSurabhi Vishnoi goto out; 3779075cc964SSurabhi Vishnoi } 3780075cc964SSurabhi Vishnoi 3781075cc964SSurabhi Vishnoi ret = qmi_txn_wait(&txn, penv->ctrl_params.qmi_timeout); 3782075cc964SSurabhi Vishnoi if (ret < 0) { 3783075cc964SSurabhi Vishnoi icnss_pr_err("HW init cfg timed out with ret %d\n", 3784075cc964SSurabhi Vishnoi ret); 3785075cc964SSurabhi Vishnoi goto out; 3786075cc964SSurabhi Vishnoi 3787075cc964SSurabhi Vishnoi } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 3788075cc964SSurabhi Vishnoi icnss_pr_err("HW init cfg request rejected,result:%d error:%d\n", 3789075cc964SSurabhi Vishnoi resp->resp.result, resp->resp.error); 3790075cc964SSurabhi Vishnoi ret = -resp->resp.result; 3791075cc964SSurabhi Vishnoi goto out; 3792075cc964SSurabhi Vishnoi } 3793075cc964SSurabhi Vishnoi 3794075cc964SSurabhi Vishnoi kfree(resp); 3795075cc964SSurabhi Vishnoi kfree(req); 3796075cc964SSurabhi Vishnoi return 0; 3797075cc964SSurabhi Vishnoi 3798075cc964SSurabhi Vishnoi out: 3799075cc964SSurabhi Vishnoi kfree(req); 3800075cc964SSurabhi Vishnoi kfree(resp); 3801075cc964SSurabhi Vishnoi return ret; 3802075cc964SSurabhi Vishnoi } 380387ab436eSNaman Padhiar 380487ab436eSNaman Padhiar /* IMS Service */ 380587ab436eSNaman Padhiar int ims_subscribe_for_indication_send_async(struct icnss_priv *priv) 380687ab436eSNaman Padhiar { 380787ab436eSNaman Padhiar int ret; 380887ab436eSNaman Padhiar struct ims_private_service_subscribe_for_indications_req_msg_v01 *req; 380987ab436eSNaman Padhiar struct qmi_txn *txn; 381087ab436eSNaman Padhiar 381187ab436eSNaman Padhiar if (!priv) 381287ab436eSNaman Padhiar return -ENODEV; 381387ab436eSNaman Padhiar 381487ab436eSNaman Padhiar icnss_pr_dbg("Sending ASYNC ims subscribe for indication\n"); 381587ab436eSNaman Padhiar 381687ab436eSNaman Padhiar req = kzalloc(sizeof(*req), GFP_KERNEL); 381787ab436eSNaman Padhiar if (!req) 381887ab436eSNaman Padhiar return -ENOMEM; 381987ab436eSNaman Padhiar 382087ab436eSNaman Padhiar req->wfc_call_status_valid = 1; 382187ab436eSNaman Padhiar req->wfc_call_status = 1; 382287ab436eSNaman Padhiar 382387ab436eSNaman Padhiar txn = &priv->ims_async_txn; 382487ab436eSNaman Padhiar ret = qmi_txn_init(&priv->ims_qmi, txn, NULL, NULL); 382587ab436eSNaman Padhiar if (ret < 0) { 382687ab436eSNaman Padhiar icnss_pr_err("Fail to init txn for ims subscribe for indication resp %d\n", 382787ab436eSNaman Padhiar ret); 382887ab436eSNaman Padhiar goto out; 382987ab436eSNaman Padhiar } 383087ab436eSNaman Padhiar 383187ab436eSNaman Padhiar ret = qmi_send_request 383287ab436eSNaman Padhiar (&priv->ims_qmi, NULL, txn, 383387ab436eSNaman Padhiar QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01, 383487ab436eSNaman Padhiar IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_MSG_V01_MAX_MSG_LEN, 383587ab436eSNaman Padhiar ims_private_service_subscribe_ind_req_msg_v01_ei, req); 383687ab436eSNaman Padhiar if (ret < 0) { 383787ab436eSNaman Padhiar qmi_txn_cancel(txn); 383887ab436eSNaman Padhiar icnss_pr_err("Fail to send ims subscribe for indication req %d\n", 383987ab436eSNaman Padhiar ret); 384087ab436eSNaman Padhiar goto out; 384187ab436eSNaman Padhiar } 384287ab436eSNaman Padhiar 384387ab436eSNaman Padhiar kfree(req); 384487ab436eSNaman Padhiar return 0; 384587ab436eSNaman Padhiar 384687ab436eSNaman Padhiar out: 384787ab436eSNaman Padhiar kfree(req); 384887ab436eSNaman Padhiar return ret; 384987ab436eSNaman Padhiar } 385087ab436eSNaman Padhiar 385187ab436eSNaman Padhiar static void ims_subscribe_for_indication_resp_cb(struct qmi_handle *qmi, 385287ab436eSNaman Padhiar struct sockaddr_qrtr *sq, 385387ab436eSNaman Padhiar struct qmi_txn *txn, 385487ab436eSNaman Padhiar const void *data) 385587ab436eSNaman Padhiar { 385687ab436eSNaman Padhiar const 385787ab436eSNaman Padhiar struct ims_private_service_subscribe_for_indications_rsp_msg_v01 *resp = 385887ab436eSNaman Padhiar data; 385987ab436eSNaman Padhiar 386087ab436eSNaman Padhiar icnss_pr_dbg("Received IMS subscribe indication response\n"); 386187ab436eSNaman Padhiar 386287ab436eSNaman Padhiar if (!txn) { 386387ab436eSNaman Padhiar icnss_pr_err("spurious response\n"); 386487ab436eSNaman Padhiar return; 386587ab436eSNaman Padhiar } 386687ab436eSNaman Padhiar 386787ab436eSNaman Padhiar if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { 386887ab436eSNaman Padhiar icnss_pr_err("IMS subscribe for indication request rejected, result:%d error:%d\n", 386987ab436eSNaman Padhiar resp->resp.result, resp->resp.error); 387087ab436eSNaman Padhiar txn->result = -resp->resp.result; 387187ab436eSNaman Padhiar } 387287ab436eSNaman Padhiar } 387387ab436eSNaman Padhiar 387487ab436eSNaman Padhiar int icnss_process_wfc_call_ind_event(struct icnss_priv *priv, 387587ab436eSNaman Padhiar void *data) 387687ab436eSNaman Padhiar { 387787ab436eSNaman Padhiar int ret; 387887ab436eSNaman Padhiar struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data; 387987ab436eSNaman Padhiar 388087ab436eSNaman Padhiar ret = icnss_wlfw_wfc_call_status_send_sync(priv, ind_msg); 388187ab436eSNaman Padhiar kfree(data); 388287ab436eSNaman Padhiar return ret; 388387ab436eSNaman Padhiar } 388487ab436eSNaman Padhiar 388587ab436eSNaman Padhiar static void 388687ab436eSNaman Padhiar icnss_ims_process_wfc_call_ind_cb(struct qmi_handle *ims_qmi, 388787ab436eSNaman Padhiar struct sockaddr_qrtr *sq, 388887ab436eSNaman Padhiar struct qmi_txn *txn, const void *data) 388987ab436eSNaman Padhiar { 389087ab436eSNaman Padhiar struct icnss_priv *priv = 389187ab436eSNaman Padhiar container_of(ims_qmi, struct icnss_priv, ims_qmi); 389287ab436eSNaman Padhiar const 389387ab436eSNaman Padhiar struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data; 389487ab436eSNaman Padhiar struct ims_private_service_wfc_call_status_ind_msg_v01 *event_data; 389587ab436eSNaman Padhiar 389687ab436eSNaman Padhiar if (!txn) { 389787ab436eSNaman Padhiar icnss_pr_err("IMS->CNSS: WFC_CALL_IND: Spurious indication\n"); 389887ab436eSNaman Padhiar return; 389987ab436eSNaman Padhiar } 390087ab436eSNaman Padhiar 390187ab436eSNaman Padhiar if (!ind_msg) { 390287ab436eSNaman Padhiar icnss_pr_err("IMS->CNSS: WFC_CALL_IND: Invalid indication\n"); 390387ab436eSNaman Padhiar return; 390487ab436eSNaman Padhiar } 390587ab436eSNaman Padhiar icnss_pr_dbg("IMS->CNSS: WFC_CALL_IND: %x, %x %x, %x %x, %x %llx, %x %x, %x %x\n", 390687ab436eSNaman Padhiar ind_msg->wfc_call_active, ind_msg->all_wfc_calls_held_valid, 390787ab436eSNaman Padhiar ind_msg->all_wfc_calls_held, 390887ab436eSNaman Padhiar ind_msg->is_wfc_emergency_valid, ind_msg->is_wfc_emergency, 390987ab436eSNaman Padhiar ind_msg->twt_ims_start_valid, ind_msg->twt_ims_start, 391087ab436eSNaman Padhiar ind_msg->twt_ims_int_valid, ind_msg->twt_ims_int, 391187ab436eSNaman Padhiar ind_msg->media_quality_valid, ind_msg->media_quality); 391287ab436eSNaman Padhiar 391387ab436eSNaman Padhiar event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL); 391487ab436eSNaman Padhiar if (!event_data) 391587ab436eSNaman Padhiar return; 391687ab436eSNaman Padhiar icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_IMS_WFC_CALL_IND, 391787ab436eSNaman Padhiar 0, event_data); 391887ab436eSNaman Padhiar } 391987ab436eSNaman Padhiar 392087ab436eSNaman Padhiar static struct qmi_msg_handler qmi_ims_msg_handlers[] = { 392187ab436eSNaman Padhiar { 392287ab436eSNaman Padhiar .type = QMI_RESPONSE, 392387ab436eSNaman Padhiar .msg_id = 392487ab436eSNaman Padhiar QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01, 392587ab436eSNaman Padhiar .ei = 392687ab436eSNaman Padhiar ims_private_service_subscribe_ind_rsp_msg_v01_ei, 392787ab436eSNaman Padhiar .decoded_size = sizeof(struct 392887ab436eSNaman Padhiar ims_private_service_subscribe_for_indications_rsp_msg_v01), 392987ab436eSNaman Padhiar .fn = ims_subscribe_for_indication_resp_cb 393087ab436eSNaman Padhiar }, 393187ab436eSNaman Padhiar { 393287ab436eSNaman Padhiar .type = QMI_INDICATION, 393387ab436eSNaman Padhiar .msg_id = QMI_IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_V01, 393487ab436eSNaman Padhiar .ei = ims_private_service_wfc_call_status_ind_msg_v01_ei, 393587ab436eSNaman Padhiar .decoded_size = 393687ab436eSNaman Padhiar sizeof(struct ims_private_service_wfc_call_status_ind_msg_v01), 393787ab436eSNaman Padhiar .fn = icnss_ims_process_wfc_call_ind_cb 393887ab436eSNaman Padhiar }, 393987ab436eSNaman Padhiar {} 394087ab436eSNaman Padhiar }; 394187ab436eSNaman Padhiar 394287ab436eSNaman Padhiar static int ims_new_server(struct qmi_handle *qmi, 394387ab436eSNaman Padhiar struct qmi_service *service) 394487ab436eSNaman Padhiar { 394587ab436eSNaman Padhiar struct icnss_priv *priv = 394687ab436eSNaman Padhiar container_of(qmi, struct icnss_priv, ims_qmi); 394787ab436eSNaman Padhiar struct sockaddr_qrtr sq = { 0 }; 394887ab436eSNaman Padhiar int ret = 0; 394987ab436eSNaman Padhiar 395087ab436eSNaman Padhiar icnss_pr_dbg("IMS server arrive: node %u port %u\n", 395187ab436eSNaman Padhiar service->node, service->port); 395287ab436eSNaman Padhiar 395387ab436eSNaman Padhiar sq.sq_family = AF_QIPCRTR; 395487ab436eSNaman Padhiar sq.sq_node = service->node; 395587ab436eSNaman Padhiar sq.sq_port = service->port; 395687ab436eSNaman Padhiar ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0); 395787ab436eSNaman Padhiar if (ret < 0) { 395887ab436eSNaman Padhiar icnss_pr_err("Fail to connect to remote service port\n"); 395987ab436eSNaman Padhiar return ret; 396087ab436eSNaman Padhiar } 396187ab436eSNaman Padhiar 396287ab436eSNaman Padhiar set_bit(ICNSS_IMS_CONNECTED, &priv->state); 396387ab436eSNaman Padhiar icnss_pr_dbg("IMS Server Connected: 0x%lx\n", 396487ab436eSNaman Padhiar priv->state); 396587ab436eSNaman Padhiar 396687ab436eSNaman Padhiar ret = ims_subscribe_for_indication_send_async(priv); 396787ab436eSNaman Padhiar return ret; 396887ab436eSNaman Padhiar } 396987ab436eSNaman Padhiar 397087ab436eSNaman Padhiar static void ims_del_server(struct qmi_handle *qmi, 397187ab436eSNaman Padhiar struct qmi_service *service) 397287ab436eSNaman Padhiar { 397387ab436eSNaman Padhiar struct icnss_priv *priv = 397487ab436eSNaman Padhiar container_of(qmi, struct icnss_priv, ims_qmi); 397587ab436eSNaman Padhiar 397687ab436eSNaman Padhiar icnss_pr_dbg("IMS server exit\n"); 397787ab436eSNaman Padhiar 397887ab436eSNaman Padhiar clear_bit(ICNSS_IMS_CONNECTED, &priv->state); 397987ab436eSNaman Padhiar } 398087ab436eSNaman Padhiar 398187ab436eSNaman Padhiar static struct qmi_ops ims_qmi_ops = { 398287ab436eSNaman Padhiar .new_server = ims_new_server, 398387ab436eSNaman Padhiar .del_server = ims_del_server, 398487ab436eSNaman Padhiar }; 398587ab436eSNaman Padhiar 398687ab436eSNaman Padhiar int icnss_register_ims_service(struct icnss_priv *priv) 398787ab436eSNaman Padhiar { 398887ab436eSNaman Padhiar int ret; 398987ab436eSNaman Padhiar 399087ab436eSNaman Padhiar ret = qmi_handle_init(&priv->ims_qmi, 399187ab436eSNaman Padhiar IMSPRIVATE_SERVICE_MAX_MSG_LEN, 399287ab436eSNaman Padhiar &ims_qmi_ops, qmi_ims_msg_handlers); 399387ab436eSNaman Padhiar if (ret < 0) 399487ab436eSNaman Padhiar return ret; 399587ab436eSNaman Padhiar 399687ab436eSNaman Padhiar ret = qmi_add_lookup(&priv->ims_qmi, IMSPRIVATE_SERVICE_ID_V01, 399787ab436eSNaman Padhiar IMSPRIVATE_SERVICE_VERS_V01, 0); 399887ab436eSNaman Padhiar return ret; 399987ab436eSNaman Padhiar } 400087ab436eSNaman Padhiar 400187ab436eSNaman Padhiar void icnss_unregister_ims_service(struct icnss_priv *priv) 400287ab436eSNaman Padhiar { 400387ab436eSNaman Padhiar qmi_handle_release(&priv->ims_qmi); 400487ab436eSNaman Padhiar } 4005