qcacld-3.0: Move IPA setup and initialization to IPA component

IPA module has been moved to CLD component under the converged
driver model. Move the legacy IPA setup and initialization code
to the IPA component.

Change-Id: I63717eb2601c569131c6642f7330e4182e604424
CRs-Fixed: 2177925
diff --git a/Kbuild b/Kbuild
index 1aa6abb..7cc42a0 100644
--- a/Kbuild
+++ b/Kbuild
@@ -1080,7 +1080,8 @@
 IPA_OBJS :=	$(IPA_DIR)/dispatcher/src/wlan_ipa_ucfg_api.o \
 		$(IPA_DIR)/dispatcher/src/wlan_ipa_obj_mgmt_api.o \
 		$(IPA_DIR)/dispatcher/src/wlan_ipa_tgt_api.o \
-		$(IPA_DIR)/core/src/wlan_ipa_main.o
+		$(IPA_DIR)/core/src/wlan_ipa_main.o \
+		$(IPA_DIR)/core/src/wlan_ipa_core.o
 endif
 
 ########## CLD TARGET_IF #######
diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h
new file mode 100644
index 0000000..d0d281a
--- /dev/null
+++ b/components/ipa/core/inc/wlan_ipa_core.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef _WLAN_IPA_CORE_H_
+#define _WLAN_IPA_CORE_H_
+
+#ifdef IPA_OFFLOAD
+
+#include "wlan_ipa_priv.h"
+#include "wlan_ipa_public_struct.h"
+
+/**
+ * wlan_ipa_is_enabled() - Is IPA enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if IPA is enabled, false otherwise
+ */
+static inline bool wlan_ipa_is_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_ENABLE_MASK);
+}
+
+/**
+ * wlan_ipa_uc_is_enabled() - Is IPA UC enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if IPA UC is enabled, false otherwise
+ */
+static inline bool wlan_ipa_uc_is_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_ENABLE_MASK);
+}
+
+/**
+ * wlan_ipa_setup - IPA initialize and setup
+ * @ipa_ctx: IPA priv obj
+ * @ipa_cfg: IPA config
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
+			  struct wlan_ipa_config *ipa_cfg);
+
+/**
+ * wlan_ipa_cleanup - IPA cleanup
+ * @ipa_ctx: IPA priv obj
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx);
+#endif /* IPA_OFFLOAD */
+#endif /* _WLAN_IPA_CORE_H_ */
diff --git a/components/ipa/core/inc/wlan_ipa_main.h b/components/ipa/core/inc/wlan_ipa_main.h
index c61601a..e82682b 100644
--- a/components/ipa/core/inc/wlan_ipa_main.h
+++ b/components/ipa/core/inc/wlan_ipa_main.h
@@ -48,7 +48,7 @@
 #define IPA_EXIT() ipa_debug("exit")
 
 /**
- * wlan_ipa_is_present() - get IPA hw status
+ * ipa_check_hw_present() - get IPA hw status
  *
  * ipa_uc_reg_rdyCB is not directly designed to check
  * ipa hw status. This is an undocumented function which
@@ -57,7 +57,7 @@
  * Return: true - ipa hw present
  *         false - ipa hw not present
  */
-bool wlan_ipa_is_present(void);
+bool ipa_check_hw_present(void);
 
 /**
  * wlan_get_pdev_ipa_obj() - private API to get ipa pdev object
@@ -78,6 +78,58 @@
 }
 
 /**
+ * ipa_is_hw_support() - Is IPA HW support?
+ *
+ * Return: true if IPA HW  is present or false otherwise
+ */
+bool ipa_is_hw_support(void);
+
+/**
+ * ipa_config_mem_alloc() - IPA config allocation
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ */
+QDF_STATUS ipa_config_mem_alloc(void);
+
+/**
+ * ipa_config_mem_free() - IPA config mem free
+ *
+ * Return: None
+ */
+void ipa_config_mem_free(void);
+
+/**
+ * ipa_config_update() - IPA component config update
+ * @config: IPA config
+ *
+ * Return: None
+ */
+void ipa_config_update(struct wlan_ipa_config *config);
+
+/**
+ * ipa_config_is_enabled() - Is IPA config enabled?
+ *
+ * Return: true if IPA is enabled in IPA config
+ */
+bool ipa_config_is_enabled(void);
+
+/**
+ * ipa_obj_setup() - IPA obj initialization and setup
+ * @ipa_ctx: IPA obj context
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ */
+QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * ipa_obj_cleanup() - IPA obj cleanup
+ * @ipa_ctx: IPA obj context
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ */
+QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx);
+
+/**
  * ipa_send_uc_offload_enable_disable() - wdi enable/disable notify to fw
  * @pdev: objmgr pdev object
  * @req: ipa offload control request
@@ -86,5 +138,23 @@
  */
 QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev,
 				struct ipa_uc_offload_control_params *req);
