qcacld-3.0: Move IPA stats and debug info API to IPA component

IPA module has been moved to CLD component under the converged
driver model. Move the legacy IPA stats and debug info  APIs to
the IPA component.

Change-Id: Ieb68a1579986c835f66c84e5e3b7aa2a4004383d
CRs-Fixed: 2177925
diff --git a/Kbuild b/Kbuild
index 3760d75..a58b9b5 100644
--- a/Kbuild
+++ b/Kbuild
@@ -1082,6 +1082,7 @@
 		$(IPA_DIR)/dispatcher/src/wlan_ipa_tgt_api.o \
 		$(IPA_DIR)/core/src/wlan_ipa_main.o \
 		$(IPA_DIR)/core/src/wlan_ipa_core.o \
+		$(IPA_DIR)/core/src/wlan_ipa_stats.o \
 		$(IPA_DIR)/core/src/wlan_ipa_rm.o
 endif
 
diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h
index 6182898..a6ca4db 100644
--- a/components/ipa/core/inc/wlan_ipa_core.h
+++ b/components/ipa/core/inc/wlan_ipa_core.h
@@ -81,6 +81,19 @@
 }
 
 /**
+ * wlan_ipa_is_rt_debugging_enabled() - Is IPA RT debugging enabled?
+ * @ipa_cfg: IPA config
+ *
+ * Return: true if IPA RT debugging is enabled, false otherwise
+ */
+static inline
+bool wlan_ipa_is_rt_debugging_enabled(struct wlan_ipa_config *ipa_cfg)
+{
+	return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg,
+					  WLAN_IPA_REAL_TIME_DEBUGGING);
+}
+
+/**
  * wlan_ipa_setup - IPA initialize and setup
  * @ipa_ctx: IPA priv obj
  * @ipa_cfg: IPA config
@@ -132,6 +145,16 @@
 QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx,
 				   uint64_t tx_packets, uint64_t rx_packets);
 
+/**
+ * wlan_ipa_get_iface() - Get IPA interface
+ * @ipa_ctx: IPA context
+ * @mode: Interface device mode
+ *
+ * Return: IPA interface address
+ */
+struct wlan_ipa_iface_context
+*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode);
+
 #ifndef CONFIG_IPA_WDI_UNIFIED_API
 /**
  * wlan_ipa_wdi_rm_request_resource() - IPA WDI request resource
@@ -234,5 +257,139 @@
 
 #endif /* CONFIG_IPA_WDI_UNIFIED_API */
 
+#ifdef FEATURE_METERING
+
+/**
+ * wlan_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
+ * @ipa_ctx: IPA context
+ * @op_msg: operation message received from firmware
+ *
+ * Return: QDF_STATUS enumeration
+ */
+QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
+				  struct op_msg_type *op_msg);
+
+/**
+ * wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
+ * IPA calls to get WLAN stats or set quota limit.
+ * @priv: pointer to private data registered with IPA (we register a
+ *        pointer to the global IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+				   void *data);
+#else
+
+static inline
+QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
+				   struct op_msg_type *op_msg)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline void wlan_ipa_wdi_meter_notifier_cb(void)
+{
+}
+#endif /* FEATURE_METERING */
+
+/**
+ * wlan_ipa_uc_stat() - Print IPA uC stats
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * wlan_ipa_uc_info() - Print IPA uC resource and session information
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * wlan_ipa_print_fw_wdi_stats() - Print FW IPA WDI stats
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx,
+				 struct ipa_uc_fw_stats *uc_fw_stat);
+
+/**
+ * wlan_ipa_uc_stat_request() - Get IPA stats from IPA
+ * @ipa_ctx: IPA context
+ * @reason: STAT REQ Reason
+ *
+ * Return: None
+ */
+void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason);
+
+/**
+ * wlan_ipa_uc_stat_query() - Query the IPA stats
+ * @ipa_ctx: IPA context
+ * @ipa_tx_diff: tx packet count diff from previous tx packet count
+ * @ipa_rx_diff: rx packet count diff from previous rx packet count
+ *
+ * Return: None
+ */
+void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx,
+			    uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff);
+
+/**
+ * wlan_ipa_dump_info() - dump IPA IPA struct
+ * @ipa_ctx: IPA context
+ *
+ * Dump entire struct ipa_ctx
+ *
+ * Return: none
+ */
+void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * wlan_ipa_uc_rt_debug_host_dump - dump rt debug buffer
+ * @ipa_ctx: IPA context
+ *
+ * If rt debug enabled, dump debug buffer contents based on requirement
+ *
+ * Return: none
+ */
+void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * wlan_ipa_uc_rt_debug_destructor() - called by data packet free
+ * @nbuff: packet pinter
+ *
+ * when free data packet, will be invoked by wlan client and will increase
+ * free counter
+ *
+ * Return: none
+ */
+void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff);
+
+/**
+ * wlan_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging
+ * @ipa_ctx: IPA context
+ *
+ * free all rt debugging resources
+ *
+ * Return: none
+ */
+void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx);
+
+/**
+ * wlan_ipa_uc_rt_debug_init() - initialize resources to handle rt debugging
+ * @ipa_ctx: IPA context
+ *
+ * alloc and initialize all rt debugging resources
+ *
+ * Return: none
+ */
+void wlan_ipa_uc_rt_debug_init(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 fa5330d..b8e5aa5 100644
--- a/components/ipa/core/inc/wlan_ipa_main.h
+++ b/components/ipa/core/inc/wlan_ipa_main.h
@@ -167,5 +167,59 @@
  */
 QDF_STATUS ipa_rm_set_perf_level(struct wlan_objmgr_pdev *pdev,
 				 uint64_t tx_packets, uint64_t rx_packets);
+
+/**
+ * ipa_uc_info() - Print IPA uC resource and session information
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ipa_uc_info(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ipa_uc_stat() - Print IPA uC stats
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ipa_uc_stat(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ipa_uc_rt_debug_host_dump() - IPA rt debug host dump
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ipa_dump_info() - Dump IPA context information
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ipa_dump_info(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ipa_uc_stat_request() - Get IPA stats from IPA.
+ * @pdev: pdev obj
+ * @reason: STAT REQ Reason
+ *
+ * Return: None
+ */
+void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev,
+			 uint8_t reason);
+
+/**
+ * ipa_uc_stat_query() - Query the IPA stats
+ * @pdev: pdev obj
+ * @ipa_tx_diff: tx packet count diff from previous tx packet count
+ * @ipa_rx_diff: rx packet count diff from previous rx packet count
+ *
+ * Return: None
+ */
+void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev,
+		       uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff);
+
 #endif /* IPA_OFFLOAD */
 #endif /* end  of _WLAN_IPA_MAIN_H_ */
