qcacld-3.0: Support stats quota for sta + sap ipa offload

Implement metering stats quota to support ipa offload sta plus
sap wifi sharing use cases.

Change-Id: Ic9d5ad817ffb4d671a43f3f3aebb2d8cce293873
CRs-Fixed: 2517696
diff --git a/Kbuild b/Kbuild
index e4d0596..237d8a8 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2965,6 +2965,8 @@
 ccflags-$(CONFIG_FOURTH_CONNECTION) += -DFEATURE_FOURTH_CONNECTION
 ccflags-$(CONFIG_WMI_SEND_RECV_QMI) += -DWLAN_FEATURE_WMI_SEND_RECV_QMI
 
+cppflags-$(CONFIG_WDI3_STATS_UPDATE) += -DWDI3_STATS_UPDATE
+
 KBUILD_CPPFLAGS += $(cppflags-y)
 
 # Currently, for versions of gcc which support it, the kernel Makefile
diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h
index 9543783..825ba55 100644
--- a/components/ipa/core/inc/wlan_ipa_core.h
+++ b/components/ipa/core/inc/wlan_ipa_core.h
@@ -326,6 +326,7 @@
 
 #ifdef FEATURE_METERING
 
+#ifndef WDI3_STATS_UPDATE
 /**
  * wlan_ipa_uc_op_metering() - IPA uC operation for stats and quota limit
  * @ipa_ctx: IPA context
@@ -334,7 +335,15 @@
  * Return: QDF_STATUS enumeration
  */
 QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
-				  struct op_msg_type *op_msg);
+				   struct op_msg_type *op_msg);
+#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;
+}
+#endif
 
 /**
  * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
@@ -356,6 +365,25 @@
  * Return: QDF_STATUS enumeration
  */
 void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx);
+
+#ifdef WDI3_STATS_UPDATE
+/**
+ * wlan_ipa_update_tx_stats() - send embedded tx traffic in bytes to IPA
+ * @ipa_ctx: IPA context
+ * @sta_tx: tx in bytes on sta interface
+ * @sap_tx: tx in bytes on sap interface
+ *
+ * Return: void
+ */
+void wlan_ipa_update_tx_stats(struct wlan_ipa_priv *ipa_ctx, uint64_t sta_tx,
+			      uint64_t sap_tx);
+#else
+static inline void wlan_ipa_update_tx_stats(struct wlan_ipa_priv *ipa_ctx,
+					    uint64_t sta_tx, uint64_t sap_tx)
+{
+}
+#endif /* WDI3_STATS_UPDATE */
+
 #else
 
 static inline
@@ -372,6 +400,11 @@
 static inline void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx)
 {
 }
+
+static inline void wlan_ipa_update_tx_stats(struct wlan_ipa_priv *ipa_ctx,
+					    uint64_t sta_tx, uint64_t sap_tx)
+{
+}
 #endif /* FEATURE_METERING */
 
 /**
diff --git a/components/ipa/core/inc/wlan_ipa_main.h b/components/ipa/core/inc/wlan_ipa_main.h
index 7fe4a32..e719001 100644
--- a/components/ipa/core/inc/wlan_ipa_main.h
+++ b/components/ipa/core/inc/wlan_ipa_main.h
@@ -441,9 +441,15 @@
  *
  * Return: IPA config tx buffer count
  */
-
 uint32_t ipa_get_tx_buf_count(void);
 
+/**
+ * ipa_update_tx_stats() - Update embedded tx traffic in bytes to IPA
+ *
+ * Return: IPA config tx buffer count
+ */
+void ipa_update_tx_stats(struct wlan_objmgr_pdev *pdev, uint64_t sta_tx,
+			 uint64_t ap_tx);
 #else /* Not IPA_OFFLOAD */
 typedef QDF_STATUS (*wlan_ipa_softap_xmit)(qdf_nbuf_t nbuf, qdf_netdev_t dev);
 typedef void (*wlan_ipa_send_to_nw)(qdf_nbuf_t nbuf, qdf_netdev_t dev);
diff --git a/components/ipa/core/inc/wlan_ipa_priv.h b/components/ipa/core/inc/wlan_ipa_priv.h
index 18b5cea..cf5cb05 100644
--- a/components/ipa/core/inc/wlan_ipa_priv.h
+++ b/components/ipa/core/inc/wlan_ipa_priv.h
@@ -664,6 +664,7 @@
 
 	uint32_t wdi_version;
 	bool is_smmu_enabled;	/* IPA caps returned from ipa_wdi_init */