+
+/**
+ * ipa_set_dp_handle() - set dp soc handle
+ * @psoc: psoc handle
+ * @dp_soc: dp soc handle
+ *
+ * Return: None
+ */
+void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc);
+
+/**
+ * ipa_set_txrx_handle() - set dp txrx handle
+ * @psoc: psoc handle
+ * @txrx_handle: dp txrx handle
+ *
+ * Return: None
+ */
+void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle);
 #endif /* IPA_OFFLOAD */
 #endif /* end  of _WLAN_IPA_MAIN_H_ */
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
new file mode 100644
index 0000000..a66b082
--- /dev/null
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+/* Include Files */
+#include "wlan_ipa_core.h"
+#include "wlan_ipa_main.h"
+#include <ol_txrx.h>
+#include "cdp_txrx_ipa.h"
+#include "wal_rx_desc.h"
+
+static struct wlan_ipa_priv *gp_ipa;
+
+static struct wlan_ipa_iface_2_client {
+	qdf_ipa_client_type_t cons_client;
+	qdf_ipa_client_type_t prod_client;
+} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = {
+	{
+		QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD
+	}, {
+		QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD
+	}, {
+		QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD
+	}
+};
+
+/**
+ * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if STA mode IPA uC offload is enabled, false otherwise
+ */
+static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK);
+}
+
+/**
+ * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if pre-filter is enabled, otherwise false
+ */
+static inline
+bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
+					 WLAN_IPA_PRE_FILTER_ENABLE_MASK);
+}
+
+/**
+ * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if IPv6 is enabled, otherwise false
+ */
+static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK);
+}
+
+/**
+ * wlan_ipa_msg_free_fn() - Free an IPA message
+ * @buff: pointer to the IPA message
+ * @len: length of the IPA message
+ * @type: type of IPA message
+ *
+ * Return: None
+ */
+static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type)
+{
+	ipa_debug("msg type:%d, len:%d", type, len);
+	qdf_mem_free(buff);
+}
+
+/**
+ * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback
+ * @priv_ctxt: IPA context
+ *
+ * Will be called by IPA context.
+ * It's atomic context, then should be scheduled to kworker thread
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
+{
+	struct wlan_ipa_priv *ipa_ctx;
+	struct op_msg_type *msg;
+	struct uc_op_work_struct *uc_op_work;
+
+	if (!priv_ctxt) {
+		ipa_err("Invalid IPA context");
+		return;
+	}
+
+	ipa_ctx = priv_ctxt;
+
+	msg = qdf_mem_malloc(sizeof(*msg));
+	if (!msg) {
+		ipa_err("op_msg allocation fails");
+		return;
+	}
+
+	msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY;
+
+	uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
+
+	/* When the same uC OPCODE is already pended, just return */
+	if (uc_op_work->msg)
+		goto done;
+
+	uc_op_work->msg = msg;
+	qdf_sched_work(0, &uc_op_work->work);
+	/* work handler will free the msg buffer */
+	return;
+
+done:
+	qdf_mem_free(msg);
+}
+
+/**
+ * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message
+ * @ctrl: WDI control value
+ *
+ * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise.
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl)
+{
+	qdf_ipa_msg_meta_t meta;
+	qdf_ipa_wlan_msg_t *ipa_msg;
+	int ret = 0;
+
+	/* WDI enable message to IPA */
+	QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg);
+	ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
+	if (!ipa_msg) {
+		ipa_err("msg allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	if (ctrl)
+		QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE);
+	else
+		QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE);
+
+	ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta));
+	ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn);
+	if (ret) {
+		ipa_err("ipa_send_msg(Evt:%d)-fail=%d",
+			QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
+		qdf_mem_free(ipa_msg);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef CONFIG_IPA_WDI_UNIFIED_API
+
+/*
+ * TODO: Get WDI version through FW capabilities
+ */
+#ifdef CONFIG_LITHIUM
+static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
+{
+	ipa_ctx->wdi_version = IPA_WDI_3;
+}
+#elif defined(QCA_WIFI_3_0)
+static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
+{
+	ipa_ctx->wdi_version = IPA_WDI_2;
+}
+#else
+static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
+{
+	ipa_ctx->wdi_version = IPA_WDI_1;
+}
+#endif
+
+static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
+{
+	qdf_ipa_wdi_init_in_params_t in;
+	qdf_ipa_wdi_init_out_params_t out;
+	int ret;
+
+	ipa_ctx->uc_loaded = false;
+
+	QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version;
+	QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb;
+	QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)ipa_ctx;
+
+	ret = qdf_ipa_wdi_init(&in, &out);
+	if (ret) {
+		ipa_err("ipa_wdi_init failed with ret=%d", ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) {
+		ipa_info("IPA uC READY");
+		ipa_ctx->uc_loaded = true;
+		ipa_ctx->is_smmu_enabled =
+			QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out);
+		ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled);
+	} else {
+		return QDF_STATUS_E_BUSY;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline int wlan_ipa_wdi_cleanup(void)
+{
+	int ret;
+
+	ret = qdf_ipa_wdi_cleanup();
+	if (ret)
+		ipa_info("ipa_wdi_cleanup failed ret=%d", ret);
+	return ret;
+}
+
+static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
+					     struct ipa_sys_connect_params *sys,
+					     uint32_t *handle)
+{
+	return 0;
+}
+
+static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
+						uint32_t handle)
+{
+	return 0;
+}
+
+#else /* CONFIG_IPA_WDI_UNIFIED_API */
+
+static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
+{
+}
+
+static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
+{
+	struct ipa_wdi_uc_ready_params uc_ready_param;
+
+	ipa_ctx->uc_loaded = false;
+	uc_ready_param.priv = (void *)ipa_ctx;
+	uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb;
+	if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) {
+		ipa_info("UC Ready CB register fail");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (true == uc_ready_param.is_uC_ready) {
+		ipa_info("UC Ready");
+		ipa_ctx->uc_loaded = true;
+	} else {
+		return QDF_STATUS_E_BUSY;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline int wlan_ipa_wdi_cleanup(void)
+{
+	int ret;
+
+	ret = qdf_ipa_uc_dereg_rdyCB();
+	if (ret)
+		ipa_info("UC Ready CB deregister fail");
+	return ret;
+}
+
+static inline int wlan_ipa_wdi_setup_sys_pipe(
+		struct wlan_ipa_priv *ipa_ctx,
+		struct ipa_sys_connect_params *sys, uint32_t *handle)
+{
+	return qdf_ipa_setup_sys_pipe(sys, handle);
+}
+
+static inline int wlan_ipa_wdi_teardown_sys_pipe(
+		struct wlan_ipa_priv *ipa_ctx,
+		uint32_t handle)
+{
+	return qdf_ipa_teardown_sys_pipe(handle);
+}
+
+#endif /* CONFIG_IPA_WDI_UNIFIED_API */
+
+/**
+ * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
+ * @ipa_ctx: IPA context
+ *
+ * Return: QDF_STATUS
+ */
+static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i;
+	uint32_t max_desc_cnt;
+	struct wlan_ipa_tx_desc *tmp_desc;
+
+	max_desc_cnt = ipa_ctx->config->txbuf_count;
+
+	qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt);
+
+	qdf_spin_lock_bh(&ipa_ctx->q_lock);
+	for (i = 0; i < max_desc_cnt; i++) {
+		tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc));
+		tmp_desc->id = i;
+		tmp_desc->ipa_tx_desc_ptr = NULL;
+		qdf_list_insert_back(&ipa_ctx->tx_desc_list,
+				     &tmp_desc->node);
+		tmp_desc++;
+	}
+
+	ipa_ctx->stats.num_tx_desc_q_cnt = 0;
+	ipa_ctx->stats.num_tx_desc_error = 0;
+
+	qdf_spin_unlock_bh(&ipa_ctx->q_lock);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifndef QCA_LL_TX_FLOW_CONTROL_V2
+/**
+ * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
+ * @ipa_ctx: Global IPA IPA context
+ * @desc_fifo_sz: Number of descriptors
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
+				     int32_t desc_fifo_sz)
+{
+	int i, ret = 0;
+	qdf_ipa_sys_connect_params_t *ipa;
+
+	/*setup TX pipes */
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params;
+
+		ipa->client = wlan_ipa_iface_2_client[i].cons_client;
+		ipa->desc_fifo_sz = desc_fifo_sz;
+		ipa->priv = &ipa_ctx->iface_context[i];
+		ipa->notify = NULL;
+
+		if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
+			ipa->ipa_ep_cfg.hdr.hdr_len =
+				WLAN_IPA_UC_WLAN_TX_HDR_LEN;
+			ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
+			ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
+			ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0;
+			ipa->ipa_ep_cfg.hdr.hdr_additional_const_len =
+				WLAN_IPA_UC_WLAN_8023_HDR_SIZE;
+			ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true;
+		} else {
+			ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN;
+		}
+		ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
+
+		ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa,
+				&ipa_ctx->sys_pipe[i].conn_hdl);
+		if (ret) {
+			ipa_err("Failed for pipe %d ret: %d", i, ret);
+			return ret;
+		}
+		ipa_ctx->sys_pipe[i].conn_hdl_valid = 1;
+	}
+
+	return ret;
+}
+#else
+/**
+ * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes
+ * @ipa_ctx: Global IPA IPA context
+ * @desc_fifo_sz: Number of descriptors
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
+				     int32_t desc_fifo_sz)
+{
+	/*
+	 * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2
+	 * is enabled, where per vdev descriptors are supported in firmware.
+	 */
+	return 0;
+}
+#endif
+
+/**
+ * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes
+ * @ipa_ctx: Global IPA IPA context
+ * @desc_fifo_sz: Number of descriptors
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx,
+				     int32_t desc_fifo_sz)
+{
+	int ret = 0;
+	qdf_ipa_sys_connect_params_t *ipa;
+
+	/*
+	 * Hard code it here, this can be extended if in case
+	 * PROD pipe is also per interface.
+	 * Right now there is no advantage of doing this.
+	 */
+	ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params;
+
+	ipa->client = IPA_CLIENT_WLAN1_PROD;
+
+	ipa->desc_fifo_sz = desc_fifo_sz;
+	ipa->priv = ipa_ctx;
+	ipa->notify = NULL;
+
+	ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
+	ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN;
+	ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
+	ipa->ipa_ep_cfg.mode.mode = IPA_BASIC;
+
+	ret = qdf_ipa_setup_sys_pipe(ipa,
+			&ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl);
+	if (ret) {
+		ipa_err("Failed for RX pipe: %d", ret);
+		return ret;
+	}
+	ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1;
+
+	return ret;
+}
+
+/**
+ * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
+ * @ipa_ctx: Global IPA IPA context
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i = WLAN_IPA_MAX_IFACE, ret = 0;
+	uint32_t desc_fifo_sz;
+
+	/* The maximum number of descriptors that can be provided to a BAM at
+	 * once is one less than the total number of descriptors that the buffer
+	 * can contain.
+	 * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof
+	 * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can
+	 * be provided at once.
+	 * Because of above requirement, one extra descriptor will be added to
+	 * make sure hardware always has one descriptor.
+	 */
+	desc_fifo_sz = ipa_ctx->config->desc_size
+		       + SPS_DESC_SIZE;
+
+	ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz);
+	if (ret) {
+		ipa_err("Failed for TX pipe: %d", ret);
+		goto setup_sys_pipe_fail;
+	}
+
+	if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
+		ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz);
+		if (ret) {
+			ipa_err("Failed for RX pipe: %d", ret);
+			goto setup_sys_pipe_fail;
+		}
+	}
+
+       /* Allocate free Tx desc list */
+	ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx);
+	if (ret)
+		goto setup_sys_pipe_fail;
+
+	return ret;
+
+setup_sys_pipe_fail:
+
+	for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
+		if (ipa_ctx->sys_pipe[i].conn_hdl_valid)
+			qdf_ipa_teardown_sys_pipe(
+				ipa_ctx->sys_pipe[i].conn_hdl);
+		qdf_mem_zero(&ipa_ctx->sys_pipe[i],
+			     sizeof(struct wlan_ipa_sys_pipe));
+	}
+
+	return ret;
+}
+
+/**
+ * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes
+ * @ipa_ctx: Global IPA IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
+{
+	int ret = 0, i;
+	struct wlan_ipa_tx_desc *tmp_desc;
+	qdf_ipa_rx_data_t *ipa_tx_desc;
+	qdf_list_node_t *node;
+
+	for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
+		if (ipa_ctx->sys_pipe[i].conn_hdl_valid) {
+			ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx,
+					ipa_ctx->sys_pipe[i].conn_hdl);
+			if (ret)
+				ipa_err("Failed:%d", ret);
+
+			ipa_ctx->sys_pipe[i].conn_hdl_valid = 0;
+		}
+	}
+
+	while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) ==
+	       QDF_STATUS_SUCCESS) {
+		tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc,
+					    node);
+		ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
+		if (ipa_tx_desc)
+			qdf_ipa_free_skb(ipa_tx_desc);
+
+		qdf_mem_free(tmp_desc);
+	}
+}
+
+/**
+ * wlan_ipa_setup() - IPA initialization function
+ * @ipa_ctx: IPA context
+ * @ipa_cfg: IPA config
+ *
+ * Allocate ipa_ctx resources, ipa pipe resource and register
+ * wlan interface with IPA module.
+ *
+ * Return: QDF_STATUS enumeration
+ */
+QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
+			  struct wlan_ipa_config *ipa_cfg)
+{
+	int ret, i;
+	struct wlan_ipa_iface_context *iface_context = NULL;
+	QDF_STATUS status;
+
+	ipa_debug("enter");
+
+	gp_ipa = ipa_ctx;
+	ipa_ctx->num_iface = 0;
+	ipa_ctx->config = ipa_cfg;
+
+	wlan_ipa_wdi_get_wdi_version(ipa_ctx);
+
+	/* Create the interface context */
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		iface_context = &ipa_ctx->iface_context[i];
+		iface_context->ipa_ctx = ipa_ctx;
+		iface_context->cons_client =
+			wlan_ipa_iface_2_client[i].cons_client;
+		iface_context->prod_client =
+			wlan_ipa_iface_2_client[i].prod_client;
+		iface_context->iface_id = i;
+		iface_context->dev = NULL;
+		iface_context->device_mode = QDF_MAX_NO_OF_MODE;
+		iface_context->tl_context = NULL;
+		qdf_spinlock_create(&iface_context->interface_lock);
+	}
+
+	qdf_spinlock_create(&ipa_ctx->pm_lock);
+	qdf_spinlock_create(&ipa_ctx->q_lock);
+	qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head);
+	qdf_list_create(&ipa_ctx->pending_event, 1000);
+	qdf_mutex_create(&ipa_ctx->event_lock);
+	qdf_mutex_create(&ipa_ctx->ipa_lock);
+
+	for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++)
+		qdf_mem_zero(&ipa_ctx->sys_pipe[i],
+			     sizeof(struct wlan_ipa_sys_pipe));
+
+	if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+		qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats));
+		ipa_ctx->sap_num_connected_sta = 0;
+		ipa_ctx->ipa_tx_packets_diff = 0;
+		ipa_ctx->ipa_rx_packets_diff = 0;
+		ipa_ctx->ipa_p_tx_packets = 0;
+		ipa_ctx->ipa_p_rx_packets = 0;
+		ipa_ctx->resource_loading = false;
+		ipa_ctx->resource_unloading = false;
+		ipa_ctx->sta_connected = 0;
+		ipa_ctx->ipa_pipes_down = true;
+		ipa_ctx->wdi_enabled = false;
+		/* Setup IPA system pipes */
+		if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) {
+			ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
+			if (ret)
+				goto fail_create_sys_pipe;
+		}
+
+		status = wlan_ipa_wdi_init(ipa_ctx);
+		if (status == QDF_STATUS_E_BUSY)
+			status = wlan_ipa_uc_send_wdi_control_msg(false);
+		if (status != QDF_STATUS_SUCCESS) {
+			ipa_err("IPA WDI init failed: ret=%d", ret);
+			goto fail_create_sys_pipe;
+		}
+	} else {
+		ret = wlan_ipa_setup_sys_pipe(ipa_ctx);
+		if (ret)
+			goto fail_create_sys_pipe;
+	}
+
+	qdf_event_create(&ipa_ctx->ipa_resource_comp);
+
+	ipa_debug("exit: success");
+
+	return QDF_STATUS_SUCCESS;
+
+fail_create_sys_pipe:
+	qdf_spinlock_destroy(&ipa_ctx->pm_lock);
+	gp_ipa = NULL;
+	ipa_debug("exit: fail");
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx)
+{
+	struct wlan_ipa_iface_context *iface_context = NULL;
+	int i;
+
+	if (!wlan_ipa_uc_is_enabled(ipa_ctx->config))
+		wlan_ipa_teardown_sys_pipe(ipa_ctx);
+
+	/* Teardown IPA sys_pipe for MCC */
+	if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
+		wlan_ipa_teardown_sys_pipe(ipa_ctx);
+
+	qdf_spinlock_destroy(&ipa_ctx->pm_lock);
+	qdf_spinlock_destroy(&ipa_ctx->q_lock);
+
+	/* destroy the interface lock */
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		iface_context = &ipa_ctx->iface_context[i];
+		qdf_spinlock_destroy(&iface_context->interface_lock);
+	}
+
+	if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+		wlan_ipa_wdi_cleanup();
+		qdf_mutex_destroy(&ipa_ctx->event_lock);
+		qdf_mutex_destroy(&ipa_ctx->ipa_lock);
+		qdf_list_destroy(&ipa_ctx->pending_event);
+
+	}
+
+	gp_ipa = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c
index b30e531..d0a8ec1 100644
--- a/components/ipa/core/src/wlan_ipa_main.c
+++ b/components/ipa/core/src/wlan_ipa_main.c
@@ -21,15 +21,77 @@
  */
 
 #include "wlan_ipa_main.h"