diff --git a/components/ipa/core/inc/wlan_ipa_priv.h b/components/ipa/core/inc/wlan_ipa_priv.h
index 8f5d737..0220a5a 100644
--- a/components/ipa/core/inc/wlan_ipa_priv.h
+++ b/components/ipa/core/inc/wlan_ipa_priv.h
@@ -302,7 +302,7 @@
 	qdf_ipa_client_type_t prod_client;
 
 	uint8_t iface_id;       /* This iface ID */
-	qdf_device_t dev;
+	qdf_netdev_t dev;
 	enum tQDF_ADAPTER_MODE device_mode;
 	uint8_t sta_id;         /* This iface station ID */
 	uint8_t session_id;
@@ -682,6 +682,11 @@
 
 #define IPA_RESOURCE_COMP_WAIT_TIME	100
 
+#ifdef FEATURE_METERING
+#define IPA_UC_SHARING_STATES_WAIT_TIME	500
+#define IPA_UC_SET_QUOTA_WAIT_TIME	500
+#endif
+
 /**
  * wlan_ipa_wlan_event_to_str() - convert IPA WLAN event to string
  * @event: IPA WLAN event to be converted to a string
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
index 340eecd..78544bc 100644
--- a/components/ipa/core/src/wlan_ipa_core.c
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -180,6 +180,11 @@
 	return QDF_STATUS_SUCCESS;
 }
 
+struct wlan_ipa_priv *wlan_ipa_get_obj_context(void)
+{
+	return gp_ipa;
+}
+
 #ifdef CONFIG_IPA_WDI_UNIFIED_API
 
 /*
@@ -202,6 +207,33 @@
 }
 #endif
 
+#ifdef FEATURE_METERING
+/**
+ * wlan_ipa_wdi_init_metering() - IPA WDI metering init
+ * @ipa_ctx: IPA context
+ * @in: IPA WDI in param
+ *
+ * Return: QDF_STATUS
+ */
+static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
+					      qdf_ipa_wdi_init_in_params_t *in)
+{
+	QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) =
+				wlan_ipa_wdi_meter_notifier_cb;
+}
+#else
+static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt,
+					      qdf_ipa_wdi_init_in_params_t *in)
+{
+}
+#endif
+
+/**
+ * wlan_ipa_wdi_init() - IPA WDI init
+ * @ipa_ctx: IPA context
+ *
+ * Return: QDF_STATUS
+ */
 static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx)
 {
 	qdf_ipa_wdi_init_in_params_t in;
@@ -212,7 +244,8 @@
 
 	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;
+	QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx;
+	wlan_ipa_wdi_init_metering(ipa_ctx, &in);
 
 	ret = qdf_ipa_wdi_init(&in, &out);
 	if (ret) {
@@ -761,3 +794,19 @@
 
 	return QDF_STATUS_SUCCESS;
 }
+
+struct wlan_ipa_iface_context
+*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode)
+{
+	struct wlan_ipa_iface_context *iface_ctx = NULL;
+	int i;
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		iface_ctx = &ipa_ctx->iface_context[i];
+
+		if (iface_ctx->device_mode == mode)
+			return iface_ctx;
+	}
+
+	return NULL;
+}
diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c
index 64d6149..8baed7f 100644
--- a/components/ipa/core/src/wlan_ipa_main.c
+++ b/components/ipa/core/src/wlan_ipa_main.c
@@ -176,3 +176,112 @@
 
 	return wlan_ipa_set_perf_level(ipa_obj, tx_packets, rx_packets);
 }
