Browse Source

qcacld-3.0: Featurize Tx throttle feature

Featurize Tx throttle feature.

Change-Id: Ie97749367b8c4e7af7fe0bee68b15be5946fdd67
CRs-Fixed: 2257918
Nirav Shah 7 years ago
parent
commit
46fc6301ea
5 changed files with 337 additions and 290 deletions
  1. 4 0
      Kbuild
  2. 17 14
      core/dp/ol/inc/ol_txrx_ctrl_api.h
  3. 0 276
      core/dp/txrx/ol_tx_queue.c
  4. 8 0
      core/dp/txrx/ol_tx_queue.h
  5. 308 0
      core/dp/txrx/ol_tx_throttle.c

+ 4 - 0
Kbuild

@@ -898,6 +898,10 @@ else
 TXRX_OBJS +=     $(TXRX_DIR)/ol_tx_ll_legacy.o
 endif
 
+ifeq ($(CONFIG_QCA_SUPPORT_TX_THROTTLE), y)
+TXRX_OBJS +=     $(TXRX_DIR)/ol_tx_throttle.o
+endif
+
 ifeq ($(CONFIG_LITHIUM), y)
 ############ DP 3.0 ############
 DP_INC := -I$(WLAN_COMMON_ROOT)/dp/inc \

+ 17 - 14
core/dp/ol/inc/ol_txrx_ctrl_api.h

@@ -154,6 +154,22 @@ void ol_txrx_tx_release(ol_txrx_peer_handle peer,
 			u_int32_t tid_mask,
 			int max_frms);
 
+#else
+static inline void
+ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid)
+{
+}
+
+static inline void
+ol_txrx_tx_release(ol_txrx_peer_handle peer,
+		   u_int32_t tid_mask,
+		   int max_frms)
+{
+}
+
+#endif /* CONFIG_HL_SUPPORT */
+
+#ifdef QCA_SUPPORT_TX_THROTTLE
 /**
  * @brief Suspend all tx data per thermal event/timer for the
  *  specified physical device
@@ -174,19 +190,7 @@ ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev);
  */
 void
 ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev);
-
 #else
-static inline void
-ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid)
-{
-}
-
-static inline void
-ol_txrx_tx_release(ol_txrx_peer_handle peer,
-		   u_int32_t tid_mask,
-		   int max_frms)
-{
-}
 
 static inline void
 ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev)
@@ -197,8 +201,7 @@ static inline void
 ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev)
 {
 }