+#include "wlan_ipa_core.h"
 #include "wlan_ipa_tgt_api.h"
 
-bool wlan_ipa_is_present(void)
+static struct wlan_ipa_config *g_ipa_config;
+static bool g_ipa_hw_support;
+
+bool ipa_check_hw_present(void)
 {
 	/* Check if ipa hw is enabled */
-	if (WLAN_IPA_CHECK_HW() != -EPERM)
+	if (WLAN_IPA_CHECK_HW() != -EPERM) {
+		g_ipa_hw_support = true;
 		return true;
-	else
+	} else {
 		return false;
+	}
+}
+
+QDF_STATUS ipa_config_mem_alloc(void)
+{
+	struct wlan_ipa_config *ipa_cfg;
+
+	ipa_cfg = qdf_mem_malloc(sizeof(*ipa_cfg));
+	if (!ipa_cfg) {
+		ipa_err("Failed to allocate memory for ipa config");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	g_ipa_config = ipa_cfg;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void ipa_config_mem_free(void)
+{
+	if (!g_ipa_config) {
+		ipa_err("IPA config already freed");
+		return;
+	}
+
+	qdf_mem_free(g_ipa_config);
+	g_ipa_config = NULL;
+}
+
+bool ipa_is_hw_support(void)
+{
+	return g_ipa_hw_support;
+}
+
+void ipa_config_update(struct wlan_ipa_config *config)
+{
+	if (!g_ipa_config) {
+		ipa_err("IPA config already freed");
+		return;
+	}
+
+	qdf_mem_copy(g_ipa_config, config, sizeof(*g_ipa_config));
+}
+
+bool ipa_config_is_enabled(void)
+{
+	return wlan_ipa_is_enabled(g_ipa_config);
+}
+
+QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx)
+{
+	return wlan_ipa_setup(ipa_ctx, g_ipa_config);
+}
+
+QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx)
+{
+	return wlan_ipa_cleanup(ipa_ctx);
 }
 
 QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev,