+
+void ipa_uc_info(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_uc_info(ipa_obj);
+}
+
+void ipa_uc_stat(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_uc_stat(ipa_obj);
+}
+
+void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_uc_rt_debug_host_dump(ipa_obj);
+}
+
+void ipa_dump_info(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_dump_info(ipa_obj);
+}
+
+void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, uint8_t reason)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_uc_stat_request(ipa_obj, reason);
+}
+
+void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev,
+		       uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	return wlan_ipa_uc_stat_query(ipa_obj, ipa_tx_diff, ipa_rx_diff);
+}
diff --git a/components/ipa/core/src/wlan_ipa_stats.c b/components/ipa/core/src/wlan_ipa_stats.c
new file mode 100644
index 0000000..05fddd7
--- /dev/null
+++ b/components/ipa/core/src/wlan_ipa_stats.c
@@ -0,0 +1,961 @@
+/*
+ * 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_main.h"
+#include "wlan_ipa_core.h"
+#include "cdp_txrx_ipa.h"
+
+/**
+ * wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer
+ * @ctext: pointer to ipa context.
+ *
+ * If rt debug enabled, periodically called, and fill debug buffer
+ *
+ * Return: none
+ */
+static void wlan_ipa_uc_rt_debug_host_fill(void *ctext)
+{
+	struct wlan_ipa_priv *ipa_ctx = ctext;
+	struct uc_rt_debug_info *dump_info = NULL;
+
+	if (!ipa_ctx)
+		return;
+
+	qdf_mutex_acquire(&ipa_ctx->rt_debug_lock);
+	dump_info = &ipa_ctx->rt_bug_buffer[
+		ipa_ctx->rt_buf_fill_index % WLAN_IPA_UC_RT_DEBUG_BUF_COUNT];
+
+	dump_info->time = (uint64_t)qdf_mc_timer_get_system_time();
+	dump_info->ipa_excep_count = ipa_ctx->stats.num_rx_excep;
+	dump_info->rx_drop_count = ipa_ctx->ipa_rx_internal_drop_count;
+	dump_info->net_sent_count = ipa_ctx->ipa_rx_net_send_count;
+	dump_info->tx_fwd_count = ipa_ctx->ipa_tx_forward;
+	dump_info->tx_fwd_ok_count = ipa_ctx->stats.num_tx_fwd_ok;
+	dump_info->rx_discard_count = ipa_ctx->ipa_rx_discard;
+	dump_info->rx_destructor_call = ipa_ctx->ipa_rx_destructor_count;
+	ipa_ctx->rt_buf_fill_index++;
+	qdf_mutex_release(&ipa_ctx->rt_debug_lock);
+
+	qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer,
+		WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL);
+}
+
+void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx)
+{
+	unsigned int dump_count;
+	unsigned int dump_index;
+	struct uc_rt_debug_info *dump_info = NULL;
+
+	if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) {
+		ipa_debug("IPA RT debug is not enabled");
+		return;
+	}
+
+	ipa_info("========= WLAN-IPA DEBUG BUF DUMP ==========\n");
+	ipa_info("     TM     :   EXEP   :   DROP   :   NETS   :   FWOK"
+		 ":   TXFD   :   DSTR   :   DSCD\n");
+
+	qdf_mutex_acquire(&ipa_ctx->rt_debug_lock);
+	for (dump_count = 0;
+		dump_count < WLAN_IPA_UC_RT_DEBUG_BUF_COUNT;
+		dump_count++) {
+		dump_index = (ipa_ctx->rt_buf_fill_index + dump_count) %
+			WLAN_IPA_UC_RT_DEBUG_BUF_COUNT;
+		dump_info = &ipa_ctx->rt_bug_buffer[dump_index];
+		ipa_info("%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n",
+			dump_info->time, dump_info->ipa_excep_count,
+			dump_info->rx_drop_count, dump_info->net_sent_count,
+			dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count,
+			dump_info->rx_destructor_call,
+			dump_info->rx_discard_count);
+	}
+	qdf_mutex_release(&ipa_ctx->rt_debug_lock);
+}
+
+/**
+ * wlan_ipa_uc_rt_debug_handler - periodic memory health monitor handler
+ * @ctext: pointer to ipa context.
+ *
+ * periodically called by timer expire
+ * will try to alloc dummy memory and detect out of memory condition
+ * if out of memory detected, dump wlan-ipa stats
+ *
+ * Return: none
+ */
+static void wlan_ipa_uc_rt_debug_handler(void *ctext)
+{
+	struct wlan_ipa_priv *ipa_ctx = ctext;
+	void *dummy_ptr = NULL;
+
+	if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) {
+		ipa_debug("IPA RT debug is not enabled");
+		return;
+	}
+
+	/* Allocate dummy buffer periodically and free immediately. this will
+	 * proactively detect OOM and if allocation fails dump ipa stats
+	 */
+	dummy_ptr = qdf_mem_malloc(WLAN_IPA_UC_DEBUG_DUMMY_MEM_SIZE);
+	if (!dummy_ptr) {
+		wlan_ipa_uc_rt_debug_host_dump(ipa_ctx);
+		wlan_ipa_uc_stat_request(ipa_ctx,
+					 WLAN_IPA_UC_STAT_REASON_DEBUG);
+	} else {
+		qdf_mem_free(dummy_ptr);
+	}
+
+	qdf_mc_timer_start(&ipa_ctx->rt_debug_timer,
+		WLAN_IPA_UC_RT_DEBUG_PERIOD);
+}
+
+void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff)
+{
+	struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context();
+
+	if (!ipa_ctx) {
+		ipa_err("invalid ipa context");
+		return;
+	}
+
+	ipa_ctx->ipa_rx_destructor_count++;
+}
+
+void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx)
+{
+	qdf_mutex_destroy(&ipa_ctx->rt_debug_lock);
+
+	if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) {
+		ipa_debug("IPA RT debug is not enabled");
+		return;
+	}
+
+	if (QDF_TIMER_STATE_STOPPED !=
+		qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_fill_timer)) {
+		qdf_mc_timer_stop(&ipa_ctx->rt_debug_fill_timer);
+	}
+	qdf_mc_timer_destroy(&ipa_ctx->rt_debug_fill_timer);
+
+	if (QDF_TIMER_STATE_STOPPED !=
+		qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_timer)) {
+		qdf_mc_timer_stop(&ipa_ctx->rt_debug_timer);
+	}
+	qdf_mc_timer_destroy(&ipa_ctx->rt_debug_timer);
+}
+
+void wlan_ipa_uc_rt_debug_init(struct wlan_ipa_priv *ipa_ctx)
+{
+	qdf_mutex_create(&ipa_ctx->rt_debug_lock);
+	ipa_ctx->rt_buf_fill_index = 0;
+	qdf_mem_zero(ipa_ctx->rt_bug_buffer,
+		sizeof(struct uc_rt_debug_info) *
+		WLAN_IPA_UC_RT_DEBUG_BUF_COUNT);
+	ipa_ctx->ipa_tx_forward = 0;
+	ipa_ctx->ipa_rx_discard = 0;
+	ipa_ctx->ipa_rx_net_send_count = 0;
+	ipa_ctx->ipa_rx_internal_drop_count = 0;
+	ipa_ctx->ipa_rx_destructor_count = 0;
+
+	/* Reatime debug enable on feature enable */
+	if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) {
+		ipa_debug("IPA RT debug is not enabled");
+		return;
+	}
+
+	qdf_mc_timer_init(&ipa_ctx->rt_debug_fill_timer, QDF_TIMER_TYPE_SW,
+		wlan_ipa_uc_rt_debug_host_fill, (void *)ipa_ctx);
+	qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer,
+		WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL);
+
+	qdf_mc_timer_init(&ipa_ctx->rt_debug_timer, QDF_TIMER_TYPE_SW,
+		wlan_ipa_uc_rt_debug_handler, (void *)ipa_ctx);
+	qdf_mc_timer_start(&ipa_ctx->rt_debug_timer,
+		WLAN_IPA_UC_RT_DEBUG_PERIOD);
+
+}
+
+/**
+ * wlan_ipa_dump_ipa_ctx() - dump entries in IPA IPA struct
+ * @ipa_ctx: IPA context
+ *
+ * Dump entries in struct ipa_ctx
+ *
+ * Return: none
+ */
+static void wlan_ipa_dump_ipa_ctx(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i;
+
+	/* IPA IPA */
+	ipa_info("\n==== IPA IPA ====\n"
+		"num_iface: %d\n"
+		"rm_state: %d\n"
+		"rm_lock: %pK\n"
+		"uc_rm_work: %pK\n"
+		"uc_op_work: %pK\n"
+		"wake_lock: %pK\n"
+		"wake_lock_work: %pK\n"
+		"wake_lock_released: %d\n"
+		"tx_ref_cnt: %d\n"
+		"pm_queue_head----\n"
+		"\thead: %pK\n"
+		"\ttail: %pK\n"
+		"\tqlen: %d\n"
+		"pm_work: %pK\n"
+		"pm_lock: %pK\n"
+		"suspended: %d\n",
+		ipa_ctx->num_iface,
+		ipa_ctx->rm_state,
+		&ipa_ctx->rm_lock,
+		&ipa_ctx->uc_rm_work,
+		&ipa_ctx->uc_op_work,
+		&ipa_ctx->wake_lock,
+		&ipa_ctx->wake_lock_work,
+		ipa_ctx->wake_lock_released,
+		ipa_ctx->tx_ref_cnt.counter,
+		ipa_ctx->pm_queue_head.head,
+		ipa_ctx->pm_queue_head.tail,
+		ipa_ctx->pm_queue_head.qlen,
+		&ipa_ctx->pm_work,
+		&ipa_ctx->pm_lock,
+		ipa_ctx->suspended);
+
+	ipa_info("\nq_lock: %pK\n"
+		"pend_desc_head----\n"
+		"\tnext: %pK\n"
+		"\tprev: %pK\n"
+		"stats: %pK\n"
+		"curr_prod_bw: %d\n"
+		"curr_cons_bw: %d\n"
+		"activated_fw_pipe: %d\n"
+		"sap_num_connected_sta: %d\n"
+		"sta_connected: %d\n",
+		&ipa_ctx->q_lock,
+		ipa_ctx->pend_desc_head.next,
+		ipa_ctx->pend_desc_head.prev,
+		&ipa_ctx->stats,
+		ipa_ctx->curr_prod_bw,
+		ipa_ctx->curr_cons_bw,
+		ipa_ctx->activated_fw_pipe,
+		ipa_ctx->sap_num_connected_sta,
+		(unsigned int)ipa_ctx->sta_connected);
+
+	ipa_info("\ntx_pipe_handle: 0x%x\n"
+		"rx_pipe_handle: 0x%x\n"
+		"resource_loading: %d\n"
+		"resource_unloading: %d\n"
+		"pending_cons_req: %d\n"
+		"pending_event----\n"
+		"\tanchor.next: %pK\n"
+		"\tanchor.prev: %pK\n"
+		"\tcount: %d\n"
+		"\tmax_size: %d\n"
+		"event_lock: %pK\n"
+		"ipa_tx_packets_diff: %d\n"
+		"ipa_rx_packets_diff: %d\n"
+		"ipa_p_tx_packets: %d\n"
+		"ipa_p_rx_packets: %d\n"
+		"stat_req_reason: %d\n",
+		ipa_ctx->tx_pipe_handle,
+		ipa_ctx->rx_pipe_handle,
+		ipa_ctx->resource_loading,
+		ipa_ctx->resource_unloading,
+		ipa_ctx->pending_cons_req,
+		ipa_ctx->pending_event.anchor.next,
+		ipa_ctx->pending_event.anchor.prev,
+		ipa_ctx->pending_event.count,
+		ipa_ctx->pending_event.max_size,
+		&ipa_ctx->event_lock,
+		ipa_ctx->ipa_tx_packets_diff,
+		ipa_ctx->ipa_rx_packets_diff,
+		ipa_ctx->ipa_p_tx_packets,
+		ipa_ctx->ipa_p_rx_packets,
+		ipa_ctx->stat_req_reason);
+
+	ipa_info("\ncons_pipe_in----\n"
+		"\tsys: %pK\n"
+		"\tdl.comp_ring_base_pa: 0x%x\n"
+		"\tdl.comp_ring_size: %d\n"
+		"\tdl.ce_ring_base_pa: 0x%x\n"
+		"\tdl.ce_door_bell_pa: 0x%x\n"
+		"\tdl.ce_ring_size: %d\n"
+		"\tdl.num_tx_buffers: %d\n"
+		"prod_pipe_in----\n"
+		"\tsys: %pK\n"
+		"\tul.rdy_ring_base_pa: 0x%x\n"
+		"\tul.rdy_ring_size: %d\n"
+		"\tul.rdy_ring_rp_pa: 0x%x\n"
+		"uc_loaded: %d\n"
+		"wdi_enabled: %d\n"
+		"rt_debug_fill_timer: %pK\n"
+		"rt_debug_lock: %pK\n"
+		"ipa_lock: %pK\n",
+		&ipa_ctx->cons_pipe_in.sys,
+		(unsigned int)ipa_ctx->cons_pipe_in.u.dl.comp_ring_base_pa,
+		ipa_ctx->cons_pipe_in.u.dl.comp_ring_size,
+		(unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_ring_base_pa,
+		(unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_door_bell_pa,
+		ipa_ctx->cons_pipe_in.u.dl.ce_ring_size,
+		ipa_ctx->cons_pipe_in.u.dl.num_tx_buffers,
+		&ipa_ctx->prod_pipe_in.sys,
+		(unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_base_pa,
+		ipa_ctx->prod_pipe_in.u.ul.rdy_ring_size,
+		(unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_rp_pa,
+		ipa_ctx->uc_loaded,
+		ipa_ctx->wdi_enabled,
+		&ipa_ctx->rt_debug_fill_timer,
+		&ipa_ctx->rt_debug_lock,
+		&ipa_ctx->ipa_lock);
+
+	ipa_info("\nvdev_to_iface----");
+	for (i = 0; i < WLAN_IPA_MAX_SESSION; i++)
+		ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_to_iface[i]);
+
+	QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO,
+		"\nvdev_offload_enabled----");
+	for (i = 0; i < WLAN_IPA_MAX_SESSION; i++)
+		ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_offload_enabled[i]);
+
+	QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO,
+		"\nassoc_stas_map ----");
+	for (i = 0; i < WLAN_IPA_MAX_STA_COUNT; i++) {
+		ipa_info("\n\t[%d]: is_reserved=%d, sta_id=%d", i,
+			ipa_ctx->assoc_stas_map[i].is_reserved,
+			ipa_ctx->assoc_stas_map[i].sta_id);
+	}
+}
+
+/**
+ * wlan_ipa_dump_sys_pipe() - dump IPA IPA SYS Pipe struct
+ * @ipa_ctx: IPA IPA struct
+ *
+ * Dump entire struct wlan_ipa_sys_pipe
+ *
+ * Return: none
+ */
+static void wlan_ipa_dump_sys_pipe(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i;
+
+	/* IPA SYS Pipes */
+	ipa_info("==== IPA SYS Pipes ====");
+
+	for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) {
+		struct wlan_ipa_sys_pipe *sys_pipe;
+		qdf_ipa_sys_connect_params_t *ipa_sys_params;
+
+		sys_pipe = &ipa_ctx->sys_pipe[i];
+		ipa_sys_params = &sys_pipe->ipa_sys_params;
+
+		ipa_info("\nsys_pipe[%d]----\n"
+			"\tconn_hdl: 0x%x\n"
+			"\tconn_hdl_valid: %d\n"
+			"\tnat_en: %d\n"
+			"\thdr_len %d\n"
+			"\thdr_additional_const_len: %d\n"
+			"\thdr_ofst_pkt_size_valid: %d\n"
+			"\thdr_ofst_pkt_size: %d\n"
+			"\thdr_little_endian: %d\n"
+			"\tmode: %d\n"
+			"\tclient: %d\n"
+			"\tdesc_fifo_sz: %d\n"
+			"\tpriv: %pK\n"
+			"\tnotify: %pK\n"
+			"\tskip_ep_cfg: %d\n"
+			"\tkeep_ipa_awake: %d\n",
+			i,
+			sys_pipe->conn_hdl,
+			sys_pipe->conn_hdl_valid,
+			QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN(
+				ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID(
+				ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params),
+			QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params));
+	}
+}
+
+/**
+ * wlan_ipa_dump_iface_context() - dump IPA IPA Interface Context struct
+ * @ipa_ctx: IPA IPA struct
+ *
+ * Dump entire struct wlan_ipa_iface_context
+ *
+ * Return: none
+ */
+static void wlan_ipa_dump_iface_context(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i;
+
+	/* IPA Interface Contexts */
+	ipa_info("\n==== IPA Interface Contexts ====\n");
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		struct wlan_ipa_iface_context *iface_context;
+
+		iface_context = &ipa_ctx->iface_context[i];
+
+		ipa_info("\niface_context[%d]----\n"
+			"\tipa_ctx: %pK\n"
+			"\ttl_context: %pK\n"
+			"\tcons_client: %d\n"
+			"\tprod_client: %d\n"
+			"\tiface_id: %d\n"
+			"\tsta_id: %d\n"
+			"\tinterface_lock: %pK\n"
+			"\tifa_address: 0x%x\n",
+			i,
+			iface_context->ipa_ctx,
+			iface_context->tl_context,
+			iface_context->cons_client,
+			iface_context->prod_client,
+			iface_context->iface_id,
+			iface_context->sta_id,
+			&iface_context->interface_lock,
+			iface_context->ifa_address);
+	}
+}
+
+void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx)
+{
+	wlan_ipa_dump_ipa_ctx(ipa_ctx);
+	wlan_ipa_dump_sys_pipe(ipa_ctx);
+	wlan_ipa_dump_iface_context(ipa_ctx);
+}
+
+void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx,
+			    uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
+{
+	*ipa_tx_diff = 0;
+	*ipa_rx_diff = 0;
+
+	qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+	if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) &&
+	    (false == ipa_ctx->resource_loading)) {
+		*ipa_tx_diff = ipa_ctx->ipa_tx_packets_diff;
+		*ipa_rx_diff = ipa_ctx->ipa_rx_packets_diff;
+	}
+	qdf_mutex_release(&ipa_ctx->ipa_lock);
+}
+
+void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason)
+{
+	qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+	if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) &&
+	    (false == ipa_ctx->resource_loading)) {
+		ipa_ctx->stat_req_reason = reason;
+		cdp_ipa_get_stat(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else {
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	}
+}
+
+/**
+ * wlan_ipa_print_session_info - Print IPA session info
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_print_session_info(struct wlan_ipa_priv *ipa_ctx)
+{
+	struct wlan_ipa_uc_pending_event *event = NULL, *next = NULL;
+	struct wlan_ipa_iface_context *iface_context = NULL;
+	int i;
+
+	ipa_info("\n==== IPA SESSION INFO ====\n"
+		"NUM IFACE: %d\n"
+		"RM STATE: %d\n"
+		"ACTIVATED FW PIPE: %d\n"
+		"SAP NUM STAs: %d\n"
+		"STA CONNECTED: %d\n"
+		"CONCURRENT MODE: %s\n"
+		"RSC LOADING: %d\n"
+		"RSC UNLOADING: %d\n"
+		"PENDING CONS REQ: %d\n"
+		"IPA PIPES DOWN: %d\n"
+		"IPA UC LOADED: %d\n"
+		"IPA WDI ENABLED: %d\n"
+		"NUM SEND MSG: %d\n"
+		"NUM FREE MSG: %d\n",
+		ipa_ctx->num_iface,
+		ipa_ctx->rm_state,
+		ipa_ctx->activated_fw_pipe,
+		ipa_ctx->sap_num_connected_sta,
+		ipa_ctx->sta_connected,
+		(ipa_ctx->mcc_mode ? "MCC" : "SCC"),
+		ipa_ctx->resource_loading,
+		ipa_ctx->resource_unloading,
+		ipa_ctx->pending_cons_req,
+		ipa_ctx->ipa_pipes_down,
+		ipa_ctx->uc_loaded,
+		ipa_ctx->wdi_enabled,
+		(unsigned int)ipa_ctx->stats.num_send_msg,
+		(unsigned int)ipa_ctx->stats.num_free_msg);
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		iface_context = &ipa_ctx->iface_context[i];
+
+		if (!iface_context->tl_context)
+			continue;
+
+		ipa_info("\nIFACE[%d]: sta_id:%d, mode:%d, offload:%d",
+			 i, iface_context->sta_id,
+			 iface_context->device_mode,
+			 ipa_ctx->vdev_offload_enabled[iface_context->
+						       session_id]);
+	}
+
+	for (i = 0; i < IPA_WLAN_EVENT_MAX; i++)
+		ipa_info("\nEVENT[%d]=%d",
+			 i, ipa_ctx->stats.event[i]);
+
+	i = 0;
+	qdf_list_peek_front(&ipa_ctx->pending_event,
+			(qdf_list_node_t **)&event);
+	while (event != NULL) {
+		ipa_info("PENDING EVENT[%d]: EVT:%s, sta_id:%d, MAC:%pM",
+			 i, wlan_ipa_wlan_event_to_str(event->type),
+			 event->sta_id, event->mac_addr);
+
+		qdf_list_peek_next(&ipa_ctx->pending_event,
+				   (qdf_list_node_t *)event,
+				   (qdf_list_node_t **)&next);
+		event = next;
+		next = NULL;
+		i++;
+	}
+}
+
+/**
+ * wlan_ipa_print_txrx_stats - Print IPA IPA TX/RX stats
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_print_txrx_stats(struct wlan_ipa_priv *ipa_ctx)
+{
+	int i;
+	struct wlan_ipa_iface_context *iface_context = NULL;
+
+	ipa_info("\n==== IPA IPA TX/RX STATS ====\n"
+		"NUM RM GRANT: %llu\n"
+		"NUM RM RELEASE: %llu\n"
+		"NUM RM GRANT IMM: %llu\n"
+		"NUM CONS PERF REQ: %llu\n"
+		"NUM PROD PERF REQ: %llu\n"
+		"NUM RX DROP: %llu\n"
+		"NUM EXCP PKT: %llu\n"
+		"NUM TX FWD OK: %llu\n"
+		"NUM TX FWD ERR: %llu\n"
+		"NUM TX DESC Q CNT: %llu\n"
+		"NUM TX DESC ERROR: %llu\n"
+		"NUM TX COMP CNT: %llu\n"
+		"NUM TX QUEUED: %llu\n"
+		"NUM TX DEQUEUED: %llu\n"
+		"NUM MAX PM QUEUE: %llu\n"
+		"TX REF CNT: %d\n"
+		"SUSPENDED: %d\n"
+		"PEND DESC HEAD: %pK\n"
+		"TX DESC LIST: %pK\n",
+		ipa_ctx->stats.num_rm_grant,
+		ipa_ctx->stats.num_rm_release,
+		ipa_ctx->stats.num_rm_grant_imm,
+		ipa_ctx->stats.num_cons_perf_req,
+		ipa_ctx->stats.num_prod_perf_req,
+		ipa_ctx->stats.num_rx_drop,
+		ipa_ctx->stats.num_rx_excep,
+		ipa_ctx->stats.num_tx_fwd_ok,
+		ipa_ctx->stats.num_tx_fwd_err,
+		ipa_ctx->stats.num_tx_desc_q_cnt,
+		ipa_ctx->stats.num_tx_desc_error,
+		ipa_ctx->stats.num_tx_comp_cnt,
+		ipa_ctx->stats.num_tx_queued,
+		ipa_ctx->stats.num_tx_dequeued,
+		ipa_ctx->stats.num_max_pm_queue,
+		ipa_ctx->tx_ref_cnt.counter,
+		ipa_ctx->suspended,
+		&ipa_ctx->pend_desc_head,
+		&ipa_ctx->tx_desc_list);
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+
+		iface_context = &ipa_ctx->iface_context[i];
+		if (!iface_context->tl_context)
+			continue;
+
+		ipa_info("IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu,"
+			 " TX CAC DROP:%llu, RX IPA EXCEP:%llu",
+			 i, iface_context->stats.num_tx,
+			 iface_context->stats.num_tx_drop,
+			 iface_context->stats.num_tx_err,
+			 iface_context->stats.num_tx_cac_drop,
+			 iface_context->stats.num_rx_ipa_excep);
+	}
+}
+
+void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx,
+				 struct ipa_uc_fw_stats *uc_fw_stat)
+{
+	ipa_info("\n==== WLAN FW WDI TX STATS ====\n"
+		"COMP RING BASE: 0x%x\n"
+		"COMP RING SIZE: %d\n"
+		"COMP RING DBELL : 0x%x\n"
+		"COMP RING DBELL IND VAL : %d\n"
+		"COMP RING DBELL CACHED VAL : %d\n"
+		"PKTS ENQ : %d\n"
+		"PKTS COMP : %d\n"
+		"IS SUSPEND : %d\n",
+		uc_fw_stat->tx_comp_ring_base,
+		uc_fw_stat->tx_comp_ring_size,
+		uc_fw_stat->tx_comp_ring_dbell_addr,
+		uc_fw_stat->tx_comp_ring_dbell_ind_val,
+		uc_fw_stat->tx_comp_ring_dbell_cached_val,
+		uc_fw_stat->tx_pkts_enqueued,
+		uc_fw_stat->tx_pkts_completed,
+		uc_fw_stat->tx_is_suspend);
+
+	ipa_info("\n==== WLAN FW WDI RX STATS ====\n"
+		"IND RING BASE: 0x%x\n"
+		"IND RING SIZE: %d\n"
+		"IND RING DBELL : 0x%x\n"
+		"IND RING DBELL IND VAL : %d\n"
+		"IND RING DBELL CACHED VAL : %d\n"
+		"RDY IND ADDR : 0x%x\n"
+		"RDY IND CACHE VAL : %d\n"
+		"RFIL IND : %d\n"
+		"NUM PKT INDICAT : %d\n"
+		"BUF REFIL : %d\n"
+		"NUM DROP NO SPC : %d\n"
+		"NUM DROP NO BUF : %d\n"
+		"IS SUSPND : %d\n",
+		uc_fw_stat->rx_ind_ring_base,
+		uc_fw_stat->rx_ind_ring_size,
+		uc_fw_stat->rx_ind_ring_dbell_addr,
+		uc_fw_stat->rx_ind_ring_dbell_ind_val,
+		uc_fw_stat->rx_ind_ring_dbell_ind_cached_val,
+		uc_fw_stat->rx_ind_ring_rdidx_addr,
+		uc_fw_stat->rx_ind_ring_rd_idx_cached_val,
+		uc_fw_stat->rx_refill_idx,
+		uc_fw_stat->rx_num_pkts_indicated,
+		uc_fw_stat->rx_buf_refilled,
+		uc_fw_stat->rx_num_ind_drop_no_space,
+		uc_fw_stat->rx_num_ind_drop_no_buf,
+		uc_fw_stat->rx_is_suspend);
+}
+
+/**
+ * wlan_ipa_print_ipa_wdi_stats - Print IPA WDI stats
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_print_ipa_wdi_stats(struct wlan_ipa_priv *ipa_ctx)
+{
+	qdf_ipa_hw_stats_wdi_info_data_t ipa_stat;
+
+	qdf_ipa_get_wdi_stats(&ipa_stat);
+
+	ipa_info("\n==== IPA WDI TX STATS ====\n"
+		"NUM PROCD : %d\n"
+		"CE DBELL : 0x%x\n"
+		"NUM DBELL FIRED : %d\n"
+		"COMP RNG FULL : %d\n"
+		"COMP RNG EMPT : %d\n"
+		"COMP RNG USE HGH : %d\n"
+		"COMP RNG USE LOW : %d\n"
+		"BAM FIFO FULL : %d\n"
+		"BAM FIFO EMPT : %d\n"
+		"BAM FIFO USE HGH : %d\n"
+		"BAM FIFO USE LOW : %d\n"
+		"NUM DBELL : %d\n"
+		"NUM UNEXP DBELL : %d\n"
+		"NUM BAM INT HDL : 0x%x\n"
+		"NUM QMB INT HDL : 0x%x\n",
+		ipa_stat.tx_ch_stats.num_pkts_processed,
+		ipa_stat.tx_ch_stats.copy_engine_doorbell_value,
+		ipa_stat.tx_ch_stats.num_db_fired,
+		ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull,
+		ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
+		ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
+		ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
+		ipa_stat.tx_ch_stats.bam_stats.bamFifoFull,
+		ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty,
+		ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh,
+		ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow,
+		ipa_stat.tx_ch_stats.num_db,
+		ipa_stat.tx_ch_stats.num_unexpected_db,
+		ipa_stat.tx_ch_stats.num_bam_int_handled,
+		ipa_stat.tx_ch_stats.num_qmb_int_handled);
+
+	ipa_info("\n==== IPA WDI RX STATS ====\n"
+		"MAX OST PKT : %d\n"
+		"NUM PKT PRCSD : %d\n"
+		"RNG RP : 0x%x\n"
+		"IND RNG FULL : %d\n"
+		"IND RNG EMPT : %d\n"
+		"IND RNG USE HGH : %d\n"
+		"IND RNG USE LOW : %d\n"
+		"BAM FIFO FULL : %d\n"
+		"BAM FIFO EMPT : %d\n"
+		"BAM FIFO USE HGH : %d\n"
+		"BAM FIFO USE LOW : %d\n"
+		"NUM DB : %d\n"
+		"NUM UNEXP DB : %d\n"
+		"NUM BAM INT HNDL : 0x%x\n",
+		ipa_stat.rx_ch_stats.max_outstanding_pkts,
+		ipa_stat.rx_ch_stats.num_pkts_processed,
+		ipa_stat.rx_ch_stats.rx_ring_rp_value,
+		ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull,
+		ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
+		ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
+		ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
+		ipa_stat.rx_ch_stats.bam_stats.bamFifoFull,
+		ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty,
+		ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh,
+		ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow,
+		ipa_stat.rx_ch_stats.num_db,
+		ipa_stat.rx_ch_stats.num_unexpected_db,
+		ipa_stat.rx_ch_stats.num_bam_int_handled);
+}
+
+void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx)
+{
+	wlan_ipa_print_session_info(ipa_ctx);
+}
+
+void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx)
+{
+	/* IPA IPA TX/RX stats */
+	wlan_ipa_print_txrx_stats(ipa_ctx);
+	/* IPA WDI stats */
+	wlan_ipa_print_ipa_wdi_stats(ipa_ctx);
+	/* WLAN FW WDI stats */
+	wlan_ipa_uc_stat_request(ipa_ctx, WLAN_IPA_UC_STAT_REASON_DEBUG);
+}
+
+#ifdef FEATURE_METERING
+/**
+ * wlan_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
+ * @ipa_ctx: IPA context
+ * @reset_stats: reset stat countis after response
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_sharing_stats_request(struct wlan_ipa_priv *ipa_ctx,
+					      uint8_t reset_stats)
+{
+	qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+	if (false == ipa_ctx->resource_loading) {
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+		cdp_ipa_uc_get_share_stats(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
+					   reset_stats);
+	} else {
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	}
+}
+
+/**
+ * wlan_ipa_uc_set_quota() - Set quota limit bytes from IPA.
+ * @ipa_ctx: IPA context
+ * @set_quota: when 1, FW starts quota monitoring
+ * @quota_bytes: quota limit in bytes
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_set_quota(struct wlan_ipa_priv *ipa_ctx,
+				  uint8_t set_quota,
+				  uint64_t quota_bytes)
+{
+	ipa_info("SET_QUOTA: set_quota=%d, quota_bytes=%llu",
+		 set_quota, quota_bytes);
+
+	qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+	if (false == ipa_ctx->resource_loading) {
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else {
+		cdp_ipa_uc_set_quota(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
+				     quota_bytes);
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	}
+}
+
+QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
+				   struct op_msg_type *op_msg)
+{
+	struct op_msg_type *msg = op_msg;
+	struct ipa_uc_sharing_stats *uc_sharing_stats;
+	struct ipa_uc_quota_rsp *uc_quota_rsp;
+	struct ipa_uc_quota_ind *uc_quota_ind;
+	struct wlan_ipa_iface_context *iface_ctx;
+
+	if (msg->op_code == WLAN_IPA_UC_OPCODE_SHARING_STATS) {
+		/* fill-up ipa_uc_sharing_stats structure from FW */
+		uc_sharing_stats = (struct ipa_uc_sharing_stats *)
+			     ((uint8_t *)op_msg + sizeof(struct op_msg_type));
+
+		memcpy(&(ipa_ctx->ipa_sharing_stats), uc_sharing_stats,
+		       sizeof(struct ipa_uc_sharing_stats));
+
+		qdf_event_set(&ipa_ctx->ipa_uc_sharing_stats_comp);
+	} else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_RSP) {
+		/* received set quota response */
+		uc_quota_rsp = (struct ipa_uc_quota_rsp *)
+			     ((uint8_t *)op_msg + sizeof(struct op_msg_type));
+
+		memcpy(&(ipa_ctx->ipa_quota_rsp), uc_quota_rsp,
+			   sizeof(struct ipa_uc_quota_rsp));
+
+		qdf_event_set(&ipa_ctx->ipa_uc_set_quota_comp);
+	} else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_IND) {
+		/* hit quota limit */
+		uc_quota_ind = (struct ipa_uc_quota_ind *)
+			     ((uint8_t *)op_msg + sizeof(struct op_msg_type));
+
+		ipa_ctx->ipa_quota_ind.quota_bytes =
+					uc_quota_ind->quota_bytes;
+
+		/* send quota exceeded indication to IPA */
+		iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
+		if (iface_ctx)
+			qdf_ipa_broadcast_wdi_quota_reach_ind(
+						iface_ctx->dev->ifindex,
+						uc_quota_ind->quota_bytes);
+		else
+			ipa_err("Failed quota_reach_ind: NULL interface");
+	} else {
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
+ * IPA calls to get WLAN stats or set quota limit.
+ * @priv: pointer to private data registered with IPA (we register a
+ *	  pointer to the IPA context)
+ * @evt: the IPA event which triggered the callback
+ * @data: data associated with the event
+ *
+ * Return: None
+ */
+void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+				    void *data)
+{
+	struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context();
+	struct wlan_ipa_iface_context *iface_ctx;
+	qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats;
+	qdf_ipa_set_wifi_quota_t *ipa_set_quota;
+	QDF_STATUS status;
+
+	ipa_info("event=%d", evt);
+
+	iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
+	if (!iface_ctx) {
+		ipa_err("IPA uC share stats failed - no iface");
+		QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) =
+			0;
+		return;
+	}
+
+	switch (evt) {
+	case IPA_GET_WDI_SAP_STATS:
+		/* fill-up ipa_get_wdi_sap_stats structure after getting
+		 * ipa_uc_fw_stats from FW
+		 */
+		wdi_sap_stats = data;
+
+		qdf_event_reset(&ipa_ctx->ipa_uc_sharing_stats_comp);
+		wlan_ipa_uc_sharing_stats_request(ipa_ctx,
+			QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats));
+		status = qdf_wait_for_event_completion(
+			&ipa_ctx->ipa_uc_sharing_stats_comp,
+			msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME));
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			ipa_err("IPA uC share stats request timed out");
+			QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
+				= 0;
+		} else {
+			QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats)
+				= 1;
+
+			QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv4_rx_packets;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv4_rx_bytes;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv6_rx_packets;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv6_rx_bytes;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv4_tx_packets;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv4_tx_bytes;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv6_tx_packets;
+			QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats)
+				= ipa_ctx->ipa_sharing_stats.ipv6_tx_bytes;
+		}
+		break;
+
+	case IPA_SET_WIFI_QUOTA:
+		/* get ipa_set_wifi_quota structure from IPA and pass to FW
+		 * through quota_exceeded field in ipa_uc_fw_stats
+		 */
+		ipa_set_quota = data;
+
+		qdf_event_reset(&ipa_ctx->ipa_uc_set_quota_comp);
+		wlan_ipa_uc_set_quota(ipa_ctx, ipa_set_quota->set_quota,
+				      ipa_set_quota->quota_bytes);
+
+		status = qdf_wait_for_event_completion(
+				&ipa_ctx->ipa_uc_set_quota_comp,
+				msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME));
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			ipa_err("IPA uC set quota request timed out");
+			QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota)	= 0;
+		} else {
+			QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) =
+				((uint64_t)(ipa_ctx->ipa_quota_rsp.quota_hi)
+				  <<32)|ipa_ctx->ipa_quota_rsp.quota_lo;
+			QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota)	=
+				ipa_ctx->ipa_quota_rsp.success;
+		}
+		break;
+	}
+}
+#endif /* FEATURE_METERING */
diff --git a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
index f33f7a3..28b4e80 100644
--- a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
+++ b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
@@ -60,6 +60,7 @@
 /**
  * ucfg_ipa_set_txrx_handle() - register pdev txrx handler
  * @psoc: psoc handle
+ * @psoc: psoc obj
  * @txrx_handle: data path pdev txrx handle
  *
  * Return: None
@@ -69,7 +70,7 @@
 
 /**
  * ucfg_ipa_set_perf_level() - Set IPA perf level
- * @pdev: Pdev obj handle
+ * @pdev: pdev obj
  * @tx_packets: Number of packets transmitted in the last sample period
  * @rx_packets: Number of packets received in the last sample period
  *
@@ -78,6 +79,60 @@
 QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev,
 				   uint64_t tx_packets, uint64_t rx_packets);
 
+/**
+ * ucfg_ipa_uc_info() - Print IPA uC resource and session information
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ucfg_ipa_uc_stat() - Print IPA uC stats
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev);
+
+
+/**
+ * ucfg_ipa_uc_rt_debug_host_dump() - IPA rt debug host dump
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ucfg_ipa_dump_info() - Dump IPA context information
+ * @pdev: pdev obj
+ *
+ * Return: None
+ */
+void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ucfg_ipa_uc_stat_request() - Get IPA stats from IPA.
+ * @pdev: pdev obj
+ * @reason: STAT REQ Reason
+ *
+ * Return: None
+ */
+void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev,
+			      uint8_t reason);
+
+/**
+ * ucfg_ipa_uc_stat_query() - Query the IPA stats
+ * @pdev: pdev obj
+ * @ipa_tx_diff: tx packet count diff from previous tx packet count
+ * @ipa_rx_diff: rx packet count diff from previous rx packet count
+ *
+ * Return: None
+ */
+void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev,
+			    uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff);
+
 #else
 
 static inline bool ucfg_ipa_is_present(void)