+	qdf_atomic_t stats_quota;
 };
 
 #define WLAN_IPA_WLAN_FRAG_HEADER        sizeof(struct frag_header)
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
index a558ae5..bb96705 100644
--- a/components/ipa/core/src/wlan_ipa_core.c
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -1952,6 +1952,7 @@
 				SIR_STA_RX_DATA_OFFLOAD, session_id,
 				true);
 			qdf_mutex_acquire(&ipa_ctx->event_lock);
+			qdf_atomic_set(&ipa_ctx->stats_quota, 1);
 		}
 
 		if (!wlan_ipa_is_sta_only_offload_enabled()) {
@@ -2075,6 +2076,7 @@
 		if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
 		    (ipa_ctx->sap_num_connected_sta > 0 ||
 		     wlan_ipa_is_sta_only_offload_enabled())) {
+			qdf_atomic_set(&ipa_ctx->stats_quota, 0);
 			qdf_mutex_release(&ipa_ctx->event_lock);
 			wlan_ipa_uc_offload_enable_disable(ipa_ctx,
 				SIR_STA_RX_DATA_OFFLOAD, session_id, false);
@@ -2178,6 +2180,7 @@
 							SIR_STA_RX_DATA_OFFLOAD,
 							sta_session_id, true);
 				qdf_mutex_acquire(&ipa_ctx->event_lock);
+				qdf_atomic_set(&ipa_ctx->stats_quota, 1);
 			}
 
 			/*
@@ -2195,6 +2198,8 @@
 					ipa_ctx->config) &&
 				    ipa_ctx->sta_connected &&
 				    !wlan_ipa_is_sta_only_offload_enabled()) {
+					qdf_atomic_set(&ipa_ctx->stats_quota,
+						       0);
 					qdf_mutex_release(&ipa_ctx->event_lock);
 					wlan_ipa_uc_offload_enable_disable(
 							ipa_ctx,
@@ -2304,6 +2309,7 @@
 			if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
 			    ipa_ctx->sta_connected &&
 			    !wlan_ipa_is_sta_only_offload_enabled()) {
+				qdf_atomic_set(&ipa_ctx->stats_quota, 0);
 				qdf_mutex_release(&ipa_ctx->event_lock);
 				wlan_ipa_uc_offload_enable_disable(ipa_ctx,
 							SIR_STA_RX_DATA_OFFLOAD,
diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c
index e8f4a7a..424062b 100644
--- a/components/ipa/core/src/wlan_ipa_main.c
+++ b/components/ipa/core/src/wlan_ipa_main.c
@@ -643,3 +643,20 @@
 {
 	return g_ipa_config ? g_ipa_config->txbuf_count : 0;
 }
+
+void ipa_update_tx_stats(struct wlan_objmgr_pdev *pdev, uint64_t sta_tx,
+			 uint64_t ap_tx)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!ipa_config_is_enabled())
+		return;
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	wlan_ipa_update_tx_stats(ipa_obj, sta_tx, ap_tx);
+}
diff --git a/components/ipa/core/src/wlan_ipa_stats.c b/components/ipa/core/src/wlan_ipa_stats.c
index 3e8fdee..c701bf2 100644
--- a/components/ipa/core/src/wlan_ipa_stats.c
+++ b/components/ipa/core/src/wlan_ipa_stats.c
@@ -748,6 +748,39 @@
 }
 
 #ifdef FEATURE_METERING
+
+#ifdef WDI3_STATS_UPDATE
+/**
+ * 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
+ */
+static void __wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
+					     void *data)
+{
+}
+
+void wlan_ipa_update_tx_stats(struct wlan_ipa_priv *ipa_ctx, uint64_t sta_tx,
+			      uint64_t ap_tx)
+{
+	qdf_ipa_wdi_tx_info_t tx_stats;
+
+	if (!qdf_atomic_read(&ipa_ctx->stats_quota))
+		return;
+
+	QDF_IPA_WDI_TX_INFO_STA_TX_BYTES(&tx_stats) = sta_tx;
+	QDF_IPA_WDI_TX_INFO_SAP_TX_BYTES(&tx_stats) = ap_tx;
+
+	qdf_ipa_wdi_wlan_stats(&tx_stats);
+}
+
+#else
+
 /**
  * wlan_ipa_uc_sharing_stats_request() - Get IPA stats from IPA.
  * @ipa_ctx: IPA context
@@ -793,56 +826,6 @@
 	}
 }
 
-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.
@@ -940,6 +923,60 @@
 	}
 }
 
+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;
+	uint32_t ifindex;
+	uint64_t quota_bytes;
+
+	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);
+		ifindex = iface_ctx->dev->ifindex;
+		quota_bytes = uc_quota_ind->quota_bytes;
+		if (iface_ctx)
+			qdf_ipa_broadcast_wdi_quota_reach_ind(ifindex,
+							      quota_bytes);
+		else
+			ipa_err("Failed quota_reach_ind: NULL interface");
+	} else {
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WDI3_STATS_UPDATE */
+
 /**
  * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
  * __wlan_ipa_wdi_meter_notifier_cb
@@ -962,5 +999,4 @@
 
 	qdf_op_unprotect(op_sync);
 }
-
 #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 4f34907..c0cdc5e 100644
--- a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
+++ b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h
@@ -355,6 +355,17 @@
  */
 uint32_t ucfg_ipa_get_tx_buf_count(void);
 