@@ -37,3 +99,61 @@
 {
 	return tgt_ipa_uc_offload_enable_disable(pdev, req);
 }
+
+void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc)
+{
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
+					  WLAN_IPA_ID);
+
+	if (!pdev) {
+		ipa_err("Failed to get pdev handle");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
+		return;
+	}
+
+	ipa_obj->dp_soc = dp_soc;
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
+}
+
+void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle)
+{
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
+					  WLAN_IPA_ID);
+
+	if (!pdev) {
+		ipa_err("Failed to get pdev handle");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
+		return;
+	}
+
+	ipa_obj->dp_pdev = txrx_handle;
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID);
+}
diff --git a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
index 7c91e30..31f7ab3 100644
--- a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
+++ b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
@@ -39,6 +39,34 @@
  *         false - ipa hw not present
  */
 bool ucfg_ipa_is_present(void);
+
+/**
+ * ucfg_ipa_update_config() - Update IPA component config
+ *
+ * Return: None
+ */
+void ucfg_ipa_update_config(struct wlan_ipa_config *config);
+
+/**
+ * ucfg_ipa_set_dp_handle() - register DP handle
+ * @psoc: psoc handle
+ * @dp_soc: data path soc handle
+ *
+ * Return: None
+ */
+void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc,
+			       void *dp_soc);
+
+/**
+ * ucfg_ipa_set_txrx_handle() - register pdev txrx handler
+ * @psoc: psoc handle
+ * @txrx_handle: data path pdev txrx handle
+ *
+ * Return: None
+ */
+void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc,
+			      void *txrx_handle);
+
 #else
 
 static inline bool ucfg_ipa_is_present(void)
