Merge "icnss2: Add support for MHI state info"
diff --git a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.c
index ca3f998..5419b1b 100644
--- a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.c
+++ b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2021, The Linux Foundation. All rights reserved. */
 
 #include "wlan_firmware_service_v01.h"
 
@@ -464,7 +464,8 @@
 		.elem_size      = sizeof(enum wlfw_m3_segment_type_v01),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_m3_segment_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
 					   type),
 	},
 	{
@@ -473,7 +474,8 @@
 		.elem_size      = sizeof(u64),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_m3_segment_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
 					   addr),
 	},
 	{
@@ -482,7 +484,8 @@
 		.elem_size      = sizeof(u64),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_m3_segment_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
 					   size),
 	},
 	{
@@ -491,7 +494,8 @@
 		.elem_size      = sizeof(char),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_m3_segment_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
 					   name),
 	},
 	{
@@ -508,7 +512,8 @@
 		.elem_size      = sizeof(u64),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_dev_mem_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_dev_mem_info_s_v01,
 					   start),
 	},
 	{
@@ -517,7 +522,8 @@
 		.elem_size      = sizeof(u64),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0,
-		.offset         = offsetof(struct wlfw_dev_mem_info_s_v01,
+		.offset         = offsetof(struct
+					   wlfw_dev_mem_info_s_v01,
 					   size),
 	},
 	{
@@ -877,7 +883,8 @@
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x23,
 		.offset         =
-		offsetof(struct wlfw_ind_register_req_msg_v01,
+		offsetof(struct
+			 wlfw_ind_register_req_msg_v01,
 			 m3_dump_upload_segments_req_enable_valid),
 	},
 	{
@@ -886,7 +893,8 @@
 		.elem_size      = sizeof(u8),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x23,
-		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
 					   m3_dump_upload_segments_req_enable),
 	},
 	{
@@ -1556,7 +1564,8 @@
 		.elem_size      = sizeof(u8),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x1C,
-		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
 					   dev_mem_info_valid),
 	},
 	{
@@ -1565,7 +1574,8 @@
 		.elem_size      = sizeof(struct wlfw_dev_mem_info_s_v01),
 		.array_type       = STATIC_ARRAY,
 		.tlv_type       = 0x1C,
-		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
 					   dev_mem_info),
 		.ei_array      = wlfw_dev_mem_info_s_v01_ei,
 	},
@@ -1805,6 +1815,26 @@
 					   cal_remove_supported),
 	},
 	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_file_download_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_file_download_size),
+	},
+	{
 		.data_type      = QMI_EOTI,
 		.array_type       = NO_ARRAY,
 		.tlv_type       = QMI_COMMON_TLV_TYPE,
@@ -3041,7 +3071,8 @@
 		.elem_size      = sizeof(u8),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
-		.offset         = offsetof(struct wlfw_fw_init_done_ind_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
 					   hang_data_addr_offset_valid),
 	},
 	{
@@ -3050,7 +3081,8 @@
 		.elem_size      = sizeof(u32),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x10,
-		.offset         = offsetof(struct wlfw_fw_init_done_ind_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
 					   hang_data_addr_offset),
 	},
 	{
@@ -3059,7 +3091,8 @@
 		.elem_size      = sizeof(u8),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x11,
-		.offset         = offsetof(struct wlfw_fw_init_done_ind_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
 					   hang_data_length_valid),
 	},
 	{
@@ -3068,7 +3101,8 @@
 		.elem_size      = sizeof(u16),
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x11,
-		.offset         = offsetof(struct wlfw_fw_init_done_ind_msg_v01,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
 					   hang_data_length),
 	},
 	{
@@ -3335,6 +3369,26 @@
 
 struct qmi_elem_info wlfw_cal_done_ind_msg_v01_ei[] = {
 	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_done_ind_msg_v01,
+					   cal_file_upload_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_done_ind_msg_v01,
+					   cal_file_upload_size),
+	},
+	{
 		.data_type      = QMI_EOTI,
 		.array_type       = NO_ARRAY,
 		.tlv_type       = QMI_COMMON_TLV_TYPE,
@@ -4369,6 +4423,46 @@
 					   bar_size),
 	},
 	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_addr),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_size),
