Merge "msm: ipa: unify wdi 1/2 and wdi 3 API"
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index bf498f9..b99435d 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -3167,52 +3167,53 @@
 EXPORT_SYMBOL(ipa_get_smmu_params);
 
 /**
- * ipa_conn_wdi3_pipes() - connect wdi3 pipes
+ * ipa_conn_wdi_pipes() - connect wdi pipes
  */
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_conn_wdi3_pipes, in, out);
+	IPA_API_DISPATCH_RETURN(ipa_conn_wdi_pipes, in, out, wdi_notify);
 
 	return ret;
 }
 
 /**
- * ipa_disconn_wdi3_pipes() - disconnect wdi3 pipes
+ * ipa_disconn_wdi_pipes() - disconnect wdi pipes
  */
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_disconn_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_disconn_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
 }
 
 /**
- * ipa_enable_wdi3_pipes() - enable wdi3 pipes
+ * ipa_enable_wdi_pipes() - enable wdi pipes
  */
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_enable_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_enable_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
 }
 
 /**
- * ipa_disable_wdi3_pipes() - disable wdi3 pipes
+ * ipa_disable_wdi_pipes() - disable wdi pipes
  */
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
 {
 	int ret;
 
-	IPA_API_DISPATCH_RETURN(ipa_disable_wdi3_pipes, ipa_ep_idx_tx,
+	IPA_API_DISPATCH_RETURN(ipa_disable_wdi_pipes, ipa_ep_idx_tx,
 		ipa_ep_idx_rx);
 
 	return ret;
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index 79d0c70..fc4362f 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -403,16 +403,17 @@
 
 	void (*ipa_ntn_uc_dereg_rdyCB)(void);
 
-	int (*ipa_conn_wdi3_pipes)(struct ipa_wdi3_conn_in_params *in,
-		struct ipa_wdi3_conn_out_params *out);
+	int (*ipa_conn_wdi_pipes)(struct ipa_wdi_conn_in_params *in,
+		struct ipa_wdi_conn_out_params *out,
+		ipa_wdi_meter_notifier_cb wdi_notify);
 
-	int (*ipa_disconn_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_disconn_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
-	int (*ipa_enable_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_enable_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
-	int (*ipa_disable_wdi3_pipes)(int ipa_ep_idx_tx,
+	int (*ipa_disable_wdi_pipes)(int ipa_ep_idx_tx,
 		int ipa_ep_idx_rx);
 
 	int (*ipa_tz_unlock_reg)(struct ipa_tz_unlock_reg_info *reg_info,
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
index f4c8763..b2e454a 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,9 +14,10 @@
 #include <linux/msm_ipa.h>
 #include <linux/string.h>
 #include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
 
-#define OFFLOAD_DRV_NAME "ipa_wdi3"
-#define IPA_WDI3_DBG(fmt, args...) \
+#define OFFLOAD_DRV_NAME "ipa_wdi"
+#define IPA_WDI_DBG(fmt, args...) \
 	do { \
 		pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -26,7 +27,7 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-#define IPA_WDI3_DBG_LOW(fmt, args...) \
+#define IPA_WDI_DBG_LOW(fmt, args...) \
 	do { \
 		pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -34,7 +35,7 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-#define IPA_WDI3_ERR(fmt, args...) \
+#define IPA_WDI_ERR(fmt, args...) \
 	do { \
 		pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \
 			__func__, __LINE__, ## args); \
@@ -44,32 +45,107 @@
 			OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
 	} while (0)
 
-struct ipa_wdi3_intf_info {
+struct ipa_wdi_intf_info {
 	char netdev_name[IPA_RESOURCE_NAME_MAX];
 	u8 hdr_len;
 	u32 partial_hdr_hdl[IPA_IP_MAX];
 	struct list_head link;
 };
 
-struct ipa_wdi3_context {
+struct ipa_wdi_context {
 	struct list_head head_intf_list;
-	ipa_notify_cb notify;
-	void *priv;
-	struct completion wdi3_completion;
+	struct completion wdi_completion;
 	struct mutex lock;
+	enum ipa_wdi_version wdi_version;
+	u8 is_smmu_enabled;
+	u32 tx_pipe_hdl;
+	u32 rx_pipe_hdl;
+	u8 num_sys_pipe_needed;
+	u32 sys_pipe_hdl[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+	u32 ipa_pm_hdl;
+	ipa_wdi_meter_notifier_cb wdi_notify;
 };
 
-static struct ipa_wdi3_context *ipa_wdi3_ctx;
+static struct ipa_wdi_context *ipa_wdi_ctx;
 
-static int ipa_wdi3_commit_partial_hdr(
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out)
+{
+	struct ipa_wdi_uc_ready_params uc_ready_params;
+	struct ipa_smmu_in_params smmu_in;
+	struct ipa_smmu_out_params smmu_out;
+
+	if (ipa_wdi_ctx) {
+		IPA_WDI_ERR("ipa_wdi_ctx was initialized before\n");
+		return -EFAULT;
+	}
+
+	if (in->wdi_version > IPA_WDI_3 || in->wdi_version < IPA_WDI_1) {
+		IPA_WDI_ERR("wrong wdi version: %d\n", in->wdi_version);
+		return -EFAULT;
+	}
+
+	ipa_wdi_ctx = kzalloc(sizeof(*ipa_wdi_ctx), GFP_KERNEL);
+	if (ipa_wdi_ctx == NULL)
+		return -ENOMEM;
+
+	mutex_init(&ipa_wdi_ctx->lock);
+	init_completion(&ipa_wdi_ctx->wdi_completion);
+	INIT_LIST_HEAD(&ipa_wdi_ctx->head_intf_list);
+
+	ipa_wdi_ctx->wdi_version = in->wdi_version;
+	uc_ready_params.notify = in->notify;
+	uc_ready_params.priv = in->priv;
+	ipa_wdi_ctx->wdi_notify = in->wdi_notify;
+
+	if (ipa_uc_reg_rdyCB(&uc_ready_params) != 0) {
+		mutex_destroy(&ipa_wdi_ctx->lock);
+		kfree(ipa_wdi_ctx);
+		ipa_wdi_ctx = NULL;
+		return -EFAULT;
+	}
+
+	out->is_uC_ready = uc_ready_params.is_uC_ready;
+
+	smmu_in.smmu_client = IPA_SMMU_WLAN_CLIENT;
+	if (ipa_get_smmu_params(&smmu_in, &smmu_out))
+		out->is_smmu_enabled = false;
+	else
+		out->is_smmu_enabled = smmu_out.smmu_enable;
+
+	ipa_wdi_ctx->is_smmu_enabled = out->is_smmu_enabled;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_init);
+
+int ipa_wdi_cleanup(void)
+{
+	struct ipa_wdi_intf_info *entry;
+	struct ipa_wdi_intf_info *next;
+
+	/* clear interface list */
+	list_for_each_entry_safe(entry, next,
+		&ipa_wdi_ctx->head_intf_list, link) {
+		list_del(&entry->link);
+		kfree(entry);
+	}
+	mutex_destroy(&ipa_wdi_ctx->lock);
+	kfree(ipa_wdi_ctx);
+	ipa_wdi_ctx = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_cleanup);
+
+static int ipa_wdi_commit_partial_hdr(
 	struct ipa_ioc_add_hdr *hdr,
 	const char *netdev_name,
-	struct ipa_wdi3_hdr_info *hdr_info)
+	struct ipa_wdi_hdr_info *hdr_info)
 {
 	int i;
 
 	if (!hdr || !hdr_info || !netdev_name) {
-		IPA_WDI3_ERR("Invalid input\n");
+		IPA_WDI_ERR("Invalid input\n");
 		return -EINVAL;
 	}
 
@@ -90,18 +166,18 @@
 	}
 
 	if (ipa_add_hdr(hdr)) {
-		IPA_WDI3_ERR("fail to add partial headers\n");
+		IPA_WDI_ERR("fail to add partial headers\n");
 		return -EFAULT;
 	}
 
 	return 0;
 }
 
-int ipa_wdi3_reg_intf(struct ipa_wdi3_reg_intf_in_params *in)
+int ipa_wdi_reg_intf(struct ipa_wdi_reg_intf_in_params *in)
 {
 	struct ipa_ioc_add_hdr *hdr;
-	struct ipa_wdi3_intf_info *new_intf;
-	struct ipa_wdi3_intf_info *entry;
+	struct ipa_wdi_intf_info *new_intf;
+	struct ipa_wdi_intf_info *entry;
 	struct ipa_tx_intf tx;
 	struct ipa_rx_intf rx;
 	struct ipa_ioc_tx_intf_prop tx_prop[2];
@@ -110,36 +186,30 @@
 	int ret = 0;
 
 	if (in == NULL) {
-		IPA_WDI3_ERR("invalid params in=%pK\n", in);
+		IPA_WDI_ERR("invalid params in=NULL\n");
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
-		if (ipa_wdi3_ctx == NULL) {
-			IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
-			return -ENOMEM;
-		}
-		mutex_init(&ipa_wdi3_ctx->lock);
-		INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
 	}
 
-	IPA_WDI3_DBG("register interface for netdev %s\n",
+	IPA_WDI_DBG("register interface for netdev %s\n",
 		in->netdev_name);
 
-	mutex_lock(&ipa_wdi3_ctx->lock);
-	list_for_each_entry(entry, &ipa_wdi3_ctx->head_intf_list, link)
+	mutex_lock(&ipa_wdi_ctx->lock);
+	list_for_each_entry(entry, &ipa_wdi_ctx->head_intf_list, link)
 		if (strcmp(entry->netdev_name, in->netdev_name) == 0) {
-			IPA_WDI3_DBG("intf was added before.\n");
-			mutex_unlock(&ipa_wdi3_ctx->lock);
+			IPA_WDI_DBG("intf was added before\n");
+			mutex_unlock(&ipa_wdi_ctx->lock);
 			return 0;
 		}
 
-	IPA_WDI3_DBG("intf was not added before, proceed.\n");
+	IPA_WDI_DBG("intf was not added before, proceed\n");
 	new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL);
 	if (new_intf == NULL) {
-		IPA_WDI3_ERR("fail to alloc new intf\n");
-		mutex_unlock(&ipa_wdi3_ctx->lock);
+		mutex_unlock(&ipa_wdi_ctx->lock);
 		return -ENOMEM;
 	}
 
@@ -152,20 +222,19 @@
 	len = sizeof(struct ipa_ioc_add_hdr) + 2 * sizeof(struct ipa_hdr_add);
 	hdr = kzalloc(len, GFP_KERNEL);
 	if (hdr == NULL) {
-		IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
 		ret = -EFAULT;
 		goto fail_alloc_hdr;
 	}
 
-	if (ipa_wdi3_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
-		IPA_WDI3_ERR("fail to commit partial headers\n");
+	if (ipa_wdi_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
+		IPA_WDI_ERR("fail to commit partial headers\n");
 		ret = -EFAULT;
 		goto fail_commit_hdr;
 	}
 
 	new_intf->partial_hdr_hdl[IPA_IP_v4] = hdr->hdr[IPA_IP_v4].hdr_hdl;
 	new_intf->partial_hdr_hdl[IPA_IP_v6] = hdr->hdr[IPA_IP_v6].hdr_hdl;
-	IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+	IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
 		hdr->hdr[IPA_IP_v4].hdr_hdl, hdr->hdr[IPA_IP_v6].hdr_hdl);
 
 	/* populate tx prop */
@@ -175,12 +244,14 @@
 	memset(tx_prop, 0, sizeof(tx_prop));
 	tx_prop[0].ip = IPA_IP_v4;
 	tx_prop[0].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+	tx_prop[0].alt_dst_pipe = in->alt_dst_pipe;
 	tx_prop[0].hdr_l2_type = in->hdr_info[0].hdr_type;
 	strlcpy(tx_prop[0].hdr_name, hdr->hdr[IPA_IP_v4].name,
 		sizeof(tx_prop[0].hdr_name));
 
 	tx_prop[1].ip = IPA_IP_v6;
 	tx_prop[1].dst_pipe = IPA_CLIENT_WLAN1_CONS;
+	tx_prop[1].alt_dst_pipe = in->alt_dst_pipe;
 	tx_prop[1].hdr_l2_type = in->hdr_info[1].hdr_type;
 	strlcpy(tx_prop[1].hdr_name, hdr->hdr[IPA_IP_v6].name,
 		sizeof(tx_prop[1].hdr_name));
@@ -209,54 +280,53 @@
 	}
 
 	if (ipa_register_intf(in->netdev_name, &tx, &rx)) {
-		IPA_WDI3_ERR("fail to add interface prop\n");
+		IPA_WDI_ERR("fail to add interface prop\n");
 		ret = -EFAULT;
 		goto fail_commit_hdr;
 	}
 
-	list_add(&new_intf->link, &ipa_wdi3_ctx->head_intf_list);
-	init_completion(&ipa_wdi3_ctx->wdi3_completion);
+	list_add(&new_intf->link, &ipa_wdi_ctx->head_intf_list);
+	init_completion(&ipa_wdi_ctx->wdi_completion);
 
 	kfree(hdr);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return 0;
 
 fail_commit_hdr:
 	kfree(hdr);
 fail_alloc_hdr:
 	kfree(new_intf);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_reg_intf);
+EXPORT_SYMBOL(ipa_wdi_reg_intf);
 
-int ipa_wdi3_dereg_intf(const char *netdev_name)
+int ipa_wdi_dereg_intf(const char *netdev_name)
 {
 	int len, ret = 0;
 	struct ipa_ioc_del_hdr *hdr = NULL;
-	struct ipa_wdi3_intf_info *entry;
-	struct ipa_wdi3_intf_info *next;
+	struct ipa_wdi_intf_info *entry;
+	struct ipa_wdi_intf_info *next;
 
 	if (!netdev_name) {
-		IPA_WDI3_ERR("no netdev name.\n");
+		IPA_WDI_ERR("no netdev name\n");
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		return -EPERM;
 	}
 
-	mutex_lock(&ipa_wdi3_ctx->lock);
-	list_for_each_entry_safe(entry, next, &ipa_wdi3_ctx->head_intf_list,
+	mutex_lock(&ipa_wdi_ctx->lock);
+	list_for_each_entry_safe(entry, next, &ipa_wdi_ctx->head_intf_list,
 		link)
 		if (strcmp(entry->netdev_name, netdev_name) == 0) {
 			len = sizeof(struct ipa_ioc_del_hdr) +
 				2 * sizeof(struct ipa_hdr_del);
 			hdr = kzalloc(len, GFP_KERNEL);
 			if (hdr == NULL) {
-				IPA_WDI3_ERR("fail to alloc %d bytes\n", len);
-				mutex_unlock(&ipa_wdi3_ctx->lock);
+				mutex_unlock(&ipa_wdi_ctx->lock);
 				return -ENOMEM;
 			}
 
@@ -264,20 +334,21 @@
 			hdr->num_hdls = 2;
 			hdr->hdl[0].hdl = entry->partial_hdr_hdl[0];
 			hdr->hdl[1].hdl = entry->partial_hdr_hdl[1];
-			IPA_WDI3_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
+			IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
 				hdr->hdl[0].hdl, hdr->hdl[1].hdl);
 
 			if (ipa_del_hdr(hdr)) {
-				IPA_WDI3_ERR("fail to delete partial header\n");
+				IPA_WDI_ERR("fail to delete partial header\n");
 				ret = -EFAULT;
 				goto fail;
 			}
 
 			if (ipa_deregister_intf(entry->netdev_name)) {
-				IPA_WDI3_ERR("fail to del interface props\n");
+				IPA_WDI_ERR("fail to del interface props\n");
 				ret = -EFAULT;
 				goto fail;
 			}
+
 			list_del(&entry->link);
 			kfree(entry);
 
@@ -286,241 +357,512 @@
 
 fail:
 	kfree(hdr);
-	mutex_unlock(&ipa_wdi3_ctx->lock);
+	mutex_unlock(&ipa_wdi_ctx->lock);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_dereg_intf);
+EXPORT_SYMBOL(ipa_wdi_dereg_intf);
 
-static void ipa_wdi3_rm_notify(void *user_data, enum ipa_rm_event event,
+static void ipa_wdi_rm_notify(void *user_data, enum ipa_rm_event event,
 		unsigned long data)
 {
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("Invalid context\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("Invalid context\n");
 		return;
 	}
 
 	switch (event) {
 	case IPA_RM_RESOURCE_GRANTED:
-		complete_all(&ipa_wdi3_ctx->wdi3_completion);
+		complete_all(&ipa_wdi_ctx->wdi_completion);
 		break;
 
 	case IPA_RM_RESOURCE_RELEASED:
 		break;
 
 	default:
-		IPA_WDI3_ERR("Invalid RM Evt: %d", event);
+		IPA_WDI_ERR("Invalid RM Evt: %d", event);
 		break;
 	}
 }
 
-static int ipa_wdi3_cons_release(void)
+static int ipa_wdi_cons_release(void)
 {
 	return 0;
 }
 
-static int ipa_wdi3_cons_request(void)
+static int ipa_wdi_cons_request(void)
 {
 	int ret = 0;
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		ret = -EFAULT;
 	}
 
 	return ret;
 }
 
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out)
+static void ipa_wdi_pm_cb(void *p, enum ipa_pm_cb_event event)
 {
-	int ret = 0;
+	IPA_WDI_DBG("received pm event %d\n", event);
+}
+
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+			struct ipa_wdi_conn_out_params *out)
+{
+	int i, j, ret = 0;
 	struct ipa_rm_create_params param;
+	struct ipa_pm_register_params pm_params;
+	struct ipa_wdi_in_params in_tx;
+	struct ipa_wdi_in_params in_rx;
+	struct ipa_wdi_out_params out_tx;
+	struct ipa_wdi_out_params out_rx;
 
 	if (!(in && out)) {
-		IPA_WDI3_ERR("empty parameters. in=%pK out=%pK\n", in, out);
+		IPA_WDI_ERR("empty parameters. in=%pK out=%pK\n", in, out);
 		return -EINVAL;
 	}
 
-	if (!ipa_wdi3_ctx) {
-		ipa_wdi3_ctx = kzalloc(sizeof(*ipa_wdi3_ctx), GFP_KERNEL);
-		if (ipa_wdi3_ctx == NULL) {
-			IPA_WDI3_ERR("fail to alloc wdi3 ctx\n");
-			return -EFAULT;
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
+	}
+
+	if (in->num_sys_pipe_needed > IPA_WDI_MAX_SUPPORTED_SYS_PIPE) {
+		IPA_WDI_ERR("ipa can only support up to %d sys pipe\n",
+			IPA_WDI_MAX_SUPPORTED_SYS_PIPE);
+		return -EINVAL;
+	}
+	ipa_wdi_ctx->num_sys_pipe_needed = in->num_sys_pipe_needed;
+	IPA_WDI_DBG("number of sys pipe %d\n", in->num_sys_pipe_needed);
+
+	/* setup sys pipe when needed */
+	for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+		ret = ipa_setup_sys_pipe(&in->sys_in[i],
+			&ipa_wdi_ctx->sys_pipe_hdl[i]);
+		if (ret) {
+			IPA_WDI_ERR("fail to setup sys pipe %d\n", i);
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
 		}
-		mutex_init(&ipa_wdi3_ctx->lock);
-		INIT_LIST_HEAD(&ipa_wdi3_ctx->head_intf_list);
-	}
-	ipa_wdi3_ctx->notify = in->notify;
-	ipa_wdi3_ctx->priv = in->priv;
-
-	memset(&param, 0, sizeof(param));
-	param.name = IPA_RM_RESOURCE_WLAN_PROD;
-	param.reg_params.user_data = ipa_wdi3_ctx;
-	param.reg_params.notify_cb = ipa_wdi3_rm_notify;
-	param.floor_voltage = IPA_VOLTAGE_SVS;
-	ret = ipa_rm_create_resource(&param);
-	if (ret) {
-		IPA_WDI3_ERR("fail to create WLAN_PROD resource\n");
-		return -EFAULT;
 	}
 
-	memset(&param, 0, sizeof(param));
-	param.name = IPA_RM_RESOURCE_WLAN_CONS;
-	param.request_resource = ipa_wdi3_cons_request;
-	param.release_resource = ipa_wdi3_cons_release;
-	ret = ipa_rm_create_resource(&param);
-	if (ret) {
-		IPA_WDI3_ERR("fail to create WLAN_CONS resource\n");
-		goto fail_create_rm_cons;
+	if (!ipa_pm_is_used()) {
+		memset(&param, 0, sizeof(param));
+		param.name = IPA_RM_RESOURCE_WLAN_PROD;
+		param.reg_params.user_data = ipa_wdi_ctx;
+		param.reg_params.notify_cb = ipa_wdi_rm_notify;
+		param.floor_voltage = IPA_VOLTAGE_SVS;
+		ret = ipa_rm_create_resource(&param);
+		if (ret) {
+			IPA_WDI_ERR("fail to create WLAN_PROD resource\n");
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
+		}
+
+		memset(&param, 0, sizeof(param));
+		param.name = IPA_RM_RESOURCE_WLAN_CONS;
+		param.request_resource = ipa_wdi_cons_request;
+		param.release_resource = ipa_wdi_cons_release;
+		ret = ipa_rm_create_resource(&param);
+		if (ret) {
+			IPA_WDI_ERR("fail to create WLAN_CONS resource\n");
+			goto fail_create_rm_cons;
+		}
+
+		if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+			IPA_RM_RESOURCE_APPS_CONS)) {
+			IPA_WDI_ERR("fail to add rm dependency\n");
+			ret = -EFAULT;
+			goto fail_add_dependency;
+		}
+	} else {
+		pm_params.name = "wdi";
+		pm_params.callback = ipa_wdi_pm_cb;
+		pm_params.user_data = NULL;
+		pm_params.group = IPA_PM_GROUP_DEFAULT;
+		if (ipa_pm_register(&pm_params, &ipa_wdi_ctx->ipa_pm_hdl)) {
+			IPA_WDI_ERR("fail to register ipa pm\n");
+			ret = -EFAULT;
+			goto fail_setup_sys_pipe;
+		}
 	}
 
-	if (ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD,
-		IPA_RM_RESOURCE_APPS_CONS)) {
-		IPA_WDI3_ERR("fail to add rm dependency\n");
-		ret = -EFAULT;
-		goto fail;
-	}
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_conn_wdi_pipes(in, out, ipa_wdi_ctx->wdi_notify)) {
+			IPA_WDI_ERR("fail to setup wdi pipes\n");
+			ret = -EFAULT;
+			goto fail_connect_pipe;
+		}
+	} else {
+		memset(&in_tx, 0, sizeof(in_tx));
+		memset(&in_rx, 0, sizeof(in_rx));
+		memset(&out_tx, 0, sizeof(out_tx));
+		memset(&out_rx, 0, sizeof(out_rx));
+		in_rx.wdi_notify = ipa_wdi_ctx->wdi_notify;
+		if (in->is_smmu_enabled == false) {
+			/* firsr setup rx pipe */
+			in_rx.sys.ipa_ep_cfg = in->u_rx.rx.ipa_ep_cfg;
+			in_rx.sys.client = in->u_rx.rx.client;
+			in_rx.sys.notify = in->notify;
+			in_rx.sys.priv = in->priv;
+			in_rx.smmu_enabled = in->is_smmu_enabled;
+			in_rx.u.ul.rdy_ring_base_pa =
+				in->u_rx.rx.transfer_ring_base_pa;
+			in_rx.u.ul.rdy_ring_size =
+				in->u_rx.rx.transfer_ring_size;
+			in_rx.u.ul.rdy_ring_rp_pa =
+				in->u_rx.rx.transfer_ring_doorbell_pa;
+			in_rx.u.ul.rdy_comp_ring_base_pa =
+				in->u_rx.rx.event_ring_base_pa;
+			in_rx.u.ul.rdy_comp_ring_wp_pa =
+				in->u_rx.rx.event_ring_doorbell_pa;
+			in_rx.u.ul.rdy_comp_ring_size =
+				in->u_rx.rx.event_ring_size;
+			if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+				IPA_WDI_ERR("fail to setup rx pipe\n");
+				ret = -EFAULT;
+				goto fail_connect_pipe;
+			}
+			ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+			out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+			IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
 
-	if (ipa_conn_wdi3_pipes(in, out)) {
-		IPA_WDI3_ERR("fail to setup wdi3 pipes\n");
-		ret = -EFAULT;
-		goto fail;
+			/* then setup tx pipe */
+			in_tx.sys.ipa_ep_cfg = in->u_tx.tx.ipa_ep_cfg;
+			in_tx.sys.client = in->u_tx.tx.client;
+			in_tx.smmu_enabled = in->is_smmu_enabled;
+			in_tx.u.dl.comp_ring_base_pa =
+				in->u_tx.tx.transfer_ring_base_pa;
+			in_tx.u.dl.comp_ring_size =
+				in->u_tx.tx.transfer_ring_size;
+			in_tx.u.dl.ce_ring_base_pa =
+				in->u_tx.tx.event_ring_base_pa;
+			in_tx.u.dl.ce_door_bell_pa =
+				in->u_tx.tx.event_ring_doorbell_pa;
+			in_tx.u.dl.ce_ring_size =
+				in->u_tx.tx.event_ring_size;
+			in_tx.u.dl.num_tx_buffers =
+				in->u_tx.tx.num_pkt_buffers;
+			if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+				IPA_WDI_ERR("fail to setup tx pipe\n");
+				ret = -EFAULT;
+				goto fail;
+			}
+			ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+			out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+			IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+		} else { /* smmu is enabled */
+			/* firsr setup rx pipe */
+			in_rx.sys.ipa_ep_cfg = in->u_rx.rx_smmu.ipa_ep_cfg;
+			in_rx.sys.client = in->u_rx.rx_smmu.client;
+			in_rx.sys.notify = in->notify;
+			in_rx.sys.priv = in->priv;
+			in_rx.smmu_enabled = in->is_smmu_enabled;
+			in_rx.u.ul_smmu.rdy_ring =
+				in->u_rx.rx_smmu.transfer_ring_base;
+			in_rx.u.ul_smmu.rdy_ring_size =
+				in->u_rx.rx_smmu.transfer_ring_size;
+			in_rx.u.ul_smmu.rdy_ring_rp_pa =
+				in->u_rx.rx_smmu.transfer_ring_doorbell_pa;
+			in_rx.u.ul_smmu.rdy_comp_ring =
+				in->u_rx.rx_smmu.event_ring_base;
+			in_rx.u.ul_smmu.rdy_comp_ring_wp_pa =
+				in->u_rx.rx_smmu.event_ring_doorbell_pa;
+			in_rx.u.ul_smmu.rdy_comp_ring_size =
+				in->u_rx.rx_smmu.event_ring_size;
+			if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
+				IPA_WDI_ERR("fail to setup rx pipe\n");
+				ret = -EFAULT;
+				goto fail_connect_pipe;
+			}
+			ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
+			out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
+			IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
+
+			/* then setup tx pipe */
+			in_tx.sys.ipa_ep_cfg = in->u_tx.tx_smmu.ipa_ep_cfg;
+			in_tx.sys.client = in->u_tx.tx_smmu.client;
+			in_tx.smmu_enabled = in->is_smmu_enabled;
+			in_tx.u.dl_smmu.comp_ring =
+				in->u_tx.tx_smmu.transfer_ring_base;
+			in_tx.u.dl_smmu.comp_ring_size =
+				in->u_tx.tx_smmu.transfer_ring_size;
+			in_tx.u.dl_smmu.ce_ring =
+				in->u_tx.tx_smmu.event_ring_base;
+			in_tx.u.dl_smmu.ce_door_bell_pa =
+				in->u_tx.tx_smmu.event_ring_doorbell_pa;
+			in_tx.u.dl_smmu.ce_ring_size =
+				in->u_tx.tx_smmu.event_ring_size;
+			in_tx.u.dl_smmu.num_tx_buffers =
+				in->u_tx.tx_smmu.num_pkt_buffers;
+			if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
+				IPA_WDI_ERR("fail to setup tx pipe\n");
+				ret = -EFAULT;
+				goto fail;
+			}
+			ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
+			out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
+			IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
+		}
 	}
 
 	return 0;
 
 fail:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
+	ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl);
+fail_connect_pipe:
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+			IPA_RM_RESOURCE_APPS_CONS);
+	else
+		ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl);
+fail_add_dependency:
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS);
 fail_create_rm_cons:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