@@ -46,5 +74,22 @@
 	return false;
 }
 
+static inline void ucfg_ipa_update_config(struct wlan_ipa_config *config)
+{
+}
+
+static inline
+QDF_STATUS ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc,
+				     void *dp_soc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline
+QDF_STATUS ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc,
+				    void *txrx_handle)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* IPA_OFFLOAD */
 #endif /* _WLAN_IPA_UCFG_API_H_ */
diff --git a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c
index 4697b5a..b57e76c 100644
--- a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c
+++ b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c
@@ -51,6 +51,7 @@
 	if (QDF_IS_STATUS_ERROR(status))
 		ipa_err("Failed to detatch ipa pdev object");
 
+	ipa_obj_cleanup(ipa_obj);
 	qdf_mem_free(ipa_obj);
 
 	return status;
@@ -72,10 +73,17 @@
 
 	ipa_info("ipa pdev created");
 
+	if (!ipa_config_is_enabled()) {
+		ipa_info("IPA is disabled");
+		wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_IPA,
+				ipa_pdev_obj_destroy_notification, NULL);
+		return QDF_STATUS_COMP_DISABLED;
+	}
+
 	ipa_obj = qdf_mem_malloc(sizeof(*ipa_obj));
 	if (!ipa_obj) {
 		ipa_err("Failed to allocate memory for ipa pdev object");
-		return QDF_STATUS_E_FAILURE;
+		return QDF_STATUS_E_NOMEM;
 	}
 
 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