+	},
+	{
 		.data_type      = QMI_EOTI,
 		.array_type       = NO_ARRAY,
 		.tlv_type       = QMI_COMMON_TLV_TYPE,
@@ -4730,7 +4824,8 @@
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         =
-		offsetof(struct wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+		offsetof(struct
+			 wlfw_m3_dump_upload_segments_req_ind_msg_v01,
 			 pdev_id),
 	},
 	{
@@ -4740,7 +4835,8 @@
 		.array_type       = NO_ARRAY,
 		.tlv_type       = 0x02,
 		.offset         =
-		offsetof(struct wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+		offsetof(struct
+			 wlfw_m3_dump_upload_segments_req_ind_msg_v01,
 			 no_of_valid_segments),
 	},
 	{
@@ -4750,7 +4846,8 @@
 		.array_type       = STATIC_ARRAY,
 		.tlv_type       = 0x03,
 		.offset         =
-		offsetof(struct wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+		offsetof(struct
+			 wlfw_m3_dump_upload_segments_req_ind_msg_v01,
 			 m3_segment),
 		.ei_array      = wlfw_m3_segment_info_s_v01_ei,
 	},
diff --git a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h
index d3a2dd6..b5ed622 100644
--- a/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss_utils/wlan_firmware_service_v01.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2021, The Linux Foundation. All rights reserved. */
 
 #ifndef WLAN_FIRMWARE_SERVICE_V01_H
 #define WLAN_FIRMWARE_SERVICE_V01_H
@@ -99,7 +99,7 @@
 
 #define QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01 10
 #define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
-#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 32
+#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 52
 #define QMI_WLFW_MAX_NUM_CAL_V01 5
 #define QMI_WLFW_MAX_DATA_SIZE_V01 6144
 #define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
@@ -396,7 +396,6 @@
 	u8 m3_dump_upload_segments_req_enable_valid;
 	u8 m3_dump_upload_segments_req_enable;
 };
-
 #define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 86
 extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[];
 
@@ -516,7 +515,6 @@
 	struct wlfw_dev_mem_info_s_v01
 		dev_mem_info[QMI_WLFW_MAX_DEV_MEM_NUM_V01];
 };
-
 #define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 320
 extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[];
 
@@ -555,8 +553,11 @@
 	u8 xo_cal_data;
 	u8 cal_remove_supported_valid;
 	u8 cal_remove_supported;
+	u8 cal_file_download_size_valid;
+	u64 cal_file_download_size;
 };
