diff --git a/Kbuild b/Kbuild index de909f12956d..bb36be87d85a 100644 --- a/Kbuild +++ b/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 \ diff --git a/core/dp/ol/inc/ol_txrx_ctrl_api.h b/core/dp/ol/inc/ol_txrx_ctrl_api.h index ab7519f17a4f..8d57d023f203 100644 --- a/core/dp/ol/inc/ol_txrx_ctrl_api.h +++ b/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. diff --git a/core/dp/txrx/ol_tx_queue.c b/core/dp/txrx/ol_tx_queue.c index dc8a36590d62..a46d845f7467 100644 --- a/core/dp/txrx/ol_tx_queue.c +++ b/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 /** diff --git a/core/dp/txrx/ol_tx_queue.h b/core/dp/txrx/ol_tx_queue.h index deb9b844794e..e021129dcfbe 100644 --- a/core/dp/txrx/ol_tx_queue.h +++ b/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 diff --git a/core/dp/txrx/ol_tx_throttle.c b/core/dp/txrx/ol_tx_throttle.c new file mode 100644 index 000000000000..486b2596edcb --- /dev/null +++ b/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_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* ol_cfg_addba_retry */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync, ol_tx_addba_conf */ +#include +#include /* ol_ctrl_addba_req */ +#include /* TXRX_ASSERT1, etc. */ +#include /* ol_tx_desc, ol_tx_desc_frame_list_free */ +#include /* ol_tx_vdev_ll_pause_queue_send */ +#include /* ol_tx_sched_notify, etc. */ +#include +#include /* ol_tx_desc_pool_size_hl */ +#include /* ENABLE_TX_QUEUE_LOG */ +#include /* bool */ +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include + +#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); +}