@@ -88,6 +96,16 @@
 		return status;
 	}
 
+	status = ipa_obj_setup(ipa_obj);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ipa_err("Failed to setup ipa component");
+		wlan_objmgr_pdev_component_obj_detach(pdev,
+						      WLAN_UMAC_COMP_IPA,
+						      ipa_obj);
+		qdf_mem_free(ipa_obj);
+		return status;
+	}
+
 	target_if_ipa_register_tx_ops(ipa_obj->ipa_tx_op);
 
 	ipa_info("ipa pdev attached");
@@ -101,11 +119,15 @@
 
 	ipa_info("ipa module dispatcher init");
 
-	if (!wlan_ipa_is_present()) {
+	if (!ipa_check_hw_present()) {
 		ipa_info("ipa hw not present");
 		return status;
 	}
 
+	status = ipa_config_mem_alloc();
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
 	status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_IPA,
 		ipa_pdev_obj_create_notification, NULL);
 
@@ -138,7 +160,7 @@
 
 	ipa_info("ipa module dispatcher deinit");
 
-	if (!wlan_ipa_is_present()) {
+	if (!ipa_is_hw_support()) {
 		ipa_info("ipa hw not present");
 		return status;
 	}
@@ -153,5 +175,7 @@
 	if (QDF_IS_STATUS_ERROR(status))
 		ipa_err("Failed to unregister pdev create handler");
 
+	ipa_config_mem_free();
+
 	return status;
 }
