xref: /wlan-dirver/platform/icnss2/qmi.c (revision ae9e2e6bd55f5e4b33ce59e33fe796d851354660)
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