-
-#endif /* CONFIG_HL_SUPPORT */
+#endif
 
 /**
  * @brief notify tx data SW that a peer's transmissions are suspended.

+ 0 - 276
core/dp/txrx/ol_tx_queue.c

@@ -537,40 +537,6 @@ ol_txrx_peer_tid_unpause(ol_txrx_peer_handle peer, int tid)
 	TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__);
 }
 
-void
-ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev)
-{
-#if defined(QCA_SUPPORT_TX_THROTTLE)
-	qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
-
-	if (pdev->tx_throttle.is_paused == true) {
-		qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
-		return;
-	}
-
-	pdev->tx_throttle.is_paused = true;
-	qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
-#endif
-	ol_txrx_pdev_pause(pdev, 0);
-}
-
-void
-ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev)
-{
-#if defined(QCA_SUPPORT_TX_THROTTLE)
-	qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
-
-	if (pdev->tx_throttle.is_paused == false) {
-		qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
-		return;
-	}
-
-	pdev->tx_throttle.is_paused = false;
-	qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
-#endif
-	ol_txrx_pdev_unpause(pdev, 0);
-}
-
 void
 ol_txrx_vdev_pause(struct cdp_vdev *pvdev, uint32_t reason)
 {
@@ -1735,248 +1701,6 @@ void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason)
 }
 #endif
 
-/*--- LL tx throttle queue code --------------------------------------------*/
-#if defined(QCA_SUPPORT_TX_THROTTLE)
-#ifdef QCA_LL_TX_FLOW_CONTROL_V2
-/**
- * ol_txrx_thermal_pause() - pause due to thermal mitigation
- * @pdev: pdev handle
- *
- * Return: none
- */
-static inline
-void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
-{
-	ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
-}
-/**
- * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
- * @pdev: pdev handle
- *
- * Return: none
- */
-static inline
-void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
-{
-	ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
-}
-#else
-/**
- * ol_txrx_thermal_pause() - pause due to thermal mitigation
- * @pdev: pdev handle
- *
- * Return: none
- */
-static inline
-void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
-{
-}
-
-/**
- * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
- * @pdev: pdev handle
- *
- * Return: none
- */
-static inline
-void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
-{
-	ol_tx_pdev_ll_pause_queue_send_all(pdev);
-}
-#endif
-
-static void ol_tx_pdev_throttle_phase_timer(void *context)
-{
-	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
-	int ms;
-	enum throttle_level cur_level;
-	enum throttle_phase cur_phase;
-
-	/* update the phase */
-	pdev->tx_throttle.current_throttle_phase++;
-
-	if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX)
-		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
-
-	if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) {
-		/* Traffic is stopped */
-		ol_txrx_dbg(
-				   "throttle phase --> OFF\n");
-		ol_txrx_throttle_pause(pdev);
-		ol_txrx_thermal_pause(pdev);
-		cur_level = pdev->tx_throttle.current_throttle_level;
-		cur_phase = pdev->tx_throttle.current_throttle_phase;
-		ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
-		if (pdev->tx_throttle.current_throttle_level !=
-				THROTTLE_LEVEL_0) {
-			ol_txrx_dbg(
-					   "start timer %d ms\n", ms);
-			qdf_timer_start(&pdev->tx_throttle.
-							phase_timer, ms);
-		}
-	} else {
-		/* Traffic can go */
-		ol_txrx_dbg(
-					"throttle phase --> ON\n");
-		ol_txrx_throttle_unpause(pdev);
-		ol_txrx_thermal_unpause(pdev);
-		cur_level = pdev->tx_throttle.current_throttle_level;
-		cur_phase = pdev->tx_throttle.current_throttle_phase;
-		ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
-		if (pdev->tx_throttle.current_throttle_level !=
-		    THROTTLE_LEVEL_0) {
-			ol_txrx_dbg("start timer %d ms\n",
-				   ms);
-			qdf_timer_start(&pdev->tx_throttle.phase_timer,
-						ms);
-		}
-	}
-}
-
-#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
-static void ol_tx_pdev_throttle_tx_timer(void *context)
-{
-	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
-
-	ol_tx_pdev_ll_pause_queue_send_all(pdev);
-}
-#endif
-
-#ifdef CONFIG_HL_SUPPORT
-
-/**
- * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase
- *				     and time
- * @pdev: the peer device object
- * @level: throttle phase level
- * @ms: throttle time
- *
- * Return: None
- */
-static void
-ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
-{
-	qdf_timer_stop(&pdev->tx_throttle.phase_timer);
-
-	/* Set the phase */
-	if (level != THROTTLE_LEVEL_0) {
-		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
-		*ms = pdev->tx_throttle.throttle_time_ms[level]
-						[THROTTLE_PHASE_OFF];
-
-		/* pause all */
-		ol_txrx_throttle_pause(pdev);
-	} else {
-		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON;
-		*ms = pdev->tx_throttle.throttle_time_ms[level]
-						[THROTTLE_PHASE_ON];
-
-		/* unpause all */
-		ol_txrx_throttle_unpause(pdev);
-	}
-}
-#else
-
-static void
-ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
-{
-	/* Reset the phase */
-	pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
-
-	/* Start with the new time */
-	*ms = pdev->tx_throttle.
-		throttle_time_ms[level][THROTTLE_PHASE_OFF];
-
-	qdf_timer_stop(&pdev->tx_throttle.phase_timer);
-}
-#endif
-
-void ol_tx_throttle_set_level(struct cdp_pdev *ppdev, int level)
-{
-	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
-	int ms = 0;
-
-	if (level >= THROTTLE_LEVEL_MAX) {
-		ol_txrx_dbg(
-			   "%s invalid throttle level set %d, ignoring\n",
-			   __func__, level);
-		return;
-	}
-
-	ol_txrx_info("Setting throttle level %d\n", level);
-
-	/* Set the current throttle level */
-	pdev->tx_throttle.current_throttle_level = (enum throttle_level) level;
-
-	ol_tx_set_throttle_phase_time(pdev, level, &ms);
-
-	if (level != THROTTLE_LEVEL_0)
-		qdf_timer_start(&pdev->tx_throttle.phase_timer, ms);
-}
-
-void ol_tx_throttle_init_period(struct cdp_pdev *ppdev, int period,
-				uint8_t *dutycycle_level)
-{
-	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
-	int i;
-
-	/* Set the current throttle level */
-	pdev->tx_throttle.throttle_period_ms = period;
-
-	ol_txrx_dbg("level  OFF  ON\n");
-	for (i = 0; i < THROTTLE_LEVEL_MAX; i++) {
-		pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] =
-			pdev->tx_throttle.throttle_period_ms -
-				((dutycycle_level[i] *
-				  pdev->tx_throttle.throttle_period_ms)/100);
-		pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] =
-			pdev->tx_throttle.throttle_period_ms -
-			pdev->tx_throttle.throttle_time_ms[
-				i][THROTTLE_PHASE_ON];
-		ol_txrx_dbg("%d      %d    %d\n", i,
-			   pdev->tx_throttle.
-			   throttle_time_ms[i][THROTTLE_PHASE_OFF],
-			   pdev->tx_throttle.
-			   throttle_time_ms[i][THROTTLE_PHASE_ON]);
-	}
-
-}
-
-void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev)
-{
-	uint32_t throttle_period;
-	uint8_t dutycycle_level[THROTTLE_LEVEL_MAX];
-	int i;
-
-	pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0;
-	pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
-	qdf_spinlock_create(&pdev->tx_throttle.mutex);
-
-	throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev);
-
-	for (i = 0; i < THROTTLE_LEVEL_MAX; i++)
-		dutycycle_level[i] =
-			ol_cfg_throttle_duty_cycle_level(pdev->ctrl_pdev, i);
-
-	ol_tx_throttle_init_period((struct cdp_pdev *)pdev,
-			throttle_period, &dutycycle_level[0]);
-
-	qdf_timer_init(pdev->osdev,
-			       &pdev->tx_throttle.phase_timer,
-			       ol_tx_pdev_throttle_phase_timer, pdev,
-			       QDF_TIMER_TYPE_SW);
-
-#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
-	qdf_timer_init(pdev->osdev,
-			       &pdev->tx_throttle.tx_timer,
-			       ol_tx_pdev_throttle_tx_timer, pdev,
-			       QDF_TIMER_TYPE_SW);
-#endif
-
-	pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD;
-}
-#endif /* QCA_SUPPORT_TX_THROTTLE */
-
 #ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL
 
 /**

+ 8 - 0
core/dp/txrx/ol_tx_queue.h

@@ -445,6 +445,14 @@ void ol_tx_throttle_init_period(struct cdp_pdev *ppdev, int period,
 void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev);
 #else
 static inline void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) {}
+
+static inline void ol_tx_throttle_set_level(struct cdp_pdev *ppdev, int level)
+{}
+
+static inline void ol_tx_throttle_init_period(struct cdp_pdev *ppdev,
+					      int period,
+					      uint8_t *dutycycle_level)
+{}
 #endif
 
 #ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL

+ 308 - 0
core/dp/txrx/ol_tx_throttle.c

@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2012-2018 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
+ * 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 <qdf_nbuf.h>           /* qdf_nbuf_t, etc. */
+#include <qdf_atomic.h>         /* qdf_atomic_read, etc. */
+#include <ol_cfg.h>             /* ol_cfg_addba_retry */
+#include <htt.h>                /* HTT_TX_EXT_TID_MGMT */
+#include <ol_htt_tx_api.h>      /* htt_tx_desc_tid */
+#include <ol_txrx_api.h>        /* ol_txrx_vdev_handle */
+#include <ol_txrx_ctrl_api.h>   /* ol_txrx_sync, ol_tx_addba_conf */
+#include <cdp_txrx_tx_throttle.h>
+#include <ol_ctrl_txrx_api.h>   /* ol_ctrl_addba_req */
+#include <ol_txrx_internal.h>   /* TXRX_ASSERT1, etc. */
+#include <ol_tx_desc.h>         /* ol_tx_desc, ol_tx_desc_frame_list_free */
+#include <ol_tx.h>              /* ol_tx_vdev_ll_pause_queue_send */
+#include <ol_tx_sched.h>	/* ol_tx_sched_notify, etc. */
+#include <ol_tx_queue.h>
+#include <ol_txrx.h>          /* ol_tx_desc_pool_size_hl */
+#include <ol_txrx_dbg.h>        /* ENABLE_TX_QUEUE_LOG */
+#include <qdf_types.h>          /* bool */
+#include "cdp_txrx_flow_ctrl_legacy.h"
+#include <ol_txrx_peer_find.h>
+#include <cdp_txrx_handle.h>
+
+#ifdef QCA_LL_TX_FLOW_CONTROL_V2
+/**
+ * ol_txrx_thermal_pause() - pause due to thermal mitigation
+ * @pdev: pdev handle
+ *
+ * Return: none
+ */
+static inline
+void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
+{
+	ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
+}
+
+/**
+ * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
+ * @pdev: pdev handle
+ *
+ * Return: none
+ */
+static inline
+void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
+{
+	ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
+}
+#else
+/**
+ * ol_txrx_thermal_pause() - pause due to thermal mitigation
+ * @pdev: pdev handle
+ *
+ * Return: none
+ */
+static inline
+void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
+{
+}
+
+/**
+ * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
+ * @pdev: pdev handle
+ *
+ * Return: none
+ */
+static inline
+void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
+{
+	ol_tx_pdev_ll_pause_queue_send_all(pdev);
+}
+#endif
+
+static void ol_tx_pdev_throttle_phase_timer(void *context)
+{
+	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
+	int ms;
+	enum throttle_level cur_level;
+	enum throttle_phase cur_phase;
+
+	/* update the phase */
+	pdev->tx_throttle.current_throttle_phase++;
+
+	if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX)
+		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
+
+	if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) {
+		/* Traffic is stopped */
+		ol_txrx_dbg(
+				   "throttle phase --> OFF\n");
+		ol_txrx_throttle_pause(pdev);
+		ol_txrx_thermal_pause(pdev);
+		cur_level = pdev->tx_throttle.current_throttle_level;
+		cur_phase = pdev->tx_throttle.current_throttle_phase;
+		ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
+		if (pdev->tx_throttle.current_throttle_level !=
+				THROTTLE_LEVEL_0) {
+			ol_txrx_dbg(
+					   "start timer %d ms\n", ms);
+			qdf_timer_start(&pdev->tx_throttle.
+							phase_timer, ms);
+		}
+	} else {
+		/* Traffic can go */
+		ol_txrx_dbg(
+					"throttle phase --> ON\n");
+		ol_txrx_throttle_unpause(pdev);
+		ol_txrx_thermal_unpause(pdev);
+		cur_level = pdev->tx_throttle.current_throttle_level;
+		cur_phase = pdev->tx_throttle.current_throttle_phase;
+		ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
+		if (pdev->tx_throttle.current_throttle_level !=
+		    THROTTLE_LEVEL_0) {
+			ol_txrx_dbg("start timer %d ms\n", ms);
+			qdf_timer_start(&pdev->tx_throttle.phase_timer,	ms);
+		}
+	}
+}
+
+#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
+static void ol_tx_pdev_throttle_tx_timer(void *context)
+{
+	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
+
+	ol_tx_pdev_ll_pause_queue_send_all(pdev);
+}
+#endif
+
+#ifdef CONFIG_HL_SUPPORT
+
+/**
+ * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase
+ *				     and time
+ * @pdev: the peer device object
+ * @level: throttle phase level
+ * @ms: throttle time
+ *
+ * Return: None
+ */
+static void
+ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
+{
+	qdf_timer_stop(&pdev->tx_throttle.phase_timer);
+
+	/* Set the phase */
+	if (level != THROTTLE_LEVEL_0) {
+		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
+		*ms = pdev->tx_throttle.throttle_time_ms[level]
+						[THROTTLE_PHASE_OFF];
+
+		/* pause all */
+		ol_txrx_throttle_pause(pdev);
+	} else {
+		pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON;
+		*ms = pdev->tx_throttle.throttle_time_ms[level]
+						[THROTTLE_PHASE_ON];
+
+		/* unpause all */
+		ol_txrx_throttle_unpause(pdev);
+	}
+}
+#else
+
+static void
+ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
+{
+	/* Reset the phase */
+	pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
+
+	/* Start with the new time */
+	*ms = pdev->tx_throttle.
+		throttle_time_ms[level][THROTTLE_PHASE_OFF];
+
+	qdf_timer_stop(&pdev->tx_throttle.phase_timer);
+}
+#endif
+
+void ol_tx_throttle_set_level(struct cdp_pdev *ppdev, int level)
+{
+	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
+	int ms = 0;
+
+	if (level >= THROTTLE_LEVEL_MAX) {
+		ol_txrx_dbg(
+			   "%s invalid throttle level set %d, ignoring\n",
+			   __func__, level);
+		return;
+	}
+
+	ol_txrx_info("Setting throttle level %d\n", level);
+
+	/* Set the current throttle level */
+	pdev->tx_throttle.current_throttle_level = (enum throttle_level)level;
+
+	ol_tx_set_throttle_phase_time(pdev, level, &ms);
+
+	if (level != THROTTLE_LEVEL_0)
+		qdf_timer_start(&pdev->tx_throttle.phase_timer, ms);
+}
+
+void ol_tx_throttle_init_period(struct cdp_pdev *ppdev, int period,
+				uint8_t *dutycycle_level)
+{
+	struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev;
+	int i;
+
+	/* Set the current throttle level */
+	pdev->tx_throttle.throttle_period_ms = period;
+
+	ol_txrx_dbg("level  OFF  ON\n");
+	for (i = 0; i < THROTTLE_LEVEL_MAX; i++) {
+		pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] =
+			pdev->tx_throttle.throttle_period_ms -
+				((dutycycle_level[i] *
+				  pdev->tx_throttle.throttle_period_ms) / 100);
+		pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] =
+			pdev->tx_throttle.throttle_period_ms -
+			pdev->tx_throttle.throttle_time_ms[
+				i][THROTTLE_PHASE_ON];
+		ol_txrx_dbg("%d      %d    %d\n", i,
+			    pdev->tx_throttle.
+			    throttle_time_ms[i][THROTTLE_PHASE_OFF],
+			    pdev->tx_throttle.
+			    throttle_time_ms[i][THROTTLE_PHASE_ON]);
+	}
+}
+
+void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev)
+{
+	uint32_t throttle_period;
+	uint8_t dutycycle_level[THROTTLE_LEVEL_MAX];
+	int i;
+
+	pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0;
+	pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
+	qdf_spinlock_create(&pdev->tx_throttle.mutex);
+
+	throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev);
+
+	for (i = 0; i < THROTTLE_LEVEL_MAX; i++)
+		dutycycle_level[i] =
+			ol_cfg_throttle_duty_cycle_level(pdev->ctrl_pdev, i);
+
+	ol_tx_throttle_init_period((struct cdp_pdev *)pdev,
+				   throttle_period, &dutycycle_level[0]);
+
+	qdf_timer_init(pdev->osdev, &pdev->tx_throttle.phase_timer,
+		       ol_tx_pdev_throttle_phase_timer, pdev,
+		       QDF_TIMER_TYPE_SW);
+
+#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
+	qdf_timer_init(pdev->osdev, &pdev->tx_throttle.tx_timer,
+		       ol_tx_pdev_throttle_tx_timer, pdev, QDF_TIMER_TYPE_SW);
+#endif
+
+	pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD;
+}
+
+void
+ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev)
+{
+	qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
+
+	if (pdev->tx_throttle.is_paused) {
+		qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
+		return;
+	}
+
+	pdev->tx_throttle.is_paused = true;
+	qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
+	ol_txrx_pdev_pause(pdev, 0);
+}
+
+void
+ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev)
+{
+	qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
+
+	if (!pdev->tx_throttle.is_paused) {
+		qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
+		return;
+	}
+
+	pdev->tx_throttle.is_paused = false;
+	qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
+	ol_txrx_pdev_unpause(pdev, 0);
+}