qcacld-3.0: Genoa: SDIO: Handle Tx Padding & Credits

In Genoa SDIO ADMA implementation Host sends packets to FW in
multiples of SDIO Block size.
If the packet/bundle is not block aligned Host adds padding at the
end of Packet/Bundle.

If the TX packet plus padding exceeds one FW TX Buffer, Padding data
will occupy the next FW TX buffer. Same applies for bundle TX packet.

For above scenario, HTC_FLAGS_PADDING_CHECK of HTC header Flags is used
to notify the FW that - Padding data follows the currentHTC packet

Since the padding data will take one extra FW Tx Buffer, host need to
handle the extra Tx credit being used by the padding data/buffer

CRs-Fixed: 2516619
Change-Id: Ie2d2292fabb30e1a13eebe4d11b57f452e42afa8
diff --git a/Kbuild b/Kbuild
index aa7fcb2..225b8c7 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2545,6 +2545,7 @@
 cppflags-$(CONFIG_DUP_RX_DESC_WAR) += -DDUP_RX_DESC_WAR
 cppflags-$(CONFIG_HTT_PADDR64) += -DHTT_PADDR64
 cppflags-$(CONFIG_WLAN_FEATURE_BMI) += -DWLAN_FEATURE_BMI
+cppflags-$(CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT) += -DQCA_TX_PADDING_CREDIT_SUPPORT
 cppflags-$(CONFIG_QCN7605_SUPPORT) += -DQCN7605_SUPPORT -DPLATFORM_GENOA
 cppflags-$(CONFIG_HIF_REG_WINDOW_SUPPORT) += -DHIF_REG_WINDOW_SUPPORT
 cppflags-$(CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY) += -DWLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY
diff --git a/configs/genoa.sdio.debug_defconfig b/configs/genoa.sdio.debug_defconfig
index 53e8d3b..99f9266 100644
--- a/configs/genoa.sdio.debug_defconfig
+++ b/configs/genoa.sdio.debug_defconfig
@@ -54,4 +54,5 @@
 CONFIG_TGT_NUM_MSDU_DESC := 0
 CONFIG_RX_PN_CHECK_OFFLOAD := y
 CONFIG_QCN7605_SUPPORT := y
+CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT := y
 ###################################
diff --git a/configs/genoa.sdio.perf_defconfig b/configs/genoa.sdio.perf_defconfig
index 7919f0f..f767051 100644
--- a/configs/genoa.sdio.perf_defconfig
+++ b/configs/genoa.sdio.perf_defconfig
@@ -59,4 +59,5 @@
 CONFIG_TGT_NUM_MSDU_DESC := 0
 CONFIG_RX_PN_CHECK_OFFLOAD := y
 CONFIG_QCN7605_SUPPORT := y
+CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT := y
 ###################################
diff --git a/core/dp/htt/htt.c b/core/dp/htt/htt.c
index 65b1da1..8481221 100644
--- a/core/dp/htt/htt.c
+++ b/core/dp/htt/htt.c
@@ -794,6 +794,8 @@
 	connect.EpCallbacks.EpTxCompleteMultiple = NULL;
 	connect.EpCallbacks.EpRecv = htt_t2h_msg_handler;
 	connect.EpCallbacks.ep_resume_tx_queue = htt_tx_resume_handler;
+	connect.EpCallbacks.ep_padding_credit_update =
+					htt_tx_padding_credit_update_handler;
 
 	/* rx buffers currently are provided by HIF, not by EpRecvRefill */
 	connect.EpCallbacks.EpRecvRefill = NULL;
diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h
index 9e39ae6..8a14792 100644
--- a/core/dp/htt/htt_internal.h
+++ b/core/dp/htt/htt_internal.h
@@ -582,6 +582,8 @@
 
 QDF_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev);
 
+int htt_tx_padding_credit_update_handler(void *context, int pad_credit);
+
 #if defined(HELIUMPLUS)
 QDF_STATUS
 htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev);
diff --git a/core/dp/htt/htt_tx.c b/core/dp/htt/htt_tx.c
index c7c5c2b..658a47f 100644
--- a/core/dp/htt/htt_tx.c
+++ b/core/dp/htt/htt_tx.c
@@ -865,8 +865,43 @@
 	return htt_tx_send_std(pdev, msdu, msdu_id);
 }
 
+#ifndef QCA_TX_PADDING_CREDIT_SUPPORT
+int htt_tx_padding_credit_update_handler(void *context, int pad_credit)
+{
+	return 1;
+}
+#endif
+
 #else                           /*ATH_11AC_TXCOMPACT */
 
+#ifdef QCA_TX_PADDING_CREDIT_SUPPORT
+static int htt_tx_padding_credit_update(htt_pdev_handle htt_pdev,
+					int pad_credit)
+{
+	int ret = 0;
+
+	if (pad_credit)
+		qdf_atomic_add(pad_credit,
+			       &htt_pdev->txrx_pdev->pad_reserve_tx_credit);
+
+	ret = qdf_atomic_read(&htt_pdev->txrx_pdev->pad_reserve_tx_credit);
+
+	return ret;
+}
+
+int htt_tx_padding_credit_update_handler(void *context, int pad_credit)
+{
+	struct htt_pdev_t *htt_pdev = (struct htt_pdev_t *)context;
+
+	return htt_tx_padding_credit_update(htt_pdev, pad_credit);
+}
+#else
+int htt_tx_padding_credit_update_handler(void *context, int pad_credit)
+{
+	return 1;
+}
+#endif
+
 #ifdef QCA_TX_HTT2_SUPPORT
 static inline HTC_ENDPOINT_ID
 htt_tx_htt2_get_ep_id(htt_pdev_handle pdev, qdf_nbuf_t msdu)