-
+	if (!ipa_pm_is_used())
+		ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD);
+fail_setup_sys_pipe:
+	for (j = 0; j < i; j++)
+		ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[j]);
 	return ret;
 }
-EXPORT_SYMBOL(ipa_wdi3_conn_pipes);
+EXPORT_SYMBOL(ipa_wdi_conn_pipes);
 
-int ipa_wdi3_disconn_pipes(void)
+int ipa_wdi_disconn_pipes(void)
 {
-	int ipa_ep_idx_rx, ipa_ep_idx_tx;
+	int i, ipa_ep_idx_rx, ipa_ep_idx_tx;
 
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized\n");
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
 		return -EPERM;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_disconn_wdi3_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
-		IPA_WDI3_ERR("fail to tear down wdi3 pipes\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
-				IPA_RM_RESOURCE_APPS_CONS)) {
-		IPA_WDI3_ERR("fail to delete rm dependency\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
-		IPA_WDI3_ERR("fail to delete WLAN_PROD resource\n");
-		return -EFAULT;
-	}
-
-	if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
-		IPA_WDI3_ERR("fail to delete WLAN_CONS resource\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_disconn_pipes);
-
-int ipa_wdi3_enable_pipes(void)
-{
-	int ret;
-	int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
-		return -EPERM;
-	}
-
-	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_enable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
-		IPA_WDI3_ERR("fail to enable wdi3 pipes\n");
-		return -EFAULT;
-	}
-
-	ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
-	if (ret == -EINPROGRESS) {
-		if (wait_for_completion_timeout(&ipa_wdi3_ctx->wdi3_completion,
-			10*HZ) == 0) {
-			IPA_WDI3_ERR("WLAN_PROD resource req time out\n");
+	/* tear down sys pipe if needed */
+	for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
+		if (ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[i])) {
+			IPA_WDI_ERR("fail to tear down sys pipe %d\n", i);
 			return -EFAULT;
 		}
-	} else if (ret != 0) {
-		IPA_WDI3_ERR("fail to request resource\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(ipa_wdi3_enable_pipes);
-
-int ipa_wdi3_disable_pipes(void)
-{
-	int ret;
-	int ipa_ep_idx_tx, ipa_ep_idx_rx;
-
-	if (!ipa_wdi3_ctx) {
-		IPA_WDI3_ERR("wdi3 ctx is not initialized.\n");
-		return -EPERM;
-	}
-
-	ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
-	if (ret != 0) {
-		IPA_WDI3_ERR("fail to release resource\n");
-		return -EFAULT;
 	}
 
 	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
 	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
-	if (ipa_disable_wdi3_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
-		IPA_WDI3_ERR("fail to disable wdi3 pipes\n");
-		return -EFAULT;
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_disconn_wdi_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
+			IPA_WDI_ERR("fail to tear down wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to tear down wdi tx pipes\n");
+			return -EFAULT;
+		}
+		if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to tear down wdi rx pipes\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		if (ipa_rm_delete_dependency(IPA_RM_RESOURCE_WLAN_PROD,
+					IPA_RM_RESOURCE_APPS_CONS)) {
+			IPA_WDI_ERR("fail to delete rm dependency\n");
+			return -EFAULT;
+		}
+
+		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
+			IPA_WDI_ERR("fail to delete WLAN_PROD resource\n");
+			return -EFAULT;
+		}
+
+		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS)) {
+			IPA_WDI_ERR("fail to delete WLAN_CONS resource\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl)) {
+			IPA_WDI_ERR("fail to deregister ipa pm\n");
+			return -EFAULT;
+		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(ipa_wdi3_disable_pipes);
+EXPORT_SYMBOL(ipa_wdi_disconn_pipes);
 
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile)
+int ipa_wdi_enable_pipes(void)
+{
+	int ret;
+	int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized\n");
+		return -EPERM;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_enable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+			IPA_WDI_ERR("fail to enable wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_enable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to enable wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_resume_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to resume wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_enable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to enable wdi rx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_resume_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to resume wdi rx pipe\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		ret = ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD);
+		if (ret == -EINPROGRESS) {
+			if (wait_for_completion_timeout(
+				&ipa_wdi_ctx->wdi_completion, 10*HZ) == 0) {
+				IPA_WDI_ERR("WLAN_PROD res req time out\n");
+				return -EFAULT;
+			}
+		} else if (ret != 0) {
+			IPA_WDI_ERR("fail to request resource\n");
+			return -EFAULT;
+		}
+	} else {
+		ret = ipa_pm_activate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+		if (ret) {
+			IPA_WDI_ERR("fail to activate ipa pm\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_enable_pipes);
+
+int ipa_wdi_disable_pipes(void)
+{
+	int ret;
+	int ipa_ep_idx_tx, ipa_ep_idx_rx;
+
+	if (!ipa_wdi_ctx) {
+		IPA_WDI_ERR("wdi ctx is not initialized.\n");
+		return -EPERM;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
+
+	if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
+		if (ipa_disable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
+			IPA_WDI_ERR("fail to disable wdi pipes\n");
+			return -EFAULT;
+		}
+	} else {
+		if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to suspend wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_disable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to disable wdi tx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to suspend wdi rx pipe\n");
+			return -EFAULT;
+		}
+		if (ipa_disable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
+			IPA_WDI_ERR("fail to disable wdi rx pipe\n");
+			return -EFAULT;
+		}
+	}
+
+	if (!ipa_pm_is_used()) {
+		ret = ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD);
+		if (ret != 0) {
+			IPA_WDI_ERR("fail to release resource\n");
+			return -EFAULT;
+		}
+	} else {
+		ret = ipa_pm_deactivate_sync(ipa_wdi_ctx->ipa_pm_hdl);
+		if (ret) {
+			IPA_WDI_ERR("fail to deactivate ipa pm\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_wdi_disable_pipes);
+
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile)
 {
 	struct ipa_rm_perf_profile rm_profile;
 	enum ipa_rm_resource_name resource_name;
 
 	if (profile == NULL) {
-		IPA_WDI3_ERR("Invalid input\n");
+		IPA_WDI_ERR("Invalid input\n");
 		return -EINVAL;
 	}
 
-	rm_profile.max_supported_bandwidth_mbps =
-		profile->max_supported_bw_mbps;
+	if (!ipa_pm_is_used()) {
+		rm_profile.max_supported_bandwidth_mbps =
+			profile->max_supported_bw_mbps;
 
-	if (profile->client == IPA_CLIENT_WLAN1_PROD) {
-		resource_name = IPA_RM_RESOURCE_WLAN_PROD;
-	} else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
-		resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+		if (profile->client == IPA_CLIENT_WLAN1_PROD) {
+			resource_name = IPA_RM_RESOURCE_WLAN_PROD;
+		} else if (profile->client == IPA_CLIENT_WLAN1_CONS) {
+			resource_name = IPA_RM_RESOURCE_WLAN_CONS;
+		} else {
+			IPA_WDI_ERR("not supported\n");
+			return -EINVAL;
+		}
+
+		if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
+			IPA_WDI_ERR("fail to setup rm perf profile\n");
+			return -EFAULT;
+		}
 	} else {
-		IPA_WDI3_ERR("not supported\n");
-		return -EINVAL;
-	}
-
-	if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
-		IPA_WDI3_ERR("fail to setup rm perf profile\n");
-		return -EFAULT;
+		if (ipa_pm_set_perf_profile(ipa_wdi_ctx->ipa_pm_hdl,
+			profile->max_supported_bw_mbps)) {
+			IPA_WDI_ERR("fail to setup pm perf profile\n");
+			return -EFAULT;
+		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(ipa_wdi3_set_perf_profile);
+EXPORT_SYMBOL(ipa_wdi_set_perf_profile);
+
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return ipa_create_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_create_smmu_mapping);
+
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return ipa_release_wdi_mapping(num_buffers, info);
+}
+EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping);
+
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
+{
+	return ipa_get_wdi_stats(stats);
+}
+EXPORT_SYMBOL(ipa_wdi_get_stats);
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 98a1cf9..b37a127 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -419,14 +419,15 @@
 			      void *user_data);
 void ipa_ntn_uc_dereg_rdyCB(void);
 
-int ipa_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa_conn_wdi_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 
-int ipa_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disconn_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
-int ipa_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_enable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
-int ipa_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
+int ipa_disable_wdi_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 
 const char *ipa_get_version_string(enum ipa_hw_type ver);
 int ipa_start_gsi_channel(u32 clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 78d1c96..e43a201 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -4358,7 +4358,7 @@
 	else
 		IPADBG(":ipa Uc interface init ok\n");
 
-	result = ipa_wdi_init();
+	result = ipa2_wdi_init();
 	if (result)
 		IPAERR(":wdi init failed (%d)\n", -result);
 	else
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 91017a5..bd7f600 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -67,6 +67,16 @@
 #define IPA_MAX_NUM_REQ_CACHE 10
 #define IPA_IPC_LOG_PAGES 50
 
+#define IPA_WDI_RX_RING_RES 0
+#define IPA_WDI_RX_RING_RP_RES 1
+#define IPA_WDI_RX_COMP_RING_RES 2
+#define IPA_WDI_RX_COMP_RING_WP_RES 3
+#define IPA_WDI_TX_RING_RES 4
+#define IPA_WDI_CE_RING_RES 5
+#define IPA_WDI_CE_DB_RES 6
+#define IPA_WDI_TX_DB_RES 7
+#define IPA_WDI_MAX_RES 8
+
 #define IPADBG(fmt, args...) \
 	do { \
 		pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\
@@ -1578,8 +1588,9 @@
 int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
 void ipa2_ntn_uc_dereg_rdyCB(void);
 
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 int ipa2_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa2_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa2_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1601,6 +1612,9 @@
  */
 int ipa2_uc_dereg_rdyCB(void);
 
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+		unsigned long *iova);
 /*
  * Tethering bridge (Rmnet / MBIM)
  */
@@ -1864,7 +1878,7 @@
 int ipa_active_clients_trylock(unsigned long *flags);
 void ipa_active_clients_unlock(void);
 void ipa_active_clients_trylock_unlock(unsigned long *flags);
-int ipa_wdi_init(void);
+int ipa2_wdi_init(void);
 int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id);
 int ipa_tag_process(struct ipa_desc *desc, int num_descs,
 		    unsigned long timeout);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
index cf8f0b8..459c207 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
@@ -26,15 +26,6 @@
 #define IPA_WDI_RESUMED BIT(2)
 #define IPA_UC_POLL_SLEEP_USEC 100
 
-#define IPA_WDI_RX_RING_RES 0
-#define IPA_WDI_RX_RING_RP_RES 1
-#define IPA_WDI_RX_COMP_RING_RES 2
-#define IPA_WDI_RX_COMP_RING_WP_RES 3
-#define IPA_WDI_TX_RING_RES 4
-#define IPA_WDI_CE_RING_RES 5
-#define IPA_WDI_CE_DB_RES 6
-#define IPA_WDI_MAX_RES 7
-
 struct ipa_wdi_res {
 	struct ipa_wdi_buffer_info *res;
 	unsigned int nents;
@@ -448,7 +439,7 @@
 	return 0;
 }
 
-int ipa_wdi_init(void)
+int ipa2_wdi_init(void)
 {
 	struct ipa_uc_hdlrs uc_wdi_cbs = { 0 };
 
@@ -629,7 +620,7 @@
 	}
 }
 
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa2_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
 		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
 		unsigned long *iova)
 {
@@ -845,7 +836,7 @@
 				in->smmu_enabled,
 				in->u.dl_smmu.comp_ring_size,
 				in->u.dl.comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
 					in->smmu_enabled,
 					in->u.dl.comp_ring_base_pa,
 					&in->u.dl_smmu.comp_ring,
@@ -870,7 +861,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.ce_ring_size,
 					in->u.dl.ce_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.ce_ring_base_pa,
 						&in->u.dl_smmu.ce_ring,
@@ -891,7 +882,7 @@
 
 			pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
 				in->u.dl.ce_door_bell_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -919,7 +910,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.comp_ring_size,
 					in->u.dl.comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.comp_ring_base_pa,
 						&in->u.dl_smmu.comp_ring,
@@ -939,7 +930,7 @@
 					in->smmu_enabled,
 					in->u.dl_smmu.ce_ring_size,
 					in->u.dl.ce_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
 						in->smmu_enabled,
 						in->u.dl.ce_ring_base_pa,
 						&in->u.dl_smmu.ce_ring,
@@ -954,7 +945,7 @@
 			tx->ce_ring_size = len;
 			pa = in->smmu_enabled ? in->u.dl_smmu.ce_door_bell_pa :
 				in->u.dl.ce_door_bell_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -995,7 +986,7 @@
 				in->smmu_enabled,
 				in->u.ul_smmu.rdy_ring_size,
 				in->u.ul.rdy_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_ring_base_pa,
 						&in->u.ul_smmu.rdy_ring,
@@ -1016,7 +1007,7 @@
 
 			pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
 				in->u.ul.rdy_ring_rp_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
@@ -1040,7 +1031,8 @@
 					in->smmu_enabled,
 					in->u.ul_smmu.rdy_comp_ring_size,
 					in->u.ul.rdy_comp_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_COMP_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(
+						IPA_WDI_RX_COMP_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_comp_ring_base_pa,
 						&in->u.ul_smmu.rdy_comp_ring,
@@ -1062,7 +1054,7 @@
 			pa = in->smmu_enabled ?
 				in->u.ul_smmu.rdy_comp_ring_wp_pa :
 				in->u.ul.rdy_comp_ring_wp_pa;
-			if (ipa_create_uc_smmu_mapping(
+			if (ipa2_create_uc_smmu_mapping(
 						IPA_WDI_RX_COMP_RING_WP_RES,
 						in->smmu_enabled,
 						pa,
@@ -1090,7 +1082,7 @@
 					in->smmu_enabled,
 					in->u.ul_smmu.rdy_ring_size,
 					in->u.ul.rdy_ring_size);
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
 						in->smmu_enabled,
 						in->u.ul.rdy_ring_base_pa,
 						&in->u.ul_smmu.rdy_ring,
@@ -1106,7 +1098,7 @@
 
 			pa = in->smmu_enabled ? in->u.ul_smmu.rdy_ring_rp_pa :
 				in->u.ul.rdy_ring_rp_pa;
-			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
 						in->smmu_enabled,
 						pa,
 						NULL,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 27120c8..c9273ec 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -5160,10 +5160,10 @@
 	api_ctrl->ipa_get_pdev = ipa2_get_pdev;
 	api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB;
 	api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB;
-	api_ctrl->ipa_conn_wdi3_pipes = ipa2_conn_wdi3_pipes;
-	api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
-	api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
-	api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+	api_ctrl->ipa_conn_wdi_pipes = ipa2_conn_wdi3_pipes;
+	api_ctrl->ipa_disconn_wdi_pipes = ipa2_disconn_wdi3_pipes;
+	api_ctrl->ipa_enable_wdi_pipes = ipa2_enable_wdi3_pipes;
+	api_ctrl->ipa_disable_wdi_pipes = ipa2_disable_wdi3_pipes;
 	api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
 
 	return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
index a2c33a1..62748b2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,43 +10,27 @@
  * GNU General Public License for more details.
  */
 #include "ipa_i.h"
-#include "ipa_uc_offload_i.h"
 #include <linux/ipa_wdi3.h>
 
 #define IPA_HW_WDI3_RX_MBOX_START_INDEX 48
 #define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
 
 static int ipa_send_wdi3_setup_pipe_cmd(
-	struct ipa_wdi3_setup_info *info, u8 dir)
+	u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+	struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
 {
 	int ipa_ep_idx;
-	int result = 0;
+	int result = 0, len;
+	unsigned long va;
 	struct ipa_mem_buffer cmd;
 	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
 	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
 
-	if (info == NULL) {
+	if (info == NULL || info_smmu == NULL) {
 		IPAERR("invalid input\n");
 		return -EINVAL;
 	}
 
-	ipa_ep_idx = ipa_get_ep_mapping(info->client);
-	IPAERR("ep number: %d\n", ipa_ep_idx);
-	if (ipa_ep_idx == -1) {
-		IPAERR("fail to get ep idx.\n");
-		return -EFAULT;
-	}
-
-	IPAERR("client=%d ep=%d\n", info->client, ipa_ep_idx);
-	IPAERR("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
-	IPAERR("ring_size = %hu\n", info->transfer_ring_size);
-	IPAERR("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
-	IPAERR("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
-	IPAERR("evt_ring_size = %hu\n", info->event_ring_size);
-	IPAERR("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
-	IPAERR("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
-	IPAERR("pkt_offset = %d.\n", info->pkt_offset);
-
 	cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa_ctx->uc_pdev, cmd.size,
 			&cmd.phys_base, GFP_KERNEL);
@@ -54,35 +38,181 @@
 		IPAERR("fail to get DMA memory.\n");
 		return -ENOMEM;
 	}
-	IPAERR("suceeded in allocating memory.\n");
 
 	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
 	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
 
-	wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
-	wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
-	wdi3_params->transfer_ring_base_pa_hi =
-		(u32)((u64)info->transfer_ring_base_pa >> 32);
-	wdi3_params->transfer_ring_size = info->transfer_ring_size;
-	wdi3_params->transfer_ring_doorbell_pa =
-		(u32)info->transfer_ring_doorbell_pa;
-	wdi3_params->transfer_ring_doorbell_pa_hi =
-		(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
-	wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
-	wdi3_params->event_ring_base_pa_hi =
-		(u32)((u64)info->event_ring_base_pa >> 32);
-	wdi3_params->event_ring_size = info->event_ring_size;
-	wdi3_params->event_ring_doorbell_pa =
-		(u32)info->event_ring_doorbell_pa;
-	wdi3_params->event_ring_doorbell_pa_hi =
-		(u32)((u64)info->event_ring_doorbell_pa >> 32);
-	wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
-	wdi3_params->ipa_pipe_number = ipa_ep_idx;
-	wdi3_params->dir = dir;
-	wdi3_params->pkt_offset = info->pkt_offset;
-	memcpy(wdi3_params->desc_format_template, info->desc_format_template,
-		sizeof(wdi3_params->desc_format_template));
-	IPAERR("suceeded in populating the command memory.\n");
+	if (!is_smmu_enabled) {
+		ipa_ep_idx = ipa_get_ep_mapping(info->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx.\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+		IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+		IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_base_pa = 0x%pad\n",
+			&info->event_ring_base_pa);
+		IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+		wdi3_params->transfer_ring_base_pa =
+			(u32)info->transfer_ring_base_pa;
+		wdi3_params->transfer_ring_base_pa_hi =
+			(u32)((u64)info->transfer_ring_base_pa >> 32);
+		wdi3_params->transfer_ring_size = info->transfer_ring_size;
+		wdi3_params->transfer_ring_doorbell_pa =
+			(u32)info->transfer_ring_doorbell_pa;
+		wdi3_params->transfer_ring_doorbell_pa_hi =
+			(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+		wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+		wdi3_params->event_ring_base_pa_hi =
+			(u32)((u64)info->event_ring_base_pa >> 32);
+		wdi3_params->event_ring_size = info->event_ring_size;
+		wdi3_params->event_ring_doorbell_pa =
+			(u32)info->event_ring_doorbell_pa;
+		wdi3_params->event_ring_doorbell_pa_hi =
+			(u32)((u64)info->event_ring_doorbell_pa >> 32);
+		wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	} else {
+		ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+		IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info_smmu->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info_smmu->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+		if (dir == IPA_WDI3_TX_DIR) {
+			len = info_smmu->transfer_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+				true, info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+				true, info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		} else {
+			len = info_smmu->transfer_ring_size;
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa2_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_RES, true,
+				info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa2_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_WP_RES, true,
+				info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		}
+		wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info_smmu->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info_smmu->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	}
 
 	result = ipa_uc_send_cmd((u32)(cmd.phys_base),
 				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -94,13 +224,15 @@
 	}
 
 	dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
-	IPAERR("suceeded in freeing memory.\n");
 	return result;
 }
 
-int ipa2_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa2_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
+	enum ipa_client_type rx_client;
+	enum ipa_client_type tx_client;
 	struct ipa_ep_context *ep_rx;
 	struct ipa_ep_context *ep_tx;
 	int ipa_ep_idx_rx;
@@ -112,12 +244,26 @@
 		return -EINVAL;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+	if (in->is_smmu_enabled == false) {
+		rx_client = in->u_rx.rx.client;
+		tx_client = in->u_tx.tx.client;
+	} else {
+		rx_client = in->u_rx.rx_smmu.client;
+		tx_client = in->u_tx.tx_smmu.client;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
 	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
 		IPAERR("fail to alloc EP.\n");
 		return -EFAULT;
 	}
+	if (ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES ||
+		ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES) {
+		IPAERR("ep out of range.\n");
+		return -EFAULT;
+	}
 
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
@@ -132,9 +278,14 @@
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
+	if (wdi_notify)
+		ipa_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+	else
+		IPADBG("wdi_notify is null\n");
+
 	/* setup rx ep cfg */
 	ep_rx->valid = 1;
-	ep_rx->client = in->rx.client;
+	ep_rx->client = rx_client;
 	result = ipa_disable_data_path(ipa_ep_idx_rx);
 	if (result) {
 		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,65 +296,71 @@
 	ep_rx->client_notify = in->notify;
 	ep_rx->priv = in->priv;
 
-	memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
+	else
+		memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
 
 	if (ipa_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
 		IPAERR("fail to setup rx pipe cfg\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("configured RX EP.\n");
 
-	if (ipa_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+	if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
 		IPAERR("fail to send cmd to uc for rx pipe\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("rx pipe was setup.\n");
-
 	ipa_install_dflt_flt_rules(ipa_ep_idx_rx);
 	out->rx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
 		IPA_REG_BASE_OFST_v2_5 +
 		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
 		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
-	IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+
+	IPADBG("client %d (ep: %d) connected\n", rx_client,
 		ipa_ep_idx_rx);
 
-	/* setup dl ep cfg */
+	/* setup tx ep cfg */
 	ep_tx->valid = 1;
-	ep_tx->client = in->tx.client;
+	ep_tx->client = tx_client;
 	result = ipa_disable_data_path(ipa_ep_idx_tx);
 	if (result) {
-		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+		IPAERR("disable data path failed res=%d ep=%d.\n", result,
 			ipa_ep_idx_tx);
 		result = -EFAULT;
 		goto fail;
 	}
 
-	memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
+	else
+		memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
 
 	if (ipa_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
 		IPAERR("fail to setup tx pipe cfg\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("configured TX EP in DMA mode.\n");
 
-	if (ipa_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+	if (ipa_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
 		IPAERR("fail to send cmd to uc for tx pipe\n");
 		result = -EFAULT;
 		goto fail;
 	}
-	IPAERR("tx pipe was setup.\n");
-
 	out->tx_uc_db_pa = ipa_ctx->ipa_wrapper_base +
 		IPA_REG_BASE_OFST_v2_5 +
 		IPA_UC_MAILBOX_m_n_OFFS_v2_5(
 		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
-	out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
-	IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+	IPADBG("client %d (ep: %d) connected\n", tx_client,
 		ipa_ep_idx_tx);
 
 fail:
@@ -233,7 +390,6 @@
 
 	wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params;
 	wdi3->params.ipa_pipe_number = ipa_ep_idx;
-	IPAERR("cmd: %d ep_idx: %d\n", command, ipa_ep_idx);
 	result = ipa_uc_send_cmd((u32)(cmd.phys_base), command,
 				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
 				false, 10*HZ);
@@ -256,6 +412,12 @@
 	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
 	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
 
+	if (ipa_ep_idx_tx < 0 || ipa_ep_idx_tx >= IPA_MAX_NUM_PIPES ||
+		ipa_ep_idx_rx < 0 || ipa_ep_idx_rx >= IPA_MAX_NUM_PIPES) {
+		IPAERR("invalid ipa ep index\n");
+		return -EINVAL;
+	}
+
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
 
@@ -291,8 +453,8 @@
 	struct ipa_ep_context *ep_tx, *ep_rx;
 	int result = 0;
 
-	IPAERR("ep_tx = %d\n", ipa_ep_idx_tx);
-	IPAERR("ep_rx = %d\n", ipa_ep_idx_rx);
+	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
+	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);
 
 	ep_tx = &ipa_ctx->ep[ipa_ep_idx_tx];
 	ep_rx = &ipa_ctx->ep[ipa_ep_idx_rx];
@@ -301,7 +463,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
 		IPAERR("fail to enable tx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -310,7 +471,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
 		IPAERR("fail to resume tx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -319,7 +479,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
 		IPAERR("fail to enable rx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
@@ -328,7 +487,6 @@
 	if (ipa_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
 		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
 		IPAERR("fail to resume rx pipe\n");
-		WARN_ON(1);
 		result = -EFAULT;
 		goto fail;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 7bd1731..4a8e7c7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -185,6 +185,16 @@
 #define IPA3_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50
 #define IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN 40
 
+#define IPA_WDI_RX_RING_RES			0
+#define IPA_WDI_RX_RING_RP_RES		1
+#define IPA_WDI_RX_COMP_RING_RES	2
+#define IPA_WDI_RX_COMP_RING_WP_RES	3
+#define IPA_WDI_TX_RING_RES			4
+#define IPA_WDI_CE_RING_RES			5
+#define IPA_WDI_CE_DB_RES			6
+#define IPA_WDI_TX_DB_RES			7
+#define IPA_WDI_MAX_RES				8
+
 struct ipa3_active_client_htable_entry {
 	struct hlist_node list;
 	char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
@@ -1898,8 +1908,9 @@
 int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
 int ipa3_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
 void ipa3_ntn_uc_dereg_rdyCB(void);
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out);
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify);
 int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
 int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx);
@@ -1921,6 +1932,10 @@
  */
 int ipa3_uc_dereg_rdyCB(void);
 
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
+		unsigned long *iova);
+
 /*
  * Tethering bridge (Rmnet / MBIM)
  */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index d5fe3fb..ec777bc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -28,15 +28,6 @@
 #define IPA_WDI_RESUMED BIT(2)
 #define IPA_UC_POLL_SLEEP_USEC 100
 
-#define IPA_WDI_RX_RING_RES			0
-#define IPA_WDI_RX_RING_RP_RES		1
-#define IPA_WDI_RX_COMP_RING_RES	2
-#define IPA_WDI_RX_COMP_RING_WP_RES	3
-#define IPA_WDI_TX_RING_RES			4
-#define IPA_WDI_CE_RING_RES			5
-#define IPA_WDI_CE_DB_RES			6
-#define IPA_WDI_MAX_RES				7
-
 struct ipa_wdi_res {
 	struct ipa_wdi_buffer_info *res;
 	unsigned int nents;
@@ -670,7 +661,7 @@
 	}
 }
 
-static int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
+int ipa_create_uc_smmu_mapping(int res_idx, bool wlan_smmu_en,
 		phys_addr_t pa, struct sg_table *sgt, size_t len, bool device,
 		unsigned long *iova)
 {
@@ -703,6 +694,7 @@
 		case IPA_WDI_RX_RING_RP_RES:
 		case IPA_WDI_RX_COMP_RING_WP_RES:
 		case IPA_WDI_CE_DB_RES:
+		case IPA_WDI_TX_DB_RES:
 			if (ipa_create_uc_smmu_mapping_pa(pa, len,
 				(res_idx == IPA_WDI_CE_DB_RES) ? true : false,
 				iova)) {
@@ -840,35 +832,6 @@
 			in->u.ul.rdy_comp_ring_wp_pa;
 		ipa3_ctx->uc_ctx.rdy_comp_ring_size =
 			in->u.ul.rdy_comp_ring_size;
-
-		/* check if the VA is empty */
-		if (ipa3_ctx->ipa_wdi2) {
-			if (in->smmu_enabled) {
-				if (!in->u.ul_smmu.rdy_ring_rp_va ||
-					!in->u.ul_smmu.rdy_comp_ring_wp_va)
-					goto dma_alloc_fail;
-			} else {
-				if (!in->u.ul.rdy_ring_rp_va ||
-					!in->u.ul.rdy_comp_ring_wp_va)
-					goto dma_alloc_fail;
-			}
-			IPADBG("rdy_ring_rp value =%d\n",
-				in->smmu_enabled ?
-				*in->u.ul_smmu.rdy_ring_rp_va :
-				*in->u.ul.rdy_ring_rp_va);
-			IPADBG("rx_comp_ring_wp value=%d\n",
-				in->smmu_enabled ?
-				*in->u.ul_smmu.rdy_comp_ring_wp_va :
-				*in->u.ul.rdy_comp_ring_wp_va);
-				ipa3_ctx->uc_ctx.rdy_ring_rp_va =
-					in->smmu_enabled ?
-					in->u.ul_smmu.rdy_ring_rp_va :
-					in->u.ul.rdy_ring_rp_va;
-				ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va =
-					in->smmu_enabled ?
-					in->u.ul_smmu.rdy_comp_ring_wp_va :
-					in->u.ul.rdy_comp_ring_wp_va;
-		}
 	}
 
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index b3726e1..d2b3b4e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4519,10 +4519,10 @@
 	api_ctrl->ipa_get_pdev = ipa3_get_pdev;
 	api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa3_ntn_uc_reg_rdyCB;
 	api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa3_ntn_uc_dereg_rdyCB;
-	api_ctrl->ipa_conn_wdi3_pipes = ipa3_conn_wdi3_pipes;
-	api_ctrl->ipa_disconn_wdi3_pipes = ipa3_disconn_wdi3_pipes;
-	api_ctrl->ipa_enable_wdi3_pipes = ipa3_enable_wdi3_pipes;
-	api_ctrl->ipa_disable_wdi3_pipes = ipa3_disable_wdi3_pipes;
+	api_ctrl->ipa_conn_wdi_pipes = ipa3_conn_wdi3_pipes;
+	api_ctrl->ipa_disconn_wdi_pipes = ipa3_disconn_wdi3_pipes;
+	api_ctrl->ipa_enable_wdi_pipes = ipa3_enable_wdi3_pipes;
+	api_ctrl->ipa_disable_wdi_pipes = ipa3_disable_wdi3_pipes;
 	api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
 	api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
 	api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
index 7801745..6c019b9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,35 +16,21 @@
 #define IPA_HW_WDI3_TX_MBOX_START_INDEX 50
 
 static int ipa3_send_wdi3_setup_pipe_cmd(
-	struct ipa_wdi3_setup_info *info, u8 dir)
+	u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
+	struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
 {
 	int ipa_ep_idx;
-	int result = 0;
+	int result = 0, len;
+	unsigned long va;
 	struct ipa_mem_buffer cmd;
 	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
 	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
 
-	if (info == NULL) {
+	if (info == NULL || info_smmu == NULL) {
 		IPAERR("invalid input\n");
 		return -EINVAL;
 	}
 
-	ipa_ep_idx = ipa_get_ep_mapping(info->client);
-	if (ipa_ep_idx == -1) {
-		IPAERR("fail to get ep idx.\n");
-		return -EFAULT;
-	}
-
-	IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
-	IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
-	IPADBG("ring_size = %hu\n", info->transfer_ring_size);
-	IPADBG("ring_db_pa = 0x%pad\n", &info->transfer_ring_doorbell_pa);
-	IPADBG("evt_ring_base_pa = 0x%pad\n", &info->event_ring_base_pa);
-	IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
-	IPADBG("evt_ring_db_pa = 0x%pad\n", &info->event_ring_doorbell_pa);
-	IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
-	IPADBG("pkt_offset = %d\n", info->pkt_offset);
-
 	cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
 			&cmd.phys_base, GFP_KERNEL);
@@ -56,29 +42,177 @@
 	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
 	cmd_data->protocol = IPA_HW_FEATURE_WDI3;
 
-	wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
-	wdi3_params->transfer_ring_base_pa = (u32)info->transfer_ring_base_pa;
-	wdi3_params->transfer_ring_base_pa_hi =
-		(u32)((u64)info->transfer_ring_base_pa >> 32);
-	wdi3_params->transfer_ring_size = info->transfer_ring_size;
-	wdi3_params->transfer_ring_doorbell_pa =
-		(u32)info->transfer_ring_doorbell_pa;
-	wdi3_params->transfer_ring_doorbell_pa_hi =
-		(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
-	wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
-	wdi3_params->event_ring_base_pa_hi =
-		(u32)((u64)info->event_ring_base_pa >> 32);
-	wdi3_params->event_ring_size = info->event_ring_size;
-	wdi3_params->event_ring_doorbell_pa =
-		(u32)info->event_ring_doorbell_pa;
-	wdi3_params->event_ring_doorbell_pa_hi =
-		(u32)((u64)info->event_ring_doorbell_pa >> 32);
-	wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
-	wdi3_params->ipa_pipe_number = ipa_ep_idx;
-	wdi3_params->dir = dir;
-	wdi3_params->pkt_offset = info->pkt_offset;
-	memcpy(wdi3_params->desc_format_template, info->desc_format_template,
-		sizeof(wdi3_params->desc_format_template));
+	if (!is_smmu_enabled) {
+		ipa_ep_idx = ipa_get_ep_mapping(info->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx.\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
+		IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
+		IPADBG("ring_size = %hu\n", info->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_base_pa = 0x%pad\n",
+			&info->event_ring_base_pa);
+		IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+		wdi3_params->transfer_ring_base_pa =
+			(u32)info->transfer_ring_base_pa;
+		wdi3_params->transfer_ring_base_pa_hi =
+			(u32)((u64)info->transfer_ring_base_pa >> 32);
+		wdi3_params->transfer_ring_size = info->transfer_ring_size;
+		wdi3_params->transfer_ring_doorbell_pa =
+			(u32)info->transfer_ring_doorbell_pa;
+		wdi3_params->transfer_ring_doorbell_pa_hi =
+			(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
+		wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
+		wdi3_params->event_ring_base_pa_hi =
+			(u32)((u64)info->event_ring_base_pa >> 32);
+		wdi3_params->event_ring_size = info->event_ring_size;
+		wdi3_params->event_ring_doorbell_pa =
+			(u32)info->event_ring_doorbell_pa;
+		wdi3_params->event_ring_doorbell_pa_hi =
+			(u32)((u64)info->event_ring_doorbell_pa >> 32);
+		wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	} else {
+		ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
+		if (ipa_ep_idx == -1) {
+			IPAERR("fail to get ep idx\n");
+			return -EFAULT;
+		}
+
+		IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
+		IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
+		IPADBG("ring_db_pa = 0x%pad\n",
+			&info_smmu->transfer_ring_doorbell_pa);
+		IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
+		IPADBG("evt_ring_db_pa = 0x%pad\n",
+			&info_smmu->event_ring_doorbell_pa);
+		IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
+		IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);
+
+		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
+
+		if (dir == IPA_WDI3_TX_DIR) {
+			len = info_smmu->transfer_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
+				true, info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
+				true, info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		} else {
+			len = info_smmu->transfer_ring_size;
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
+				true, info->transfer_ring_base_pa,
+				&info_smmu->transfer_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_base_pa = (u32)va;
+			wdi3_params->transfer_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->transfer_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
+				true, info_smmu->transfer_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->transfer_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->transfer_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+
+			len = info_smmu->event_ring_size;
+			if (ipa_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_RES, true,
+				info->event_ring_base_pa,
+				&info_smmu->event_ring_base, len,
+				false, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_base_pa = (u32)va;
+			wdi3_params->event_ring_base_pa_hi =
+				(u32)((u64)va >> 32);
+			wdi3_params->event_ring_size = len;
+
+			if (ipa_create_uc_smmu_mapping(
+				IPA_WDI_RX_COMP_RING_WP_RES, true,
+				info_smmu->event_ring_doorbell_pa,
+				NULL, 4, true, &va)) {
+				IPAERR("failed to get smmu mapping\n");
+				return -EFAULT;
+			}
+			wdi3_params->event_ring_doorbell_pa =
+				(u32)va;
+			wdi3_params->event_ring_doorbell_pa_hi =
+				(u32)((u64)va >> 32);
+		}
+		wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
+		wdi3_params->ipa_pipe_number = ipa_ep_idx;
+		wdi3_params->dir = dir;
+		wdi3_params->pkt_offset = info_smmu->pkt_offset;
+		memcpy(wdi3_params->desc_format_template,
+			info_smmu->desc_format_template,
+			sizeof(wdi3_params->desc_format_template));
+	}
 
 	result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
 				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
@@ -93,9 +227,12 @@
 	return result;
 }
 
-int ipa3_conn_wdi3_pipes(struct ipa_wdi3_conn_in_params *in,
-	struct ipa_wdi3_conn_out_params *out)
+int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out,
+	ipa_wdi_meter_notifier_cb wdi_notify)
 {
+	enum ipa_client_type rx_client;
+	enum ipa_client_type tx_client;
 	struct ipa3_ep_context *ep_rx;
 	struct ipa3_ep_context *ep_tx;
 	int ipa_ep_idx_rx;
@@ -107,8 +244,17 @@
 		return -EINVAL;
 	}
 
-	ipa_ep_idx_rx = ipa_get_ep_mapping(in->rx.client);
-	ipa_ep_idx_tx = ipa_get_ep_mapping(in->tx.client);
+	if (in->is_smmu_enabled == false) {
+		rx_client = in->u_rx.rx.client;
+		tx_client = in->u_tx.tx.client;
+	} else {
+		rx_client = in->u_rx.rx_smmu.client;
+		tx_client = in->u_tx.tx_smmu.client;
+	}
+
+	ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
+	ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);
+
 	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
 		IPAERR("fail to alloc EP.\n");
 		return -EFAULT;
@@ -132,9 +278,14 @@
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
+	if (wdi_notify)
+		ipa3_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
+	else
+		IPADBG("wdi_notify is null\n");
+
 	/* setup rx ep cfg */
 	ep_rx->valid = 1;
-	ep_rx->client = in->rx.client;
+	ep_rx->client = rx_client;
 	result = ipa3_disable_data_path(ipa_ep_idx_rx);
 	if (result) {
 		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -145,7 +296,12 @@
 	ep_rx->client_notify = in->notify;
 	ep_rx->priv = in->priv;
 
-	memcpy(&ep_rx->cfg, &in->rx.ipa_ep_cfg, sizeof(ep_rx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
+	else
+		memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
+			sizeof(ep_rx->cfg));
 
 	if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
 		IPAERR("fail to setup rx pipe cfg\n");
@@ -153,7 +309,8 @@
 		goto fail;
 	}
 
-	if (ipa3_send_wdi3_setup_pipe_cmd(&in->rx, IPA_WDI3_RX_DIR)) {
+	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
 		IPAERR("fail to send cmd to uc for rx pipe\n");
 		result = -EFAULT;
 		goto fail;
@@ -165,12 +322,12 @@
 		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);
 
-	IPADBG("client %d (ep: %d) connected\n", in->rx.client,
+	IPADBG("client %d (ep: %d) connected\n", rx_client,
 		ipa_ep_idx_rx);
 
-	/* setup dl ep cfg */
+	/* setup tx ep cfg */
 	ep_tx->valid = 1;
-	ep_tx->client = in->tx.client;
+	ep_tx->client = tx_client;
 	result = ipa3_disable_data_path(ipa_ep_idx_tx);
 	if (result) {
 		IPAERR("disable data path failed res=%d ep=%d.\n", result,
@@ -179,7 +336,12 @@
 		goto fail;
 	}
 
-	memcpy(&ep_tx->cfg, &in->tx.ipa_ep_cfg, sizeof(ep_tx->cfg));
+	if (in->is_smmu_enabled == false)
+		memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
+	else
+		memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
+			sizeof(ep_tx->cfg));
 
 	if (ipa3_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
 		IPAERR("fail to setup tx pipe cfg\n");
@@ -187,7 +349,8 @@
 		goto fail;
 	}
 
-	if (ipa3_send_wdi3_setup_pipe_cmd(&in->tx, IPA_WDI3_TX_DIR)) {
+	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
+		&in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
 		IPAERR("fail to send cmd to uc for tx pipe\n");
 		result = -EFAULT;
 		goto fail;
@@ -197,13 +360,7 @@
 		ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
 		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
-	out->tx_uc_db_va = ioremap(out->tx_uc_db_pa, 4);
-	if (!out->tx_uc_db_va) {
-		IPAERR("fail to ioremap tx uc db\n");
-		result = -EFAULT;
-		goto fail;
-	}
-	IPADBG("client %d (ep: %d) connected\n", in->tx.client,
+	IPADBG("client %d (ep: %d) connected\n", tx_client,
 		ipa_ep_idx_tx);
 
 fail:
diff --git a/include/linux/ipa_wdi3.h b/include/linux/ipa_wdi3.h
index aed8c59..6f00711 100644
--- a/include/linux/ipa_wdi3.h
+++ b/include/linux/ipa_wdi3.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,15 +24,49 @@
 	(IPA_HW_WDI3_TCL_DATA_CMD_ER_DESC_SIZE) : \
 	(IPA_HW_WDI3_IPA2FW_ER_DESC_SIZE))
 
+#define IPA_WDI_MAX_SUPPORTED_SYS_PIPE 3
+
+enum ipa_wdi_version {
+	IPA_WDI_1,
+	IPA_WDI_2,
+	IPA_WDI_3
+};
+
 /**
- * struct ipa_wdi3_hdr_info - Header to install on IPA HW
+ * struct ipa_wdi_init_in_params - wdi init input parameters
+ *
+ * @wdi_version: wdi version
+ * @notify: uc ready callback
+ * @priv: uc ready callback cookie
+ */
+struct ipa_wdi_init_in_params {
+	enum ipa_wdi_version wdi_version;
+	ipa_uc_ready_cb notify;
+	void *priv;
+	ipa_wdi_meter_notifier_cb wdi_notify;
+};
+
+/**
+ * struct ipa_wdi_init_out_params - wdi init output parameters
+ *
+ * @is_uC_ready: is uC ready. No API should be called until uC
+    is ready.
+ * @is_smmu_enable: is smmu enabled
+ */
+struct ipa_wdi_init_out_params {
+	bool is_uC_ready;
+	bool is_smmu_enabled;
+};
+
+/**
+ * struct ipa_wdi_hdr_info - Header to install on IPA HW
  *
  * @hdr: header to install on IPA HW
  * @hdr_len: length of header
  * @dst_mac_addr_offset: destination mac address offset
  * @hdr_type: layer two header type
  */
-struct ipa_wdi3_hdr_info {
+struct ipa_wdi_hdr_info {
 	u8 *hdr;
 	u8 hdr_len;
 	u8 dst_mac_addr_offset;
@@ -40,7 +74,7 @@
 };
 
 /**
- * struct ipa_wdi3_reg_intf_in_params - parameters for uC offload
+ * struct ipa_wdi_reg_intf_in_params - parameters for uC offload
  *	interface registration
  *
  * @netdev_name: network interface name
@@ -49,16 +83,17 @@
  * @meta_data: meta data if any
  * @meta_data_mask: meta data mask
  */
-struct ipa_wdi3_reg_intf_in_params {
+struct ipa_wdi_reg_intf_in_params {
 	const char *netdev_name;
-	struct ipa_wdi3_hdr_info hdr_info[IPA_IP_MAX];
+	struct ipa_wdi_hdr_info hdr_info[IPA_IP_MAX];
+	enum ipa_client_type alt_dst_pipe;
 	u8 is_meta_data_valid;
 	u32 meta_data;
 	u32 meta_data_mask;
 };
 
 /**
- * struct  ipa_wdi3_setup_info - WDI3 TX/Rx configuration
+ * struct  ipa_wdi_pipe_setup_info - WDI TX/Rx configuration
  * @ipa_ep_cfg: ipa endpoint configuration
  * @client: type of "client"
  * @transfer_ring_base_pa:  physical address of the base of the transfer ring
@@ -71,20 +106,20 @@
 	will update the headpointer of the event ring
  * @num_pkt_buffers:  Number of pkt buffers allocated. The size of the event
 	ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
- * @pkt_offset: packet offset (wdi3 header length)
+ * @pkt_offset: packet offset (wdi header length)
  * @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]:  Holds a cached
 	template of the desc format
  */
-struct ipa_wdi3_setup_info {
+struct ipa_wdi_pipe_setup_info {
 	struct ipa_ep_cfg ipa_ep_cfg;
 	enum ipa_client_type client;
-	dma_addr_t  transfer_ring_base_pa;
+	phys_addr_t  transfer_ring_base_pa;
 	u32  transfer_ring_size;
-	dma_addr_t  transfer_ring_doorbell_pa;
+	phys_addr_t  transfer_ring_doorbell_pa;
 
-	dma_addr_t  event_ring_base_pa;
+	phys_addr_t  event_ring_base_pa;
 	u32  event_ring_size;
-	dma_addr_t  event_ring_doorbell_pa;
+	phys_addr_t  event_ring_doorbell_pa;
 	u16  num_pkt_buffers;
 
 	u16 pkt_offset;
@@ -93,40 +128,87 @@
 };
 
 /**
- * struct  ipa_wdi3_conn_in_params - information provided by
+ * struct  ipa_wdi_pipe_setup_info_smmu - WDI TX/Rx configuration
+ * @ipa_ep_cfg: ipa endpoint configuration
+ * @client: type of "client"
+ * @transfer_ring_base_pa:  physical address of the base of the transfer ring
+ * @transfer_ring_size:  size of the transfer ring
+ * @transfer_ring_doorbell_pa:  physical address of the doorbell that
+	IPA uC will update the tailpointer of the transfer ring
+ * @event_ring_base_pa:  physical address of the base of the event ring
+ * @event_ring_size:  event ring size
+ * @event_ring_doorbell_pa:  physical address of the doorbell that IPA uC
+	will update the headpointer of the event ring
+ * @num_pkt_buffers:  Number of pkt buffers allocated. The size of the event
+	ring and the transfer ring has to be atleast ( num_pkt_buffers + 1)
+ * @pkt_offset: packet offset (wdi header length)
+ * @desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE]:  Holds a cached
+	template of the desc format
+ */
+struct ipa_wdi_pipe_setup_info_smmu {
+	struct ipa_ep_cfg ipa_ep_cfg;
+	enum ipa_client_type client;
+	struct sg_table  transfer_ring_base;
+	u32  transfer_ring_size;
+	phys_addr_t  transfer_ring_doorbell_pa;
+
+	struct sg_table  event_ring_base;
+	u32  event_ring_size;
+	phys_addr_t  event_ring_doorbell_pa;
+	u16  num_pkt_buffers;
+
+	u16 pkt_offset;
+
+	u32  desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE];
+};
+
+/**
+ * struct  ipa_wdi_conn_in_params - information provided by
  *		uC offload client
  * @notify: client callback function
  * @priv: client cookie
+ * @is_smmu_enabled: if smmu is enabled
+ * @num_sys_pipe_needed: number of sys pipe needed
+ * @sys_in: parameters to setup sys pipe in mcc mode
  * @tx: parameters to connect TX pipe(from IPA to WLAN)
+ * @tx_smmu: smmu parameters to connect TX pipe(from IPA to WLAN)
  * @rx: parameters to connect RX pipe(from WLAN to IPA)
+ * @rx_smmu: smmu parameters to connect RX pipe(from WLAN to IPA)
  */
-struct ipa_wdi3_conn_in_params {
+struct ipa_wdi_conn_in_params {
 	ipa_notify_cb notify;
 	void *priv;
-	struct ipa_wdi3_setup_info tx;
-	struct ipa_wdi3_setup_info rx;
+	bool is_smmu_enabled;
+	u8 num_sys_pipe_needed;
+	struct ipa_sys_connect_params sys_in[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
+	union {
+		struct ipa_wdi_pipe_setup_info tx;
+		struct ipa_wdi_pipe_setup_info_smmu tx_smmu;
+	} u_tx;
+	union {
+		struct ipa_wdi_pipe_setup_info rx;
+		struct ipa_wdi_pipe_setup_info_smmu rx_smmu;
+	} u_rx;
 };
 
 /**
- * struct  ipa_wdi3_conn_out_params - information provided
+ * struct  ipa_wdi_conn_out_params - information provided
  *				to WLAN driver
  * @tx_uc_db_pa: physical address of IPA uC doorbell for TX
- * @tx_uc_db_va: virtual address of IPA uC doorbell for TX
  * @rx_uc_db_pa: physical address of IPA uC doorbell for RX
  */
-struct ipa_wdi3_conn_out_params {
-	dma_addr_t tx_uc_db_pa;
-	void __iomem *tx_uc_db_va;
-	dma_addr_t rx_uc_db_pa;
+struct ipa_wdi_conn_out_params {
+	phys_addr_t tx_uc_db_pa;
+	phys_addr_t rx_uc_db_pa;
 };
 
 /**
- * struct  ipa_wdi3_perf_profile - To set BandWidth profile
+ * struct  ipa_wdi_perf_profile - To set BandWidth profile
  *
  * @client: type of client
  * @max_supported_bw_mbps: maximum bandwidth needed (in Mbps)
  */
-struct ipa_wdi3_perf_profile {
+struct ipa_wdi_perf_profile {
 	enum ipa_client_type client;
 	u32 max_supported_bw_mbps;
 };
@@ -134,117 +216,193 @@
 #if defined CONFIG_IPA || defined CONFIG_IPA3
 
 /**
- * ipa_wdi3_reg_intf - Client should call this function to
- * init WDI3 IPA offload data path
+ * ipa_wdi_init - Client should call this function to
+ * init WDI IPA offload data path
  *
  * Note: Should not be called from atomic context and only
  * after checking IPA readiness using ipa_register_ipa_ready_cb()
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_reg_intf(
-	struct ipa_wdi3_reg_intf_in_params *in);
+int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out);
 
 /**
- * ipa_wdi3_dereg_intf - Client Driver should call this
+ * ipa_wdi_cleanup - Client should call this function to
+ * clean up WDI IPA offload data path
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_cleanup(void);
+
+/**
+ * ipa_wdi_reg_intf - Client should call this function to
+ * register interface
+ *
+ * Note: Should not be called from atomic context
+ *
+ * @Return 0 on success, negative on failure
+ */
+int ipa_wdi_reg_intf(
+	struct ipa_wdi_reg_intf_in_params *in);
+
+/**
+ * ipa_wdi_dereg_intf - Client Driver should call this
  * function to deregister before unload and after disconnect
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_dereg_intf(const char *netdev_name);
+int ipa_wdi_dereg_intf(const char *netdev_name);
 
 /**
- * ipa_wdi3_conn_pipes - Client should call this
+ * ipa_wdi_conn_pipes - Client should call this
  * function to connect pipes
  *
  * @in:	[in] input parameters from client
  * @out: [out] output params to client
  *
- * Note: Should not be called from atomic context and only
- * after checking IPA readiness using ipa_register_ipa_ready_cb()
+ * Note: Should not be called from atomic context
  *
  * @Return 0 on success, negative on failure
  */
-int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out);
+int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out);
 
 /**
- * ipa_wdi3_disconn_pipes() - Client should call this
+ * ipa_wdi_disconn_pipes() - Client should call this
  *		function to disconnect pipes
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_disconn_pipes(void);
+int ipa_wdi_disconn_pipes(void);
 
 /**
- * ipa_wdi3_enable_pipes() - Client should call this
+ * ipa_wdi_enable_pipes() - Client should call this
  *		function to enable IPA offload data path
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_enable_pipes(void);
+int ipa_wdi_enable_pipes(void);
 
 /**
- * ipa_wdi3_disable_pipes() - Client should call this
+ * ipa_wdi_disable_pipes() - Client should call this
  *		function to disable IPA offload data path
  *
  * Note: Should not be called from atomic context
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_disable_pipes(void);
+int ipa_wdi_disable_pipes(void);
 
 /**
- * ipa_wdi3_set_perf_profile() - Client should call this function to
+ * ipa_wdi_set_perf_profile() - Client should call this function to
  *		set IPA clock bandwidth based on data rates
  *
  * @profile: [in] BandWidth profile to use
  *
  * Returns: 0 on success, negative on failure
  */
-int ipa_wdi3_set_perf_profile(struct ipa_wdi3_perf_profile *profile);
+int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile);
 
+/**
+ * ipa_wdi_create_smmu_mapping() - Create smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_release_smmu_mapping() - Release smmu mapping
+ *
+ * @num_buffers: number of buffers
+ *
+ * @info: wdi buffer info
+ */
+int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info);
+
+/**
+ * ipa_wdi_get_stats() - Query WDI statistics
+ * @stats:	[inout] stats blob from client populated by driver
+ *
+ * Returns:	0 on success, negative on failure
+ *
+ * @note Cannot be called from atomic context
+ *
+ */
+int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats);
 
 #else /* (CONFIG_IPA || CONFIG_IPA3) */
 
-static inline int ipa_wdi3_reg_intf(
-	struct ipa_wdi3_reg_intf_in_params *in)
+static inline int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
+	struct ipa_wdi_init_out_params *out)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_dereg_intf(const char *netdev_name)
+static inline int ipa_wdi_cleanup(void)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_conn_pipes(struct ipa_wdi3_conn_in_params *in,
-			struct ipa_wdi3_conn_out_params *out)
+static inline int ipa_wdi_reg_intf(
+	struct ipa_wdi_reg_intf_in_params *in)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_disconn_pipes(void)
+static inline int ipa_wdi_dereg_intf(const char *netdev_name)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_enable_pipes(void)
+static inline int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
+	struct ipa_wdi_conn_out_params *out)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_disable_pipes(void)
+static inline int ipa_wdi_disconn_pipes(void)
 {
 	return -EPERM;
 }
 
-static inline int ipa_wdi3_set_perf_profile(
-	struct ipa_wdi3_perf_profile *profile)
+static inline int ipa_wdi_enable_pipes(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_disable_pipes(void)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_set_perf_profile(
+	struct ipa_wdi_perf_profile *profile)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_create_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_release_smmu_mapping(u32 num_buffers,
+	struct ipa_wdi_buffer_info *info)
+{
+	return -EPERM;
+}
+
+static inline int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
 {
 	return -EPERM;
 }