1*5113495bSYour Name /*
2*5113495bSYour Name * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name *
5*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name * above copyright notice and this permission notice appear in all
8*5113495bSYour Name * copies.
9*5113495bSYour Name *
10*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name */
19*5113495bSYour Name
20*5113495bSYour Name /*
21*5113495bSYour Name * This file was originally distributed by Qualcomm Atheros, Inc.
22*5113495bSYour Name * under proprietary terms before Copyright ownership was assigned
23*5113495bSYour Name * to the Linux Foundation.
24*5113495bSYour Name */
25*5113495bSYour Name
26*5113495bSYour Name #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
27*5113495bSYour Name #include <qdf_atomic.h> /* qdf_atomic_read, etc. */
28*5113495bSYour Name #include <ol_cfg.h> /* ol_cfg_addba_retry */
29*5113495bSYour Name #include <htt.h> /* HTT_TX_EXT_TID_MGMT */
30*5113495bSYour Name #include <ol_htt_tx_api.h> /* htt_tx_desc_tid */
31*5113495bSYour Name #include <ol_txrx_api.h> /* ol_txrx_vdev_handle */
32*5113495bSYour Name #include <ol_txrx_ctrl_api.h> /* ol_txrx_sync, ol_tx_addba_conf */
33*5113495bSYour Name #include <cdp_txrx_tx_throttle.h>
34*5113495bSYour Name #include <ol_ctrl_txrx_api.h> /* ol_ctrl_addba_req */
35*5113495bSYour Name #include <ol_txrx_internal.h> /* TXRX_ASSERT1, etc. */
36*5113495bSYour Name #include <ol_tx_desc.h> /* ol_tx_desc, ol_tx_desc_frame_list_free */
37*5113495bSYour Name #include <ol_tx.h> /* ol_tx_vdev_ll_pause_queue_send */
38*5113495bSYour Name #include <ol_tx_sched.h> /* ol_tx_sched_notify, etc. */
39*5113495bSYour Name #include <ol_tx_queue.h>
40*5113495bSYour Name #include <ol_txrx.h> /* ol_tx_desc_pool_size_hl */
41*5113495bSYour Name #include <ol_txrx_dbg.h> /* ENABLE_TX_QUEUE_LOG */
42*5113495bSYour Name #include <qdf_types.h> /* bool */
43*5113495bSYour Name #include "cdp_txrx_flow_ctrl_legacy.h"
44*5113495bSYour Name #include <ol_txrx_peer_find.h>
45*5113495bSYour Name #include <cdp_txrx_handle.h>
46*5113495bSYour Name
47*5113495bSYour Name #ifdef QCA_LL_TX_FLOW_CONTROL_V2
48*5113495bSYour Name /**
49*5113495bSYour Name * ol_txrx_thermal_pause() - pause due to thermal mitigation
50*5113495bSYour Name * @pdev: pdev handle
51*5113495bSYour Name *
52*5113495bSYour Name * Return: none
53*5113495bSYour Name */
54*5113495bSYour Name static inline
ol_txrx_thermal_pause(struct ol_txrx_pdev_t * pdev)55*5113495bSYour Name void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
56*5113495bSYour Name {
57*5113495bSYour Name ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
58*5113495bSYour Name }
59*5113495bSYour Name
60*5113495bSYour Name /**
61*5113495bSYour Name * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
62*5113495bSYour Name * @pdev: pdev handle
63*5113495bSYour Name *
64*5113495bSYour Name * Return: none
65*5113495bSYour Name */
66*5113495bSYour Name static inline
ol_txrx_thermal_unpause(struct ol_txrx_pdev_t * pdev)67*5113495bSYour Name void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
68*5113495bSYour Name {
69*5113495bSYour Name ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION);
70*5113495bSYour Name }
71*5113495bSYour Name #else
72*5113495bSYour Name /**
73*5113495bSYour Name * ol_txrx_thermal_pause() - pause due to thermal mitigation
74*5113495bSYour Name * @pdev: pdev handle
75*5113495bSYour Name *
76*5113495bSYour Name * Return: none
77*5113495bSYour Name */
78*5113495bSYour Name static inline
ol_txrx_thermal_pause(struct ol_txrx_pdev_t * pdev)79*5113495bSYour Name void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev)
80*5113495bSYour Name {
81*5113495bSYour Name }
82*5113495bSYour Name
83*5113495bSYour Name /**
84*5113495bSYour Name * ol_txrx_thermal_unpause() - unpause due to thermal mitigation
85*5113495bSYour Name * @pdev: pdev handle
86*5113495bSYour Name *
87*5113495bSYour Name * Return: none
88*5113495bSYour Name */
89*5113495bSYour Name static inline
ol_txrx_thermal_unpause(struct ol_txrx_pdev_t * pdev)90*5113495bSYour Name void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev)
91*5113495bSYour Name {
92*5113495bSYour Name ol_tx_pdev_ll_pause_queue_send_all(pdev);
93*5113495bSYour Name }
94*5113495bSYour Name #endif
95*5113495bSYour Name
ol_tx_pdev_throttle_phase_timer(void * context)96*5113495bSYour Name static void ol_tx_pdev_throttle_phase_timer(void *context)
97*5113495bSYour Name {
98*5113495bSYour Name struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
99*5113495bSYour Name int ms;
100*5113495bSYour Name enum throttle_level cur_level;
101*5113495bSYour Name enum throttle_phase cur_phase;
102*5113495bSYour Name
103*5113495bSYour Name /* update the phase */
104*5113495bSYour Name pdev->tx_throttle.current_throttle_phase++;
105*5113495bSYour Name
106*5113495bSYour Name if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX)
107*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
108*5113495bSYour Name
109*5113495bSYour Name if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) {
110*5113495bSYour Name /* Traffic is stopped */
111*5113495bSYour Name ol_txrx_dbg(
112*5113495bSYour Name "throttle phase --> OFF");
113*5113495bSYour Name ol_txrx_throttle_pause(pdev);
114*5113495bSYour Name ol_txrx_thermal_pause(pdev);
115*5113495bSYour Name pdev->tx_throttle.prev_outstanding_num = 0;
116*5113495bSYour Name cur_level = pdev->tx_throttle.current_throttle_level;
117*5113495bSYour Name cur_phase = pdev->tx_throttle.current_throttle_phase;
118*5113495bSYour Name ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
119*5113495bSYour Name if (pdev->tx_throttle.current_throttle_level !=
120*5113495bSYour Name THROTTLE_LEVEL_0) {
121*5113495bSYour Name ol_txrx_dbg(
122*5113495bSYour Name "start timer %d ms", ms);
123*5113495bSYour Name qdf_timer_start(&pdev->tx_throttle.
124*5113495bSYour Name phase_timer, ms);
125*5113495bSYour Name }
126*5113495bSYour Name } else {
127*5113495bSYour Name /* Traffic can go */
128*5113495bSYour Name ol_txrx_dbg(
129*5113495bSYour Name "throttle phase --> ON");
130*5113495bSYour Name ol_txrx_throttle_unpause(pdev);
131*5113495bSYour Name ol_txrx_thermal_unpause(pdev);
132*5113495bSYour Name cur_level = pdev->tx_throttle.current_throttle_level;
133*5113495bSYour Name cur_phase = pdev->tx_throttle.current_throttle_phase;
134*5113495bSYour Name ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase];
135*5113495bSYour Name if (pdev->tx_throttle.current_throttle_level !=
136*5113495bSYour Name THROTTLE_LEVEL_0) {
137*5113495bSYour Name ol_txrx_dbg("start timer %d ms", ms);
138*5113495bSYour Name qdf_timer_start(&pdev->tx_throttle.phase_timer, ms);
139*5113495bSYour Name }
140*5113495bSYour Name }
141*5113495bSYour Name }
142*5113495bSYour Name
143*5113495bSYour Name #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
ol_tx_pdev_throttle_tx_timer(void * context)144*5113495bSYour Name static void ol_tx_pdev_throttle_tx_timer(void *context)
145*5113495bSYour Name {
146*5113495bSYour Name struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context;
147*5113495bSYour Name
148*5113495bSYour Name ol_tx_pdev_ll_pause_queue_send_all(pdev);
149*5113495bSYour Name }
150*5113495bSYour Name #endif
151*5113495bSYour Name
152*5113495bSYour Name #ifdef CONFIG_HL_SUPPORT
153*5113495bSYour Name
154*5113495bSYour Name /**
155*5113495bSYour Name * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase
156*5113495bSYour Name * and time
157*5113495bSYour Name * @pdev: the peer device object
158*5113495bSYour Name * @level: throttle phase level
159*5113495bSYour Name * @ms: throttle time
160*5113495bSYour Name *
161*5113495bSYour Name * Return: None
162*5113495bSYour Name */
163*5113495bSYour Name static void
ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t * pdev,int level,int * ms)164*5113495bSYour Name ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
165*5113495bSYour Name {
166*5113495bSYour Name qdf_timer_stop(&pdev->tx_throttle.phase_timer);
167*5113495bSYour Name
168*5113495bSYour Name /* Set the phase */
169*5113495bSYour Name if (level != THROTTLE_LEVEL_0) {
170*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
171*5113495bSYour Name *ms = pdev->tx_throttle.throttle_time_ms[level]
172*5113495bSYour Name [THROTTLE_PHASE_OFF];
173*5113495bSYour Name
174*5113495bSYour Name /* pause all */
175*5113495bSYour Name ol_txrx_throttle_pause(pdev);
176*5113495bSYour Name } else {
177*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON;
178*5113495bSYour Name *ms = pdev->tx_throttle.throttle_time_ms[level]
179*5113495bSYour Name [THROTTLE_PHASE_ON];
180*5113495bSYour Name
181*5113495bSYour Name /* unpause all */
182*5113495bSYour Name ol_txrx_throttle_unpause(pdev);
183*5113495bSYour Name }
184*5113495bSYour Name }
185*5113495bSYour Name #else
186*5113495bSYour Name
187*5113495bSYour Name static void
ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t * pdev,int level,int * ms)188*5113495bSYour Name ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms)
189*5113495bSYour Name {
190*5113495bSYour Name int phase_on_time, phase_off_time;
191*5113495bSYour Name
192*5113495bSYour Name qdf_timer_stop(&pdev->tx_throttle.phase_timer);
193*5113495bSYour Name
194*5113495bSYour Name phase_on_time =
195*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_ON];
196*5113495bSYour Name phase_off_time =
197*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_OFF];
198*5113495bSYour Name if (phase_on_time && phase_off_time) {
199*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
200*5113495bSYour Name *ms =
201*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_OFF];
202*5113495bSYour Name ol_txrx_throttle_pause(pdev);
203*5113495bSYour Name ol_txrx_thermal_pause(pdev);
204*5113495bSYour Name } else if (!phase_off_time) {
205*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
206*5113495bSYour Name *ms = 0;
207*5113495bSYour Name ol_txrx_throttle_unpause(pdev);
208*5113495bSYour Name ol_txrx_thermal_unpause(pdev);
209*5113495bSYour Name } else {
210*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
211*5113495bSYour Name *ms = 0;
212*5113495bSYour Name ol_txrx_throttle_pause(pdev);
213*5113495bSYour Name ol_txrx_thermal_pause(pdev);
214*5113495bSYour Name }
215*5113495bSYour Name }
216*5113495bSYour Name #endif
217*5113495bSYour Name
ol_tx_throttle_set_level(struct cdp_soc_t * soc_hdl,uint8_t pdev_id,int level)218*5113495bSYour Name void ol_tx_throttle_set_level(struct cdp_soc_t *soc_hdl,
219*5113495bSYour Name uint8_t pdev_id, int level)
220*5113495bSYour Name {
221*5113495bSYour Name struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
222*5113495bSYour Name ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id);
223*5113495bSYour Name int ms = 0;
224*5113495bSYour Name
225*5113495bSYour Name if (level >= THROTTLE_LEVEL_MAX) {
226*5113495bSYour Name ol_txrx_dbg("invalid throttle level set %d, ignoring", level);
227*5113495bSYour Name return;
228*5113495bSYour Name }
229*5113495bSYour Name
230*5113495bSYour Name if (qdf_unlikely(!pdev)) {
231*5113495bSYour Name ol_txrx_err("pdev is NULL");
232*5113495bSYour Name return;
233*5113495bSYour Name }
234*5113495bSYour Name
235*5113495bSYour Name ol_txrx_info("Setting throttle level %d", level);
236*5113495bSYour Name
237*5113495bSYour Name /* Set the current throttle level */
238*5113495bSYour Name pdev->tx_throttle.current_throttle_level = (enum throttle_level)level;
239*5113495bSYour Name pdev->tx_throttle.prev_outstanding_num = 0;
240*5113495bSYour Name
241*5113495bSYour Name ol_tx_set_throttle_phase_time(pdev, level, &ms);
242*5113495bSYour Name
243*5113495bSYour Name if (ms)
244*5113495bSYour Name qdf_timer_start(&pdev->tx_throttle.phase_timer, ms);
245*5113495bSYour Name }
246*5113495bSYour Name
ol_tx_throttle_init_period(struct cdp_soc_t * soc_hdl,uint8_t pdev_id,int period,uint8_t * dutycycle_level)247*5113495bSYour Name void ol_tx_throttle_init_period(struct cdp_soc_t *soc_hdl,
248*5113495bSYour Name uint8_t pdev_id, int period,
249*5113495bSYour Name uint8_t *dutycycle_level)
250*5113495bSYour Name {
251*5113495bSYour Name struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl);
252*5113495bSYour Name ol_txrx_pdev_handle pdev;
253*5113495bSYour Name int i;
254*5113495bSYour Name
255*5113495bSYour Name if (qdf_unlikely(!soc)) {
256*5113495bSYour Name ol_txrx_err("soc is NULL");
257*5113495bSYour Name return;
258*5113495bSYour Name }
259*5113495bSYour Name
260*5113495bSYour Name pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id);
261*5113495bSYour Name if (qdf_unlikely(!pdev)) {
262*5113495bSYour Name ol_txrx_err("pdev is NULL");
263*5113495bSYour Name return;
264*5113495bSYour Name }
265*5113495bSYour Name
266*5113495bSYour Name /* Set the current throttle level */
267*5113495bSYour Name pdev->tx_throttle.throttle_period_ms = period;
268*5113495bSYour Name
269*5113495bSYour Name ol_txrx_dbg("level OFF ON");
270*5113495bSYour Name for (i = 0; i < THROTTLE_LEVEL_MAX; i++) {
271*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] =
272*5113495bSYour Name pdev->tx_throttle.throttle_period_ms -
273*5113495bSYour Name ((dutycycle_level[i] *
274*5113495bSYour Name pdev->tx_throttle.throttle_period_ms) / 100);
275*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] =
276*5113495bSYour Name pdev->tx_throttle.throttle_period_ms -
277*5113495bSYour Name pdev->tx_throttle.throttle_time_ms[
278*5113495bSYour Name i][THROTTLE_PHASE_ON];
279*5113495bSYour Name ol_txrx_dbg("%d %d %d", i,
280*5113495bSYour Name pdev->tx_throttle.
281*5113495bSYour Name throttle_time_ms[i][THROTTLE_PHASE_OFF],
282*5113495bSYour Name pdev->tx_throttle.
283*5113495bSYour Name throttle_time_ms[i][THROTTLE_PHASE_ON]);
284*5113495bSYour Name }
285*5113495bSYour Name }
286*5113495bSYour Name
ol_tx_throttle_init(struct ol_txrx_pdev_t * pdev)287*5113495bSYour Name void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev)
288*5113495bSYour Name {
289*5113495bSYour Name uint32_t throttle_period;
290*5113495bSYour Name uint8_t dutycycle_level[THROTTLE_LEVEL_MAX];
291*5113495bSYour Name int i;
292*5113495bSYour Name
293*5113495bSYour Name pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0;
294*5113495bSYour Name pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF;
295*5113495bSYour Name qdf_spinlock_create(&pdev->tx_throttle.mutex);
296*5113495bSYour Name
297*5113495bSYour Name throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev);
298*5113495bSYour Name
299*5113495bSYour Name for (i = 0; i < THROTTLE_LEVEL_MAX; i++)
300*5113495bSYour Name dutycycle_level[i] =
301*5113495bSYour Name ol_cfg_throttle_duty_cycle_level(pdev->ctrl_pdev, i);
302*5113495bSYour Name
303*5113495bSYour Name ol_tx_throttle_init_period(cds_get_context(QDF_MODULE_ID_SOC), pdev->id,
304*5113495bSYour Name throttle_period, &dutycycle_level[0]);
305*5113495bSYour Name
306*5113495bSYour Name qdf_timer_init(pdev->osdev, &pdev->tx_throttle.phase_timer,
307*5113495bSYour Name ol_tx_pdev_throttle_phase_timer, pdev,
308*5113495bSYour Name QDF_TIMER_TYPE_SW);
309*5113495bSYour Name
310*5113495bSYour Name #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
311*5113495bSYour Name qdf_timer_init(pdev->osdev, &pdev->tx_throttle.tx_timer,
312*5113495bSYour Name ol_tx_pdev_throttle_tx_timer, pdev, QDF_TIMER_TYPE_SW);
313*5113495bSYour Name #endif
314*5113495bSYour Name
315*5113495bSYour Name pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD;
316*5113495bSYour Name }
317*5113495bSYour Name
318*5113495bSYour Name void
ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev)319*5113495bSYour Name ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev)
320*5113495bSYour Name {
321*5113495bSYour Name qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
322*5113495bSYour Name
323*5113495bSYour Name if (pdev->tx_throttle.is_paused) {
324*5113495bSYour Name qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
325*5113495bSYour Name return;
326*5113495bSYour Name }
327*5113495bSYour Name
328*5113495bSYour Name pdev->tx_throttle.is_paused = true;
329*5113495bSYour Name qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
330*5113495bSYour Name ol_txrx_pdev_pause(pdev, 0);
331*5113495bSYour Name }
332*5113495bSYour Name
333*5113495bSYour Name void
ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev)334*5113495bSYour Name ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev)
335*5113495bSYour Name {
336*5113495bSYour Name qdf_spin_lock_bh(&pdev->tx_throttle.mutex);
337*5113495bSYour Name
338*5113495bSYour Name if (!pdev->tx_throttle.is_paused) {
339*5113495bSYour Name qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
340*5113495bSYour Name return;
341*5113495bSYour Name }
342*5113495bSYour Name
343*5113495bSYour Name pdev->tx_throttle.is_paused = false;
344*5113495bSYour Name qdf_spin_unlock_bh(&pdev->tx_throttle.mutex);
345*5113495bSYour Name ol_txrx_pdev_unpause(pdev, 0);
346*5113495bSYour Name }
347