diff --git a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
index 79b1d71..3f602d7 100644
--- a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
+++ b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
@@ -24,5 +24,22 @@
 
 bool ucfg_ipa_is_present(void)
 {
-	return wlan_ipa_is_present();
+	return ipa_is_hw_support();
+}
+
+void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc,
+				    void *txrx_handle)
+{
+	return ipa_set_txrx_handle(psoc, txrx_handle);
+}
+
+void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc,
+				     void *dp_soc)
+{
+	return ipa_set_dp_handle(psoc, dp_soc);
+}
+
+void ucfg_ipa_update_config(struct wlan_ipa_config *config)
+{
+	ipa_config_update(config);
 }
diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c
index 531331c..bc70728 100644
--- a/core/cds/src/cds_api.c
+++ b/core/cds/src/cds_api.c
@@ -70,6 +70,7 @@
 #include "target_type.h"
 #include "wlan_ocb_ucfg_api.h"
 #include "qdf_platform.h"
+#include "wlan_ipa_ucfg_api.h"
 
 #ifdef ENABLE_SMMU_S1_TRANSLATION
 #include "pld_common.h"
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 8bc7992..3b40e8d 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -1968,6 +1968,11 @@
 
 	ret = hdd_update_green_ap_config(hdd_ctx);
 
+	ucfg_ipa_set_dp_handle(hdd_ctx->hdd_psoc,
+			       cds_get_context(QDF_MODULE_ID_SOC));
+	ucfg_ipa_set_txrx_handle(hdd_ctx->hdd_psoc,
+				 cds_get_context(QDF_MODULE_ID_TXRX));
+
 	if (cds_cfg) {
 		if (hdd_ctx->config->enable_sub_20_channel_width !=
 			WLAN_SUB_20_CH_WIDTH_NONE && !cfg->sub_20_support) {
@@ -2553,6 +2558,36 @@
 	}
 }
 