diff --git a/core/dp/txrx/ol_tx_sched.c b/core/dp/txrx/ol_tx_sched.c
index 733f931..ca3a9a7 100644
--- a/core/dp/txrx/ol_tx_sched.c
+++ b/core/dp/txrx/ol_tx_sched.c
@@ -1439,7 +1439,50 @@
 	TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__);
 }
 
-	void
+#ifdef QCA_TX_PADDING_CREDIT_SUPPORT
+static void replenish_tx_pad_credit(struct ol_txrx_pdev_t *pdev)
+{
+	int replenish_credit = 0, avail_targ_tx_credit = 0;
+	int cur_tx_pad_credit = 0, grp_credit = 0, i = 0;
+	qdf_atomic_t *tx_grp_credit = NULL;
+
+	cur_tx_pad_credit = qdf_atomic_read(&pdev->pad_reserve_tx_credit);
+	if (cur_tx_pad_credit < MIN_TX_PAD_CREDIT_THRESH) {
+		replenish_credit = MAX_TX_PAD_CREDIT_THRESH - cur_tx_pad_credit;
+		avail_targ_tx_credit = qdf_atomic_read(&pdev->target_tx_credit);
+		replenish_credit = (replenish_credit < avail_targ_tx_credit) ?
+				   replenish_credit : avail_targ_tx_credit;
+		if (replenish_credit < 0) {
+			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL,
+				  "Tx Pad Credits = %d Target Tx Credits = %d",
+				  cur_tx_pad_credit,
+				  avail_targ_tx_credit);
+			qdf_assert(0);
+		}
+		qdf_atomic_add(replenish_credit, &pdev->pad_reserve_tx_credit);
+		qdf_atomic_add(-replenish_credit, &pdev->target_tx_credit);
+
+		while (replenish_credit > 0) {
+			for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) {
+				tx_grp_credit = &pdev->txq_grps[i].credit;
+				grp_credit = qdf_atomic_read(tx_grp_credit);
+				if (grp_credit) {
+					qdf_atomic_add(-1, tx_grp_credit);
+					replenish_credit--;
+				}
+				if (!replenish_credit)
+					break;
+			}
+		}
+	}
+}
+#else
+static void replenish_tx_pad_credit(struct ol_txrx_pdev_t *pdev)
+{
+}
+#endif
+
+void
 ol_tx_sched(struct ol_txrx_pdev_t *pdev)
 {
 	struct ol_tx_sched_ctx sctx;
@@ -1458,6 +1501,7 @@
 	 *adf_os_print("BEFORE tx sched:\n");
 	 *ol_tx_queues_display(pdev);
 	 */
+	replenish_tx_pad_credit(pdev);
 	qdf_spin_unlock_bh(&pdev->tx_queue_spinlock);
 
 	TAILQ_INIT(&sctx.head);
@@ -1468,6 +1512,7 @@
 		int num_credits;
 
 		qdf_spin_lock_bh(&pdev->tx_queue_spinlock);
+		replenish_tx_pad_credit(pdev);
 		credit = qdf_atomic_read(&pdev->target_tx_credit);
 		num_credits = ol_tx_sched_select_batch(pdev, &sctx, credit);
 		if (num_credits > 0) {
diff --git a/core/dp/txrx/ol_tx_sched.h b/core/dp/txrx/ol_tx_sched.h
index 75b554e..d80123f 100644
--- a/core/dp/txrx/ol_tx_sched.h
+++ b/core/dp/txrx/ol_tx_sched.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2016-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -157,6 +157,14 @@
 {
 	ol_tx_target_credit_adjust(1, pdev, msdu);
 }
+
+#ifdef QCA_TX_PADDING_CREDIT_SUPPORT
+
+#define MIN_TX_PAD_CREDIT_THRESH        4
+#define MAX_TX_PAD_CREDIT_THRESH        5
+
+#endif /* QCA_TX_PADDING_CREDIT_SUPPORT */
+
 #else
 /*
  * LL does not need to keep track of target credit.
@@ -180,5 +188,6 @@
 					    qdf_nbuf_t msdu)
 {
 }
+
 #endif
 #endif /* _OL_TX_SCHED__H_ */
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index d308279..8be1eec 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -743,6 +743,8 @@
 	/* initialize the counter of the target's tx buffer availability */
 	qdf_atomic_init(&pdev->target_tx_credit);
 	qdf_atomic_init(&pdev->orig_target_tx_credit);
+	qdf_atomic_init(&pdev->pad_reserve_tx_credit);
+	qdf_atomic_add(1, &pdev->pad_reserve_tx_credit);
 
 	if (ol_cfg_is_high_latency(cfg_pdev)) {
 		qdf_spinlock_create(&pdev->tx_queue_spinlock);
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index baf4e69..454754a 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -687,6 +687,11 @@
 	qdf_atomic_t target_tx_credit;
 	qdf_atomic_t orig_target_tx_credit;
 
+	/*
+	 * needed for SDIO HL, Genoa Adma
+	 */
+	qdf_atomic_t pad_reserve_tx_credit;
+
 	struct {
 		uint16_t pool_size;
 		struct ol_txrx_fw_stats_desc_elem_t *pool;