@@ -109,5 +164,37 @@
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline
+void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev)
+{
+}
+
+static inline
+void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev)
+{
+}
+
+static inline
+void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev)
+{
+}
+
+static inline
+void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev)
+{
+}
+
+static inline
+void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev,
+			      uint8_t reason)
+{
+}
+
+static inline
+void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev,
+			    uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
+{
+}
 #endif /* IPA_OFFLOAD */
 #endif /* _WLAN_IPA_UCFG_API_H_ */
diff --git a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
index 45ab2c4..5f419a5 100644
--- a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
+++ b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
@@ -49,3 +49,35 @@
 {
 	return ipa_rm_set_perf_level(pdev, tx_packets, rx_packets);
 }
+
+void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev)
+{
+	return ipa_uc_info(pdev);
+}
+
+void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev)
+{
+	return ipa_uc_stat(pdev);
+}
+
+void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev)
+{
+	return ipa_uc_rt_debug_host_dump(pdev);
+}
+
+void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev)
+{
+	return ipa_dump_info(pdev);
+}
+
+void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev,
+			      uint8_t reason)
+{
+	return ipa_uc_stat_request(pdev, reason);
+}
+
+void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev,
+			    uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff)
+{
+	return ipa_uc_stat_query(pdev, ipa_tx_diff, ipa_rx_diff);
+}
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index a805bee..04f7f0e 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -92,6 +92,7 @@
 #include <wlan_green_ap_ucfg_api.h>
 #include "sme_api.h"
 #include "wlan_hdd_regulatory.h"