+#ifdef IPA_OFFLOAD
+/**
+ * hdd_update_ipa_component_config() - update ipa config
+ * @hdd_ctx: Pointer to hdd context
+ *
+ * Return: none
+ */
+static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx)
+{
+	struct hdd_config *cfg = hdd_ctx->config;
+	struct wlan_ipa_config ipa_cfg;
+
+	ipa_cfg.ipa_config = cfg->IpaConfig;
+	ipa_cfg.desc_size = cfg->IpaDescSize;
+	ipa_cfg.txbuf_count = cfg->IpaUcTxBufCount;
+	ipa_cfg.bus_bw_high = cfg->busBandwidthHighThreshold;
+	ipa_cfg.bus_bw_medium = cfg->busBandwidthMediumThreshold;
+	ipa_cfg.bus_bw_low = cfg->busBandwidthLowThreshold;
+	ipa_cfg.ipa_bw_high = cfg->IpaHighBandwidthMbps;
+	ipa_cfg.ipa_bw_medium = cfg->IpaMediumBandwidthMbps;
+	ipa_cfg.ipa_bw_low = cfg->IpaLowBandwidthMbps;
+
+	ucfg_ipa_update_config(&ipa_cfg);
+}
+#else
+static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx)
+{
+}
+#endif
+
 #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
 static enum policy_mgr_con_mode wlan_hdd_get_mode_for_non_connected_vdev(
 			struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
@@ -2747,6 +2782,8 @@
 			goto hif_close;
 		}
 
+		hdd_update_ipa_component_config(hdd_ctx);
+
 		ret = hdd_update_config(hdd_ctx);
 		if (ret) {
 			hdd_err("Failed to update configuration; errno: %d",