-#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 32
+
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 43
 extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[];
 
 struct wlfw_cal_report_resp_msg_v01 {
@@ -784,14 +785,16 @@
 	u32 mem_seg_len;
 	struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
-#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1124
+
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1824
 extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[];
 
 struct wlfw_respond_mem_req_msg_v01 {
 	u32 mem_seg_len;
 	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
-#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 548
+
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 888
 extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[];
 
 struct wlfw_respond_mem_resp_msg_v01 {
@@ -812,7 +815,6 @@
 	u8 hang_data_length_valid;
 	u16 hang_data_length;
 };
-
 #define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 12
 extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
 
@@ -878,28 +880,33 @@
 extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[];
 
 struct wlfw_cal_done_ind_msg_v01 {
-	char placeholder;
+	u8 cal_file_upload_size_valid;
+	u64 cal_file_upload_size;
 };
-#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+
+#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 11
 extern struct qmi_elem_info wlfw_cal_done_ind_msg_v01_ei[];
 
 struct wlfw_qdss_trace_req_mem_ind_msg_v01 {
 	u32 mem_seg_len;
 	struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
-#define WLFW_QDSS_TRACE_REQ_MEM_IND_MSG_V01_MAX_MSG_LEN 1124
+
+#define WLFW_QDSS_TRACE_REQ_MEM_IND_MSG_V01_MAX_MSG_LEN 1824
 extern struct qmi_elem_info wlfw_qdss_trace_req_mem_ind_msg_v01_ei[];
 
 struct wlfw_qdss_trace_mem_info_req_msg_v01 {
 	u32 mem_seg_len;
 	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
-#define WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN 548
+
+#define WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN 888
 extern struct qmi_elem_info wlfw_qdss_trace_mem_info_req_msg_v01_ei[];
 
 struct wlfw_qdss_trace_mem_info_resp_msg_v01 {
 	struct qmi_response_type_v01 resp;
 };
+
 #define WLFW_QDSS_TRACE_MEM_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
 extern struct qmi_elem_info wlfw_qdss_trace_mem_info_resp_msg_v01_ei[];
 
@@ -912,7 +919,8 @@
 	u8 file_name_valid;
 	char file_name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
 };
-#define WLFW_QDSS_TRACE_SAVE_IND_MSG_V01_MAX_MSG_LEN 581
+
+#define WLFW_QDSS_TRACE_SAVE_IND_MSG_V01_MAX_MSG_LEN 921
 extern struct qmi_elem_info wlfw_qdss_trace_save_ind_msg_v01_ei[];
 
 struct wlfw_qdss_trace_data_req_msg_v01 {
@@ -978,7 +986,8 @@
 	u32 mem_seg_len;
 	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
-#define WLFW_QDSS_TRACE_FREE_IND_MSG_V01_MAX_MSG_LEN 548
+
+#define WLFW_QDSS_TRACE_FREE_IND_MSG_V01_MAX_MSG_LEN 888
 extern struct qmi_elem_info wlfw_qdss_trace_free_ind_msg_v01_ei[];
 
 struct wlfw_shutdown_req_msg_v01 {
@@ -1057,6 +1066,7 @@
 struct wlfw_get_info_resp_msg_v01 {
 	struct qmi_response_type_v01 resp;
 };
+
 #define WLFW_GET_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
 extern struct qmi_elem_info wlfw_get_info_resp_msg_v01_ei[];
 
@@ -1085,8 +1095,13 @@
 	u64 bar_addr;
 	u8 bar_size_valid;
 	u32 bar_size;
+	u8 mhi_state_info_addr_valid;
+	u64 mhi_state_info_addr;
+	u8 mhi_state_info_size_valid;
+	u32 mhi_state_info_size;
 };
-#define WLFW_DEVICE_INFO_RESP_MSG_V01_MAX_MSG_LEN 25
+
+#define WLFW_DEVICE_INFO_RESP_MSG_V01_MAX_MSG_LEN 43
 extern struct qmi_elem_info wlfw_device_info_resp_msg_v01_ei[];
 
 struct wlfw_m3_dump_upload_req_ind_msg_v01 {
@@ -1183,7 +1198,6 @@
 	struct wlfw_m3_segment_info_s_v01
 		m3_segment[QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01];
 };
-
 #define WLFW_M3_DUMP_UPLOAD_SEGMENTS_REQ_IND_MSG_V01_MAX_MSG_LEN 387
 extern struct qmi_elem_info wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei[];
 
diff --git a/drivers/soc/qcom/icnss2/main.c b/drivers/soc/qcom/icnss2/main.c
index 7fbe376..e82beac 100644
--- a/drivers/soc/qcom/icnss2/main.c
+++ b/drivers/soc/qcom/icnss2/main.c
@@ -618,8 +618,8 @@
 		}
 
 		priv->mem_base_va = devm_ioremap(&priv->pdev->dev,
-							 priv->mem_base_pa,
-							 priv->mem_base_size);
+						 priv->mem_base_pa,
+						 priv->mem_base_size);
 		if (!priv->mem_base_va) {
 			icnss_pr_err("Ioremap failed for bar address\n");
 			goto err_power_on;
@@ -629,6 +629,17 @@
 			     &priv->mem_base_pa,
 			     priv->mem_base_va);
 
+		if (priv->mhi_state_info_pa)
+			priv->mhi_state_info_va = devm_ioremap(&priv->pdev->dev,
+						priv->mhi_state_info_pa,
+						PAGE_SIZE);
+		if (!priv->mhi_state_info_va)
+			icnss_pr_err("Ioremap failed for MHI info address\n");
+
+		icnss_pr_dbg("MHI state info Address pa: %pa, va: 0x%pK\n",
+			     &priv->mhi_state_info_pa,
+			     priv->mhi_state_info_va);
+
 		icnss_wlfw_bdf_dnld_send_sync(priv, ICNSS_BDF_REGDB);
 
 		ret = icnss_wlfw_bdf_dnld_send_sync(priv,
@@ -1453,6 +1464,7 @@
 			break;
 		case ICNSS_DRIVER_EVENT_M3_DUMP_UPLOAD_REQ:
 			ret = icnss_m3_dump_upload_req_hdlr(priv, event->data);
+			break;
 		case ICNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA:
 			ret = icnss_qdss_trace_req_data_hdlr(priv,
 							     event->data);
@@ -1977,7 +1989,8 @@
 	return 0;
 }
 
-static int icnss_trigger_ssr_smp2p(struct icnss_priv *priv)
+static int icnss_send_smp2p(struct icnss_priv *priv,
+			    enum icnss_smp2p_msg_id msg_id)
 {
 	unsigned int value = 0;
 	int ret;
@@ -1985,19 +1998,22 @@
 	if (IS_ERR(priv->smp2p_info.smem_state))
 		return -EINVAL;
 
+	if (test_bit(ICNSS_FW_DOWN, &priv->state))
+		return -ENODEV;
+
 	value |= priv->smp2p_info.seq++;
 	value <<= ICNSS_SMEM_SEQ_NO_POS;
-	value |= ICNSS_TRIGGER_SSR;
+	value |= msg_id;
+
+	icnss_pr_vdbg1("Sending SMP2P value: 0x%X\n", value);
+
 	ret = qcom_smem_state_update_bits(
 			priv->smp2p_info.smem_state,
 			ICNSS_SMEM_VALUE_MASK,
 			value);
 	if (ret)
-		icnss_pr_vdbg1("Error in SMP2P sent ret: %d\n", ret);
+		icnss_pr_vdbg1("Error in SMP2P send ret: %d\n", ret);
 
-	icnss_pr_vdbg1("Initiate Root PD restart. SMP2P sent value: 0x%X\n",
-		     value);
-	set_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
 	return ret;
 }
 
@@ -2470,6 +2486,22 @@
 }
 EXPORT_SYMBOL(icnss_get_soc_info);
 
+int icnss_get_mhi_state(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (!priv) {
+		icnss_pr_err("Platform driver not initialized\n");
+		return -EINVAL;
+	}
+
+	if (!priv->mhi_state_info_va)
+		return -ENOMEM;
+
+	return ioread32(priv->mhi_state_info_va);
+}
+EXPORT_SYMBOL(icnss_get_mhi_state);
+
 int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode)
 {
 	int ret;
@@ -2553,9 +2585,6 @@
 {
 	struct icnss_priv *priv = dev_get_drvdata(dev);
 
-	if (!dev)
-		return -ENODEV;
-
 	if (!priv) {
 		icnss_pr_err("Platform driver not initialized\n");
 		return -EINVAL;
@@ -2565,6 +2594,22 @@
 }
 EXPORT_SYMBOL(icnss_is_device_awake);
 
+int icnss_is_pci_ep_awake(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (!priv) {
+		icnss_pr_err("Platform driver not initialized\n");
+		return -EINVAL;
+	}
+
+	if (!priv->mhi_state_info_va)
+		return -ENOMEM;
+
+	return ioread32(priv->mhi_state_info_va + ICNSS_PCI_EP_WAKE_OFFSET);
+}
+EXPORT_SYMBOL(icnss_is_pci_ep_awake);
+
 int icnss_athdiag_read(struct device *dev, uint32_t offset,
 		       uint32_t mem_type, uint32_t data_len,
 		       uint8_t *output)
@@ -2846,8 +2891,13 @@
 		goto out;
 	}
 
-	if (priv->device_id == WCN6750_DEVICE_ID)
-		return icnss_trigger_ssr_smp2p(priv);
+	if (priv->device_id == WCN6750_DEVICE_ID) {
+		icnss_pr_vdbg1("Initiate Root PD restart");
+		ret = icnss_send_smp2p(priv, ICNSS_TRIGGER_SSR);
+		if (!ret)
+			set_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
+		return ret;
+	}
 
 	if (!test_bit(ICNSS_PDR_REGISTERED, &priv->state)) {
 		icnss_pr_err("PD restart not enabled to trigger recovery: state: 0x%lx\n",
@@ -2926,8 +2976,6 @@
 int icnss_exit_power_save(struct device *dev)
 {
 	struct icnss_priv *priv = dev_get_drvdata(dev);
-	unsigned int value = 0;
-	int ret;
 
 	icnss_pr_vdbg1("Calling Exit Power Save\n");
 
@@ -2935,21 +2983,34 @@
 	    !test_bit(ICNSS_MODE_ON, &priv->state))
 		return 0;
 
-	value |= priv->smp2p_info.seq++;
-	value <<= ICNSS_SMEM_SEQ_NO_POS;
-	value |= ICNSS_POWER_SAVE_EXIT;
-	ret = qcom_smem_state_update_bits(
-			priv->smp2p_info.smem_state,
-			ICNSS_SMEM_VALUE_MASK,
-			value);
-	if (ret)
-		icnss_pr_vdbg1("Error in SMP2P sent ret: %d\n", ret);
-
-	icnss_pr_vdbg1("SMP2P sent value: 0x%X\n", value);
-	return ret;
+	return icnss_send_smp2p(priv, ICNSS_POWER_SAVE_EXIT);
 }
 EXPORT_SYMBOL(icnss_exit_power_save);
 
+int icnss_prevent_l1(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
+	    !test_bit(ICNSS_MODE_ON, &priv->state))
+		return 0;
+
+	return icnss_send_smp2p(priv, ICNSS_PCI_EP_POWER_SAVE_EXIT);
+}
+EXPORT_SYMBOL(icnss_prevent_l1);
+
+void icnss_allow_l1(struct device *dev)
+{
+	struct icnss_priv *priv = dev_get_drvdata(dev);
+
+	if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
+	    !test_bit(ICNSS_MODE_ON, &priv->state))
+		return;
+
+	icnss_send_smp2p(priv, ICNSS_PCI_EP_POWER_SAVE_ENTER);
+}
+EXPORT_SYMBOL(icnss_allow_l1);
+
 void icnss_allow_recursive_recovery(struct device *dev)
 {
 	struct icnss_priv *priv = dev_get_drvdata(dev);
@@ -3699,7 +3760,6 @@
 static int icnss_pm_suspend(struct device *dev)
 {
 	struct icnss_priv *priv = dev_get_drvdata(dev);
-	unsigned int value = 0;
 	int ret = 0;
 
 	if (priv->magic != ICNSS_MAGIC) {
@@ -3723,19 +3783,7 @@
 			    !test_bit(ICNSS_MODE_ON, &priv->state))
 				return 0;
 
-			value |= priv->smp2p_info.seq++;
-			value <<= ICNSS_SMEM_SEQ_NO_POS;
-			value |= ICNSS_POWER_SAVE_ENTER;
-
-			ret = qcom_smem_state_update_bits(
-				priv->smp2p_info.smem_state,
-				ICNSS_SMEM_VALUE_MASK,
-				value);
-			if (ret)
-				icnss_pr_vdbg1("Error in SMP2P sent ret: %d\n",
-					     ret);
-
-			icnss_pr_vdbg1("SMP2P sent value: 0x%X\n", value);
+			ret = icnss_send_smp2p(priv, ICNSS_POWER_SAVE_ENTER);
 		}
 		priv->stats.pm_suspend++;
 		set_bit(ICNSS_PM_SUSPEND, &priv->state);
@@ -3836,7 +3884,6 @@
 static int icnss_pm_runtime_suspend(struct device *dev)
 {
 	struct icnss_priv *priv = dev_get_drvdata(dev);
-	unsigned int value = 0;
 	int ret = 0;
 
 	if (priv->magic != ICNSS_MAGIC) {
@@ -3856,18 +3903,7 @@
 		    !test_bit(ICNSS_MODE_ON, &priv->state))
 			return 0;
 
-		value |= priv->smp2p_info.seq++;
-		value <<= ICNSS_SMEM_SEQ_NO_POS;
-		value |= ICNSS_POWER_SAVE_ENTER;
-
-		ret = qcom_smem_state_update_bits(
-				priv->smp2p_info.smem_state,
-				ICNSS_SMEM_VALUE_MASK,
-				value);
-		if (ret)
-			icnss_pr_vdbg1("Error in SMP2P sent ret: %d\n", ret);
-
-		icnss_pr_vdbg1("SMP2P sent value: 0x%X\n", value);
+		ret = icnss_send_smp2p(priv, ICNSS_POWER_SAVE_ENTER);
 	}
 out:
 	return ret;
diff --git a/drivers/soc/qcom/icnss2/main.h b/drivers/soc/qcom/icnss2/main.h
index c4901a6..1354ca8 100644
--- a/drivers/soc/qcom/icnss2/main.h
+++ b/drivers/soc/qcom/icnss2/main.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __MAIN_H__
@@ -25,6 +25,7 @@
 #define THERMAL_NAME_LENGTH 20
 #define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF
 #define ICNSS_SMEM_SEQ_NO_POS 16
+#define ICNSS_PCI_EP_WAKE_OFFSET 4
 
 extern uint64_t dynamic_feature_mask;
 
@@ -178,6 +179,8 @@
 	ICNSS_POWER_SAVE_ENTER = 1,
 	ICNSS_POWER_SAVE_EXIT,
 	ICNSS_TRIGGER_SSR,
+	ICNSS_PCI_EP_POWER_SAVE_ENTER = 6,
+	ICNSS_PCI_EP_POWER_SAVE_EXIT,
 };
 
 struct icnss_stats {
@@ -342,6 +345,9 @@
 	phys_addr_t mem_base_pa;
 	void __iomem *mem_base_va;
 	u32 mem_base_size;
+	phys_addr_t mhi_state_info_pa;
+	void __iomem *mhi_state_info_va;
+	u32 mhi_state_info_size;
 	struct iommu_domain *iommu_domain;
 	dma_addr_t smmu_iova_start;
 	size_t smmu_iova_len;
diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c
index 8a8b576..fad86c7 100644
--- a/drivers/soc/qcom/icnss2/qmi.c
+++ b/drivers/soc/qcom/icnss2/qmi.c
@@ -334,6 +334,15 @@
 		goto out;
 	}
 
+	if (resp->mhi_state_info_addr_valid)
+		priv->mhi_state_info_pa = resp->mhi_state_info_addr;
+
+	if (resp->mhi_state_info_size_valid)
+		priv->mhi_state_info_size = resp->mhi_state_info_size;
+
+	if (!priv->mhi_state_info_pa)
+		icnss_pr_err("Fail to get MHI info address\n");
+
 	kfree(resp);
 	kfree(req);
 	return 0;
diff --git a/include/soc/qcom/icnss2.h b/include/soc/qcom/icnss2.h
index 940241e..0a1406c 100644
--- a/include/soc/qcom/icnss2.h
+++ b/include/soc/qcom/icnss2.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 #ifndef _ICNSS_WLAN_H_
 #define _ICNSS_WLAN_H_
@@ -191,4 +191,8 @@
 					    unsigned long *thermal_state,
 					    int tcdev_id);
 extern int icnss_exit_power_save(struct device *dev);
+extern int icnss_prevent_l1(struct device *dev);
+extern void icnss_allow_l1(struct device *dev);
+extern int icnss_get_mhi_state(struct device *dev);
+extern int icnss_is_pci_ep_awake(struct device *dev);
 #endif /* _ICNSS_WLAN_H_ */