+#include <wlan_ipa_ucfg_api.h>
 
 #define    IS_UP(_dev) \
 	(((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
@@ -3904,16 +3905,16 @@
 		/* If input value is non-zero get stats */
 		switch (set_value) {
 		case 1:
-			hdd_ipa_uc_stat(adapter);
+			ucfg_ipa_uc_stat(hdd_ctx->hdd_pdev);
 			break;
 		case 2:
-			hdd_ipa_uc_info(hdd_ctx);
+			ucfg_ipa_uc_info(hdd_ctx->hdd_pdev);
 			break;
 		case 3:
-			hdd_ipa_uc_rt_debug_host_dump(hdd_ctx);
+			ucfg_ipa_uc_rt_debug_host_dump(hdd_ctx->hdd_pdev);
 			break;
 		case 4:
-			hdd_ipa_dump_info(hdd_ctx);
+			ucfg_ipa_dump_info(hdd_ctx->hdd_pdev);
 			break;
 		default:
 			/* place holder for stats clean up
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index f01fedb..b50dfe0 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -7222,7 +7222,8 @@
 	tx_packets += fwd_tx_packets_diff;
 	rx_packets += fwd_rx_packets_diff;
 
-	hdd_ipa_uc_stat_query(hdd_ctx, &ipa_tx_packets, &ipa_rx_packets);
+	ucfg_ipa_uc_stat_query(hdd_ctx->hdd_pdev, &ipa_tx_packets,
+			       &ipa_rx_packets);
 	tx_packets += (uint64_t)ipa_tx_packets;
 	rx_packets += (uint64_t)ipa_rx_packets;
 
@@ -7239,7 +7240,7 @@
 	hdd_pld_request_bus_bandwidth(hdd_ctx, tx_packets, rx_packets);
 
 	ucfg_ipa_set_perf_level(hdd_ctx->hdd_pdev, tx_packets, rx_packets);
-	hdd_ipa_uc_stat_request(adapter, 2);
+	ucfg_ipa_uc_stat_request(hdd_ctx->hdd_pdev, 2);
 
 restart_timer:
 	/* ensure periodic timer should still be running before restarting it */