+/**
+ * ucfg_ipa_update_tx_stats() - send embedded tx traffic in bytes to IPA
+ * @pdev: pdev obj
+ * @sta_tx: tx in bytes on sta vdev
+ * @ap_tx: tx in bytes on sap vdev
+ *
+ * Return: void
+ */
+void ucfg_ipa_update_tx_stats(struct wlan_objmgr_pdev *pdev, uint64_t sta_tx,
+			      uint64_t ap_tx);
+
 #else
 
 static inline bool ucfg_ipa_is_present(void)
@@ -559,5 +570,11 @@
 {
 	return 0;
 }
+
+static inline
+void ucfg_ipa_update_tx_stats(struct wlan_objmgr_pdev *pdev, uint64_t sta_tx,
+			      uint64_t ap_tx)
+{
+}
 #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 b1fedfa..aa65a52 100644
--- a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
+++ b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c
@@ -211,3 +211,9 @@
 {
 	return ipa_get_tx_buf_count();
 }
+
+void ucfg_ipa_update_tx_stats(struct wlan_objmgr_pdev *pdev, uint64_t sta_tx,
+			      uint64_t ap_tx)
+{
+	ipa_update_tx_stats(pdev, sta_tx, ap_tx);
+}
diff --git a/configs/default_defconfig b/configs/default_defconfig
index 3772246..ee791e1 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -198,6 +198,11 @@
 CONFIG_QCACLD_FEATURE_METERING := y
 endif
 
+ifeq ($(CONFIG_ARCH_KONA), y)
+CONFIG_QCACLD_FEATURE_METERING := y
+CONFIG_WDI3_STATS_UPDATE := y
+endif
+
 #Flag to enable Fast Transition (11r) feature
 CONFIG_QCOM_VOWIFI_11R := y
 
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index c6136a3..3b9ef3e 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -8552,6 +8552,7 @@
 	A_STATUS ret;
 	bool connected = false;
 	uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0;
+	uint64_t sta_tx_bytes, sap_tx_bytes;
 
 	if (wlan_hdd_validate_context(hdd_ctx))
 		goto stop_work;
@@ -8606,8 +8607,13 @@
 			}
 		}
 
-		if (adapter->device_mode == QDF_SAP_MODE)
+		if (adapter->device_mode == QDF_SAP_MODE) {
 			con_sap_adapter = adapter;
+			sap_tx_bytes = adapter->stats.tx_bytes;
+		}
+
+		if (adapter->device_mode == QDF_STA_MODE)
+			sta_tx_bytes = adapter->stats.tx_bytes;
 
 		hdd_set_driver_del_ack_enable(adapter->vdev_id, hdd_ctx,
 					      rx_packets);
@@ -8633,9 +8639,12 @@
 	tx_packets += fwd_tx_packets_diff;
 	rx_packets += fwd_rx_packets_diff;
 
+	/* Send embedded Tx packet bytes on STA & SAP interface to IPA driver */
+	ucfg_ipa_update_tx_stats(hdd_ctx->pdev, sta_tx_bytes, sap_tx_bytes);
+
 	if (ucfg_ipa_is_fw_wdi_activated(hdd_ctx->pdev)) {
 		ucfg_ipa_uc_stat_query(hdd_ctx->pdev, &ipa_tx_packets,
-				       &ipa_rx_packets);
+				&ipa_rx_packets);
 		tx_packets += (uint64_t)ipa_tx_packets;
 		rx_packets += (uint64_t)ipa_rx_packets;