xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_wmm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /** @file mlan_wmm.c
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  *  @brief This file contains functions for WMM.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Copyright 2008-2021 NXP
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  This software file (the File) is distributed by NXP
9*4882a593Smuzhiyun  *  under the terms of the GNU General Public License Version 2, June 1991
10*4882a593Smuzhiyun  *  (the License).  You may use, redistribute and/or modify the File in
11*4882a593Smuzhiyun  *  accordance with the terms and conditions of the License, a copy of which
12*4882a593Smuzhiyun  *  is available by writing to the Free Software Foundation, Inc.,
13*4882a593Smuzhiyun  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14*4882a593Smuzhiyun  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17*4882a593Smuzhiyun  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18*4882a593Smuzhiyun  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19*4882a593Smuzhiyun  *  this warranty disclaimer.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /********************************************************
24*4882a593Smuzhiyun Change log:
25*4882a593Smuzhiyun     10/24/2008: initial version
26*4882a593Smuzhiyun ********************************************************/
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include "mlan.h"
29*4882a593Smuzhiyun #ifdef STA_SUPPORT
30*4882a593Smuzhiyun #include "mlan_join.h"
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun #include "mlan_util.h"
33*4882a593Smuzhiyun #include "mlan_fw.h"
34*4882a593Smuzhiyun #include "mlan_main.h"
35*4882a593Smuzhiyun #include "mlan_wmm.h"
36*4882a593Smuzhiyun #include "mlan_11n.h"
37*4882a593Smuzhiyun #include "mlan_11ax.h"
38*4882a593Smuzhiyun #ifdef SDIO
39*4882a593Smuzhiyun #include "mlan_sdio.h"
40*4882a593Smuzhiyun #endif /* SDIO */
41*4882a593Smuzhiyun #ifdef PCIE
42*4882a593Smuzhiyun #include "mlan_pcie.h"
43*4882a593Smuzhiyun #endif /* PCIE */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /********************************************************
46*4882a593Smuzhiyun 			Local Variables
47*4882a593Smuzhiyun ********************************************************/
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /** WMM information IE */
50*4882a593Smuzhiyun static const t_u8 wmm_info_ie[] = {WMM_IE, 0x07, 0x00, 0x50, 0xf2,
51*4882a593Smuzhiyun 				   0x02,   0x00, 0x01, 0x00};
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /** Type enumeration of WMM AC_QUEUES */
54*4882a593Smuzhiyun typedef MLAN_PACK_START enum _wmm_ac_e {
55*4882a593Smuzhiyun 	AC_BE,
56*4882a593Smuzhiyun 	AC_BK,
57*4882a593Smuzhiyun 	AC_VI,
58*4882a593Smuzhiyun 	AC_VO
59*4882a593Smuzhiyun } MLAN_PACK_END wmm_ac_e;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /**
62*4882a593Smuzhiyun  * AC Priorities go from AC_BK to AC_VO.  The ACI enumeration for AC_BK (1)
63*4882a593Smuzhiyun  *   is higher than the enumeration for AC_BE (0); hence the needed
64*4882a593Smuzhiyun  *   mapping conversion for wmm AC to priority Queue Index
65*4882a593Smuzhiyun  */
66*4882a593Smuzhiyun static const t_u8 wmm_aci_to_qidx_map[] = {WMM_AC_BE, WMM_AC_BK, WMM_AC_VI,
67*4882a593Smuzhiyun 					   WMM_AC_VO};
68*4882a593Smuzhiyun /**
69*4882a593Smuzhiyun  * This table will be used to store the tid values based on ACs.
70*4882a593Smuzhiyun  * It is initialized to default values per TID.
71*4882a593Smuzhiyun  */
72*4882a593Smuzhiyun static t_u8 tos_to_tid[] = {
73*4882a593Smuzhiyun 	/* TID        DSCP_P2   DSCP_P1  DSCP_P0   WMM_AC   */
74*4882a593Smuzhiyun 	0x01, /*    0         1        0       AC_BK   */
75*4882a593Smuzhiyun 	0x02, /*    0         0        0       AC_BK   */
76*4882a593Smuzhiyun 	0x00, /*    0         0        1       AC_BE   */
77*4882a593Smuzhiyun 	0x03, /*    0         1        1       AC_BE   */
78*4882a593Smuzhiyun 	0x04, /*    1         0        0       AC_VI   */
79*4882a593Smuzhiyun 	0x05, /*    1         0        1       AC_VI   */
80*4882a593Smuzhiyun 	0x06, /*    1         1        0       AC_VO   */
81*4882a593Smuzhiyun 	0x07 /*    1         1        1       AC_VO   */
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /**
85*4882a593Smuzhiyun  * This table inverses the tos_to_tid operation to get a priority
86*4882a593Smuzhiyun  * which is in sequential order, and can be compared.
87*4882a593Smuzhiyun  * Use this to compare the priority of two different TIDs.
88*4882a593Smuzhiyun  */
89*4882a593Smuzhiyun t_u8 tos_to_tid_inv[] = {0x02, /* from tos_to_tid[2] = 0 */
90*4882a593Smuzhiyun 			 0x00, /* from tos_to_tid[0] = 1 */
91*4882a593Smuzhiyun 			 0x01, /* from tos_to_tid[1] = 2 */
92*4882a593Smuzhiyun 			 0x03, 0x04, 0x05, 0x06, 0x07};
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /**
95*4882a593Smuzhiyun  * This table will provide the tid value for given ac. This table does not
96*4882a593Smuzhiyun  * change and will be used to copy back the default values to tos_to_tid in
97*4882a593Smuzhiyun  * case of disconnect.
98*4882a593Smuzhiyun  */
99*4882a593Smuzhiyun t_u8 ac_to_tid[4][2] = {{1, 2}, {0, 3}, {4, 5}, {6, 7}};
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /* Map of TOS UP values to WMM AC */
102*4882a593Smuzhiyun static const mlan_wmm_ac_e tos_to_ac[] = {WMM_AC_BE, WMM_AC_BK, WMM_AC_BK,
103*4882a593Smuzhiyun 					  WMM_AC_BE, WMM_AC_VI, WMM_AC_VI,
104*4882a593Smuzhiyun 					  WMM_AC_VO, WMM_AC_VO};
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
107*4882a593Smuzhiyun 				    t_u8 *ra_addr);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /********************************************************
110*4882a593Smuzhiyun 			Local Functions
111*4882a593Smuzhiyun ********************************************************/
112*4882a593Smuzhiyun #ifdef DEBUG_LEVEL2
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun  *  @brief Debug print function to display the priority parameters for a WMM AC
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  *  @param pac_param	Pointer to the AC parameters to display
117*4882a593Smuzhiyun  *
118*4882a593Smuzhiyun  *  @return		N/A
119*4882a593Smuzhiyun  */
120*4882a593Smuzhiyun static void
wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)121*4882a593Smuzhiyun wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t *pac_param)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	const char *ac_str[] = {"BK", "BE", "VI", "VO"};
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	ENTER();
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	PRINTM(MINFO,
128*4882a593Smuzhiyun 	       "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
129*4882a593Smuzhiyun 	       "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
130*4882a593Smuzhiyun 	       ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
131*4882a593Smuzhiyun 	       pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
132*4882a593Smuzhiyun 	       pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
133*4882a593Smuzhiyun 	       pac_param->ecw.ecw_max,
134*4882a593Smuzhiyun 	       wlan_le16_to_cpu(pac_param->tx_op_limit));
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	LEAVE();
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun /** Print the WMM AC for debug purpose */
139*4882a593Smuzhiyun #define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
140*4882a593Smuzhiyun #else
141*4882a593Smuzhiyun /** Print the WMM AC for debug purpose */
142*4882a593Smuzhiyun #define PRINTM_AC(pac_param)
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /**
146*4882a593Smuzhiyun  *  @brief Allocate route address
147*4882a593Smuzhiyun  *
148*4882a593Smuzhiyun  *  @param pmadapter       Pointer to the mlan_adapter structure
149*4882a593Smuzhiyun  *  @param ra              Pointer to the route address
150*4882a593Smuzhiyun  *
151*4882a593Smuzhiyun  *  @return         ra_list
152*4882a593Smuzhiyun  */
wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter,t_u8 * ra)153*4882a593Smuzhiyun static raListTbl *wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter,
154*4882a593Smuzhiyun 						t_u8 *ra)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	raListTbl *ra_list = MNULL;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	ENTER();
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
161*4882a593Smuzhiyun 					     sizeof(raListTbl), MLAN_MEM_DEF,
162*4882a593Smuzhiyun 					     (t_u8 **)&ra_list)) {
163*4882a593Smuzhiyun 		PRINTM(MERROR, "Fail to allocate ra_list\n");
164*4882a593Smuzhiyun 		goto done;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 	util_init_list((pmlan_linked_list)ra_list);
167*4882a593Smuzhiyun 	util_init_list_head((t_void *)pmadapter->pmoal_handle,
168*4882a593Smuzhiyun 			    &ra_list->buf_head, MFALSE,
169*4882a593Smuzhiyun 			    pmadapter->callbacks.moal_init_lock);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	memcpy_ext(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH,
172*4882a593Smuzhiyun 		   MLAN_MAC_ADDR_LENGTH);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	ra_list->del_ba_count = 0;
175*4882a593Smuzhiyun 	ra_list->total_pkts = 0;
176*4882a593Smuzhiyun 	ra_list->tx_pause = 0;
177*4882a593Smuzhiyun 	PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
178*4882a593Smuzhiyun done:
179*4882a593Smuzhiyun 	LEAVE();
180*4882a593Smuzhiyun 	return ra_list;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /**
184*4882a593Smuzhiyun  *  @brief Add packet to TDLS pending TX queue
185*4882a593Smuzhiyun  *
186*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
187*4882a593Smuzhiyun  *  @param pmbuf      Pointer to the mlan_buffer data struct
188*4882a593Smuzhiyun  *
189*4882a593Smuzhiyun  *  @return           N/A
190*4882a593Smuzhiyun  */
wlan_add_buf_tdls_txqueue(pmlan_private priv,pmlan_buffer pmbuf)191*4882a593Smuzhiyun static t_void wlan_add_buf_tdls_txqueue(pmlan_private priv, pmlan_buffer pmbuf)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
194*4882a593Smuzhiyun 	ENTER();
195*4882a593Smuzhiyun 	util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->tdls_pending_txq,
196*4882a593Smuzhiyun 			       (pmlan_linked_list)pmbuf,
197*4882a593Smuzhiyun 			       pmadapter->callbacks.moal_spin_lock,
198*4882a593Smuzhiyun 			       pmadapter->callbacks.moal_spin_unlock);
199*4882a593Smuzhiyun 	LEAVE();
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /**
203*4882a593Smuzhiyun  *  @brief Clean up the tdls pending TX queue
204*4882a593Smuzhiyun  *
205*4882a593Smuzhiyun  *  @param priv		A pointer to mlan_private
206*4882a593Smuzhiyun  *
207*4882a593Smuzhiyun  *  @return      N/A
208*4882a593Smuzhiyun  */
wlan_cleanup_tdls_txq(pmlan_private priv)209*4882a593Smuzhiyun static t_void wlan_cleanup_tdls_txq(pmlan_private priv)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
212*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
213*4882a593Smuzhiyun 	ENTER();
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
216*4882a593Smuzhiyun 					    priv->tdls_pending_txq.plock);
217*4882a593Smuzhiyun 	while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
218*4882a593Smuzhiyun 						     &priv->tdls_pending_txq,
219*4882a593Smuzhiyun 						     MNULL, MNULL))) {
220*4882a593Smuzhiyun 		util_unlink_list(pmadapter->pmoal_handle,
221*4882a593Smuzhiyun 				 &priv->tdls_pending_txq,
222*4882a593Smuzhiyun 				 (pmlan_linked_list)pmbuf, MNULL, MNULL);
223*4882a593Smuzhiyun 		wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
226*4882a593Smuzhiyun 					      priv->tdls_pending_txq.plock);
227*4882a593Smuzhiyun 	LEAVE();
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun /**
231*4882a593Smuzhiyun  * @brief Map ACs to TID
232*4882a593Smuzhiyun  *
233*4882a593Smuzhiyun  * @param priv             Pointer to the mlan_private driver data struct
234*4882a593Smuzhiyun  * @param queue_priority   Queue_priority structure
235*4882a593Smuzhiyun  *
236*4882a593Smuzhiyun  * @return 	   N/A
237*4882a593Smuzhiyun  */
wlan_wmm_queue_priorities_tid(pmlan_private priv,t_u8 queue_priority[])238*4882a593Smuzhiyun static void wlan_wmm_queue_priorities_tid(pmlan_private priv,
239*4882a593Smuzhiyun 					  t_u8 queue_priority[])
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	int i;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	ENTER();
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	for (i = 0; i < 4; ++i) {
246*4882a593Smuzhiyun 		tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
247*4882a593Smuzhiyun 		tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; i++)
251*4882a593Smuzhiyun 		tos_to_tid_inv[tos_to_tid[i]] = (t_u8)i;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* in case priorities have changed, force highest priority so
254*4882a593Smuzhiyun 	 * next packet will check from top to re-establish the highest
255*4882a593Smuzhiyun 	 */
256*4882a593Smuzhiyun 	util_scalar_write(priv->adapter->pmoal_handle,
257*4882a593Smuzhiyun 			  &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
258*4882a593Smuzhiyun 			  priv->adapter->callbacks.moal_spin_lock,
259*4882a593Smuzhiyun 			  priv->adapter->callbacks.moal_spin_unlock);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	LEAVE();
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun /**
265*4882a593Smuzhiyun  *  @brief Evaluate whether or not an AC is to be downgraded
266*4882a593Smuzhiyun  *
267*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
268*4882a593Smuzhiyun  *  @param eval_ac  AC to evaluate for downgrading
269*4882a593Smuzhiyun  *
270*4882a593Smuzhiyun  *  @return WMM AC  The eval_ac traffic is to be sent on.
271*4882a593Smuzhiyun  */
wlan_wmm_eval_downgrade_ac(pmlan_private priv,mlan_wmm_ac_e eval_ac)272*4882a593Smuzhiyun static mlan_wmm_ac_e wlan_wmm_eval_downgrade_ac(pmlan_private priv,
273*4882a593Smuzhiyun 						mlan_wmm_ac_e eval_ac)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	int down_ac;
276*4882a593Smuzhiyun 	mlan_wmm_ac_e ret_ac;
277*4882a593Smuzhiyun 	WmmAcStatus_t *pac_status;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ENTER();
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	pac_status = &priv->wmm.ac_status[eval_ac];
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (pac_status->disabled == MFALSE) {
284*4882a593Smuzhiyun 		LEAVE();
285*4882a593Smuzhiyun 		/* Okay to use this AC, its enabled */
286*4882a593Smuzhiyun 		return eval_ac;
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/* Setup a default return value of the lowest priority */
290*4882a593Smuzhiyun 	ret_ac = WMM_AC_BK;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	/*
293*4882a593Smuzhiyun 	 * Find the highest AC that is enabled and does not require admission
294*4882a593Smuzhiyun 	 * control.  The spec disallows downgrading to an AC, which is enabled
295*4882a593Smuzhiyun 	 * due to a completed admission control.  Unadmitted traffic is not
296*4882a593Smuzhiyun 	 * to be sent on an AC with admitted traffic.
297*4882a593Smuzhiyun 	 */
298*4882a593Smuzhiyun 	for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
299*4882a593Smuzhiyun 		pac_status = &priv->wmm.ac_status[down_ac];
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		if ((pac_status->disabled == MFALSE) &&
302*4882a593Smuzhiyun 		    (pac_status->flow_required == MFALSE))
303*4882a593Smuzhiyun 			/* AC is enabled and does not require admission control
304*4882a593Smuzhiyun 			 */
305*4882a593Smuzhiyun 			ret_ac = (mlan_wmm_ac_e)down_ac;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	LEAVE();
309*4882a593Smuzhiyun 	return ret_ac;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun /**
313*4882a593Smuzhiyun  *  @brief Convert the IP TOS field to an WMM AC Queue assignment
314*4882a593Smuzhiyun  *
315*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
316*4882a593Smuzhiyun  *  @param tos       IP TOS field
317*4882a593Smuzhiyun  *
318*4882a593Smuzhiyun  *  @return     WMM AC Queue mapping of the IP TOS field
319*4882a593Smuzhiyun  */
wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter,t_u32 tos)320*4882a593Smuzhiyun static INLINE mlan_wmm_ac_e wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter,
321*4882a593Smuzhiyun 						       t_u32 tos)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	ENTER();
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (tos >= NELEMENTS(tos_to_ac)) {
326*4882a593Smuzhiyun 		LEAVE();
327*4882a593Smuzhiyun 		return WMM_AC_BE;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	LEAVE();
331*4882a593Smuzhiyun 	return tos_to_ac[tos];
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun /**
335*4882a593Smuzhiyun  *  @brief  Evaluate a given TID and downgrade it to a lower TID if the
336*4882a593Smuzhiyun  *          WMM Parameter IE received from the AP indicates that the AP
337*4882a593Smuzhiyun  *          is disabled (due to call admission control (ACM bit). Mapping
338*4882a593Smuzhiyun  *          of TID to AC is taken care internally
339*4882a593Smuzhiyun  *
340*4882a593Smuzhiyun  *  @param priv		Pointer to the mlan_private data struct
341*4882a593Smuzhiyun  *  @param tid      tid to evaluate for downgrading
342*4882a593Smuzhiyun  *
343*4882a593Smuzhiyun  *  @return       Same tid as input if downgrading not required or
344*4882a593Smuzhiyun  *                the tid the traffic for the given tid should be downgraded to
345*4882a593Smuzhiyun  */
wlan_wmm_downgrade_tid(pmlan_private priv,t_u32 tid)346*4882a593Smuzhiyun static INLINE t_u8 wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	mlan_wmm_ac_e ac_down;
349*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ENTER();
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	ac_down = priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(
354*4882a593Smuzhiyun 		pmadapter, tid)];
355*4882a593Smuzhiyun 	LEAVE();
356*4882a593Smuzhiyun 	/*
357*4882a593Smuzhiyun 	 * Send the index to tid array, picking from the array will be
358*4882a593Smuzhiyun 	 * taken care by dequeuing function
359*4882a593Smuzhiyun 	 */
360*4882a593Smuzhiyun 	if (tid == 1 || tid == 2)
361*4882a593Smuzhiyun 		return ac_to_tid[ac_down][(tid + 1) % 2];
362*4882a593Smuzhiyun 	else if (tid >= MAX_NUM_TID)
363*4882a593Smuzhiyun 		return ac_to_tid[ac_down][0];
364*4882a593Smuzhiyun 	else
365*4882a593Smuzhiyun 		return ac_to_tid[ac_down][tid % 2];
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /**
369*4882a593Smuzhiyun  *  @brief Delete packets in RA node
370*4882a593Smuzhiyun  *
371*4882a593Smuzhiyun  *  @param priv         Pointer to the mlan_private driver data struct
372*4882a593Smuzhiyun  *  @param ra_list      Pointer to raListTbl
373*4882a593Smuzhiyun  *
374*4882a593Smuzhiyun  *  @return             N/A
375*4882a593Smuzhiyun  */
wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv,raListTbl * ra_list)376*4882a593Smuzhiyun static INLINE void wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv,
377*4882a593Smuzhiyun 						    raListTbl *ra_list)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
380*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	ENTER();
383*4882a593Smuzhiyun 	while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
384*4882a593Smuzhiyun 						     &ra_list->buf_head, MNULL,
385*4882a593Smuzhiyun 						     MNULL))) {
386*4882a593Smuzhiyun 		util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
387*4882a593Smuzhiyun 				 (pmlan_linked_list)pmbuf, MNULL, MNULL);
388*4882a593Smuzhiyun 		wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 	util_free_list_head((t_void *)pmadapter->pmoal_handle,
391*4882a593Smuzhiyun 			    &ra_list->buf_head,
392*4882a593Smuzhiyun 			    pmadapter->callbacks.moal_free_lock);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	LEAVE();
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun /**
398*4882a593Smuzhiyun  *  @brief Delete packets in RA list
399*4882a593Smuzhiyun  *
400*4882a593Smuzhiyun  *  @param priv			Pointer to the mlan_private driver data struct
401*4882a593Smuzhiyun  *  @param ra_list_head	ra list header
402*4882a593Smuzhiyun  *
403*4882a593Smuzhiyun  *  @return		N/A
404*4882a593Smuzhiyun  */
wlan_wmm_del_pkts_in_ralist(pmlan_private priv,mlan_list_head * ra_list_head)405*4882a593Smuzhiyun static INLINE void wlan_wmm_del_pkts_in_ralist(pmlan_private priv,
406*4882a593Smuzhiyun 					       mlan_list_head *ra_list_head)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	raListTbl *ra_list;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	ENTER();
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	ra_list = (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
413*4882a593Smuzhiyun 					      ra_list_head, MNULL, MNULL);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	while (ra_list && ra_list != (raListTbl *)ra_list_head) {
416*4882a593Smuzhiyun 		wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		ra_list = ra_list->pnext;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	LEAVE();
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /**
425*4882a593Smuzhiyun  *  @brief Clean up the wmm queue
426*4882a593Smuzhiyun  *
427*4882a593Smuzhiyun  *  @param priv  Pointer to the mlan_private driver data struct
428*4882a593Smuzhiyun  *
429*4882a593Smuzhiyun  *  @return      N/A
430*4882a593Smuzhiyun  */
wlan_wmm_cleanup_queues(pmlan_private priv)431*4882a593Smuzhiyun static void wlan_wmm_cleanup_queues(pmlan_private priv)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	int i;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	ENTER();
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; i++) {
438*4882a593Smuzhiyun 		wlan_wmm_del_pkts_in_ralist(priv,
439*4882a593Smuzhiyun 					    &priv->wmm.tid_tbl_ptr[i].ra_list);
440*4882a593Smuzhiyun 		priv->wmm.pkts_queued[i] = 0;
441*4882a593Smuzhiyun 		priv->wmm.pkts_paused[i] = 0;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 	util_scalar_write(priv->adapter->pmoal_handle,
444*4882a593Smuzhiyun 			  &priv->wmm.tx_pkts_queued, 0, MNULL, MNULL);
445*4882a593Smuzhiyun 	util_scalar_write(priv->adapter->pmoal_handle,
446*4882a593Smuzhiyun 			  &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
447*4882a593Smuzhiyun 			  MNULL);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	LEAVE();
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun /**
453*4882a593Smuzhiyun  *  @brief Delete all route address from RA list
454*4882a593Smuzhiyun  *
455*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
456*4882a593Smuzhiyun  *
457*4882a593Smuzhiyun  *  @return         N/A
458*4882a593Smuzhiyun  */
wlan_wmm_delete_all_ralist(pmlan_private priv)459*4882a593Smuzhiyun static void wlan_wmm_delete_all_ralist(pmlan_private priv)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	raListTbl *ra_list;
462*4882a593Smuzhiyun 	int i;
463*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	ENTER();
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
468*4882a593Smuzhiyun 		PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
469*4882a593Smuzhiyun 		while ((ra_list = (raListTbl *)util_peek_list(
470*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
471*4882a593Smuzhiyun 				&priv->wmm.tid_tbl_ptr[i].ra_list, MNULL,
472*4882a593Smuzhiyun 				MNULL))) {
473*4882a593Smuzhiyun 			util_unlink_list(pmadapter->pmoal_handle,
474*4882a593Smuzhiyun 					 &priv->wmm.tid_tbl_ptr[i].ra_list,
475*4882a593Smuzhiyun 					 (pmlan_linked_list)ra_list, MNULL,
476*4882a593Smuzhiyun 					 MNULL);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
479*4882a593Smuzhiyun 							(t_u8 *)ra_list);
480*4882a593Smuzhiyun 		}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		util_init_list(
483*4882a593Smuzhiyun 			(pmlan_linked_list)&priv->wmm.tid_tbl_ptr[i].ra_list);
484*4882a593Smuzhiyun 		priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	LEAVE();
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun /**
491*4882a593Smuzhiyun  *   @brief Get queue RA pointer
492*4882a593Smuzhiyun  *
493*4882a593Smuzhiyun  *   @param priv     Pointer to the mlan_private driver data struct
494*4882a593Smuzhiyun  *   @param tid      TID
495*4882a593Smuzhiyun  *   @param ra_addr  Pointer to the route address
496*4882a593Smuzhiyun  *
497*4882a593Smuzhiyun  *   @return         ra_list
498*4882a593Smuzhiyun  */
wlan_wmm_get_queue_raptr(pmlan_private priv,t_u8 tid,t_u8 * ra_addr)499*4882a593Smuzhiyun static raListTbl *wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid,
500*4882a593Smuzhiyun 					   t_u8 *ra_addr)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun 	raListTbl *ra_list;
503*4882a593Smuzhiyun #ifdef UAP_SUPPORT
504*4882a593Smuzhiyun 	t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
505*4882a593Smuzhiyun #endif
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	ENTER();
508*4882a593Smuzhiyun 	ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
509*4882a593Smuzhiyun 	if (ra_list) {
510*4882a593Smuzhiyun 		LEAVE();
511*4882a593Smuzhiyun 		return ra_list;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun #ifdef UAP_SUPPORT
514*4882a593Smuzhiyun 	if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
515*4882a593Smuzhiyun 	    (0 !=
516*4882a593Smuzhiyun 	     memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
517*4882a593Smuzhiyun 		if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
518*4882a593Smuzhiyun 			PRINTM_NETINTF(MERROR, priv);
519*4882a593Smuzhiyun 			PRINTM(MERROR,
520*4882a593Smuzhiyun 			       "Drop packets to unknow station " MACSTR "\n",
521*4882a593Smuzhiyun 			       MAC2STR(ra_addr));
522*4882a593Smuzhiyun 			LEAVE();
523*4882a593Smuzhiyun 			return MNULL;
524*4882a593Smuzhiyun 		}
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun #endif
527*4882a593Smuzhiyun 	wlan_ralist_add(priv, ra_addr);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
530*4882a593Smuzhiyun 	LEAVE();
531*4882a593Smuzhiyun 	return ra_list;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun #ifdef STA_SUPPORT
535*4882a593Smuzhiyun /**
536*4882a593Smuzhiyun  *  @brief Sends wmmac host event
537*4882a593Smuzhiyun  *
538*4882a593Smuzhiyun  *  @param priv      Pointer to the mlan_private driver data struct
539*4882a593Smuzhiyun  *  @param type_str  Type of host event
540*4882a593Smuzhiyun  *  @param src_addr  Pointer to the source Address
541*4882a593Smuzhiyun  *  @param tid       TID
542*4882a593Smuzhiyun  *  @param up        User priority
543*4882a593Smuzhiyun  *  @param status    Status code or Reason code
544*4882a593Smuzhiyun  *
545*4882a593Smuzhiyun  *  @return     N/A
546*4882a593Smuzhiyun  */
wlan_send_wmmac_host_event(pmlan_private priv,char * type_str,t_u8 * src_addr,t_u8 tid,t_u8 up,t_u8 status)547*4882a593Smuzhiyun static void wlan_send_wmmac_host_event(pmlan_private priv, char *type_str,
548*4882a593Smuzhiyun 				       t_u8 *src_addr, t_u8 tid, t_u8 up,
549*4882a593Smuzhiyun 				       t_u8 status)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun 	t_u8 event_buf[100];
552*4882a593Smuzhiyun 	mlan_event *pevent;
553*4882a593Smuzhiyun 	t_u8 *pout_buf;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	ENTER();
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/* Format one of the following two output strings:
558*4882a593Smuzhiyun 	**    - TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y
559*4882a593Smuzhiyun 	**    - TSPEC:DELTS_RX:[<reason code>]:TID=X:UP=Y
560*4882a593Smuzhiyun 	*/
561*4882a593Smuzhiyun 	pevent = (mlan_event *)event_buf;
562*4882a593Smuzhiyun 	pout_buf = pevent->event_buf;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	memcpy_ext(priv->adapter, pout_buf, (t_u8 *)"TSPEC:", 6, 6);
565*4882a593Smuzhiyun 	pout_buf += 6;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	memcpy_ext(priv->adapter, pout_buf, (t_u8 *)type_str,
568*4882a593Smuzhiyun 		   wlan_strlen(type_str), wlan_strlen(type_str));
569*4882a593Smuzhiyun 	pout_buf += wlan_strlen(type_str);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	*pout_buf++ = ':';
572*4882a593Smuzhiyun 	*pout_buf++ = '[';
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	if (status >= 100) {
575*4882a593Smuzhiyun 		*pout_buf++ = (status / 100) + '0';
576*4882a593Smuzhiyun 		status = (status % 100);
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (status >= 10) {
580*4882a593Smuzhiyun 		*pout_buf++ = (status / 10) + '0';
581*4882a593Smuzhiyun 		status = (status % 10);
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	*pout_buf++ = status + '0';
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	memcpy_ext(priv->adapter, pout_buf, (t_u8 *)"]:TID", 5, 5);
587*4882a593Smuzhiyun 	pout_buf += 5;
588*4882a593Smuzhiyun 	*pout_buf++ = tid + '0';
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	memcpy_ext(priv->adapter, pout_buf, (t_u8 *)":UP", 3, 3);
591*4882a593Smuzhiyun 	pout_buf += 3;
592*4882a593Smuzhiyun 	*pout_buf++ = up + '0';
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	*pout_buf = '\0';
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	pevent->bss_index = priv->bss_index;
597*4882a593Smuzhiyun 	pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
598*4882a593Smuzhiyun 	pevent->event_len = wlan_strlen((const char *)(pevent->event_buf));
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
601*4882a593Smuzhiyun 	LEAVE();
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun #endif /* STA_SUPPORT */
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun /**
606*4882a593Smuzhiyun  *  @brief This function gets the highest priority list pointer
607*4882a593Smuzhiyun  *
608*4882a593Smuzhiyun  *  @param pmadapter      A pointer to mlan_adapter
609*4882a593Smuzhiyun  *  @param priv           A pointer to mlan_private
610*4882a593Smuzhiyun  *  @param tid            A pointer to return tid
611*4882a593Smuzhiyun  *
612*4882a593Smuzhiyun  *  @return             raListTbl
613*4882a593Smuzhiyun  */
wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,pmlan_private * priv,int * tid)614*4882a593Smuzhiyun static raListTbl *wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
615*4882a593Smuzhiyun 						    pmlan_private *priv,
616*4882a593Smuzhiyun 						    int *tid)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun 	pmlan_private priv_tmp;
619*4882a593Smuzhiyun 	raListTbl *ptr, *head;
620*4882a593Smuzhiyun 	mlan_bssprio_node *bssprio_node, *bssprio_head;
621*4882a593Smuzhiyun 	tid_tbl_t *tid_ptr;
622*4882a593Smuzhiyun 	int i, j;
623*4882a593Smuzhiyun 	int next_prio = 0;
624*4882a593Smuzhiyun 	int next_tid = 0;
625*4882a593Smuzhiyun 	ENTER();
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	PRINTM(MDAT_D, "POP\n");
628*4882a593Smuzhiyun 	for (j = pmadapter->priv_num - 1; j >= 0; --j) {
629*4882a593Smuzhiyun 		if (!(util_peek_list(pmadapter->pmoal_handle,
630*4882a593Smuzhiyun 				     &pmadapter->bssprio_tbl[j].bssprio_head,
631*4882a593Smuzhiyun 				     MNULL, MNULL)))
632*4882a593Smuzhiyun 			continue;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		if (pmadapter->bssprio_tbl[j].bssprio_cur ==
635*4882a593Smuzhiyun 		    (mlan_bssprio_node *)&pmadapter->bssprio_tbl[j]
636*4882a593Smuzhiyun 			    .bssprio_head) {
637*4882a593Smuzhiyun 			pmadapter->bssprio_tbl[j].bssprio_cur =
638*4882a593Smuzhiyun 				pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
639*4882a593Smuzhiyun 		}
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 		bssprio_head = bssprio_node =
642*4882a593Smuzhiyun 			pmadapter->bssprio_tbl[j].bssprio_cur;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 		do {
645*4882a593Smuzhiyun 			priv_tmp = bssprio_node->priv;
646*4882a593Smuzhiyun 			if ((priv_tmp->port_ctrl_mode == MTRUE) &&
647*4882a593Smuzhiyun 			    (priv_tmp->port_open == MFALSE)) {
648*4882a593Smuzhiyun 				PRINTM(MINFO,
649*4882a593Smuzhiyun 				       "get_highest_prio_ptr(): "
650*4882a593Smuzhiyun 				       "PORT_CLOSED Ignore pkts from BSS%d\n",
651*4882a593Smuzhiyun 				       priv_tmp->bss_index);
652*4882a593Smuzhiyun 				/* Ignore data pkts from a BSS if port is closed
653*4882a593Smuzhiyun 				 */
654*4882a593Smuzhiyun 				goto next_intf;
655*4882a593Smuzhiyun 			}
656*4882a593Smuzhiyun 			if (priv_tmp->tx_pause == MTRUE) {
657*4882a593Smuzhiyun 				PRINTM(MINFO,
658*4882a593Smuzhiyun 				       "get_highest_prio_ptr(): "
659*4882a593Smuzhiyun 				       "TX PASUE Ignore pkts from BSS%d\n",
660*4882a593Smuzhiyun 				       priv_tmp->bss_index);
661*4882a593Smuzhiyun 				/* Ignore data pkts from a BSS if tx pause */
662*4882a593Smuzhiyun 				goto next_intf;
663*4882a593Smuzhiyun 			}
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_lock(
666*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
667*4882a593Smuzhiyun 				priv_tmp->wmm.ra_list_spinlock);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 			for (i = util_scalar_read(
670*4882a593Smuzhiyun 				     pmadapter->pmoal_handle,
671*4882a593Smuzhiyun 				     &priv_tmp->wmm.highest_queued_prio, MNULL,
672*4882a593Smuzhiyun 				     MNULL);
673*4882a593Smuzhiyun 			     i >= LOW_PRIO_TID; --i) {
674*4882a593Smuzhiyun 				tid_ptr = &(priv_tmp)
675*4882a593Smuzhiyun 						   ->wmm
676*4882a593Smuzhiyun 						   .tid_tbl_ptr[tos_to_tid[i]];
677*4882a593Smuzhiyun 				if (!util_peek_list(pmadapter->pmoal_handle,
678*4882a593Smuzhiyun 						    &tid_ptr->ra_list, MNULL,
679*4882a593Smuzhiyun 						    MNULL))
680*4882a593Smuzhiyun 					continue;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 				/*
683*4882a593Smuzhiyun 				 * Always choose the next ra we transmitted
684*4882a593Smuzhiyun 				 * last time, this way we pick the ra's in
685*4882a593Smuzhiyun 				 * round robin fashion.
686*4882a593Smuzhiyun 				 */
687*4882a593Smuzhiyun 				head = ptr = tid_ptr->ra_list_curr->pnext;
688*4882a593Smuzhiyun 				if (ptr == (raListTbl *)&tid_ptr->ra_list)
689*4882a593Smuzhiyun 					head = ptr = ptr->pnext;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 				do {
692*4882a593Smuzhiyun 					if (!ptr->tx_pause &&
693*4882a593Smuzhiyun 					    util_peek_list(
694*4882a593Smuzhiyun 						    pmadapter->pmoal_handle,
695*4882a593Smuzhiyun 						    &ptr->buf_head, MNULL,
696*4882a593Smuzhiyun 						    MNULL)) {
697*4882a593Smuzhiyun 						/* Because WMM only support
698*4882a593Smuzhiyun 						 * BK/BE/VI/VO, we have 8 tid
699*4882a593Smuzhiyun 						 * We should balance the traffic
700*4882a593Smuzhiyun 						 * of the same AC */
701*4882a593Smuzhiyun 						if (i % 2)
702*4882a593Smuzhiyun 							next_prio = i - 1;
703*4882a593Smuzhiyun 						else
704*4882a593Smuzhiyun 							next_prio = i + 1;
705*4882a593Smuzhiyun 						next_tid =
706*4882a593Smuzhiyun 							tos_to_tid[next_prio];
707*4882a593Smuzhiyun 						if (priv_tmp->wmm.pkts_queued
708*4882a593Smuzhiyun 							    [next_tid] &&
709*4882a593Smuzhiyun 						    (priv_tmp->wmm.pkts_queued
710*4882a593Smuzhiyun 							     [next_tid] >
711*4882a593Smuzhiyun 						     priv_tmp->wmm.pkts_paused
712*4882a593Smuzhiyun 							     [next_tid]))
713*4882a593Smuzhiyun 							util_scalar_write(
714*4882a593Smuzhiyun 								pmadapter->pmoal_handle,
715*4882a593Smuzhiyun 								&priv_tmp->wmm
716*4882a593Smuzhiyun 									 .highest_queued_prio,
717*4882a593Smuzhiyun 								next_prio,
718*4882a593Smuzhiyun 								MNULL, MNULL);
719*4882a593Smuzhiyun 						else
720*4882a593Smuzhiyun 							/* if
721*4882a593Smuzhiyun 							 * highest_queued_prio >
722*4882a593Smuzhiyun 							 * i, set it to i */
723*4882a593Smuzhiyun 							util_scalar_conditional_write(
724*4882a593Smuzhiyun 								pmadapter->pmoal_handle,
725*4882a593Smuzhiyun 								&priv_tmp->wmm
726*4882a593Smuzhiyun 									 .highest_queued_prio,
727*4882a593Smuzhiyun 								MLAN_SCALAR_COND_GREATER_THAN,
728*4882a593Smuzhiyun 								i, i, MNULL,
729*4882a593Smuzhiyun 								MNULL);
730*4882a593Smuzhiyun 						*priv = priv_tmp;
731*4882a593Smuzhiyun 						*tid = tos_to_tid[i];
732*4882a593Smuzhiyun 						/* hold priv->ra_list_spinlock
733*4882a593Smuzhiyun 						 * to maintain ptr */
734*4882a593Smuzhiyun 						PRINTM(MDAT_D,
735*4882a593Smuzhiyun 						       "get highest prio ptr %p, tid %d\n",
736*4882a593Smuzhiyun 						       ptr, *tid);
737*4882a593Smuzhiyun 						LEAVE();
738*4882a593Smuzhiyun 						return ptr;
739*4882a593Smuzhiyun 					}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 					ptr = ptr->pnext;
742*4882a593Smuzhiyun 					if (ptr ==
743*4882a593Smuzhiyun 					    (raListTbl *)&tid_ptr->ra_list)
744*4882a593Smuzhiyun 						ptr = ptr->pnext;
745*4882a593Smuzhiyun 				} while (ptr != head);
746*4882a593Smuzhiyun 			}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 			/* If priv still has packets queued, reset to
749*4882a593Smuzhiyun 			 * HIGH_PRIO_TID */
750*4882a593Smuzhiyun 			if (util_scalar_read(pmadapter->pmoal_handle,
751*4882a593Smuzhiyun 					     &priv_tmp->wmm.tx_pkts_queued,
752*4882a593Smuzhiyun 					     MNULL, MNULL))
753*4882a593Smuzhiyun 				util_scalar_write(
754*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
755*4882a593Smuzhiyun 					&priv_tmp->wmm.highest_queued_prio,
756*4882a593Smuzhiyun 					HIGH_PRIO_TID, MNULL, MNULL);
757*4882a593Smuzhiyun 			else
758*4882a593Smuzhiyun 				/* No packet at any TID for this priv.  Mark as
759*4882a593Smuzhiyun 				 * such to skip checking TIDs for this priv
760*4882a593Smuzhiyun 				 * (until pkt is added). */
761*4882a593Smuzhiyun 				util_scalar_write(
762*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
763*4882a593Smuzhiyun 					&priv_tmp->wmm.highest_queued_prio,
764*4882a593Smuzhiyun 					NO_PKT_PRIO_TID, MNULL, MNULL);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
767*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
768*4882a593Smuzhiyun 				priv_tmp->wmm.ra_list_spinlock);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 		next_intf:
771*4882a593Smuzhiyun 			bssprio_node = bssprio_node->pnext;
772*4882a593Smuzhiyun 			if (bssprio_node ==
773*4882a593Smuzhiyun 			    (mlan_bssprio_node *)&pmadapter->bssprio_tbl[j]
774*4882a593Smuzhiyun 				    .bssprio_head)
775*4882a593Smuzhiyun 				bssprio_node = bssprio_node->pnext;
776*4882a593Smuzhiyun 			pmadapter->bssprio_tbl[j].bssprio_cur = bssprio_node;
777*4882a593Smuzhiyun 		} while (bssprio_node != bssprio_head);
778*4882a593Smuzhiyun 	}
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	LEAVE();
781*4882a593Smuzhiyun 	return MNULL;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun /**
785*4882a593Smuzhiyun  *  @brief This function gets the number of packets in the Tx queue
786*4882a593Smuzhiyun  *
787*4882a593Smuzhiyun  *  @param priv           A pointer to mlan_private
788*4882a593Smuzhiyun  *  @param ptr            A pointer to RA list table
789*4882a593Smuzhiyun  *  @param max_buf_size   Maximum buffer size
790*4882a593Smuzhiyun  *
791*4882a593Smuzhiyun  *  @return             Packet count
792*4882a593Smuzhiyun  */
wlan_num_pkts_in_txq(mlan_private * priv,raListTbl * ptr,int max_buf_size)793*4882a593Smuzhiyun static int wlan_num_pkts_in_txq(mlan_private *priv, raListTbl *ptr,
794*4882a593Smuzhiyun 				int max_buf_size)
795*4882a593Smuzhiyun {
796*4882a593Smuzhiyun 	int count = 0, total_size = 0;
797*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	ENTER();
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	for (pmbuf = (pmlan_buffer)ptr->buf_head.pnext;
802*4882a593Smuzhiyun 	     pmbuf != (pmlan_buffer)(&ptr->buf_head); pmbuf = pmbuf->pnext) {
803*4882a593Smuzhiyun 		total_size += pmbuf->data_len;
804*4882a593Smuzhiyun 		if (total_size < max_buf_size)
805*4882a593Smuzhiyun 			++count;
806*4882a593Smuzhiyun 		else
807*4882a593Smuzhiyun 			break;
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	LEAVE();
811*4882a593Smuzhiyun 	return count;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun /**
815*4882a593Smuzhiyun  *  @brief This function sends a single packet
816*4882a593Smuzhiyun  *
817*4882a593Smuzhiyun  *  @param priv         A pointer to mlan_private
818*4882a593Smuzhiyun  *  @param ptr          A pointer to RA list table
819*4882a593Smuzhiyun  *  @param ptrindex     ptr's TID index
820*4882a593Smuzhiyun  *
821*4882a593Smuzhiyun  *  @return             N/A
822*4882a593Smuzhiyun  */
wlan_send_single_packet(pmlan_private priv,raListTbl * ptr,int ptrindex)823*4882a593Smuzhiyun static INLINE void wlan_send_single_packet(pmlan_private priv, raListTbl *ptr,
824*4882a593Smuzhiyun 					   int ptrindex)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
827*4882a593Smuzhiyun 	pmlan_buffer pmbuf_next;
828*4882a593Smuzhiyun 	mlan_tx_param tx_param;
829*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
830*4882a593Smuzhiyun 	mlan_status status = MLAN_STATUS_SUCCESS;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	ENTER();
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
835*4882a593Smuzhiyun 						&ptr->buf_head, MNULL, MNULL);
836*4882a593Smuzhiyun 	if (pmbuf) {
837*4882a593Smuzhiyun 		PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
838*4882a593Smuzhiyun 		priv->wmm.pkts_queued[ptrindex]--;
839*4882a593Smuzhiyun 		util_scalar_decrement(pmadapter->pmoal_handle,
840*4882a593Smuzhiyun 				      &priv->wmm.tx_pkts_queued, MNULL, MNULL);
841*4882a593Smuzhiyun 		ptr->total_pkts--;
842*4882a593Smuzhiyun 		pmbuf_next = (pmlan_buffer)util_peek_list(
843*4882a593Smuzhiyun 			pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
844*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
845*4882a593Smuzhiyun 			pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 		tx_param.next_pkt_len =
848*4882a593Smuzhiyun 			((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) :
849*4882a593Smuzhiyun 					0);
850*4882a593Smuzhiyun 		status = wlan_process_tx(priv, pmbuf, &tx_param);
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 		if (status == MLAN_STATUS_RESOURCE) {
853*4882a593Smuzhiyun 			/** Queue the packet back at the head */
854*4882a593Smuzhiyun 			PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n",
855*4882a593Smuzhiyun 			       ptr, pmbuf);
856*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_lock(
857*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
858*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 			if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
861*4882a593Smuzhiyun 				pmadapter->callbacks.moal_spin_unlock(
862*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
863*4882a593Smuzhiyun 					priv->wmm.ra_list_spinlock);
864*4882a593Smuzhiyun 				wlan_write_data_complete(pmadapter, pmbuf,
865*4882a593Smuzhiyun 							 MLAN_STATUS_FAILURE);
866*4882a593Smuzhiyun 				LEAVE();
867*4882a593Smuzhiyun 				return;
868*4882a593Smuzhiyun 			}
869*4882a593Smuzhiyun 			priv->wmm.pkts_queued[ptrindex]++;
870*4882a593Smuzhiyun 			util_scalar_increment(pmadapter->pmoal_handle,
871*4882a593Smuzhiyun 					      &priv->wmm.tx_pkts_queued, MNULL,
872*4882a593Smuzhiyun 					      MNULL);
873*4882a593Smuzhiyun 			util_enqueue_list_head(pmadapter->pmoal_handle,
874*4882a593Smuzhiyun 					       &ptr->buf_head,
875*4882a593Smuzhiyun 					       (pmlan_linked_list)pmbuf, MNULL,
876*4882a593Smuzhiyun 					       MNULL);
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 			ptr->total_pkts++;
879*4882a593Smuzhiyun 			pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
880*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
881*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
882*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
883*4882a593Smuzhiyun 		} else {
884*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_lock(
885*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
886*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
887*4882a593Smuzhiyun 			if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
888*4882a593Smuzhiyun 				priv->wmm.packets_out[ptrindex]++;
889*4882a593Smuzhiyun 				priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr =
890*4882a593Smuzhiyun 					ptr;
891*4882a593Smuzhiyun 			}
892*4882a593Smuzhiyun 			pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
893*4882a593Smuzhiyun 				pmadapter->bssprio_tbl[priv->bss_priority]
894*4882a593Smuzhiyun 					.bssprio_cur->pnext;
895*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
896*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
897*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
898*4882a593Smuzhiyun 		}
899*4882a593Smuzhiyun 	} else {
900*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
901*4882a593Smuzhiyun 			pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
902*4882a593Smuzhiyun 		PRINTM(MINFO, "Nothing to send\n");
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	LEAVE();
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun /**
909*4882a593Smuzhiyun  *  @brief This function checks if this mlan_buffer is already processed.
910*4882a593Smuzhiyun  *
911*4882a593Smuzhiyun  *  @param priv     A pointer to mlan_private
912*4882a593Smuzhiyun  *  @param ptr      A pointer to RA list table
913*4882a593Smuzhiyun  *
914*4882a593Smuzhiyun  *  @return         MTRUE or MFALSE
915*4882a593Smuzhiyun  */
wlan_is_ptr_processed(mlan_private * priv,raListTbl * ptr)916*4882a593Smuzhiyun static INLINE int wlan_is_ptr_processed(mlan_private *priv, raListTbl *ptr)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	pmbuf = (pmlan_buffer)util_peek_list(priv->adapter->pmoal_handle,
921*4882a593Smuzhiyun 					     &ptr->buf_head, MNULL, MNULL);
922*4882a593Smuzhiyun 	if (pmbuf && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
923*4882a593Smuzhiyun 		return MTRUE;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	return MFALSE;
926*4882a593Smuzhiyun }
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun /**
929*4882a593Smuzhiyun  *  @brief This function sends a single packet that has been processed
930*4882a593Smuzhiyun  *
931*4882a593Smuzhiyun  *  @param priv         A pointer to mlan_private
932*4882a593Smuzhiyun  *  @param ptr          A pointer to RA list table
933*4882a593Smuzhiyun  *  @param ptrindex     ptr's TID index
934*4882a593Smuzhiyun  *
935*4882a593Smuzhiyun  *  @return             N/A
936*4882a593Smuzhiyun  */
wlan_send_processed_packet(pmlan_private priv,raListTbl * ptr,int ptrindex)937*4882a593Smuzhiyun static INLINE void wlan_send_processed_packet(pmlan_private priv,
938*4882a593Smuzhiyun 					      raListTbl *ptr, int ptrindex)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun 	pmlan_buffer pmbuf_next = MNULL;
941*4882a593Smuzhiyun 	mlan_tx_param tx_param;
942*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
943*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
944*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_FAILURE;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
947*4882a593Smuzhiyun 						&ptr->buf_head, MNULL, MNULL);
948*4882a593Smuzhiyun 	if (pmbuf) {
949*4882a593Smuzhiyun 		pmbuf_next = (pmlan_buffer)util_peek_list(
950*4882a593Smuzhiyun 			pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
951*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
952*4882a593Smuzhiyun 			pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
953*4882a593Smuzhiyun 		tx_param.next_pkt_len =
954*4882a593Smuzhiyun 			((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) :
955*4882a593Smuzhiyun 					0);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 		ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf,
958*4882a593Smuzhiyun 						  &tx_param);
959*4882a593Smuzhiyun 		switch (ret) {
960*4882a593Smuzhiyun #ifdef USB
961*4882a593Smuzhiyun 		case MLAN_STATUS_PRESOURCE:
962*4882a593Smuzhiyun 			PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
963*4882a593Smuzhiyun 			break;
964*4882a593Smuzhiyun #endif
965*4882a593Smuzhiyun 		case MLAN_STATUS_RESOURCE:
966*4882a593Smuzhiyun 			PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
967*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_lock(
968*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
969*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 			if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
972*4882a593Smuzhiyun 				pmadapter->callbacks.moal_spin_unlock(
973*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
974*4882a593Smuzhiyun 					priv->wmm.ra_list_spinlock);
975*4882a593Smuzhiyun 				wlan_write_data_complete(pmadapter, pmbuf,
976*4882a593Smuzhiyun 							 MLAN_STATUS_FAILURE);
977*4882a593Smuzhiyun 				LEAVE();
978*4882a593Smuzhiyun 				return;
979*4882a593Smuzhiyun 			}
980*4882a593Smuzhiyun 			util_enqueue_list_head(pmadapter->pmoal_handle,
981*4882a593Smuzhiyun 					       &ptr->buf_head,
982*4882a593Smuzhiyun 					       (pmlan_linked_list)pmbuf, MNULL,
983*4882a593Smuzhiyun 					       MNULL);
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 			pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
986*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
987*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
988*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
989*4882a593Smuzhiyun 			break;
990*4882a593Smuzhiyun 		case MLAN_STATUS_FAILURE:
991*4882a593Smuzhiyun 			PRINTM(MERROR, "Error: Failed to write data\n");
992*4882a593Smuzhiyun 			pmadapter->dbg.num_tx_host_to_card_failure++;
993*4882a593Smuzhiyun 			pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
994*4882a593Smuzhiyun 			wlan_write_data_complete(pmadapter, pmbuf, ret);
995*4882a593Smuzhiyun 			break;
996*4882a593Smuzhiyun 		case MLAN_STATUS_PENDING:
997*4882a593Smuzhiyun 			break;
998*4882a593Smuzhiyun 		case MLAN_STATUS_SUCCESS:
999*4882a593Smuzhiyun 			DBG_HEXDUMP(MDAT_D, "Tx",
1000*4882a593Smuzhiyun 				    pmbuf->pbuf + pmbuf->data_offset,
1001*4882a593Smuzhiyun 				    MIN(pmbuf->data_len + sizeof(TxPD),
1002*4882a593Smuzhiyun 					MAX_DATA_DUMP_LEN));
1003*4882a593Smuzhiyun 			wlan_write_data_complete(pmadapter, pmbuf, ret);
1004*4882a593Smuzhiyun 			break;
1005*4882a593Smuzhiyun 		default:
1006*4882a593Smuzhiyun 			break;
1007*4882a593Smuzhiyun 		}
1008*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_RESOURCE) {
1009*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_lock(
1010*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
1011*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
1012*4882a593Smuzhiyun 			if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
1013*4882a593Smuzhiyun 				priv->wmm.packets_out[ptrindex]++;
1014*4882a593Smuzhiyun 				priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr =
1015*4882a593Smuzhiyun 					ptr;
1016*4882a593Smuzhiyun 				ptr->total_pkts--;
1017*4882a593Smuzhiyun 			}
1018*4882a593Smuzhiyun 			pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
1019*4882a593Smuzhiyun 				pmadapter->bssprio_tbl[priv->bss_priority]
1020*4882a593Smuzhiyun 					.bssprio_cur->pnext;
1021*4882a593Smuzhiyun 			priv->wmm.pkts_queued[ptrindex]--;
1022*4882a593Smuzhiyun 			util_scalar_decrement(pmadapter->pmoal_handle,
1023*4882a593Smuzhiyun 					      &priv->wmm.tx_pkts_queued, MNULL,
1024*4882a593Smuzhiyun 					      MNULL);
1025*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
1026*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
1027*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
1028*4882a593Smuzhiyun 		}
1029*4882a593Smuzhiyun 	} else {
1030*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
1031*4882a593Smuzhiyun 			pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun /**
1036*4882a593Smuzhiyun  *  @brief This function dequeues a packet
1037*4882a593Smuzhiyun  *
1038*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter
1039*4882a593Smuzhiyun  *
1040*4882a593Smuzhiyun  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1041*4882a593Smuzhiyun  */
wlan_dequeue_tx_packet(pmlan_adapter pmadapter)1042*4882a593Smuzhiyun static int wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
1043*4882a593Smuzhiyun {
1044*4882a593Smuzhiyun 	raListTbl *ptr;
1045*4882a593Smuzhiyun 	pmlan_private priv = MNULL;
1046*4882a593Smuzhiyun 	int ptrindex = 0;
1047*4882a593Smuzhiyun 	t_u8 ra[MLAN_MAC_ADDR_LENGTH];
1048*4882a593Smuzhiyun 	int tid_del = 0;
1049*4882a593Smuzhiyun 	int tid = 0;
1050*4882a593Smuzhiyun 	mlan_buffer *pmbuf = MNULL;
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	ENTER();
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex);
1055*4882a593Smuzhiyun 	if (!ptr) {
1056*4882a593Smuzhiyun 		LEAVE();
1057*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
1058*4882a593Smuzhiyun 	}
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	/*  Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr
1061*4882a593Smuzhiyun 	 *  when it returns a pointer (for the priv it returns),
1062*4882a593Smuzhiyun 	 *  and is unlocked in wlan_send_processed_packet,
1063*4882a593Smuzhiyun 	 *  wlan_send_single_packet or wlan_11n_aggregate_pkt.
1064*4882a593Smuzhiyun 	 *  The spinlock would be required for some parts of both of function.
1065*4882a593Smuzhiyun 	 *  But, the the bulk of these function will execute w/o spinlock.
1066*4882a593Smuzhiyun 	 *  Unlocking the spinlock inside these function will help us avoid
1067*4882a593Smuzhiyun 	 *  taking the spinlock again, check to see if the ptr is still
1068*4882a593Smuzhiyun 	 *  valid and then proceed. This is done purely to increase
1069*4882a593Smuzhiyun 	 *  execution time. */
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	/* Note:- Also, anybody adding code which does not get into
1072*4882a593Smuzhiyun 	 * wlan_send_processed_packet, wlan_send_single_packet, or
1073*4882a593Smuzhiyun 	 * wlan_11n_aggregate_pkt should make sure ra_list_spinlock
1074*4882a593Smuzhiyun 	 * is freed. Otherwise there would be a lock up. */
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	tid = wlan_get_tid(priv->adapter, ptr);
1077*4882a593Smuzhiyun 	if (tid >= MAX_NUM_TID)
1078*4882a593Smuzhiyun 		tid = wlan_wmm_downgrade_tid(priv, tid);
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	if (wlan_is_ptr_processed(priv, ptr)) {
1081*4882a593Smuzhiyun 		wlan_send_processed_packet(priv, ptr, ptrindex);
1082*4882a593Smuzhiyun 		LEAVE();
1083*4882a593Smuzhiyun 		return MLAN_STATUS_SUCCESS;
1084*4882a593Smuzhiyun 	}
1085*4882a593Smuzhiyun 	if (ptr->del_ba_count >= DEL_BA_THRESHOLD)
1086*4882a593Smuzhiyun 		wlan_update_del_ba_count(priv, ptr);
1087*4882a593Smuzhiyun 	if (pmadapter->tp_state_on) {
1088*4882a593Smuzhiyun 		pmbuf = (pmlan_buffer)util_peek_list(
1089*4882a593Smuzhiyun 			pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
1090*4882a593Smuzhiyun 		if (pmbuf) {
1091*4882a593Smuzhiyun 			pmadapter->callbacks.moal_tp_accounting(
1092*4882a593Smuzhiyun 				pmadapter->pmoal_handle, pmbuf->pdesc, 3);
1093*4882a593Smuzhiyun 			if (pmadapter->tp_state_drop_point == 3) {
1094*4882a593Smuzhiyun 				pmbuf = (pmlan_buffer)util_dequeue_list(
1095*4882a593Smuzhiyun 					pmadapter->pmoal_handle, &ptr->buf_head,
1096*4882a593Smuzhiyun 					MNULL, MNULL);
1097*4882a593Smuzhiyun 				PRINTM(MERROR, "Dequeuing the packet %p %p\n",
1098*4882a593Smuzhiyun 				       ptr, pmbuf);
1099*4882a593Smuzhiyun 				priv->wmm.pkts_queued[ptrindex]--;
1100*4882a593Smuzhiyun 				util_scalar_decrement(pmadapter->pmoal_handle,
1101*4882a593Smuzhiyun 						      &priv->wmm.tx_pkts_queued,
1102*4882a593Smuzhiyun 						      MNULL, MNULL);
1103*4882a593Smuzhiyun 				ptr->total_pkts--;
1104*4882a593Smuzhiyun 				pmadapter->callbacks.moal_spin_unlock(
1105*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
1106*4882a593Smuzhiyun 					priv->wmm.ra_list_spinlock);
1107*4882a593Smuzhiyun 				wlan_write_data_complete(pmadapter, pmbuf,
1108*4882a593Smuzhiyun 							 MLAN_STATUS_SUCCESS);
1109*4882a593Smuzhiyun 				LEAVE();
1110*4882a593Smuzhiyun 				return MLAN_STATUS_SUCCESS;
1111*4882a593Smuzhiyun 			}
1112*4882a593Smuzhiyun 		}
1113*4882a593Smuzhiyun 	}
1114*4882a593Smuzhiyun 	if (!ptr->is_wmm_enabled ||
1115*4882a593Smuzhiyun 	    (ptr->ba_status || ptr->del_ba_count >= DEL_BA_THRESHOLD)
1116*4882a593Smuzhiyun #ifdef STA_SUPPORT
1117*4882a593Smuzhiyun 	    || priv->wps.session_enable
1118*4882a593Smuzhiyun #endif /* STA_SUPPORT */
1119*4882a593Smuzhiyun 	) {
1120*4882a593Smuzhiyun 		if (ptr->is_wmm_enabled && ptr->ba_status &&
1121*4882a593Smuzhiyun 		    ptr->amsdu_in_ampdu &&
1122*4882a593Smuzhiyun 		    wlan_is_amsdu_allowed(priv, ptr, tid) &&
1123*4882a593Smuzhiyun 		    (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
1124*4882a593Smuzhiyun 		     MIN_NUM_AMSDU)) {
1125*4882a593Smuzhiyun 			wlan_11n_aggregate_pkt(priv, ptr, priv->intf_hr_len,
1126*4882a593Smuzhiyun 					       ptrindex);
1127*4882a593Smuzhiyun 		} else
1128*4882a593Smuzhiyun 			wlan_send_single_packet(priv, ptr, ptrindex);
1129*4882a593Smuzhiyun 	} else {
1130*4882a593Smuzhiyun 		if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
1131*4882a593Smuzhiyun 		    (ptr->packet_count > ptr->ba_packet_threshold)) {
1132*4882a593Smuzhiyun 			if (wlan_is_bastream_avail(priv)) {
1133*4882a593Smuzhiyun 				PRINTM(MINFO,
1134*4882a593Smuzhiyun 				       "BA setup threshold %d reached. tid=%d\n",
1135*4882a593Smuzhiyun 				       ptr->packet_count, tid);
1136*4882a593Smuzhiyun 				if (!wlan_11n_get_txbastream_tbl(
1137*4882a593Smuzhiyun 					    priv, tid, ptr->ra, MFALSE)) {
1138*4882a593Smuzhiyun 					wlan_11n_create_txbastream_tbl(
1139*4882a593Smuzhiyun 						priv, ptr->ra, tid,
1140*4882a593Smuzhiyun 						BA_STREAM_SETUP_INPROGRESS);
1141*4882a593Smuzhiyun 					wlan_send_addba(priv, tid, ptr->ra);
1142*4882a593Smuzhiyun 				}
1143*4882a593Smuzhiyun 			} else if (wlan_find_stream_to_delete(priv, ptr, tid,
1144*4882a593Smuzhiyun 							      &tid_del, ra)) {
1145*4882a593Smuzhiyun 				PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del,
1146*4882a593Smuzhiyun 				       tid);
1147*4882a593Smuzhiyun 				if (!wlan_11n_get_txbastream_tbl(
1148*4882a593Smuzhiyun 					    priv, tid, ptr->ra, MFALSE)) {
1149*4882a593Smuzhiyun 					wlan_11n_create_txbastream_tbl(
1150*4882a593Smuzhiyun 						priv, ptr->ra, tid,
1151*4882a593Smuzhiyun 						BA_STREAM_SETUP_INPROGRESS);
1152*4882a593Smuzhiyun 					wlan_send_delba(priv, MNULL, tid_del,
1153*4882a593Smuzhiyun 							ra, 1);
1154*4882a593Smuzhiyun 				}
1155*4882a593Smuzhiyun 			}
1156*4882a593Smuzhiyun 		}
1157*4882a593Smuzhiyun 		if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
1158*4882a593Smuzhiyun 		    (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
1159*4882a593Smuzhiyun 		     MIN_NUM_AMSDU)) {
1160*4882a593Smuzhiyun 			wlan_11n_aggregate_pkt(priv, ptr, priv->intf_hr_len,
1161*4882a593Smuzhiyun 					       ptrindex);
1162*4882a593Smuzhiyun 		} else {
1163*4882a593Smuzhiyun 			wlan_send_single_packet(priv, ptr, ptrindex);
1164*4882a593Smuzhiyun 		}
1165*4882a593Smuzhiyun 	}
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	LEAVE();
1168*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun /**
1172*4882a593Smuzhiyun  *  @brief update tx_pause flag in ra_list
1173*4882a593Smuzhiyun  *
1174*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
1175*4882a593Smuzhiyun  *  @param mac        peer mac address
1176*4882a593Smuzhiyun  *  @param tx_pause   tx_pause flag (0/1)
1177*4882a593Smuzhiyun  *
1178*4882a593Smuzhiyun  *
1179*4882a593Smuzhiyun  *  @return           packets queued for this mac
1180*4882a593Smuzhiyun  */
wlan_update_ralist_tx_pause(pmlan_private priv,t_u8 * mac,t_u8 tx_pause)1181*4882a593Smuzhiyun t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun 	raListTbl *ra_list;
1184*4882a593Smuzhiyun 	int i;
1185*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
1186*4882a593Smuzhiyun 	t_u32 pkt_cnt = 0;
1187*4882a593Smuzhiyun 	t_u32 tx_pkts_queued = 0;
1188*4882a593Smuzhiyun 	ENTER();
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1191*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
1192*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
1193*4882a593Smuzhiyun 		ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
1194*4882a593Smuzhiyun 		if (ra_list && ra_list->tx_pause != tx_pause) {
1195*4882a593Smuzhiyun 			pkt_cnt += ra_list->total_pkts;
1196*4882a593Smuzhiyun 			ra_list->tx_pause = tx_pause;
1197*4882a593Smuzhiyun 			if (tx_pause)
1198*4882a593Smuzhiyun 				priv->wmm.pkts_paused[i] += ra_list->total_pkts;
1199*4882a593Smuzhiyun 			else
1200*4882a593Smuzhiyun 				priv->wmm.pkts_paused[i] -= ra_list->total_pkts;
1201*4882a593Smuzhiyun 		}
1202*4882a593Smuzhiyun 	}
1203*4882a593Smuzhiyun 	if (pkt_cnt) {
1204*4882a593Smuzhiyun 		tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
1205*4882a593Smuzhiyun 						  &priv->wmm.tx_pkts_queued,
1206*4882a593Smuzhiyun 						  MNULL, MNULL);
1207*4882a593Smuzhiyun 		if (tx_pause)
1208*4882a593Smuzhiyun 			tx_pkts_queued -= pkt_cnt;
1209*4882a593Smuzhiyun 		else
1210*4882a593Smuzhiyun 			tx_pkts_queued += pkt_cnt;
1211*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
1212*4882a593Smuzhiyun 				  &priv->wmm.tx_pkts_queued, tx_pkts_queued,
1213*4882a593Smuzhiyun 				  MNULL, MNULL);
1214*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
1215*4882a593Smuzhiyun 				  &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
1216*4882a593Smuzhiyun 				  MNULL, MNULL);
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1219*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
1220*4882a593Smuzhiyun 	LEAVE();
1221*4882a593Smuzhiyun 	return pkt_cnt;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun #ifdef STA_SUPPORT
1225*4882a593Smuzhiyun /**
1226*4882a593Smuzhiyun  *  @brief update tx_pause flag in none tdls ra_list
1227*4882a593Smuzhiyun  *
1228*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
1229*4882a593Smuzhiyun  *  @param mac        peer mac address
1230*4882a593Smuzhiyun  *  @param tx_pause   tx_pause flag (0/1)
1231*4882a593Smuzhiyun  *
1232*4882a593Smuzhiyun  *  @return           N/A
1233*4882a593Smuzhiyun  */
wlan_update_non_tdls_ralist(mlan_private * priv,t_u8 * mac,t_u8 tx_pause)1234*4882a593Smuzhiyun t_void wlan_update_non_tdls_ralist(mlan_private *priv, t_u8 *mac, t_u8 tx_pause)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	raListTbl *ra_list;
1237*4882a593Smuzhiyun 	int i;
1238*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
1239*4882a593Smuzhiyun 	t_u32 pkt_cnt = 0;
1240*4882a593Smuzhiyun 	t_u32 tx_pkts_queued = 0;
1241*4882a593Smuzhiyun 	ENTER();
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1244*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
1245*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
1246*4882a593Smuzhiyun 		ra_list = (raListTbl *)util_peek_list(
1247*4882a593Smuzhiyun 			priv->adapter->pmoal_handle,
1248*4882a593Smuzhiyun 			&priv->wmm.tid_tbl_ptr[i].ra_list, MNULL, MNULL);
1249*4882a593Smuzhiyun 		while (ra_list &&
1250*4882a593Smuzhiyun 		       (ra_list !=
1251*4882a593Smuzhiyun 			(raListTbl *)&priv->wmm.tid_tbl_ptr[i].ra_list)) {
1252*4882a593Smuzhiyun 			if (memcmp(priv->adapter, ra_list->ra, mac,
1253*4882a593Smuzhiyun 				   MLAN_MAC_ADDR_LENGTH) &&
1254*4882a593Smuzhiyun 			    ra_list->tx_pause != tx_pause) {
1255*4882a593Smuzhiyun 				pkt_cnt += ra_list->total_pkts;
1256*4882a593Smuzhiyun 				ra_list->tx_pause = tx_pause;
1257*4882a593Smuzhiyun 				if (tx_pause)
1258*4882a593Smuzhiyun 					priv->wmm.pkts_paused[i] +=
1259*4882a593Smuzhiyun 						ra_list->total_pkts;
1260*4882a593Smuzhiyun 				else
1261*4882a593Smuzhiyun 					priv->wmm.pkts_paused[i] -=
1262*4882a593Smuzhiyun 						ra_list->total_pkts;
1263*4882a593Smuzhiyun 			}
1264*4882a593Smuzhiyun 			ra_list = ra_list->pnext;
1265*4882a593Smuzhiyun 		}
1266*4882a593Smuzhiyun 	}
1267*4882a593Smuzhiyun 	if (pkt_cnt) {
1268*4882a593Smuzhiyun 		tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
1269*4882a593Smuzhiyun 						  &priv->wmm.tx_pkts_queued,
1270*4882a593Smuzhiyun 						  MNULL, MNULL);
1271*4882a593Smuzhiyun 		if (tx_pause)
1272*4882a593Smuzhiyun 			tx_pkts_queued -= pkt_cnt;
1273*4882a593Smuzhiyun 		else
1274*4882a593Smuzhiyun 			tx_pkts_queued += pkt_cnt;
1275*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
1276*4882a593Smuzhiyun 				  &priv->wmm.tx_pkts_queued, tx_pkts_queued,
1277*4882a593Smuzhiyun 				  MNULL, MNULL);
1278*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
1279*4882a593Smuzhiyun 				  &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
1280*4882a593Smuzhiyun 				  MNULL, MNULL);
1281*4882a593Smuzhiyun 	}
1282*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1283*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
1284*4882a593Smuzhiyun 	LEAVE();
1285*4882a593Smuzhiyun 	return;
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun /**
1289*4882a593Smuzhiyun  *  @brief find tdls buffer from ralist
1290*4882a593Smuzhiyun  *
1291*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
1292*4882a593Smuzhiyun  *  @param ralist     A pointer to ralistTbl
1293*4882a593Smuzhiyun  *  @param mac        TDLS peer mac address
1294*4882a593Smuzhiyun  *
1295*4882a593Smuzhiyun  *  @return           pmlan_buffer or MNULL
1296*4882a593Smuzhiyun  */
wlan_find_tdls_packets(mlan_private * priv,raListTbl * ra_list,t_u8 * mac)1297*4882a593Smuzhiyun static pmlan_buffer wlan_find_tdls_packets(mlan_private *priv,
1298*4882a593Smuzhiyun 					   raListTbl *ra_list, t_u8 *mac)
1299*4882a593Smuzhiyun {
1300*4882a593Smuzhiyun 	pmlan_buffer pmbuf = MNULL;
1301*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
1302*4882a593Smuzhiyun 	t_u8 ra[MLAN_MAC_ADDR_LENGTH];
1303*4882a593Smuzhiyun 	ENTER();
1304*4882a593Smuzhiyun 	pmbuf = (pmlan_buffer)util_peek_list(priv->adapter->pmoal_handle,
1305*4882a593Smuzhiyun 					     &ra_list->buf_head, MNULL, MNULL);
1306*4882a593Smuzhiyun 	if (!pmbuf) {
1307*4882a593Smuzhiyun 		LEAVE();
1308*4882a593Smuzhiyun 		return MNULL;
1309*4882a593Smuzhiyun 	}
1310*4882a593Smuzhiyun 	while (pmbuf != (pmlan_buffer)&ra_list->buf_head) {
1311*4882a593Smuzhiyun 		memcpy_ext(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
1312*4882a593Smuzhiyun 			   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
1313*4882a593Smuzhiyun 		if (!memcmp(priv->adapter, ra, mac, MLAN_MAC_ADDR_LENGTH)) {
1314*4882a593Smuzhiyun 			LEAVE();
1315*4882a593Smuzhiyun 			return pmbuf;
1316*4882a593Smuzhiyun 		}
1317*4882a593Smuzhiyun 		pmbuf = pmbuf->pnext;
1318*4882a593Smuzhiyun 	}
1319*4882a593Smuzhiyun 	LEAVE();
1320*4882a593Smuzhiyun 	return MNULL;
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun /**
1324*4882a593Smuzhiyun  *  @brief find tdls buffer from tdls pending queue
1325*4882a593Smuzhiyun  *
1326*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
1327*4882a593Smuzhiyun  *  @param mac        TDLS peer mac address
1328*4882a593Smuzhiyun  *
1329*4882a593Smuzhiyun  *  @return           pmlan_buffer or MNULL
1330*4882a593Smuzhiyun  */
wlan_find_packets_tdls_txq(mlan_private * priv,t_u8 * mac)1331*4882a593Smuzhiyun static pmlan_buffer wlan_find_packets_tdls_txq(mlan_private *priv, t_u8 *mac)
1332*4882a593Smuzhiyun {
1333*4882a593Smuzhiyun 	pmlan_buffer pmbuf = MNULL;
1334*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
1335*4882a593Smuzhiyun 	t_u8 ra[MLAN_MAC_ADDR_LENGTH];
1336*4882a593Smuzhiyun 	ENTER();
1337*4882a593Smuzhiyun 	pmbuf = (pmlan_buffer)util_peek_list(priv->adapter->pmoal_handle,
1338*4882a593Smuzhiyun 					     &priv->tdls_pending_txq, MNULL,
1339*4882a593Smuzhiyun 					     MNULL);
1340*4882a593Smuzhiyun 	if (!pmbuf) {
1341*4882a593Smuzhiyun 		LEAVE();
1342*4882a593Smuzhiyun 		return MNULL;
1343*4882a593Smuzhiyun 	}
1344*4882a593Smuzhiyun 	while (pmbuf != (pmlan_buffer)&priv->tdls_pending_txq) {
1345*4882a593Smuzhiyun 		memcpy_ext(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
1346*4882a593Smuzhiyun 			   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
1347*4882a593Smuzhiyun 		if (!memcmp(priv->adapter, ra, mac, MLAN_MAC_ADDR_LENGTH)) {
1348*4882a593Smuzhiyun 			LEAVE();
1349*4882a593Smuzhiyun 			return pmbuf;
1350*4882a593Smuzhiyun 		}
1351*4882a593Smuzhiyun 		pmbuf = pmbuf->pnext;
1352*4882a593Smuzhiyun 	}
1353*4882a593Smuzhiyun 	LEAVE();
1354*4882a593Smuzhiyun 	return MNULL;
1355*4882a593Smuzhiyun }
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun /**
1358*4882a593Smuzhiyun  *  @brief Remove TDLS ralist and move packets to AP's ralist
1359*4882a593Smuzhiyun  *
1360*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
1361*4882a593Smuzhiyun  *  @param mac        TDLS peer mac address
1362*4882a593Smuzhiyun  *
1363*4882a593Smuzhiyun  *  @return           N/A
1364*4882a593Smuzhiyun  */
wlan_wmm_delete_tdls_ralist(pmlan_private priv,t_u8 * mac)1365*4882a593Smuzhiyun static t_void wlan_wmm_delete_tdls_ralist(pmlan_private priv, t_u8 *mac)
1366*4882a593Smuzhiyun {
1367*4882a593Smuzhiyun 	raListTbl *ra_list;
1368*4882a593Smuzhiyun 	raListTbl *ra_list_ap = MNULL;
1369*4882a593Smuzhiyun 	int i;
1370*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
1371*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
1372*4882a593Smuzhiyun 	ENTER();
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
1375*4882a593Smuzhiyun 		ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
1376*4882a593Smuzhiyun 		if (ra_list) {
1377*4882a593Smuzhiyun 			PRINTM(MDATA, "delete TDLS ralist %p\n", ra_list);
1378*4882a593Smuzhiyun 			ra_list_ap = (raListTbl *)util_peek_list(
1379*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
1380*4882a593Smuzhiyun 				&priv->wmm.tid_tbl_ptr[i].ra_list, MNULL,
1381*4882a593Smuzhiyun 				MNULL);
1382*4882a593Smuzhiyun 			if (!ra_list_ap) {
1383*4882a593Smuzhiyun 				LEAVE();
1384*4882a593Smuzhiyun 				return;
1385*4882a593Smuzhiyun 			}
1386*4882a593Smuzhiyun 			while ((pmbuf = (pmlan_buffer)util_peek_list(
1387*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
1388*4882a593Smuzhiyun 					&ra_list->buf_head, MNULL, MNULL))) {
1389*4882a593Smuzhiyun 				util_unlink_list(pmadapter->pmoal_handle,
1390*4882a593Smuzhiyun 						 &ra_list->buf_head,
1391*4882a593Smuzhiyun 						 (pmlan_linked_list)pmbuf,
1392*4882a593Smuzhiyun 						 MNULL, MNULL);
1393*4882a593Smuzhiyun 				util_enqueue_list_tail(pmadapter->pmoal_handle,
1394*4882a593Smuzhiyun 						       &ra_list_ap->buf_head,
1395*4882a593Smuzhiyun 						       (pmlan_linked_list)pmbuf,
1396*4882a593Smuzhiyun 						       MNULL, MNULL);
1397*4882a593Smuzhiyun 				ra_list_ap->total_pkts++;
1398*4882a593Smuzhiyun 				ra_list_ap->packet_count++;
1399*4882a593Smuzhiyun 			}
1400*4882a593Smuzhiyun 			util_free_list_head(
1401*4882a593Smuzhiyun 				(t_void *)pmadapter->pmoal_handle,
1402*4882a593Smuzhiyun 				&ra_list->buf_head,
1403*4882a593Smuzhiyun 				pmadapter->callbacks.moal_free_lock);
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 			util_unlink_list(pmadapter->pmoal_handle,
1406*4882a593Smuzhiyun 					 &priv->wmm.tid_tbl_ptr[i].ra_list,
1407*4882a593Smuzhiyun 					 (pmlan_linked_list)ra_list, MNULL,
1408*4882a593Smuzhiyun 					 MNULL);
1409*4882a593Smuzhiyun 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
1410*4882a593Smuzhiyun 							(t_u8 *)ra_list);
1411*4882a593Smuzhiyun 			if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
1412*4882a593Smuzhiyun 				priv->wmm.tid_tbl_ptr[i].ra_list_curr =
1413*4882a593Smuzhiyun 					ra_list_ap;
1414*4882a593Smuzhiyun 		}
1415*4882a593Smuzhiyun 	}
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 	LEAVE();
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun #endif /* STA_SUPPORT */
1420*4882a593Smuzhiyun /********************************************************
1421*4882a593Smuzhiyun 			Global Functions
1422*4882a593Smuzhiyun ********************************************************/
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun /**
1425*4882a593Smuzhiyun  *  @brief Get the threshold value for BA setup using system time.
1426*4882a593Smuzhiyun  *
1427*4882a593Smuzhiyun  *  @param pmadapter       Pointer to the mlan_adapter structure
1428*4882a593Smuzhiyun  *
1429*4882a593Smuzhiyun  *  @return         threshold value.
1430*4882a593Smuzhiyun  */
wlan_get_random_ba_threshold(pmlan_adapter pmadapter)1431*4882a593Smuzhiyun t_u8 wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
1432*4882a593Smuzhiyun {
1433*4882a593Smuzhiyun 	t_u32 sec, usec;
1434*4882a593Smuzhiyun 	t_u8 ba_threshold = 0;
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	ENTER();
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	/* setup ba_packet_threshold here random number between
1439*4882a593Smuzhiyun 	   [BA_SETUP_PACKET_OFFSET,
1440*4882a593Smuzhiyun 	   BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun #define BA_SETUP_MAX_PACKET_THRESHOLD 16
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
1445*4882a593Smuzhiyun 						  &usec);
1446*4882a593Smuzhiyun 	sec = (sec & 0xFFFF) + (sec >> 16);
1447*4882a593Smuzhiyun 	usec = (usec & 0xFFFF) + (usec >> 16);
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	ba_threshold = (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
1450*4882a593Smuzhiyun 		       pmadapter->min_ba_threshold;
1451*4882a593Smuzhiyun 	PRINTM(MINFO, "pmadapter->min_ba_threshold = %d\n",
1452*4882a593Smuzhiyun 	       pmadapter->min_ba_threshold);
1453*4882a593Smuzhiyun 	PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	LEAVE();
1456*4882a593Smuzhiyun 	return ba_threshold;
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun /**
1460*4882a593Smuzhiyun  *  @brief  This function cleans Tx/Rx queues
1461*4882a593Smuzhiyun  *
1462*4882a593Smuzhiyun  *  @param priv		A pointer to mlan_private
1463*4882a593Smuzhiyun  *
1464*4882a593Smuzhiyun  *  @return		N/A
1465*4882a593Smuzhiyun  */
wlan_clean_txrx(pmlan_private priv)1466*4882a593Smuzhiyun t_void wlan_clean_txrx(pmlan_private priv)
1467*4882a593Smuzhiyun {
1468*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
1469*4882a593Smuzhiyun 	t_u8 i = 0;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	ENTER();
1472*4882a593Smuzhiyun 	wlan_cleanup_bypass_txq(priv);
1473*4882a593Smuzhiyun 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1474*4882a593Smuzhiyun 		wlan_cleanup_tdls_txq(priv);
1475*4882a593Smuzhiyun 	}
1476*4882a593Smuzhiyun 	wlan_11n_cleanup_reorder_tbl(priv);
1477*4882a593Smuzhiyun 	wlan_11n_deleteall_txbastream_tbl(priv);
1478*4882a593Smuzhiyun #if defined(USB)
1479*4882a593Smuzhiyun 	if (IS_USB(pmadapter->card_type))
1480*4882a593Smuzhiyun 		wlan_reset_usb_tx_aggr(priv->adapter);
1481*4882a593Smuzhiyun #endif
1482*4882a593Smuzhiyun #ifdef PCIE
1483*4882a593Smuzhiyun 	if (IS_PCIE(pmadapter->card_type))
1484*4882a593Smuzhiyun 		wlan_clean_pcie_ring_buf(priv->adapter);
1485*4882a593Smuzhiyun #endif
1486*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1487*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
1488*4882a593Smuzhiyun 	wlan_wmm_cleanup_queues(priv);
1489*4882a593Smuzhiyun 	wlan_wmm_delete_all_ralist(priv);
1490*4882a593Smuzhiyun 	memcpy_ext(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid),
1491*4882a593Smuzhiyun 		   sizeof(tos_to_tid));
1492*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; i++)
1493*4882a593Smuzhiyun 		tos_to_tid_inv[tos_to_tid[i]] = (t_u8)i;
1494*4882a593Smuzhiyun #ifdef UAP_SUPPORT
1495*4882a593Smuzhiyun 	priv->num_drop_pkts = 0;
1496*4882a593Smuzhiyun #endif
1497*4882a593Smuzhiyun #ifdef SDIO
1498*4882a593Smuzhiyun 	if (IS_SD(pmadapter->card_type)) {
1499*4882a593Smuzhiyun 		memset(pmadapter, pmadapter->pcard_sd->mpa_tx_count, 0,
1500*4882a593Smuzhiyun 		       sizeof(pmadapter->pcard_sd->mpa_tx_count));
1501*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_sent_no_ports = 0;
1502*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_sent_last_pkt = 0;
1503*4882a593Smuzhiyun 		memset(pmadapter, pmadapter->pcard_sd->mpa_rx_count, 0,
1504*4882a593Smuzhiyun 		       sizeof(pmadapter->pcard_sd->mpa_rx_count));
1505*4882a593Smuzhiyun 	}
1506*4882a593Smuzhiyun #endif
1507*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1508*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 	LEAVE();
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun /**
1514*4882a593Smuzhiyun  *  @brief Set the WMM queue priorities to their default values
1515*4882a593Smuzhiyun  *
1516*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
1517*4882a593Smuzhiyun  *
1518*4882a593Smuzhiyun  *  @return         N/A
1519*4882a593Smuzhiyun  */
wlan_wmm_default_queue_priorities(pmlan_private priv)1520*4882a593Smuzhiyun void wlan_wmm_default_queue_priorities(pmlan_private priv)
1521*4882a593Smuzhiyun {
1522*4882a593Smuzhiyun 	ENTER();
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	/* Default queue priorities: VO->VI->BE->BK */
1525*4882a593Smuzhiyun 	priv->wmm.queue_priority[0] = WMM_AC_VO;
1526*4882a593Smuzhiyun 	priv->wmm.queue_priority[1] = WMM_AC_VI;
1527*4882a593Smuzhiyun 	priv->wmm.queue_priority[2] = WMM_AC_BE;
1528*4882a593Smuzhiyun 	priv->wmm.queue_priority[3] = WMM_AC_BK;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 	LEAVE();
1531*4882a593Smuzhiyun }
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun /**
1534*4882a593Smuzhiyun  *  @brief Initialize WMM priority queues
1535*4882a593Smuzhiyun  *
1536*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
1537*4882a593Smuzhiyun  *  @param pwmm_ie  Pointer to the IEEEtypes_WmmParameter_t data struct
1538*4882a593Smuzhiyun  *
1539*4882a593Smuzhiyun  *  @return         N/A
1540*4882a593Smuzhiyun  */
wlan_wmm_setup_queue_priorities(pmlan_private priv,IEEEtypes_WmmParameter_t * pwmm_ie)1541*4882a593Smuzhiyun void wlan_wmm_setup_queue_priorities(pmlan_private priv,
1542*4882a593Smuzhiyun 				     IEEEtypes_WmmParameter_t *pwmm_ie)
1543*4882a593Smuzhiyun {
1544*4882a593Smuzhiyun 	t_u16 cw_min, avg_back_off, tmp[4];
1545*4882a593Smuzhiyun 	t_u32 i, j, num_ac;
1546*4882a593Smuzhiyun 	t_u8 ac_idx;
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	ENTER();
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 	if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
1551*4882a593Smuzhiyun 		/* WMM is not enabled, just set the defaults and return */
1552*4882a593Smuzhiyun 		wlan_wmm_default_queue_priorities(priv);
1553*4882a593Smuzhiyun 		LEAVE();
1554*4882a593Smuzhiyun 		return;
1555*4882a593Smuzhiyun 	}
1556*4882a593Smuzhiyun 	memset(priv->adapter, tmp, 0, sizeof(tmp));
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	HEXDUMP("WMM: setup_queue_priorities: param IE", (t_u8 *)pwmm_ie,
1559*4882a593Smuzhiyun 		sizeof(IEEEtypes_WmmParameter_t));
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	PRINTM(MINFO,
1562*4882a593Smuzhiyun 	       "WMM Parameter IE: version=%d, "
1563*4882a593Smuzhiyun 	       "qos_info Parameter Set Count=%d, Reserved=%#x\n",
1564*4882a593Smuzhiyun 	       pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
1565*4882a593Smuzhiyun 	       pwmm_ie->reserved);
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun 	for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
1568*4882a593Smuzhiyun 		cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
1569*4882a593Smuzhiyun 		avg_back_off = (cw_min >> 1) +
1570*4882a593Smuzhiyun 			       pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun 		ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac]
1573*4882a593Smuzhiyun 						     .aci_aifsn.aci];
1574*4882a593Smuzhiyun 		priv->wmm.queue_priority[ac_idx] = ac_idx;
1575*4882a593Smuzhiyun 		tmp[ac_idx] = avg_back_off;
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 		PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
1578*4882a593Smuzhiyun 		       (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
1579*4882a593Smuzhiyun 		       cw_min, avg_back_off);
1580*4882a593Smuzhiyun 		PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
1581*4882a593Smuzhiyun 	}
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	HEXDUMP("WMM: avg_back_off", (t_u8 *)tmp, sizeof(tmp));
1584*4882a593Smuzhiyun 	HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
1585*4882a593Smuzhiyun 		sizeof(priv->wmm.queue_priority));
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 	/* Bubble sort */
1588*4882a593Smuzhiyun 	for (i = 0; i < num_ac; i++) {
1589*4882a593Smuzhiyun 		for (j = 1; j < num_ac - i; j++) {
1590*4882a593Smuzhiyun 			if (tmp[j - 1] > tmp[j]) {
1591*4882a593Smuzhiyun 				SWAP_U16(tmp[j - 1], tmp[j]);
1592*4882a593Smuzhiyun 				SWAP_U8(priv->wmm.queue_priority[j - 1],
1593*4882a593Smuzhiyun 					priv->wmm.queue_priority[j]);
1594*4882a593Smuzhiyun 			} else if (tmp[j - 1] == tmp[j]) {
1595*4882a593Smuzhiyun 				if (priv->wmm.queue_priority[j - 1] <
1596*4882a593Smuzhiyun 				    priv->wmm.queue_priority[j]) {
1597*4882a593Smuzhiyun 					SWAP_U8(priv->wmm.queue_priority[j - 1],
1598*4882a593Smuzhiyun 						priv->wmm.queue_priority[j]);
1599*4882a593Smuzhiyun 				}
1600*4882a593Smuzhiyun 			}
1601*4882a593Smuzhiyun 		}
1602*4882a593Smuzhiyun 	}
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 	wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 	HEXDUMP("WMM: avg_back_off, sort", (t_u8 *)tmp, sizeof(tmp));
1607*4882a593Smuzhiyun 	DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort",
1608*4882a593Smuzhiyun 		    priv->wmm.queue_priority, sizeof(priv->wmm.queue_priority));
1609*4882a593Smuzhiyun 	LEAVE();
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun /**
1613*4882a593Smuzhiyun  *  @brief Downgrade WMM priority queue
1614*4882a593Smuzhiyun  *
1615*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
1616*4882a593Smuzhiyun  *
1617*4882a593Smuzhiyun  *  @return         N/A
1618*4882a593Smuzhiyun  */
wlan_wmm_setup_ac_downgrade(pmlan_private priv)1619*4882a593Smuzhiyun void wlan_wmm_setup_ac_downgrade(pmlan_private priv)
1620*4882a593Smuzhiyun {
1621*4882a593Smuzhiyun 	int ac_val;
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	ENTER();
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun 	PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 	if (priv->wmm_enabled == MFALSE) {
1628*4882a593Smuzhiyun 		/* WMM is not enabled, default priorities */
1629*4882a593Smuzhiyun 		for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
1630*4882a593Smuzhiyun 			priv->wmm.ac_down_graded_vals[ac_val] =
1631*4882a593Smuzhiyun 				(mlan_wmm_ac_e)ac_val;
1632*4882a593Smuzhiyun 		}
1633*4882a593Smuzhiyun 	} else {
1634*4882a593Smuzhiyun 		for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
1635*4882a593Smuzhiyun 			priv->wmm.ac_down_graded_vals[ac_val] =
1636*4882a593Smuzhiyun 				wlan_wmm_eval_downgrade_ac(
1637*4882a593Smuzhiyun 					priv, (mlan_wmm_ac_e)ac_val);
1638*4882a593Smuzhiyun 			PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n", ac_val,
1639*4882a593Smuzhiyun 			       priv->wmm.ac_down_graded_vals[ac_val]);
1640*4882a593Smuzhiyun 		}
1641*4882a593Smuzhiyun 	}
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 	LEAVE();
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun /**
1647*4882a593Smuzhiyun  *  @brief This function checks whether a station has WMM enabled or not
1648*4882a593Smuzhiyun  *
1649*4882a593Smuzhiyun  *  @param priv     A pointer to mlan_private
1650*4882a593Smuzhiyun  *  @param mac      station mac address
1651*4882a593Smuzhiyun  *  @return         MTRUE or MFALSE
1652*4882a593Smuzhiyun  */
is_station_wmm_enabled(mlan_private * priv,t_u8 * mac)1653*4882a593Smuzhiyun static t_u8 is_station_wmm_enabled(mlan_private *priv, t_u8 *mac)
1654*4882a593Smuzhiyun {
1655*4882a593Smuzhiyun 	sta_node *sta_ptr = MNULL;
1656*4882a593Smuzhiyun 	sta_ptr = wlan_get_station_entry(priv, mac);
1657*4882a593Smuzhiyun 	if (sta_ptr) {
1658*4882a593Smuzhiyun 		if (sta_ptr->is_11n_enabled || sta_ptr->is_11ax_enabled)
1659*4882a593Smuzhiyun 			return MTRUE;
1660*4882a593Smuzhiyun 	}
1661*4882a593Smuzhiyun 	return MFALSE;
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun /**
1665*4882a593Smuzhiyun  *  @brief This function checks whether wmm is supported
1666*4882a593Smuzhiyun  *
1667*4882a593Smuzhiyun  *  @param priv     A pointer to mlan_private
1668*4882a593Smuzhiyun  *  @param ra       Address of the receiver STA
1669*4882a593Smuzhiyun  *
1670*4882a593Smuzhiyun  *  @return         MTRUE or MFALSE
1671*4882a593Smuzhiyun  */
wlan_is_wmm_enabled(mlan_private * priv,t_u8 * ra)1672*4882a593Smuzhiyun static int wlan_is_wmm_enabled(mlan_private *priv, t_u8 *ra)
1673*4882a593Smuzhiyun {
1674*4882a593Smuzhiyun 	int ret = MFALSE;
1675*4882a593Smuzhiyun 	ENTER();
1676*4882a593Smuzhiyun #ifdef UAP_SUPPORT
1677*4882a593Smuzhiyun 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
1678*4882a593Smuzhiyun 		if ((!(ra[0] & 0x01)) &&
1679*4882a593Smuzhiyun 		    (priv->is_11n_enabled || priv->is_11ax_enabled))
1680*4882a593Smuzhiyun 			ret = is_station_wmm_enabled(priv, ra);
1681*4882a593Smuzhiyun 	}
1682*4882a593Smuzhiyun #endif /* UAP_SUPPORT */
1683*4882a593Smuzhiyun 	LEAVE();
1684*4882a593Smuzhiyun 	return ret;
1685*4882a593Smuzhiyun }
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun /**
1688*4882a593Smuzhiyun  *  @brief  Allocate and add a RA list for all TIDs with the given RA
1689*4882a593Smuzhiyun  *
1690*4882a593Smuzhiyun  *  @param priv  Pointer to the mlan_private driver data struct
1691*4882a593Smuzhiyun  *  @param ra	 Address of the receiver STA (AP in case of infra)
1692*4882a593Smuzhiyun  *
1693*4882a593Smuzhiyun  *  @return      N/A
1694*4882a593Smuzhiyun  */
wlan_ralist_add(mlan_private * priv,t_u8 * ra)1695*4882a593Smuzhiyun void wlan_ralist_add(mlan_private *priv, t_u8 *ra)
1696*4882a593Smuzhiyun {
1697*4882a593Smuzhiyun 	int i;
1698*4882a593Smuzhiyun 	raListTbl *ra_list;
1699*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
1700*4882a593Smuzhiyun 	tdlsStatus_e status;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 	ENTER();
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
1705*4882a593Smuzhiyun 		ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
1706*4882a593Smuzhiyun 		PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
1707*4882a593Smuzhiyun 		if (!ra_list)
1708*4882a593Smuzhiyun 			break;
1709*4882a593Smuzhiyun 		ra_list->max_amsdu = 0;
1710*4882a593Smuzhiyun 		ra_list->ba_status = BA_STREAM_NOT_SETUP;
1711*4882a593Smuzhiyun 		ra_list->amsdu_in_ampdu = MFALSE;
1712*4882a593Smuzhiyun 		if (queuing_ra_based(priv)) {
1713*4882a593Smuzhiyun 			ra_list->is_wmm_enabled = wlan_is_wmm_enabled(priv, ra);
1714*4882a593Smuzhiyun 			if (ra_list->is_wmm_enabled)
1715*4882a593Smuzhiyun 				ra_list->max_amsdu =
1716*4882a593Smuzhiyun 					get_station_max_amsdu_size(priv, ra);
1717*4882a593Smuzhiyun 			ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
1718*4882a593Smuzhiyun 		} else {
1719*4882a593Smuzhiyun 			ra_list->is_tdls_link = MFALSE;
1720*4882a593Smuzhiyun 			ra_list->tx_pause = MFALSE;
1721*4882a593Smuzhiyun 			status = wlan_get_tdls_link_status(priv, ra);
1722*4882a593Smuzhiyun 			if (MTRUE == wlan_is_tdls_link_setup(status)) {
1723*4882a593Smuzhiyun 				ra_list->is_wmm_enabled =
1724*4882a593Smuzhiyun 					is_station_wmm_enabled(priv, ra);
1725*4882a593Smuzhiyun 				if (ra_list->is_wmm_enabled)
1726*4882a593Smuzhiyun 					ra_list->max_amsdu =
1727*4882a593Smuzhiyun 						get_station_max_amsdu_size(priv,
1728*4882a593Smuzhiyun 									   ra);
1729*4882a593Smuzhiyun 				ra_list->is_tdls_link = MTRUE;
1730*4882a593Smuzhiyun 			} else {
1731*4882a593Smuzhiyun 				ra_list->is_wmm_enabled = IS_11N_ENABLED(priv);
1732*4882a593Smuzhiyun 				if (ra_list->is_wmm_enabled)
1733*4882a593Smuzhiyun 					ra_list->max_amsdu = priv->max_amsdu;
1734*4882a593Smuzhiyun 			}
1735*4882a593Smuzhiyun 		}
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 		PRINTM_NETINTF(MDATA, priv);
1738*4882a593Smuzhiyun 		PRINTM(MDATA, "ralist %p: is_wmm_enabled=%d max_amsdu=%d\n",
1739*4882a593Smuzhiyun 		       ra_list, ra_list->is_wmm_enabled, ra_list->max_amsdu);
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 		if (ra_list->is_wmm_enabled) {
1742*4882a593Smuzhiyun 			ra_list->packet_count = 0;
1743*4882a593Smuzhiyun 			ra_list->ba_packet_threshold =
1744*4882a593Smuzhiyun 				wlan_get_random_ba_threshold(pmadapter);
1745*4882a593Smuzhiyun 		}
1746*4882a593Smuzhiyun 
1747*4882a593Smuzhiyun 		util_enqueue_list_tail(pmadapter->pmoal_handle,
1748*4882a593Smuzhiyun 				       &priv->wmm.tid_tbl_ptr[i].ra_list,
1749*4882a593Smuzhiyun 				       (pmlan_linked_list)ra_list, MNULL,
1750*4882a593Smuzhiyun 				       MNULL);
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 		if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
1753*4882a593Smuzhiyun 			priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
1754*4882a593Smuzhiyun 	}
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun 	LEAVE();
1757*4882a593Smuzhiyun }
1758*4882a593Smuzhiyun 
1759*4882a593Smuzhiyun /**
1760*4882a593Smuzhiyun  *  @brief Initialize the WMM parameter.
1761*4882a593Smuzhiyun  *
1762*4882a593Smuzhiyun  *  @param pmadapter  Pointer to the mlan_adapter data structure
1763*4882a593Smuzhiyun  *
1764*4882a593Smuzhiyun  *  @return         N/A
1765*4882a593Smuzhiyun  */
wlan_init_wmm_param(pmlan_adapter pmadapter)1766*4882a593Smuzhiyun t_void wlan_init_wmm_param(pmlan_adapter pmadapter)
1767*4882a593Smuzhiyun {
1768*4882a593Smuzhiyun 	/* Reuse the same structure of WmmAcParameters_t for configuration
1769*4882a593Smuzhiyun 	 * purpose here. the definition of acm bit is changed to ucm (user
1770*4882a593Smuzhiyun 	 * configuration mode) FW will take the setting of
1771*4882a593Smuzhiyun 	 * aifsn,ecw_max,ecw_min, tx_op_limit only when ucm is set to 1.
1772*4882a593Smuzhiyun 	 * othewise the default setting/behavoir in firmware will be used.
1773*4882a593Smuzhiyun 	 */
1774*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].aci_aifsn.acm = 0;
1775*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].aci_aifsn.aci = AC_BE;
1776*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].aci_aifsn.aifsn = 3;
1777*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].ecw.ecw_max = 10;
1778*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].ecw.ecw_min = 4;
1779*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BE].tx_op_limit = 0;
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].aci_aifsn.acm = 0;
1782*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].aci_aifsn.aci = AC_BK;
1783*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].aci_aifsn.aifsn = 7;
1784*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].ecw.ecw_max = 10;
1785*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].ecw.ecw_min = 4;
1786*4882a593Smuzhiyun 	pmadapter->ac_params[AC_BK].tx_op_limit = 0;
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].aci_aifsn.acm = 0;
1789*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].aci_aifsn.aci = AC_VI;
1790*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].aci_aifsn.aifsn = 2;
1791*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].ecw.ecw_max = 4;
1792*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].ecw.ecw_min = 3;
1793*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VI].tx_op_limit = 188;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].aci_aifsn.acm = 0;
1796*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].aci_aifsn.aci = AC_VO;
1797*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].aci_aifsn.aifsn = 2;
1798*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].ecw.ecw_max = 3;
1799*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].ecw.ecw_min = 2;
1800*4882a593Smuzhiyun 	pmadapter->ac_params[AC_VO].tx_op_limit = 102;
1801*4882a593Smuzhiyun }
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun /**
1804*4882a593Smuzhiyun  *  @brief Initialize the WMM state information and the WMM data path queues.
1805*4882a593Smuzhiyun  *
1806*4882a593Smuzhiyun  *  @param pmadapter  Pointer to the mlan_adapter data structure
1807*4882a593Smuzhiyun  *
1808*4882a593Smuzhiyun  *  @return         N/A
1809*4882a593Smuzhiyun  */
wlan_wmm_init(pmlan_adapter pmadapter)1810*4882a593Smuzhiyun t_void wlan_wmm_init(pmlan_adapter pmadapter)
1811*4882a593Smuzhiyun {
1812*4882a593Smuzhiyun 	int i, j;
1813*4882a593Smuzhiyun 	pmlan_private priv;
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	ENTER();
1816*4882a593Smuzhiyun 
1817*4882a593Smuzhiyun 	for (j = 0; j < pmadapter->priv_num; ++j) {
1818*4882a593Smuzhiyun 		priv = pmadapter->priv[j];
1819*4882a593Smuzhiyun 		if (priv) {
1820*4882a593Smuzhiyun 			for (i = 0; i < MAX_NUM_TID; ++i) {
1821*4882a593Smuzhiyun 				priv->aggr_prio_tbl[i].amsdu =
1822*4882a593Smuzhiyun 					tos_to_tid_inv[i];
1823*4882a593Smuzhiyun 				priv->aggr_prio_tbl[i].ampdu_ap =
1824*4882a593Smuzhiyun 					priv->aggr_prio_tbl[i].ampdu_user =
1825*4882a593Smuzhiyun 						tos_to_tid_inv[i];
1826*4882a593Smuzhiyun 				priv->ibss_ampdu[i] =
1827*4882a593Smuzhiyun 					priv->aggr_prio_tbl[i].ampdu_user;
1828*4882a593Smuzhiyun 				priv->wmm.pkts_queued[i] = 0;
1829*4882a593Smuzhiyun 				priv->wmm.pkts_paused[i] = 0;
1830*4882a593Smuzhiyun 				priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
1831*4882a593Smuzhiyun 			}
1832*4882a593Smuzhiyun 			priv->wmm.drv_pkt_delay_max = WMM_DRV_DELAY_MAX;
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun 			priv->aggr_prio_tbl[6].amsdu = BA_STREAM_NOT_ALLOWED;
1835*4882a593Smuzhiyun 			priv->aggr_prio_tbl[7].amsdu = BA_STREAM_NOT_ALLOWED;
1836*4882a593Smuzhiyun 			priv->aggr_prio_tbl[6].ampdu_ap =
1837*4882a593Smuzhiyun 				priv->aggr_prio_tbl[6].ampdu_user =
1838*4882a593Smuzhiyun 					BA_STREAM_NOT_ALLOWED;
1839*4882a593Smuzhiyun 			priv->ibss_ampdu[6] = BA_STREAM_NOT_ALLOWED;
1840*4882a593Smuzhiyun 
1841*4882a593Smuzhiyun 			priv->aggr_prio_tbl[7].ampdu_ap =
1842*4882a593Smuzhiyun 				priv->aggr_prio_tbl[7].ampdu_user =
1843*4882a593Smuzhiyun 					BA_STREAM_NOT_ALLOWED;
1844*4882a593Smuzhiyun 			priv->ibss_ampdu[7] = BA_STREAM_NOT_ALLOWED;
1845*4882a593Smuzhiyun 
1846*4882a593Smuzhiyun 			priv->add_ba_param.timeout =
1847*4882a593Smuzhiyun 				MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
1848*4882a593Smuzhiyun #ifdef STA_SUPPORT
1849*4882a593Smuzhiyun 			if (priv->bss_type == MLAN_BSS_TYPE_STA) {
1850*4882a593Smuzhiyun 				priv->add_ba_param.tx_win_size =
1851*4882a593Smuzhiyun 					MLAN_STA_AMPDU_DEF_TXWINSIZE;
1852*4882a593Smuzhiyun 				priv->add_ba_param.rx_win_size =
1853*4882a593Smuzhiyun 					MLAN_STA_AMPDU_DEF_RXWINSIZE;
1854*4882a593Smuzhiyun 			}
1855*4882a593Smuzhiyun #endif
1856*4882a593Smuzhiyun #ifdef WIFI_DIRECT_SUPPORT
1857*4882a593Smuzhiyun 			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
1858*4882a593Smuzhiyun 				priv->add_ba_param.tx_win_size =
1859*4882a593Smuzhiyun 					MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
1860*4882a593Smuzhiyun 				priv->add_ba_param.rx_win_size =
1861*4882a593Smuzhiyun 					MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
1862*4882a593Smuzhiyun 			}
1863*4882a593Smuzhiyun #endif
1864*4882a593Smuzhiyun #ifdef UAP_SUPPORT
1865*4882a593Smuzhiyun 			if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
1866*4882a593Smuzhiyun 				priv->add_ba_param.tx_win_size =
1867*4882a593Smuzhiyun 					MLAN_UAP_AMPDU_DEF_TXWINSIZE;
1868*4882a593Smuzhiyun 				priv->add_ba_param.rx_win_size =
1869*4882a593Smuzhiyun 					MLAN_UAP_AMPDU_DEF_RXWINSIZE;
1870*4882a593Smuzhiyun 			}
1871*4882a593Smuzhiyun #endif
1872*4882a593Smuzhiyun 			priv->user_rxwinsize = priv->add_ba_param.rx_win_size;
1873*4882a593Smuzhiyun 			priv->add_ba_param.tx_amsdu = MTRUE;
1874*4882a593Smuzhiyun 			priv->add_ba_param.rx_amsdu = MTRUE;
1875*4882a593Smuzhiyun 			memset(priv->adapter, priv->rx_seq, 0xff,
1876*4882a593Smuzhiyun 			       sizeof(priv->rx_seq));
1877*4882a593Smuzhiyun 			wlan_wmm_default_queue_priorities(priv);
1878*4882a593Smuzhiyun 		}
1879*4882a593Smuzhiyun 	}
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 	LEAVE();
1882*4882a593Smuzhiyun }
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun /**
1885*4882a593Smuzhiyun  *  @brief Setup the queue priorities and downgrade any queues as required
1886*4882a593Smuzhiyun  *         by the WMM info.  Setups default values if WMM is not active
1887*4882a593Smuzhiyun  *         for this association.
1888*4882a593Smuzhiyun  *
1889*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
1890*4882a593Smuzhiyun  *
1891*4882a593Smuzhiyun  *  @return         N/A
1892*4882a593Smuzhiyun  */
wlan_wmm_setup_queues(pmlan_private priv)1893*4882a593Smuzhiyun void wlan_wmm_setup_queues(pmlan_private priv)
1894*4882a593Smuzhiyun {
1895*4882a593Smuzhiyun 	ENTER();
1896*4882a593Smuzhiyun 	wlan_wmm_setup_queue_priorities(priv, MNULL);
1897*4882a593Smuzhiyun 	wlan_wmm_setup_ac_downgrade(priv);
1898*4882a593Smuzhiyun 	LEAVE();
1899*4882a593Smuzhiyun }
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun #ifdef STA_SUPPORT
1902*4882a593Smuzhiyun /**
1903*4882a593Smuzhiyun  *  @brief  Send a command to firmware to retrieve the current WMM status
1904*4882a593Smuzhiyun  *
1905*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
1906*4882a593Smuzhiyun  *
1907*4882a593Smuzhiyun  *  @return         MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
1908*4882a593Smuzhiyun  */
wlan_cmd_wmm_status_change(pmlan_private priv)1909*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_status_change(pmlan_private priv)
1910*4882a593Smuzhiyun {
1911*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun 	ENTER();
1914*4882a593Smuzhiyun 
1915*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, MNULL,
1916*4882a593Smuzhiyun 			       MNULL);
1917*4882a593Smuzhiyun 	LEAVE();
1918*4882a593Smuzhiyun 	return ret;
1919*4882a593Smuzhiyun }
1920*4882a593Smuzhiyun #endif
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun /**
1923*4882a593Smuzhiyun  *  @brief Check if wmm TX queue is empty
1924*4882a593Smuzhiyun  *
1925*4882a593Smuzhiyun  *  @param pmadapter  Pointer to the mlan_adapter driver data struct
1926*4882a593Smuzhiyun  *
1927*4882a593Smuzhiyun  *  @return         MFALSE if not empty; MTRUE if empty
1928*4882a593Smuzhiyun  */
wlan_wmm_lists_empty(pmlan_adapter pmadapter)1929*4882a593Smuzhiyun int wlan_wmm_lists_empty(pmlan_adapter pmadapter)
1930*4882a593Smuzhiyun {
1931*4882a593Smuzhiyun 	int j;
1932*4882a593Smuzhiyun 	pmlan_private priv;
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	ENTER();
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun 	for (j = 0; j < pmadapter->priv_num; ++j) {
1937*4882a593Smuzhiyun 		priv = pmadapter->priv[j];
1938*4882a593Smuzhiyun 		if (priv) {
1939*4882a593Smuzhiyun 			if ((priv->port_ctrl_mode == MTRUE) &&
1940*4882a593Smuzhiyun 			    (priv->port_open == MFALSE)) {
1941*4882a593Smuzhiyun 				PRINTM(MINFO,
1942*4882a593Smuzhiyun 				       "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
1943*4882a593Smuzhiyun 				       j);
1944*4882a593Smuzhiyun 				continue;
1945*4882a593Smuzhiyun 			}
1946*4882a593Smuzhiyun 			if (priv->tx_pause)
1947*4882a593Smuzhiyun 				continue;
1948*4882a593Smuzhiyun 
1949*4882a593Smuzhiyun 			if (util_scalar_read(
1950*4882a593Smuzhiyun 				    pmadapter->pmoal_handle,
1951*4882a593Smuzhiyun 				    &priv->wmm.tx_pkts_queued,
1952*4882a593Smuzhiyun 				    pmadapter->callbacks.moal_spin_lock,
1953*4882a593Smuzhiyun 				    pmadapter->callbacks.moal_spin_unlock)) {
1954*4882a593Smuzhiyun 				LEAVE();
1955*4882a593Smuzhiyun 				return MFALSE;
1956*4882a593Smuzhiyun 			}
1957*4882a593Smuzhiyun 		}
1958*4882a593Smuzhiyun 	}
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun 	LEAVE();
1961*4882a593Smuzhiyun 	return MTRUE;
1962*4882a593Smuzhiyun }
1963*4882a593Smuzhiyun 
1964*4882a593Smuzhiyun /**
1965*4882a593Smuzhiyun  *   @brief Get ralist node
1966*4882a593Smuzhiyun  *
1967*4882a593Smuzhiyun  *   @param priv     Pointer to the mlan_private driver data struct
1968*4882a593Smuzhiyun  *   @param tid      TID
1969*4882a593Smuzhiyun  *   @param ra_addr  Pointer to the route address
1970*4882a593Smuzhiyun  *
1971*4882a593Smuzhiyun  *   @return         ra_list or MNULL
1972*4882a593Smuzhiyun  */
wlan_wmm_get_ralist_node(pmlan_private priv,t_u8 tid,t_u8 * ra_addr)1973*4882a593Smuzhiyun raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 *ra_addr)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	raListTbl *ra_list;
1976*4882a593Smuzhiyun 	ENTER();
1977*4882a593Smuzhiyun 	ra_list =
1978*4882a593Smuzhiyun 		(raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
1979*4882a593Smuzhiyun 					    &priv->wmm.tid_tbl_ptr[tid].ra_list,
1980*4882a593Smuzhiyun 					    MNULL, MNULL);
1981*4882a593Smuzhiyun 	while (ra_list &&
1982*4882a593Smuzhiyun 	       (ra_list != (raListTbl *)&priv->wmm.tid_tbl_ptr[tid].ra_list)) {
1983*4882a593Smuzhiyun 		if (!memcmp(priv->adapter, ra_list->ra, ra_addr,
1984*4882a593Smuzhiyun 			    MLAN_MAC_ADDR_LENGTH)) {
1985*4882a593Smuzhiyun 			LEAVE();
1986*4882a593Smuzhiyun 			return ra_list;
1987*4882a593Smuzhiyun 		}
1988*4882a593Smuzhiyun 		ra_list = ra_list->pnext;
1989*4882a593Smuzhiyun 	}
1990*4882a593Smuzhiyun 	LEAVE();
1991*4882a593Smuzhiyun 	return MNULL;
1992*4882a593Smuzhiyun }
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun /**
1995*4882a593Smuzhiyun  *   @brief Check if RA list is valid or not
1996*4882a593Smuzhiyun  *
1997*4882a593Smuzhiyun  *   @param priv     Pointer to the mlan_private driver data struct
1998*4882a593Smuzhiyun  *   @param ra_list  Pointer to raListTbl
1999*4882a593Smuzhiyun  *   @param ptrindex TID pointer index
2000*4882a593Smuzhiyun  *
2001*4882a593Smuzhiyun  *   @return         MTRUE- valid. MFALSE- invalid.
2002*4882a593Smuzhiyun  */
wlan_is_ralist_valid(mlan_private * priv,raListTbl * ra_list,int ptrindex)2003*4882a593Smuzhiyun int wlan_is_ralist_valid(mlan_private *priv, raListTbl *ra_list, int ptrindex)
2004*4882a593Smuzhiyun {
2005*4882a593Smuzhiyun 	raListTbl *rlist;
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	ENTER();
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun 	rlist = (raListTbl *)util_peek_list(
2010*4882a593Smuzhiyun 		priv->adapter->pmoal_handle,
2011*4882a593Smuzhiyun 		&priv->wmm.tid_tbl_ptr[ptrindex].ra_list, MNULL, MNULL);
2012*4882a593Smuzhiyun 
2013*4882a593Smuzhiyun 	while (rlist &&
2014*4882a593Smuzhiyun 	       (rlist !=
2015*4882a593Smuzhiyun 		(raListTbl *)&priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
2016*4882a593Smuzhiyun 		if (rlist == ra_list) {
2017*4882a593Smuzhiyun 			LEAVE();
2018*4882a593Smuzhiyun 			return MTRUE;
2019*4882a593Smuzhiyun 		}
2020*4882a593Smuzhiyun 
2021*4882a593Smuzhiyun 		rlist = rlist->pnext;
2022*4882a593Smuzhiyun 	}
2023*4882a593Smuzhiyun 	LEAVE();
2024*4882a593Smuzhiyun 	return MFALSE;
2025*4882a593Smuzhiyun }
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun /**
2028*4882a593Smuzhiyun  *  @brief  Update an existing raList with a new RA and 11n capability
2029*4882a593Smuzhiyun  *
2030*4882a593Smuzhiyun  *  @param priv     Pointer to the mlan_private driver data struct
2031*4882a593Smuzhiyun  *  @param old_ra   Old receiver address
2032*4882a593Smuzhiyun  *  @param new_ra   New receiver address
2033*4882a593Smuzhiyun  *
2034*4882a593Smuzhiyun  *  @return         integer count of updated nodes
2035*4882a593Smuzhiyun  */
wlan_ralist_update(mlan_private * priv,t_u8 * old_ra,t_u8 * new_ra)2036*4882a593Smuzhiyun int wlan_ralist_update(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra)
2037*4882a593Smuzhiyun {
2038*4882a593Smuzhiyun 	t_u8 tid;
2039*4882a593Smuzhiyun 	int update_count;
2040*4882a593Smuzhiyun 	raListTbl *ra_list;
2041*4882a593Smuzhiyun 
2042*4882a593Smuzhiyun 	ENTER();
2043*4882a593Smuzhiyun 
2044*4882a593Smuzhiyun 	update_count = 0;
2045*4882a593Smuzhiyun 
2046*4882a593Smuzhiyun 	for (tid = 0; tid < MAX_NUM_TID; ++tid) {
2047*4882a593Smuzhiyun 		ra_list = wlan_wmm_get_ralist_node(priv, tid, old_ra);
2048*4882a593Smuzhiyun 
2049*4882a593Smuzhiyun 		if (ra_list) {
2050*4882a593Smuzhiyun 			update_count++;
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 			if (queuing_ra_based(priv)) {
2053*4882a593Smuzhiyun 				ra_list->is_wmm_enabled =
2054*4882a593Smuzhiyun 					wlan_is_wmm_enabled(priv, new_ra);
2055*4882a593Smuzhiyun 				if (ra_list->is_wmm_enabled)
2056*4882a593Smuzhiyun 					ra_list->max_amsdu =
2057*4882a593Smuzhiyun 						get_station_max_amsdu_size(
2058*4882a593Smuzhiyun 							priv, new_ra);
2059*4882a593Smuzhiyun 			} else {
2060*4882a593Smuzhiyun 				ra_list->is_wmm_enabled = IS_11N_ENABLED(priv);
2061*4882a593Smuzhiyun 				if (ra_list->is_wmm_enabled)
2062*4882a593Smuzhiyun 					ra_list->max_amsdu = priv->max_amsdu;
2063*4882a593Smuzhiyun 			}
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 			ra_list->tx_pause = MFALSE;
2066*4882a593Smuzhiyun 			ra_list->packet_count = 0;
2067*4882a593Smuzhiyun 			ra_list->ba_packet_threshold =
2068*4882a593Smuzhiyun 				wlan_get_random_ba_threshold(priv->adapter);
2069*4882a593Smuzhiyun 			ra_list->amsdu_in_ampdu = MFALSE;
2070*4882a593Smuzhiyun 			ra_list->ba_status = BA_STREAM_NOT_SETUP;
2071*4882a593Smuzhiyun 			PRINTM(MINFO,
2072*4882a593Smuzhiyun 			       "ralist_update: %p, %d, " MACSTR "-->" MACSTR
2073*4882a593Smuzhiyun 			       "\n",
2074*4882a593Smuzhiyun 			       ra_list, ra_list->is_wmm_enabled,
2075*4882a593Smuzhiyun 			       MAC2STR(ra_list->ra), MAC2STR(new_ra));
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 			memcpy_ext(priv->adapter, ra_list->ra, new_ra,
2078*4882a593Smuzhiyun 				   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
2079*4882a593Smuzhiyun 		}
2080*4882a593Smuzhiyun 	}
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	LEAVE();
2083*4882a593Smuzhiyun 	return update_count;
2084*4882a593Smuzhiyun }
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun /**
2087*4882a593Smuzhiyun  *  @brief Add packet to WMM queue
2088*4882a593Smuzhiyun  *
2089*4882a593Smuzhiyun  *  @param pmadapter  Pointer to the mlan_adapter driver data struct
2090*4882a593Smuzhiyun  *  @param pmbuf      Pointer to the mlan_buffer data struct
2091*4882a593Smuzhiyun  *
2092*4882a593Smuzhiyun  *  @return         N/A
2093*4882a593Smuzhiyun  */
wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter,pmlan_buffer pmbuf)2094*4882a593Smuzhiyun t_void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
2095*4882a593Smuzhiyun {
2096*4882a593Smuzhiyun 	pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
2097*4882a593Smuzhiyun 	t_u32 tid;
2098*4882a593Smuzhiyun 	raListTbl *ra_list;
2099*4882a593Smuzhiyun 	t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
2100*4882a593Smuzhiyun 	tdlsStatus_e status;
2101*4882a593Smuzhiyun #ifdef UAP_SUPPORT
2102*4882a593Smuzhiyun 	psta_node sta_ptr = MNULL;
2103*4882a593Smuzhiyun #endif
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 	ENTER();
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 	pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
2108*4882a593Smuzhiyun 	if (!priv->media_connected) {
2109*4882a593Smuzhiyun 		PRINTM_NETINTF(MWARN, priv);
2110*4882a593Smuzhiyun 		PRINTM(MWARN, "Drop packet %p in disconnect state\n", pmbuf);
2111*4882a593Smuzhiyun 		wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
2112*4882a593Smuzhiyun 		LEAVE();
2113*4882a593Smuzhiyun 		return;
2114*4882a593Smuzhiyun 	}
2115*4882a593Smuzhiyun 	tid = pmbuf->priority;
2116*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
2117*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
2118*4882a593Smuzhiyun 	tid_down = wlan_wmm_downgrade_tid(priv, tid);
2119*4882a593Smuzhiyun 
2120*4882a593Smuzhiyun 	/* In case of infra as we have already created the list during
2121*4882a593Smuzhiyun 	   association we just don't have to call get_queue_raptr, we will have
2122*4882a593Smuzhiyun 	   only 1 raptr for a tid in case of infra */
2123*4882a593Smuzhiyun 	if (!queuing_ra_based(priv)) {
2124*4882a593Smuzhiyun 		memcpy_ext(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
2125*4882a593Smuzhiyun 			   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
2126*4882a593Smuzhiyun 		status = wlan_get_tdls_link_status(priv, ra);
2127*4882a593Smuzhiyun 		if (MTRUE == wlan_is_tdls_link_setup(status)) {
2128*4882a593Smuzhiyun 			ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
2129*4882a593Smuzhiyun 			pmbuf->flags |= MLAN_BUF_FLAG_TDLS;
2130*4882a593Smuzhiyun 		} else if (status == TDLS_SETUP_INPROGRESS) {
2131*4882a593Smuzhiyun 			wlan_add_buf_tdls_txqueue(priv, pmbuf);
2132*4882a593Smuzhiyun 			pmadapter->callbacks.moal_spin_unlock(
2133*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
2134*4882a593Smuzhiyun 				priv->wmm.ra_list_spinlock);
2135*4882a593Smuzhiyun 			LEAVE();
2136*4882a593Smuzhiyun 			return;
2137*4882a593Smuzhiyun 		} else
2138*4882a593Smuzhiyun 			ra_list = (raListTbl *)util_peek_list(
2139*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
2140*4882a593Smuzhiyun 				&priv->wmm.tid_tbl_ptr[tid_down].ra_list, MNULL,
2141*4882a593Smuzhiyun 				MNULL);
2142*4882a593Smuzhiyun 	} else {
2143*4882a593Smuzhiyun 		memcpy_ext(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
2144*4882a593Smuzhiyun 			   MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
2145*4882a593Smuzhiyun 		/** put multicast/broadcast packet in the same ralist */
2146*4882a593Smuzhiyun 		if (ra[0] & 0x01)
2147*4882a593Smuzhiyun 			memset(pmadapter, ra, 0xff, sizeof(ra));
2148*4882a593Smuzhiyun #ifdef UAP_SUPPORT
2149*4882a593Smuzhiyun 		else if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
2150*4882a593Smuzhiyun 			sta_ptr = wlan_get_station_entry(priv, ra);
2151*4882a593Smuzhiyun 			if (sta_ptr) {
2152*4882a593Smuzhiyun 				sta_ptr->stats.tx_bytes += pmbuf->data_len;
2153*4882a593Smuzhiyun 				sta_ptr->stats.tx_packets++;
2154*4882a593Smuzhiyun 				if (!sta_ptr->is_wmm_enabled &&
2155*4882a593Smuzhiyun 				    !priv->is_11ac_enabled) {
2156*4882a593Smuzhiyun 					tid_down = wlan_wmm_downgrade_tid(priv,
2157*4882a593Smuzhiyun 									  0xff);
2158*4882a593Smuzhiyun 				}
2159*4882a593Smuzhiyun 			}
2160*4882a593Smuzhiyun 		}
2161*4882a593Smuzhiyun #endif
2162*4882a593Smuzhiyun 		ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
2163*4882a593Smuzhiyun 	}
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 	if (!ra_list) {
2166*4882a593Smuzhiyun 		PRINTM_NETINTF(MWARN, priv);
2167*4882a593Smuzhiyun 		PRINTM(MWARN,
2168*4882a593Smuzhiyun 		       "Drop packet %p, ra_list=%p, media_connected=%d\n",
2169*4882a593Smuzhiyun 		       pmbuf, ra_list, priv->media_connected);
2170*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
2171*4882a593Smuzhiyun 			pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
2172*4882a593Smuzhiyun 		wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
2173*4882a593Smuzhiyun 		LEAVE();
2174*4882a593Smuzhiyun 		return;
2175*4882a593Smuzhiyun 	}
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 	PRINTM_NETINTF(MDATA, priv);
2178*4882a593Smuzhiyun 	PRINTM(MDATA,
2179*4882a593Smuzhiyun 	       "Adding pkt %p (priority=%d, tid_down=%d) to ra_list %p\n",
2180*4882a593Smuzhiyun 	       pmbuf, pmbuf->priority, tid_down, ra_list);
2181*4882a593Smuzhiyun 	util_enqueue_list_tail(pmadapter->pmoal_handle, &ra_list->buf_head,
2182*4882a593Smuzhiyun 			       (pmlan_linked_list)pmbuf, MNULL, MNULL);
2183*4882a593Smuzhiyun 
2184*4882a593Smuzhiyun 	ra_list->total_pkts++;
2185*4882a593Smuzhiyun 	ra_list->packet_count++;
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun 	priv->wmm.pkts_queued[tid_down]++;
2188*4882a593Smuzhiyun 	if (ra_list->tx_pause) {
2189*4882a593Smuzhiyun 		priv->wmm.pkts_paused[tid_down]++;
2190*4882a593Smuzhiyun 	} else {
2191*4882a593Smuzhiyun 		util_scalar_increment(pmadapter->pmoal_handle,
2192*4882a593Smuzhiyun 				      &priv->wmm.tx_pkts_queued, MNULL, MNULL);
2193*4882a593Smuzhiyun 		/* if highest_queued_prio < prio(tid_down), set it to
2194*4882a593Smuzhiyun 		 * prio(tid_down) */
2195*4882a593Smuzhiyun 		util_scalar_conditional_write(
2196*4882a593Smuzhiyun 			pmadapter->pmoal_handle, &priv->wmm.highest_queued_prio,
2197*4882a593Smuzhiyun 			MLAN_SCALAR_COND_LESS_THAN, tos_to_tid_inv[tid_down],
2198*4882a593Smuzhiyun 			tos_to_tid_inv[tid_down], MNULL, MNULL);
2199*4882a593Smuzhiyun 	}
2200*4882a593Smuzhiyun 	/* Record the current time the packet was queued; used to determine
2201*4882a593Smuzhiyun 	 *   the amount of time the packet was queued in the driver before it
2202*4882a593Smuzhiyun 	 *   was sent to the firmware.  The delay is then sent along with the
2203*4882a593Smuzhiyun 	 *   packet to the firmware for aggregate delay calculation for stats
2204*4882a593Smuzhiyun 	 *   and MSDU lifetime expiry.
2205*4882a593Smuzhiyun 	 */
2206*4882a593Smuzhiyun 	pmadapter->callbacks.moal_get_system_time(
2207*4882a593Smuzhiyun 		pmadapter->pmoal_handle, &pmbuf->in_ts_sec, &pmbuf->in_ts_usec);
2208*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
2209*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun 	LEAVE();
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun #ifdef STA_SUPPORT
2215*4882a593Smuzhiyun /**
2216*4882a593Smuzhiyun  *  @brief Process the GET_WMM_STATUS command response from firmware
2217*4882a593Smuzhiyun  *
2218*4882a593Smuzhiyun  *  The GET_WMM_STATUS response may contain multiple TLVs for:
2219*4882a593Smuzhiyun  *      - AC Queue status TLVs
2220*4882a593Smuzhiyun  *      - Current WMM Parameter IE TLV
2221*4882a593Smuzhiyun  *      - Admission Control action frame TLVs
2222*4882a593Smuzhiyun  *
2223*4882a593Smuzhiyun  *  This function parses the TLVs and then calls further functions
2224*4882a593Smuzhiyun  *   to process any changes in the queue prioritize or state.
2225*4882a593Smuzhiyun  *
2226*4882a593Smuzhiyun  *  @param priv      Pointer to the mlan_private driver data struct
2227*4882a593Smuzhiyun  *  @param ptlv      Pointer to the tlv block returned in the response.
2228*4882a593Smuzhiyun  *  @param resp_len  Length of TLV block
2229*4882a593Smuzhiyun  *
2230*4882a593Smuzhiyun  *  @return MLAN_STATUS_SUCCESS
2231*4882a593Smuzhiyun  */
wlan_ret_wmm_get_status(pmlan_private priv,t_u8 * ptlv,int resp_len)2232*4882a593Smuzhiyun mlan_status wlan_ret_wmm_get_status(pmlan_private priv, t_u8 *ptlv,
2233*4882a593Smuzhiyun 				    int resp_len)
2234*4882a593Smuzhiyun {
2235*4882a593Smuzhiyun 	t_u8 *pcurrent = ptlv;
2236*4882a593Smuzhiyun 	t_u32 tlv_len;
2237*4882a593Smuzhiyun 	t_u8 send_wmm_event;
2238*4882a593Smuzhiyun 	MrvlIEtypes_Data_t *ptlv_hdr;
2239*4882a593Smuzhiyun 	MrvlIEtypes_WmmQueueStatus_t *ptlv_wmm_q_status;
2240*4882a593Smuzhiyun 	IEEEtypes_WmmParameter_t *pwmm_param_ie = MNULL;
2241*4882a593Smuzhiyun 	WmmAcStatus_t *pac_status;
2242*4882a593Smuzhiyun 
2243*4882a593Smuzhiyun 	MrvlIETypes_ActionFrame_t *ptlv_action;
2244*4882a593Smuzhiyun 	IEEEtypes_Action_WMM_AddTsRsp_t *padd_ts_rsp;
2245*4882a593Smuzhiyun 	IEEEtypes_Action_WMM_DelTs_t *pdel_ts;
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun 	ENTER();
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 	send_wmm_event = MFALSE;
2250*4882a593Smuzhiyun 
2251*4882a593Smuzhiyun 	PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
2252*4882a593Smuzhiyun 	HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 	while (resp_len >= (int)sizeof(ptlv_hdr->header)) {
2255*4882a593Smuzhiyun 		ptlv_hdr = (MrvlIEtypes_Data_t *)pcurrent;
2256*4882a593Smuzhiyun 		tlv_len = wlan_le16_to_cpu(ptlv_hdr->header.len);
2257*4882a593Smuzhiyun 		if ((int)(tlv_len + sizeof(ptlv_hdr->header)) > resp_len) {
2258*4882a593Smuzhiyun 			PRINTM(MERROR,
2259*4882a593Smuzhiyun 			       "WMM get status: Error in processing  TLV buffer\n");
2260*4882a593Smuzhiyun 			resp_len = 0;
2261*4882a593Smuzhiyun 			continue;
2262*4882a593Smuzhiyun 		}
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 		switch (wlan_le16_to_cpu(ptlv_hdr->header.type)) {
2265*4882a593Smuzhiyun 		case TLV_TYPE_WMMQSTATUS:
2266*4882a593Smuzhiyun 			ptlv_wmm_q_status =
2267*4882a593Smuzhiyun 				(MrvlIEtypes_WmmQueueStatus_t *)ptlv_hdr;
2268*4882a593Smuzhiyun 			PRINTM(MEVENT, "WMM_STATUS: QSTATUS TLV: %d\n",
2269*4882a593Smuzhiyun 			       ptlv_wmm_q_status->queue_index);
2270*4882a593Smuzhiyun 
2271*4882a593Smuzhiyun 			PRINTM(MINFO,
2272*4882a593Smuzhiyun 			       "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
2273*4882a593Smuzhiyun 			       ptlv_wmm_q_status->queue_index,
2274*4882a593Smuzhiyun 			       ptlv_wmm_q_status->flow_required,
2275*4882a593Smuzhiyun 			       ptlv_wmm_q_status->disabled);
2276*4882a593Smuzhiyun 
2277*4882a593Smuzhiyun 			/* Pick the minimum among these to avoid array out of
2278*4882a593Smuzhiyun 			 * bounds */
2279*4882a593Smuzhiyun 			ptlv_wmm_q_status->queue_index = MIN(
2280*4882a593Smuzhiyun 				ptlv_wmm_q_status->queue_index, MAX_AC_QUEUES);
2281*4882a593Smuzhiyun 
2282*4882a593Smuzhiyun 			pac_status =
2283*4882a593Smuzhiyun 				&priv->wmm.ac_status[ptlv_wmm_q_status
2284*4882a593Smuzhiyun 							     ->queue_index];
2285*4882a593Smuzhiyun 			pac_status->disabled = ptlv_wmm_q_status->disabled;
2286*4882a593Smuzhiyun 			pac_status->flow_required =
2287*4882a593Smuzhiyun 				ptlv_wmm_q_status->flow_required;
2288*4882a593Smuzhiyun 			pac_status->flow_created =
2289*4882a593Smuzhiyun 				ptlv_wmm_q_status->flow_created;
2290*4882a593Smuzhiyun 			break;
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 		case TLV_TYPE_VENDOR_SPECIFIC_IE: /* WMM_IE */
2293*4882a593Smuzhiyun 			/*
2294*4882a593Smuzhiyun 			 * Point the regular IEEE IE 2 bytes into the NXP IE
2295*4882a593Smuzhiyun 			 *   and setup the IEEE IE type and length byte fields
2296*4882a593Smuzhiyun 			 */
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 			PRINTM(MEVENT, "WMM STATUS: WMM IE\n");
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun 			HEXDUMP("WMM: WMM TLV:", (t_u8 *)ptlv_hdr, tlv_len + 4);
2301*4882a593Smuzhiyun 
2302*4882a593Smuzhiyun 			pwmm_param_ie =
2303*4882a593Smuzhiyun 				(IEEEtypes_WmmParameter_t *)(pcurrent + 2);
2304*4882a593Smuzhiyun 			pwmm_param_ie->vend_hdr.len = (t_u8)tlv_len;
2305*4882a593Smuzhiyun 			pwmm_param_ie->vend_hdr.element_id = WMM_IE;
2306*4882a593Smuzhiyun 
2307*4882a593Smuzhiyun 			PRINTM(MINFO,
2308*4882a593Smuzhiyun 			       "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
2309*4882a593Smuzhiyun 			       pwmm_param_ie->qos_info.para_set_count);
2310*4882a593Smuzhiyun 
2311*4882a593Smuzhiyun 			memcpy_ext(priv->adapter,
2312*4882a593Smuzhiyun 				   (t_u8 *)&priv->curr_bss_params.bss_descriptor
2313*4882a593Smuzhiyun 					   .wmm_ie,
2314*4882a593Smuzhiyun 				   pwmm_param_ie,
2315*4882a593Smuzhiyun 				   (pwmm_param_ie->vend_hdr.len + 2),
2316*4882a593Smuzhiyun 				   sizeof(IEEEtypes_WmmParameter_t));
2317*4882a593Smuzhiyun 			send_wmm_event = MTRUE;
2318*4882a593Smuzhiyun 			break;
2319*4882a593Smuzhiyun 
2320*4882a593Smuzhiyun 		case TLV_TYPE_IEEE_ACTION_FRAME:
2321*4882a593Smuzhiyun 			PRINTM(MEVENT, "WMM_STATUS: IEEE Action Frame\n");
2322*4882a593Smuzhiyun 			ptlv_action = (MrvlIETypes_ActionFrame_t *)pcurrent;
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 			ptlv_action->actionFrame.wmmAc.tspecAct.category =
2325*4882a593Smuzhiyun 				wlan_le32_to_cpu(ptlv_action->actionFrame.wmmAc
2326*4882a593Smuzhiyun 							 .tspecAct.category);
2327*4882a593Smuzhiyun 			if (ptlv_action->actionFrame.wmmAc.tspecAct.category ==
2328*4882a593Smuzhiyun 			    IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC) {
2329*4882a593Smuzhiyun 				ptlv_action->actionFrame.wmmAc.tspecAct.action =
2330*4882a593Smuzhiyun 					wlan_le32_to_cpu(
2331*4882a593Smuzhiyun 						ptlv_action->actionFrame.wmmAc
2332*4882a593Smuzhiyun 							.tspecAct.action);
2333*4882a593Smuzhiyun 				switch (ptlv_action->actionFrame.wmmAc.tspecAct
2334*4882a593Smuzhiyun 						.action) {
2335*4882a593Smuzhiyun 				case TSPEC_ACTION_CODE_ADDTS_RSP:
2336*4882a593Smuzhiyun 					padd_ts_rsp = &ptlv_action->actionFrame
2337*4882a593Smuzhiyun 							       .wmmAc.addTsRsp;
2338*4882a593Smuzhiyun 					wlan_send_wmmac_host_event(
2339*4882a593Smuzhiyun 						priv, "ADDTS_RSP",
2340*4882a593Smuzhiyun 						ptlv_action->srcAddr,
2341*4882a593Smuzhiyun 						padd_ts_rsp->tspecIE.TspecBody
2342*4882a593Smuzhiyun 							.TSInfo.TID,
2343*4882a593Smuzhiyun 						padd_ts_rsp->tspecIE.TspecBody
2344*4882a593Smuzhiyun 							.TSInfo.UserPri,
2345*4882a593Smuzhiyun 						padd_ts_rsp->statusCode);
2346*4882a593Smuzhiyun 					break;
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 				case TSPEC_ACTION_CODE_DELTS:
2349*4882a593Smuzhiyun 					pdel_ts = &ptlv_action->actionFrame
2350*4882a593Smuzhiyun 							   .wmmAc.delTs;
2351*4882a593Smuzhiyun 					wlan_send_wmmac_host_event(
2352*4882a593Smuzhiyun 						priv, "DELTS_RX",
2353*4882a593Smuzhiyun 						ptlv_action->srcAddr,
2354*4882a593Smuzhiyun 						pdel_ts->tspecIE.TspecBody
2355*4882a593Smuzhiyun 							.TSInfo.TID,
2356*4882a593Smuzhiyun 						pdel_ts->tspecIE.TspecBody
2357*4882a593Smuzhiyun 							.TSInfo.UserPri,
2358*4882a593Smuzhiyun 						pdel_ts->reasonCode);
2359*4882a593Smuzhiyun 					break;
2360*4882a593Smuzhiyun 
2361*4882a593Smuzhiyun 				case TSPEC_ACTION_CODE_ADDTS_REQ:
2362*4882a593Smuzhiyun 				default:
2363*4882a593Smuzhiyun 					break;
2364*4882a593Smuzhiyun 				}
2365*4882a593Smuzhiyun 			}
2366*4882a593Smuzhiyun 			break;
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 		default:
2369*4882a593Smuzhiyun 			break;
2370*4882a593Smuzhiyun 		}
2371*4882a593Smuzhiyun 
2372*4882a593Smuzhiyun 		pcurrent += (tlv_len + sizeof(ptlv_hdr->header));
2373*4882a593Smuzhiyun 		resp_len -= (tlv_len + sizeof(ptlv_hdr->header));
2374*4882a593Smuzhiyun 	}
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	wlan_wmm_setup_queue_priorities(priv, pwmm_param_ie);
2377*4882a593Smuzhiyun 	wlan_wmm_setup_ac_downgrade(priv);
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	if (send_wmm_event) {
2380*4882a593Smuzhiyun 		wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
2381*4882a593Smuzhiyun 				MNULL);
2382*4882a593Smuzhiyun 	}
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 	LEAVE();
2385*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2386*4882a593Smuzhiyun }
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun /**
2389*4882a593Smuzhiyun  *  @brief Call back from the command module to allow insertion of a WMM TLV
2390*4882a593Smuzhiyun  *
2391*4882a593Smuzhiyun  *  If the BSS we are associating to supports WMM, add the required WMM
2392*4882a593Smuzhiyun  *    Information IE to the association request command buffer in the form
2393*4882a593Smuzhiyun  *    of a NXP extended IEEE IE.
2394*4882a593Smuzhiyun  *
2395*4882a593Smuzhiyun  *  @param priv         Pointer to the mlan_private driver data struct
2396*4882a593Smuzhiyun  *  @param ppassoc_buf  Output parameter: Pointer to the TLV output buffer,
2397*4882a593Smuzhiyun  *                      modified on return to point after the appended WMM TLV
2398*4882a593Smuzhiyun  *  @param pwmm_ie      Pointer to the WMM IE for the BSS we are joining
2399*4882a593Smuzhiyun  *
2400*4882a593Smuzhiyun  *  @return Length of data appended to the association tlv buffer
2401*4882a593Smuzhiyun  */
wlan_wmm_process_association_req(pmlan_private priv,t_u8 ** ppassoc_buf,IEEEtypes_WmmParameter_t * pwmm_ie)2402*4882a593Smuzhiyun t_u32 wlan_wmm_process_association_req(pmlan_private priv, t_u8 **ppassoc_buf,
2403*4882a593Smuzhiyun 				       IEEEtypes_WmmParameter_t *pwmm_ie)
2404*4882a593Smuzhiyun {
2405*4882a593Smuzhiyun 	MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
2406*4882a593Smuzhiyun 	t_u32 ret_len = 0;
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	ENTER();
2409*4882a593Smuzhiyun 
2410*4882a593Smuzhiyun 	/* Null checks */
2411*4882a593Smuzhiyun 	if (!ppassoc_buf) {
2412*4882a593Smuzhiyun 		LEAVE();
2413*4882a593Smuzhiyun 		return 0;
2414*4882a593Smuzhiyun 	}
2415*4882a593Smuzhiyun 	if (!(*ppassoc_buf)) {
2416*4882a593Smuzhiyun 		LEAVE();
2417*4882a593Smuzhiyun 		return 0;
2418*4882a593Smuzhiyun 	}
2419*4882a593Smuzhiyun 
2420*4882a593Smuzhiyun 	if (!pwmm_ie) {
2421*4882a593Smuzhiyun 		LEAVE();
2422*4882a593Smuzhiyun 		return 0;
2423*4882a593Smuzhiyun 	}
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun 	PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
2426*4882a593Smuzhiyun 	       pwmm_ie->vend_hdr.element_id);
2427*4882a593Smuzhiyun 
2428*4882a593Smuzhiyun 	if (priv->wmm_required && pwmm_ie->vend_hdr.element_id == WMM_IE) {
2429*4882a593Smuzhiyun 		pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *)*ppassoc_buf;
2430*4882a593Smuzhiyun 		pwmm_tlv->header.type = (t_u16)wmm_info_ie[0];
2431*4882a593Smuzhiyun 		pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
2432*4882a593Smuzhiyun 		pwmm_tlv->header.len = (t_u16)wmm_info_ie[1];
2433*4882a593Smuzhiyun 		memcpy_ext(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2],
2434*4882a593Smuzhiyun 			   pwmm_tlv->header.len, pwmm_tlv->header.len);
2435*4882a593Smuzhiyun 		if (pwmm_ie->qos_info.qos_uapsd)
2436*4882a593Smuzhiyun 			memcpy_ext(priv->adapter,
2437*4882a593Smuzhiyun 				   (t_u8 *)(pwmm_tlv->wmm_ie +
2438*4882a593Smuzhiyun 					    pwmm_tlv->header.len -
2439*4882a593Smuzhiyun 					    sizeof(priv->wmm_qosinfo)),
2440*4882a593Smuzhiyun 				   &priv->wmm_qosinfo,
2441*4882a593Smuzhiyun 				   sizeof(priv->wmm_qosinfo),
2442*4882a593Smuzhiyun 				   sizeof(priv->wmm_qosinfo));
2443*4882a593Smuzhiyun 
2444*4882a593Smuzhiyun 		ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
2445*4882a593Smuzhiyun 		pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
2446*4882a593Smuzhiyun 
2447*4882a593Smuzhiyun 		HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *)pwmm_tlv, ret_len);
2448*4882a593Smuzhiyun 		*ppassoc_buf += ret_len;
2449*4882a593Smuzhiyun 	}
2450*4882a593Smuzhiyun 
2451*4882a593Smuzhiyun 	LEAVE();
2452*4882a593Smuzhiyun 	return ret_len;
2453*4882a593Smuzhiyun }
2454*4882a593Smuzhiyun #endif /* STA_SUPPORT */
2455*4882a593Smuzhiyun 
2456*4882a593Smuzhiyun /**
2457*4882a593Smuzhiyun  *   @brief Compute the time delay in the driver queues for a given packet.
2458*4882a593Smuzhiyun  *
2459*4882a593Smuzhiyun  *   When the packet is received at the OS/Driver interface, the current
2460*4882a593Smuzhiyun  *     time is set in the packet structure.  The difference between the present
2461*4882a593Smuzhiyun  *     time and that received time is computed in this function and limited
2462*4882a593Smuzhiyun  *     based on pre-compiled limits in the driver.
2463*4882a593Smuzhiyun  *
2464*4882a593Smuzhiyun  *   @param priv   Ptr to the mlan_private driver data struct
2465*4882a593Smuzhiyun  *   @param pmbuf  Ptr to the mlan_buffer which has been previously timestamped
2466*4882a593Smuzhiyun  *
2467*4882a593Smuzhiyun  *   @return  Time delay of the packet in 2ms units after having limit applied
2468*4882a593Smuzhiyun  */
wlan_wmm_compute_driver_packet_delay(pmlan_private priv,const pmlan_buffer pmbuf)2469*4882a593Smuzhiyun t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
2470*4882a593Smuzhiyun 					  const pmlan_buffer pmbuf)
2471*4882a593Smuzhiyun {
2472*4882a593Smuzhiyun 	t_u8 ret_val = 0;
2473*4882a593Smuzhiyun 	t_u32 out_ts_sec, out_ts_usec;
2474*4882a593Smuzhiyun 	t_s32 queue_delay;
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	ENTER();
2477*4882a593Smuzhiyun 
2478*4882a593Smuzhiyun 	priv->adapter->callbacks.moal_get_system_time(
2479*4882a593Smuzhiyun 		priv->adapter->pmoal_handle, &out_ts_sec, &out_ts_usec);
2480*4882a593Smuzhiyun 	if (priv->adapter->tp_state_on) {
2481*4882a593Smuzhiyun 		pmbuf->out_ts_sec = out_ts_sec;
2482*4882a593Smuzhiyun 		pmbuf->out_ts_usec = out_ts_usec;
2483*4882a593Smuzhiyun 		if (pmbuf->in_ts_sec)
2484*4882a593Smuzhiyun 			priv->adapter->callbacks.moal_tp_accounting(
2485*4882a593Smuzhiyun 				priv->adapter->pmoal_handle, pmbuf, 11);
2486*4882a593Smuzhiyun 	}
2487*4882a593Smuzhiyun 	queue_delay = (t_s32)(out_ts_sec - pmbuf->in_ts_sec) * 1000;
2488*4882a593Smuzhiyun 	queue_delay += (t_s32)(out_ts_usec - pmbuf->in_ts_usec) / 1000;
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun 	/*
2491*4882a593Smuzhiyun 	 * Queue delay is passed as a uint8 in units of 2ms (ms shifted
2492*4882a593Smuzhiyun 	 *  by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
2493*4882a593Smuzhiyun 	 *
2494*4882a593Smuzhiyun 	 * Pass max value if queue_delay is beyond the uint8 range
2495*4882a593Smuzhiyun 	 */
2496*4882a593Smuzhiyun 	ret_val = (t_u8)(MIN(queue_delay, (t_s32)priv->wmm.drv_pkt_delay_max) >>
2497*4882a593Smuzhiyun 			 1);
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun 	PRINTM(MINFO, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n", queue_delay,
2500*4882a593Smuzhiyun 	       ret_val);
2501*4882a593Smuzhiyun 
2502*4882a593Smuzhiyun 	LEAVE();
2503*4882a593Smuzhiyun 	return ret_val;
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun 
2506*4882a593Smuzhiyun /**
2507*4882a593Smuzhiyun  *  @brief Transmit the highest priority packet awaiting in the WMM Queues
2508*4882a593Smuzhiyun  *
2509*4882a593Smuzhiyun  *  @param pmadapter Pointer to the mlan_adapter driver data struct
2510*4882a593Smuzhiyun  *
2511*4882a593Smuzhiyun  *  @return        N/A
2512*4882a593Smuzhiyun  */
wlan_wmm_process_tx(pmlan_adapter pmadapter)2513*4882a593Smuzhiyun void wlan_wmm_process_tx(pmlan_adapter pmadapter)
2514*4882a593Smuzhiyun {
2515*4882a593Smuzhiyun 	ENTER();
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 	do {
2518*4882a593Smuzhiyun 		if (wlan_dequeue_tx_packet(pmadapter))
2519*4882a593Smuzhiyun 			break;
2520*4882a593Smuzhiyun #ifdef SDIO
2521*4882a593Smuzhiyun 		if (IS_SD(pmadapter->card_type) &&
2522*4882a593Smuzhiyun 		    (pmadapter->ireg & UP_LD_CMD_PORT_HOST_INT_STATUS)) {
2523*4882a593Smuzhiyun 			wlan_send_mp_aggr_buf(pmadapter);
2524*4882a593Smuzhiyun 			break;
2525*4882a593Smuzhiyun 		}
2526*4882a593Smuzhiyun #endif
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun #ifdef PCIE
2529*4882a593Smuzhiyun 		if (IS_PCIE(pmadapter->card_type) &&
2530*4882a593Smuzhiyun 		    (pmadapter->ireg &
2531*4882a593Smuzhiyun 		     pmadapter->pcard_pcie->reg->host_intr_event_rdy))
2532*4882a593Smuzhiyun 			break;
2533*4882a593Smuzhiyun #endif
2534*4882a593Smuzhiyun #ifdef USB
2535*4882a593Smuzhiyun 		if (IS_USB(pmadapter->card_type) && pmadapter->event_received)
2536*4882a593Smuzhiyun 			break;
2537*4882a593Smuzhiyun #endif
2538*4882a593Smuzhiyun 		/* Check if busy */
2539*4882a593Smuzhiyun 	} while (!pmadapter->data_sent && !pmadapter->tx_lock_flag &&
2540*4882a593Smuzhiyun 		 !wlan_wmm_lists_empty(pmadapter));
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun 	LEAVE();
2543*4882a593Smuzhiyun 	return;
2544*4882a593Smuzhiyun }
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun /**
2547*4882a593Smuzhiyun  *  @brief select wmm queue
2548*4882a593Smuzhiyun  *
2549*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
2550*4882a593Smuzhiyun  *  @param tid          TID 0-7
2551*4882a593Smuzhiyun  *
2552*4882a593Smuzhiyun  *  @return             wmm_queue priority (0-3)
2553*4882a593Smuzhiyun  */
wlan_wmm_select_queue(mlan_private * pmpriv,t_u8 tid)2554*4882a593Smuzhiyun t_u8 wlan_wmm_select_queue(mlan_private *pmpriv, t_u8 tid)
2555*4882a593Smuzhiyun {
2556*4882a593Smuzhiyun 	pmlan_adapter pmadapter = pmpriv->adapter;
2557*4882a593Smuzhiyun 	t_u8 i;
2558*4882a593Smuzhiyun 	mlan_wmm_ac_e ac_down =
2559*4882a593Smuzhiyun 		pmpriv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(
2560*4882a593Smuzhiyun 			pmadapter, tid)];
2561*4882a593Smuzhiyun 
2562*4882a593Smuzhiyun 	ENTER();
2563*4882a593Smuzhiyun 
2564*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
2565*4882a593Smuzhiyun 		if (pmpriv->wmm.queue_priority[i] == ac_down) {
2566*4882a593Smuzhiyun 			LEAVE();
2567*4882a593Smuzhiyun 			return i;
2568*4882a593Smuzhiyun 		}
2569*4882a593Smuzhiyun 	}
2570*4882a593Smuzhiyun 	LEAVE();
2571*4882a593Smuzhiyun 	return 0;
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun /**
2575*4882a593Smuzhiyun  *  @brief Delete tx packets in RA list
2576*4882a593Smuzhiyun  *
2577*4882a593Smuzhiyun  *  @param priv			Pointer to the mlan_private driver data struct
2578*4882a593Smuzhiyun  *  @param ra_list_head	ra list header
2579*4882a593Smuzhiyun  *  @param tid          tid
2580*4882a593Smuzhiyun  *
2581*4882a593Smuzhiyun  *  @return		N/A
2582*4882a593Smuzhiyun  */
wlan_del_tx_pkts_in_ralist(pmlan_private priv,mlan_list_head * ra_list_head,int tid)2583*4882a593Smuzhiyun static INLINE t_u8 wlan_del_tx_pkts_in_ralist(pmlan_private priv,
2584*4882a593Smuzhiyun 					      mlan_list_head *ra_list_head,
2585*4882a593Smuzhiyun 					      int tid)
2586*4882a593Smuzhiyun {
2587*4882a593Smuzhiyun 	raListTbl *ra_list = MNULL;
2588*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
2589*4882a593Smuzhiyun 	pmlan_buffer pmbuf = MNULL;
2590*4882a593Smuzhiyun 	t_u8 ret = MFALSE;
2591*4882a593Smuzhiyun 	ENTER();
2592*4882a593Smuzhiyun 	ra_list = (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
2593*4882a593Smuzhiyun 					      ra_list_head, MNULL, MNULL);
2594*4882a593Smuzhiyun 	while (ra_list && ra_list != (raListTbl *)ra_list_head) {
2595*4882a593Smuzhiyun 		if (ra_list->total_pkts &&
2596*4882a593Smuzhiyun 		    (ra_list->tx_pause ||
2597*4882a593Smuzhiyun 		     (ra_list->total_pkts > RX_LOW_THRESHOLD))) {
2598*4882a593Smuzhiyun 			pmbuf = (pmlan_buffer)util_dequeue_list(
2599*4882a593Smuzhiyun 				pmadapter->pmoal_handle, &ra_list->buf_head,
2600*4882a593Smuzhiyun 				MNULL, MNULL);
2601*4882a593Smuzhiyun 			if (pmbuf) {
2602*4882a593Smuzhiyun 				PRINTM(MDATA,
2603*4882a593Smuzhiyun 				       "Drop pkts: tid=%d tx_pause=%d pkts=%d " MACSTR
2604*4882a593Smuzhiyun 				       "\n",
2605*4882a593Smuzhiyun 				       tid, ra_list->tx_pause,
2606*4882a593Smuzhiyun 				       ra_list->total_pkts,
2607*4882a593Smuzhiyun 				       MAC2STR(ra_list->ra));
2608*4882a593Smuzhiyun 				wlan_write_data_complete(pmadapter, pmbuf,
2609*4882a593Smuzhiyun 							 MLAN_STATUS_FAILURE);
2610*4882a593Smuzhiyun 				priv->wmm.pkts_queued[tid]--;
2611*4882a593Smuzhiyun 				priv->num_drop_pkts++;
2612*4882a593Smuzhiyun 				ra_list->total_pkts--;
2613*4882a593Smuzhiyun 				if (ra_list->tx_pause)
2614*4882a593Smuzhiyun 					priv->wmm.pkts_paused[tid]--;
2615*4882a593Smuzhiyun 				else
2616*4882a593Smuzhiyun 					util_scalar_decrement(
2617*4882a593Smuzhiyun 						pmadapter->pmoal_handle,
2618*4882a593Smuzhiyun 						&priv->wmm.tx_pkts_queued,
2619*4882a593Smuzhiyun 						MNULL, MNULL);
2620*4882a593Smuzhiyun 				ret = MTRUE;
2621*4882a593Smuzhiyun 				break;
2622*4882a593Smuzhiyun 			}
2623*4882a593Smuzhiyun 		}
2624*4882a593Smuzhiyun 		ra_list = ra_list->pnext;
2625*4882a593Smuzhiyun 	}
2626*4882a593Smuzhiyun 
2627*4882a593Smuzhiyun 	LEAVE();
2628*4882a593Smuzhiyun 	return ret;
2629*4882a593Smuzhiyun }
2630*4882a593Smuzhiyun 
2631*4882a593Smuzhiyun /**
2632*4882a593Smuzhiyun  *  @brief Drop tx pkts
2633*4882a593Smuzhiyun  *
2634*4882a593Smuzhiyun  *  @param priv			Pointer to the mlan_private driver data struct
2635*4882a593Smuzhiyun  *
2636*4882a593Smuzhiyun  *  @return		N/A
2637*4882a593Smuzhiyun  */
wlan_drop_tx_pkts(pmlan_private priv)2638*4882a593Smuzhiyun t_void wlan_drop_tx_pkts(pmlan_private priv)
2639*4882a593Smuzhiyun {
2640*4882a593Smuzhiyun 	int j;
2641*4882a593Smuzhiyun 	static int i;
2642*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
2643*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
2644*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
2645*4882a593Smuzhiyun 	for (j = 0; j < MAX_NUM_TID; j++, i++) {
2646*4882a593Smuzhiyun 		if (i == MAX_NUM_TID)
2647*4882a593Smuzhiyun 			i = 0;
2648*4882a593Smuzhiyun 		if (wlan_del_tx_pkts_in_ralist(
2649*4882a593Smuzhiyun 			    priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i)) {
2650*4882a593Smuzhiyun 			i++;
2651*4882a593Smuzhiyun 			break;
2652*4882a593Smuzhiyun 		}
2653*4882a593Smuzhiyun 	}
2654*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
2655*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
2656*4882a593Smuzhiyun 	return;
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun /**
2660*4882a593Smuzhiyun  *  @brief Remove peer ralist
2661*4882a593Smuzhiyun  *
2662*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
2663*4882a593Smuzhiyun  *  @param mac        peer mac address
2664*4882a593Smuzhiyun  *
2665*4882a593Smuzhiyun  *  @return           N/A
2666*4882a593Smuzhiyun  */
wlan_wmm_delete_peer_ralist(pmlan_private priv,t_u8 * mac)2667*4882a593Smuzhiyun t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac)
2668*4882a593Smuzhiyun {
2669*4882a593Smuzhiyun 	raListTbl *ra_list;
2670*4882a593Smuzhiyun 	int i;
2671*4882a593Smuzhiyun 	pmlan_adapter pmadapter = priv->adapter;
2672*4882a593Smuzhiyun 	t_u32 pkt_cnt = 0;
2673*4882a593Smuzhiyun 	t_u32 tx_pkts_queued = 0;
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun 	ENTER();
2676*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
2677*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
2678*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
2679*4882a593Smuzhiyun 		ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
2680*4882a593Smuzhiyun 		if (ra_list) {
2681*4882a593Smuzhiyun 			PRINTM(MINFO, "delete sta ralist %p\n", ra_list);
2682*4882a593Smuzhiyun 			priv->wmm.pkts_queued[i] -= ra_list->total_pkts;
2683*4882a593Smuzhiyun 			if (ra_list->tx_pause)
2684*4882a593Smuzhiyun 				priv->wmm.pkts_paused[i] -= ra_list->total_pkts;
2685*4882a593Smuzhiyun 			else
2686*4882a593Smuzhiyun 				pkt_cnt += ra_list->total_pkts;
2687*4882a593Smuzhiyun 			wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
2688*4882a593Smuzhiyun 
2689*4882a593Smuzhiyun 			util_unlink_list(pmadapter->pmoal_handle,
2690*4882a593Smuzhiyun 					 &priv->wmm.tid_tbl_ptr[i].ra_list,
2691*4882a593Smuzhiyun 					 (pmlan_linked_list)ra_list, MNULL,
2692*4882a593Smuzhiyun 					 MNULL);
2693*4882a593Smuzhiyun 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
2694*4882a593Smuzhiyun 							(t_u8 *)ra_list);
2695*4882a593Smuzhiyun 			if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
2696*4882a593Smuzhiyun 				priv->wmm.tid_tbl_ptr[i].ra_list_curr =
2697*4882a593Smuzhiyun 					(raListTbl *)&priv->wmm.tid_tbl_ptr[i]
2698*4882a593Smuzhiyun 						.ra_list;
2699*4882a593Smuzhiyun 		}
2700*4882a593Smuzhiyun 	}
2701*4882a593Smuzhiyun 	if (pkt_cnt) {
2702*4882a593Smuzhiyun 		tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
2703*4882a593Smuzhiyun 						  &priv->wmm.tx_pkts_queued,
2704*4882a593Smuzhiyun 						  MNULL, MNULL);
2705*4882a593Smuzhiyun 		tx_pkts_queued -= pkt_cnt;
2706*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
2707*4882a593Smuzhiyun 				  &priv->wmm.tx_pkts_queued, tx_pkts_queued,
2708*4882a593Smuzhiyun 				  MNULL, MNULL);
2709*4882a593Smuzhiyun 		util_scalar_write(priv->adapter->pmoal_handle,
2710*4882a593Smuzhiyun 				  &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
2711*4882a593Smuzhiyun 				  MNULL, MNULL);
2712*4882a593Smuzhiyun 	}
2713*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
2714*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
2715*4882a593Smuzhiyun 	LEAVE();
2716*4882a593Smuzhiyun }
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun #ifdef STA_SUPPORT
2719*4882a593Smuzhiyun /**
2720*4882a593Smuzhiyun  *  @brief Hold TDLS packets to tdls pending queue
2721*4882a593Smuzhiyun  *
2722*4882a593Smuzhiyun  *  @param priv		A pointer to mlan_private
2723*4882a593Smuzhiyun  *  @param mac      station mac address
2724*4882a593Smuzhiyun  *
2725*4882a593Smuzhiyun  *  @return      N/A
2726*4882a593Smuzhiyun  */
wlan_hold_tdls_packets(pmlan_private priv,t_u8 * mac)2727*4882a593Smuzhiyun t_void wlan_hold_tdls_packets(pmlan_private priv, t_u8 *mac)
2728*4882a593Smuzhiyun {
2729*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
2730*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
2731*4882a593Smuzhiyun 	raListTbl *ra_list = MNULL;
2732*4882a593Smuzhiyun 	t_u8 i;
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun 	ENTER();
2735*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
2736*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
2737*4882a593Smuzhiyun 	PRINTM(MDATA, "wlan_hold_tdls_packets: " MACSTR "\n", MAC2STR(mac));
2738*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; ++i) {
2739*4882a593Smuzhiyun 		ra_list = (raListTbl *)util_peek_list(
2740*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
2741*4882a593Smuzhiyun 			&priv->wmm.tid_tbl_ptr[i].ra_list, MNULL, MNULL);
2742*4882a593Smuzhiyun 		if (ra_list) {
2743*4882a593Smuzhiyun 			while ((pmbuf = wlan_find_tdls_packets(priv, ra_list,
2744*4882a593Smuzhiyun 							       mac))) {
2745*4882a593Smuzhiyun 				util_unlink_list(pmadapter->pmoal_handle,
2746*4882a593Smuzhiyun 						 &ra_list->buf_head,
2747*4882a593Smuzhiyun 						 (pmlan_linked_list)pmbuf,
2748*4882a593Smuzhiyun 						 MNULL, MNULL);
2749*4882a593Smuzhiyun 				ra_list->total_pkts--;
2750*4882a593Smuzhiyun 				priv->wmm.pkts_queued[i]--;
2751*4882a593Smuzhiyun 				util_scalar_decrement(pmadapter->pmoal_handle,
2752*4882a593Smuzhiyun 						      &priv->wmm.tx_pkts_queued,
2753*4882a593Smuzhiyun 						      MNULL, MNULL);
2754*4882a593Smuzhiyun 				ra_list->packet_count--;
2755*4882a593Smuzhiyun 				wlan_add_buf_tdls_txqueue(priv, pmbuf);
2756*4882a593Smuzhiyun 				PRINTM(MDATA, "hold tdls packet=%p\n", pmbuf);
2757*4882a593Smuzhiyun 			}
2758*4882a593Smuzhiyun 		}
2759*4882a593Smuzhiyun 	}
2760*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
2761*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
2762*4882a593Smuzhiyun 	LEAVE();
2763*4882a593Smuzhiyun }
2764*4882a593Smuzhiyun 
2765*4882a593Smuzhiyun /**
2766*4882a593Smuzhiyun  *  @brief move TDLS packets back to ralist
2767*4882a593Smuzhiyun  *
2768*4882a593Smuzhiyun  *  @param priv		  A pointer to mlan_private
2769*4882a593Smuzhiyun  *  @param mac        TDLS peer mac address
2770*4882a593Smuzhiyun  *  @param status     tdlsStatus
2771*4882a593Smuzhiyun  *
2772*4882a593Smuzhiyun  *  @return           pmlan_buffer or MNULL
2773*4882a593Smuzhiyun  */
wlan_restore_tdls_packets(pmlan_private priv,t_u8 * mac,tdlsStatus_e status)2774*4882a593Smuzhiyun t_void wlan_restore_tdls_packets(pmlan_private priv, t_u8 *mac,
2775*4882a593Smuzhiyun 				 tdlsStatus_e status)
2776*4882a593Smuzhiyun {
2777*4882a593Smuzhiyun 	pmlan_buffer pmbuf;
2778*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
2779*4882a593Smuzhiyun 	raListTbl *ra_list = MNULL;
2780*4882a593Smuzhiyun 	t_u32 tid;
2781*4882a593Smuzhiyun 	t_u32 tid_down;
2782*4882a593Smuzhiyun 
2783*4882a593Smuzhiyun 	ENTER();
2784*4882a593Smuzhiyun 	PRINTM(MDATA, "wlan_restore_tdls_packets: " MACSTR " status=%d\n",
2785*4882a593Smuzhiyun 	       MAC2STR(mac), status);
2786*4882a593Smuzhiyun 
2787*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
2788*4882a593Smuzhiyun 					    priv->wmm.ra_list_spinlock);
2789*4882a593Smuzhiyun 
2790*4882a593Smuzhiyun 	while ((pmbuf = wlan_find_packets_tdls_txq(priv, mac))) {
2791*4882a593Smuzhiyun 		util_unlink_list(pmadapter->pmoal_handle,
2792*4882a593Smuzhiyun 				 &priv->tdls_pending_txq,
2793*4882a593Smuzhiyun 				 (pmlan_linked_list)pmbuf, MNULL, MNULL);
2794*4882a593Smuzhiyun 		tid = pmbuf->priority;
2795*4882a593Smuzhiyun 		tid_down = wlan_wmm_downgrade_tid(priv, tid);
2796*4882a593Smuzhiyun 		if (status == TDLS_SETUP_COMPLETE) {
2797*4882a593Smuzhiyun 			ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, mac);
2798*4882a593Smuzhiyun 			pmbuf->flags |= MLAN_BUF_FLAG_TDLS;
2799*4882a593Smuzhiyun 		} else {
2800*4882a593Smuzhiyun 			ra_list = (raListTbl *)util_peek_list(
2801*4882a593Smuzhiyun 				pmadapter->pmoal_handle,
2802*4882a593Smuzhiyun 				&priv->wmm.tid_tbl_ptr[tid_down].ra_list, MNULL,
2803*4882a593Smuzhiyun 				MNULL);
2804*4882a593Smuzhiyun 			pmbuf->flags &= ~MLAN_BUF_FLAG_TDLS;
2805*4882a593Smuzhiyun 		}
2806*4882a593Smuzhiyun 		if (!ra_list) {
2807*4882a593Smuzhiyun 			PRINTM_NETINTF(MWARN, priv);
2808*4882a593Smuzhiyun 			PRINTM(MWARN,
2809*4882a593Smuzhiyun 			       "Drop packet %p, ra_list=%p media_connected=%d\n",
2810*4882a593Smuzhiyun 			       pmbuf, ra_list, priv->media_connected);
2811*4882a593Smuzhiyun 			wlan_write_data_complete(pmadapter, pmbuf,
2812*4882a593Smuzhiyun 						 MLAN_STATUS_FAILURE);
2813*4882a593Smuzhiyun 			continue;
2814*4882a593Smuzhiyun 		}
2815*4882a593Smuzhiyun 		PRINTM_NETINTF(MDATA, priv);
2816*4882a593Smuzhiyun 		PRINTM(MDATA,
2817*4882a593Smuzhiyun 		       "ADD TDLS pkt %p (priority=%d) back to ra_list %p\n",
2818*4882a593Smuzhiyun 		       pmbuf, pmbuf->priority, ra_list);
2819*4882a593Smuzhiyun 		util_enqueue_list_tail(pmadapter->pmoal_handle,
2820*4882a593Smuzhiyun 				       &ra_list->buf_head,
2821*4882a593Smuzhiyun 				       (pmlan_linked_list)pmbuf, MNULL, MNULL);
2822*4882a593Smuzhiyun 		ra_list->total_pkts++;
2823*4882a593Smuzhiyun 		ra_list->packet_count++;
2824*4882a593Smuzhiyun 		priv->wmm.pkts_queued[tid_down]++;
2825*4882a593Smuzhiyun 		util_scalar_increment(pmadapter->pmoal_handle,
2826*4882a593Smuzhiyun 				      &priv->wmm.tx_pkts_queued, MNULL, MNULL);
2827*4882a593Smuzhiyun 		util_scalar_conditional_write(
2828*4882a593Smuzhiyun 			pmadapter->pmoal_handle, &priv->wmm.highest_queued_prio,
2829*4882a593Smuzhiyun 			MLAN_SCALAR_COND_LESS_THAN, tos_to_tid_inv[tid_down],
2830*4882a593Smuzhiyun 			tos_to_tid_inv[tid_down], MNULL, MNULL);
2831*4882a593Smuzhiyun 	}
2832*4882a593Smuzhiyun 	if (status != TDLS_SETUP_COMPLETE)
2833*4882a593Smuzhiyun 		wlan_wmm_delete_tdls_ralist(priv, mac);
2834*4882a593Smuzhiyun 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
2835*4882a593Smuzhiyun 					      priv->wmm.ra_list_spinlock);
2836*4882a593Smuzhiyun 	LEAVE();
2837*4882a593Smuzhiyun }
2838*4882a593Smuzhiyun 
2839*4882a593Smuzhiyun /**
2840*4882a593Smuzhiyun  *  @brief This function prepares the command of ADDTS
2841*4882a593Smuzhiyun  *
2842*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
2843*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
2844*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
2845*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
2846*4882a593Smuzhiyun  */
wlan_cmd_wmm_addts_req(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)2847*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_addts_req(pmlan_private pmpriv,
2848*4882a593Smuzhiyun 				   HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
2849*4882a593Smuzhiyun {
2850*4882a593Smuzhiyun 	mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *)pdata_buf;
2851*4882a593Smuzhiyun 	HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
2852*4882a593Smuzhiyun 
2853*4882a593Smuzhiyun 	ENTER();
2854*4882a593Smuzhiyun 
2855*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
2856*4882a593Smuzhiyun 	cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token) +
2857*4882a593Smuzhiyun 				     sizeof(pcmd_addts->timeout_ms) +
2858*4882a593Smuzhiyun 				     sizeof(pcmd_addts->command_result) +
2859*4882a593Smuzhiyun 				     sizeof(pcmd_addts->ieee_status_code) +
2860*4882a593Smuzhiyun 				     paddts->ie_data_len + S_DS_GEN);
2861*4882a593Smuzhiyun 	cmd->result = 0;
2862*4882a593Smuzhiyun 
2863*4882a593Smuzhiyun 	pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
2864*4882a593Smuzhiyun 	pcmd_addts->dialog_token = paddts->dialog_tok;
2865*4882a593Smuzhiyun 	memcpy_ext(pmpriv->adapter, pcmd_addts->tspec_data, paddts->ie_data,
2866*4882a593Smuzhiyun 		   paddts->ie_data_len, WMM_TSPEC_SIZE);
2867*4882a593Smuzhiyun 
2868*4882a593Smuzhiyun 	LEAVE();
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2871*4882a593Smuzhiyun }
2872*4882a593Smuzhiyun 
2873*4882a593Smuzhiyun /**
2874*4882a593Smuzhiyun  *  @brief This function handles the command response of ADDTS
2875*4882a593Smuzhiyun  *
2876*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
2877*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
2878*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
2879*4882a593Smuzhiyun  *
2880*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
2881*4882a593Smuzhiyun  */
wlan_ret_wmm_addts_req(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)2882*4882a593Smuzhiyun mlan_status wlan_ret_wmm_addts_req(pmlan_private pmpriv,
2883*4882a593Smuzhiyun 				   const HostCmd_DS_COMMAND *resp,
2884*4882a593Smuzhiyun 				   mlan_ioctl_req *pioctl_buf)
2885*4882a593Smuzhiyun {
2886*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm = MNULL;
2887*4882a593Smuzhiyun 	mlan_ds_wmm_addts *paddts = MNULL;
2888*4882a593Smuzhiyun 	const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
2889*4882a593Smuzhiyun 
2890*4882a593Smuzhiyun 	ENTER();
2891*4882a593Smuzhiyun 
2892*4882a593Smuzhiyun 	if (pioctl_buf) {
2893*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
2894*4882a593Smuzhiyun 		paddts = (mlan_ds_wmm_addts *)&pwmm->param.addts;
2895*4882a593Smuzhiyun 		paddts->result = wlan_le32_to_cpu(presp_addts->command_result);
2896*4882a593Smuzhiyun 		paddts->dialog_tok = presp_addts->dialog_token;
2897*4882a593Smuzhiyun 		paddts->status_code = (t_u32)presp_addts->ieee_status_code;
2898*4882a593Smuzhiyun 
2899*4882a593Smuzhiyun 		if (paddts->result == MLAN_CMD_RESULT_SUCCESS) {
2900*4882a593Smuzhiyun 			/* The tspecData field is potentially variable in size
2901*4882a593Smuzhiyun 			 * due to extra IEs that may have been in the ADDTS
2902*4882a593Smuzhiyun 			 * response action frame. Calculate the data length from
2903*4882a593Smuzhiyun 			 * the firmware command response.
2904*4882a593Smuzhiyun 			 */
2905*4882a593Smuzhiyun 			paddts->ie_data_len =
2906*4882a593Smuzhiyun 				(t_u8)(resp->size -
2907*4882a593Smuzhiyun 				       sizeof(presp_addts->command_result) -
2908*4882a593Smuzhiyun 				       sizeof(presp_addts->timeout_ms) -
2909*4882a593Smuzhiyun 				       sizeof(presp_addts->dialog_token) -
2910*4882a593Smuzhiyun 				       sizeof(presp_addts->ieee_status_code) -
2911*4882a593Smuzhiyun 				       S_DS_GEN);
2912*4882a593Smuzhiyun 
2913*4882a593Smuzhiyun 			/* Copy the TSPEC data include any extra IEs after the
2914*4882a593Smuzhiyun 			 * TSPEC */
2915*4882a593Smuzhiyun 			memcpy_ext(pmpriv->adapter, paddts->ie_data,
2916*4882a593Smuzhiyun 				   presp_addts->tspec_data, paddts->ie_data_len,
2917*4882a593Smuzhiyun 				   sizeof(paddts->ie_data));
2918*4882a593Smuzhiyun 		} else {
2919*4882a593Smuzhiyun 			paddts->ie_data_len = 0;
2920*4882a593Smuzhiyun 		}
2921*4882a593Smuzhiyun 		PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
2922*4882a593Smuzhiyun 		       paddts->result, paddts->status_code,
2923*4882a593Smuzhiyun 		       paddts->ie_data_len);
2924*4882a593Smuzhiyun 
2925*4882a593Smuzhiyun 		HEXDUMP("TSPEC: ADDTS data", paddts->ie_data,
2926*4882a593Smuzhiyun 			paddts->ie_data_len);
2927*4882a593Smuzhiyun 	}
2928*4882a593Smuzhiyun 
2929*4882a593Smuzhiyun 	LEAVE();
2930*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2931*4882a593Smuzhiyun }
2932*4882a593Smuzhiyun 
2933*4882a593Smuzhiyun /**
2934*4882a593Smuzhiyun  *  @brief This function prepares the command of DELTS
2935*4882a593Smuzhiyun  *
2936*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
2937*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
2938*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
2939*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
2940*4882a593Smuzhiyun  */
wlan_cmd_wmm_delts_req(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)2941*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_delts_req(pmlan_private pmpriv,
2942*4882a593Smuzhiyun 				   HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
2943*4882a593Smuzhiyun {
2944*4882a593Smuzhiyun 	mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *)pdata_buf;
2945*4882a593Smuzhiyun 	HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
2946*4882a593Smuzhiyun 
2947*4882a593Smuzhiyun 	ENTER();
2948*4882a593Smuzhiyun 
2949*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
2950*4882a593Smuzhiyun 	cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token) +
2951*4882a593Smuzhiyun 				     sizeof(pcmd_delts->command_result) +
2952*4882a593Smuzhiyun 				     sizeof(pcmd_delts->ieee_reason_code) +
2953*4882a593Smuzhiyun 				     pdelts->ie_data_len + S_DS_GEN);
2954*4882a593Smuzhiyun 	cmd->result = 0;
2955*4882a593Smuzhiyun 	pcmd_delts->ieee_reason_code = (t_u8)pdelts->status_code;
2956*4882a593Smuzhiyun 	memcpy_ext(pmpriv->adapter, pcmd_delts->tspec_data, pdelts->ie_data,
2957*4882a593Smuzhiyun 		   pdelts->ie_data_len, WMM_TSPEC_SIZE);
2958*4882a593Smuzhiyun 
2959*4882a593Smuzhiyun 	LEAVE();
2960*4882a593Smuzhiyun 
2961*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2962*4882a593Smuzhiyun }
2963*4882a593Smuzhiyun 
2964*4882a593Smuzhiyun /**
2965*4882a593Smuzhiyun  *  @brief This function handles the command response of DELTS
2966*4882a593Smuzhiyun  *
2967*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
2968*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
2969*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
2970*4882a593Smuzhiyun  *
2971*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
2972*4882a593Smuzhiyun  */
wlan_ret_wmm_delts_req(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)2973*4882a593Smuzhiyun mlan_status wlan_ret_wmm_delts_req(pmlan_private pmpriv,
2974*4882a593Smuzhiyun 				   const HostCmd_DS_COMMAND *resp,
2975*4882a593Smuzhiyun 				   mlan_ioctl_req *pioctl_buf)
2976*4882a593Smuzhiyun {
2977*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm;
2978*4882a593Smuzhiyun 	IEEEtypes_WMM_TSPEC_t *ptspec_ie;
2979*4882a593Smuzhiyun 	const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
2980*4882a593Smuzhiyun 
2981*4882a593Smuzhiyun 	ENTER();
2982*4882a593Smuzhiyun 
2983*4882a593Smuzhiyun 	if (pioctl_buf) {
2984*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
2985*4882a593Smuzhiyun 		pwmm->param.delts.result =
2986*4882a593Smuzhiyun 			wlan_le32_to_cpu(presp_delts->command_result);
2987*4882a593Smuzhiyun 
2988*4882a593Smuzhiyun 		PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
2989*4882a593Smuzhiyun 		       presp_delts->command_result);
2990*4882a593Smuzhiyun 
2991*4882a593Smuzhiyun 		if (pwmm->param.delts.result == 0) {
2992*4882a593Smuzhiyun 			ptspec_ie = (IEEEtypes_WMM_TSPEC_t *)
2993*4882a593Smuzhiyun 					    presp_delts->tspec_data;
2994*4882a593Smuzhiyun 			wlan_send_wmmac_host_event(
2995*4882a593Smuzhiyun 				pmpriv, "DELTS_TX", MNULL,
2996*4882a593Smuzhiyun 				ptspec_ie->TspecBody.TSInfo.TID,
2997*4882a593Smuzhiyun 				ptspec_ie->TspecBody.TSInfo.UserPri,
2998*4882a593Smuzhiyun 				presp_delts->ieee_reason_code);
2999*4882a593Smuzhiyun 		}
3000*4882a593Smuzhiyun 	}
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	LEAVE();
3003*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3004*4882a593Smuzhiyun }
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun /**
3007*4882a593Smuzhiyun  *  @brief This function prepares the command of WMM_QUEUE_STATS
3008*4882a593Smuzhiyun  *
3009*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3010*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
3011*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
3012*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3013*4882a593Smuzhiyun  */
wlan_cmd_wmm_queue_stats(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)3014*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_queue_stats(pmlan_private pmpriv,
3015*4882a593Smuzhiyun 				     HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
3016*4882a593Smuzhiyun {
3017*4882a593Smuzhiyun 	mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *)pdata_buf;
3018*4882a593Smuzhiyun 	HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
3019*4882a593Smuzhiyun 	t_u8 id;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun 	ENTER();
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
3024*4882a593Smuzhiyun 	cmd->size =
3025*4882a593Smuzhiyun 		wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS) + S_DS_GEN);
3026*4882a593Smuzhiyun 	cmd->result = 0;
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 	pcmd_qstats->action = pqstats->action;
3029*4882a593Smuzhiyun 	pcmd_qstats->select_is_userpri = 1;
3030*4882a593Smuzhiyun 	pcmd_qstats->select_bin = pqstats->user_priority;
3031*4882a593Smuzhiyun 	pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
3032*4882a593Smuzhiyun 	pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
3033*4882a593Smuzhiyun 	pcmd_qstats->avg_queue_delay =
3034*4882a593Smuzhiyun 		wlan_cpu_to_le32(pqstats->avg_queue_delay);
3035*4882a593Smuzhiyun 	pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
3036*4882a593Smuzhiyun 	pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
3037*4882a593Smuzhiyun 	pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
3038*4882a593Smuzhiyun 	for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
3039*4882a593Smuzhiyun 		pcmd_qstats->delay_histogram[id] =
3040*4882a593Smuzhiyun 			wlan_cpu_to_le16(pqstats->delay_histogram[id]);
3041*4882a593Smuzhiyun 	}
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 	LEAVE();
3044*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3045*4882a593Smuzhiyun }
3046*4882a593Smuzhiyun 
3047*4882a593Smuzhiyun /**
3048*4882a593Smuzhiyun  *  @brief This function handles the command response of WMM_QUEUE_STATS
3049*4882a593Smuzhiyun  *
3050*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3051*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
3052*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3053*4882a593Smuzhiyun  *
3054*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3055*4882a593Smuzhiyun  */
wlan_ret_wmm_queue_stats(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)3056*4882a593Smuzhiyun mlan_status wlan_ret_wmm_queue_stats(pmlan_private pmpriv,
3057*4882a593Smuzhiyun 				     const HostCmd_DS_COMMAND *resp,
3058*4882a593Smuzhiyun 				     mlan_ioctl_req *pioctl_buf)
3059*4882a593Smuzhiyun {
3060*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm = MNULL;
3061*4882a593Smuzhiyun 	mlan_ds_wmm_queue_stats *pqstats = MNULL;
3062*4882a593Smuzhiyun 	const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats =
3063*4882a593Smuzhiyun 		&resp->params.queue_stats;
3064*4882a593Smuzhiyun 	t_u8 id;
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun 	ENTER();
3067*4882a593Smuzhiyun 
3068*4882a593Smuzhiyun 	if (pioctl_buf) {
3069*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
3070*4882a593Smuzhiyun 		pqstats = (mlan_ds_wmm_queue_stats *)&pwmm->param.q_stats;
3071*4882a593Smuzhiyun 
3072*4882a593Smuzhiyun 		pqstats->action = presp_qstats->action;
3073*4882a593Smuzhiyun 		pqstats->user_priority = presp_qstats->select_bin;
3074*4882a593Smuzhiyun 		pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
3075*4882a593Smuzhiyun 		pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
3076*4882a593Smuzhiyun 		pqstats->avg_queue_delay =
3077*4882a593Smuzhiyun 			wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
3078*4882a593Smuzhiyun 		pqstats->avg_tx_delay =
3079*4882a593Smuzhiyun 			wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
3080*4882a593Smuzhiyun 		pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
3081*4882a593Smuzhiyun 		pqstats->policed_time =
3082*4882a593Smuzhiyun 			wlan_le16_to_cpu(presp_qstats->policed_time);
3083*4882a593Smuzhiyun 		for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
3084*4882a593Smuzhiyun 			pqstats->delay_histogram[id] = wlan_le16_to_cpu(
3085*4882a593Smuzhiyun 				presp_qstats->delay_histogram[id]);
3086*4882a593Smuzhiyun 		}
3087*4882a593Smuzhiyun 	}
3088*4882a593Smuzhiyun 
3089*4882a593Smuzhiyun 	LEAVE();
3090*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3091*4882a593Smuzhiyun }
3092*4882a593Smuzhiyun 
3093*4882a593Smuzhiyun /**
3094*4882a593Smuzhiyun  *  @brief This function prepares the command of WMM_TS_STATUS
3095*4882a593Smuzhiyun  *
3096*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3097*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
3098*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
3099*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3100*4882a593Smuzhiyun  */
wlan_cmd_wmm_ts_status(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)3101*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_ts_status(pmlan_private pmpriv,
3102*4882a593Smuzhiyun 				   HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
3103*4882a593Smuzhiyun {
3104*4882a593Smuzhiyun 	mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *)pdata_buf;
3105*4882a593Smuzhiyun 	HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
3106*4882a593Smuzhiyun 
3107*4882a593Smuzhiyun 	ENTER();
3108*4882a593Smuzhiyun 
3109*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
3110*4882a593Smuzhiyun 	cmd->size =
3111*4882a593Smuzhiyun 		wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS) + S_DS_GEN);
3112*4882a593Smuzhiyun 	cmd->result = 0;
3113*4882a593Smuzhiyun 
3114*4882a593Smuzhiyun 	memcpy_ext(pmpriv->adapter, (t_void *)pcmd_ts_status,
3115*4882a593Smuzhiyun 		   (t_void *)pts_status, sizeof(HostCmd_DS_WMM_TS_STATUS),
3116*4882a593Smuzhiyun 		   sizeof(HostCmd_DS_WMM_TS_STATUS));
3117*4882a593Smuzhiyun 
3118*4882a593Smuzhiyun 	LEAVE();
3119*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3120*4882a593Smuzhiyun }
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun /**
3123*4882a593Smuzhiyun  *  @brief This function handles the command response of WMM_TS_STATUS
3124*4882a593Smuzhiyun  *
3125*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3126*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
3127*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3128*4882a593Smuzhiyun  *
3129*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3130*4882a593Smuzhiyun  */
wlan_ret_wmm_ts_status(pmlan_private pmpriv,HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)3131*4882a593Smuzhiyun mlan_status wlan_ret_wmm_ts_status(pmlan_private pmpriv,
3132*4882a593Smuzhiyun 				   HostCmd_DS_COMMAND *resp,
3133*4882a593Smuzhiyun 				   mlan_ioctl_req *pioctl_buf)
3134*4882a593Smuzhiyun {
3135*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm = MNULL;
3136*4882a593Smuzhiyun 	HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
3137*4882a593Smuzhiyun 
3138*4882a593Smuzhiyun 	ENTER();
3139*4882a593Smuzhiyun 
3140*4882a593Smuzhiyun 	if (pioctl_buf) {
3141*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
3142*4882a593Smuzhiyun 		presp_ts_status->medium_time =
3143*4882a593Smuzhiyun 			wlan_le16_to_cpu(presp_ts_status->medium_time);
3144*4882a593Smuzhiyun 		memcpy_ext(pmpriv->adapter, (t_void *)&pwmm->param.ts_status,
3145*4882a593Smuzhiyun 			   (t_void *)presp_ts_status,
3146*4882a593Smuzhiyun 			   sizeof(mlan_ds_wmm_ts_status),
3147*4882a593Smuzhiyun 			   sizeof(mlan_ds_wmm_ts_status));
3148*4882a593Smuzhiyun 	}
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun 	LEAVE();
3151*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3152*4882a593Smuzhiyun }
3153*4882a593Smuzhiyun 
3154*4882a593Smuzhiyun /**
3155*4882a593Smuzhiyun  *  @brief Set/Get WMM status
3156*4882a593Smuzhiyun  *
3157*4882a593Smuzhiyun  *  @param pmadapter   A pointer to mlan_adapter structure
3158*4882a593Smuzhiyun  *  @param pioctl_req A pointer to ioctl request buffer
3159*4882a593Smuzhiyun  *
3160*4882a593Smuzhiyun  *  @return     MLAN_STATUS_SUCCESS --success
3161*4882a593Smuzhiyun  */
wlan_wmm_ioctl_enable(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3162*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_enable(pmlan_adapter pmadapter,
3163*4882a593Smuzhiyun 					 pmlan_ioctl_req pioctl_req)
3164*4882a593Smuzhiyun {
3165*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3166*4882a593Smuzhiyun 	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
3167*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *wmm = MNULL;
3168*4882a593Smuzhiyun 	ENTER();
3169*4882a593Smuzhiyun 	wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3170*4882a593Smuzhiyun 	if (pioctl_req->action == MLAN_ACT_GET)
3171*4882a593Smuzhiyun 		wmm->param.wmm_enable = (t_u32)pmpriv->wmm_required;
3172*4882a593Smuzhiyun 	else
3173*4882a593Smuzhiyun 		pmpriv->wmm_required = (t_u8)wmm->param.wmm_enable;
3174*4882a593Smuzhiyun 	pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
3175*4882a593Smuzhiyun 	LEAVE();
3176*4882a593Smuzhiyun 	return ret;
3177*4882a593Smuzhiyun }
3178*4882a593Smuzhiyun 
3179*4882a593Smuzhiyun /**
3180*4882a593Smuzhiyun  *  @brief Set/Get WMM QoS configuration
3181*4882a593Smuzhiyun  *
3182*4882a593Smuzhiyun  *  @param pmadapter   A pointer to mlan_adapter structure
3183*4882a593Smuzhiyun  *  @param pioctl_req A pointer to ioctl request buffer
3184*4882a593Smuzhiyun  *
3185*4882a593Smuzhiyun  *  @return     MLAN_STATUS_SUCCESS --success
3186*4882a593Smuzhiyun  */
wlan_wmm_ioctl_qos(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3187*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_qos(pmlan_adapter pmadapter,
3188*4882a593Smuzhiyun 				      pmlan_ioctl_req pioctl_req)
3189*4882a593Smuzhiyun {
3190*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3191*4882a593Smuzhiyun 	mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
3192*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *wmm = MNULL;
3193*4882a593Smuzhiyun 
3194*4882a593Smuzhiyun 	ENTER();
3195*4882a593Smuzhiyun 
3196*4882a593Smuzhiyun 	wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3197*4882a593Smuzhiyun 
3198*4882a593Smuzhiyun 	if (pioctl_req->action == MLAN_ACT_GET)
3199*4882a593Smuzhiyun 		wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
3200*4882a593Smuzhiyun 	else {
3201*4882a593Smuzhiyun 		pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
3202*4882a593Smuzhiyun 		pmpriv->saved_wmm_qosinfo = wmm->param.qos_cfg;
3203*4882a593Smuzhiyun 	}
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun 	pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
3206*4882a593Smuzhiyun 
3207*4882a593Smuzhiyun 	LEAVE();
3208*4882a593Smuzhiyun 	return ret;
3209*4882a593Smuzhiyun }
3210*4882a593Smuzhiyun 
3211*4882a593Smuzhiyun /**
3212*4882a593Smuzhiyun  *  @brief Request for add a TSPEC
3213*4882a593Smuzhiyun  *
3214*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3215*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3216*4882a593Smuzhiyun  *
3217*4882a593Smuzhiyun  *  @return             MLAN_STATUS_PENDING --success, otherwise fail
3218*4882a593Smuzhiyun  */
wlan_wmm_ioctl_addts_req(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3219*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_addts_req(pmlan_adapter pmadapter,
3220*4882a593Smuzhiyun 					    pmlan_ioctl_req pioctl_req)
3221*4882a593Smuzhiyun {
3222*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3223*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3224*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	ENTER();
3227*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun 	/* Send request to firmware */
3230*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ, 0, 0,
3231*4882a593Smuzhiyun 			       (t_void *)pioctl_req,
3232*4882a593Smuzhiyun 			       (t_void *)&cfg->param.addts);
3233*4882a593Smuzhiyun 
3234*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS)
3235*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
3236*4882a593Smuzhiyun 
3237*4882a593Smuzhiyun 	LEAVE();
3238*4882a593Smuzhiyun 	return ret;
3239*4882a593Smuzhiyun }
3240*4882a593Smuzhiyun 
3241*4882a593Smuzhiyun /**
3242*4882a593Smuzhiyun  *  @brief Request for delete a TSPEC
3243*4882a593Smuzhiyun  *
3244*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3245*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3246*4882a593Smuzhiyun  *
3247*4882a593Smuzhiyun  *  @return             MLAN_STATUS_PENDING --success, otherwise fail
3248*4882a593Smuzhiyun  */
wlan_wmm_ioctl_delts_req(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3249*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_delts_req(pmlan_adapter pmadapter,
3250*4882a593Smuzhiyun 					    pmlan_ioctl_req pioctl_req)
3251*4882a593Smuzhiyun {
3252*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3253*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3254*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3255*4882a593Smuzhiyun 
3256*4882a593Smuzhiyun 	ENTER();
3257*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3258*4882a593Smuzhiyun 
3259*4882a593Smuzhiyun 	/* Send request to firmware */
3260*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ, 0, 0,
3261*4882a593Smuzhiyun 			       (t_void *)pioctl_req,
3262*4882a593Smuzhiyun 			       (t_void *)&cfg->param.delts);
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS)
3265*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
3266*4882a593Smuzhiyun 
3267*4882a593Smuzhiyun 	LEAVE();
3268*4882a593Smuzhiyun 	return ret;
3269*4882a593Smuzhiyun }
3270*4882a593Smuzhiyun 
3271*4882a593Smuzhiyun /**
3272*4882a593Smuzhiyun  *  @brief To get and start/stop queue stats on a WMM AC
3273*4882a593Smuzhiyun  *
3274*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3275*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3276*4882a593Smuzhiyun  *
3277*4882a593Smuzhiyun  *  @return             MLAN_STATUS_PENDING --success, otherwise fail
3278*4882a593Smuzhiyun  */
wlan_wmm_ioctl_queue_stats(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3279*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_queue_stats(pmlan_adapter pmadapter,
3280*4882a593Smuzhiyun 					      pmlan_ioctl_req pioctl_req)
3281*4882a593Smuzhiyun {
3282*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3283*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3284*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3285*4882a593Smuzhiyun 
3286*4882a593Smuzhiyun 	ENTER();
3287*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun 	/* Send request to firmware */
3290*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS, 0, 0,
3291*4882a593Smuzhiyun 			       (t_void *)pioctl_req,
3292*4882a593Smuzhiyun 			       (t_void *)&cfg->param.q_stats);
3293*4882a593Smuzhiyun 
3294*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS)
3295*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
3296*4882a593Smuzhiyun 
3297*4882a593Smuzhiyun 	LEAVE();
3298*4882a593Smuzhiyun 	return ret;
3299*4882a593Smuzhiyun }
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun /**
3302*4882a593Smuzhiyun  *  @brief Get the status of the WMM AC queues
3303*4882a593Smuzhiyun  *
3304*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3305*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3306*4882a593Smuzhiyun  *
3307*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS --success
3308*4882a593Smuzhiyun  */
wlan_wmm_ioctl_queue_status(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3309*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_queue_status(pmlan_adapter pmadapter,
3310*4882a593Smuzhiyun 					       pmlan_ioctl_req pioctl_req)
3311*4882a593Smuzhiyun {
3312*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3313*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3314*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3315*4882a593Smuzhiyun 	mlan_ds_wmm_queue_status *pqstatus = MNULL;
3316*4882a593Smuzhiyun 	WmmAcStatus_t *pac_status = MNULL;
3317*4882a593Smuzhiyun 	mlan_wmm_ac_e ac_idx;
3318*4882a593Smuzhiyun 
3319*4882a593Smuzhiyun 	ENTER();
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3322*4882a593Smuzhiyun 	pqstatus = (mlan_ds_wmm_queue_status *)&cfg->param.q_status;
3323*4882a593Smuzhiyun 
3324*4882a593Smuzhiyun 	for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
3325*4882a593Smuzhiyun 		pac_status = &pmpriv->wmm.ac_status[ac_idx];
3326*4882a593Smuzhiyun 
3327*4882a593Smuzhiyun 		/* Firmware status */
3328*4882a593Smuzhiyun 		pqstatus->ac_status[ac_idx].flow_required =
3329*4882a593Smuzhiyun 			pac_status->flow_required;
3330*4882a593Smuzhiyun 		pqstatus->ac_status[ac_idx].flow_created =
3331*4882a593Smuzhiyun 			pac_status->flow_created;
3332*4882a593Smuzhiyun 		pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun 		/* ACM bit reflected in firmware status (redundant) */
3335*4882a593Smuzhiyun 		pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
3336*4882a593Smuzhiyun 	}
3337*4882a593Smuzhiyun 
3338*4882a593Smuzhiyun 	LEAVE();
3339*4882a593Smuzhiyun 	return ret;
3340*4882a593Smuzhiyun }
3341*4882a593Smuzhiyun 
3342*4882a593Smuzhiyun /**
3343*4882a593Smuzhiyun  *  @brief Get the status of the WMM Traffic Streams
3344*4882a593Smuzhiyun  *
3345*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3346*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3347*4882a593Smuzhiyun  *
3348*4882a593Smuzhiyun  *  @return             MLAN_STATUS_PENDING --success, otherwise fail
3349*4882a593Smuzhiyun  */
wlan_wmm_ioctl_ts_status(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3350*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_ts_status(pmlan_adapter pmadapter,
3351*4882a593Smuzhiyun 					    pmlan_ioctl_req pioctl_req)
3352*4882a593Smuzhiyun {
3353*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3354*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3355*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3356*4882a593Smuzhiyun 
3357*4882a593Smuzhiyun 	ENTER();
3358*4882a593Smuzhiyun 
3359*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3360*4882a593Smuzhiyun 
3361*4882a593Smuzhiyun 	/* Send request to firmware */
3362*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS, 0, 0,
3363*4882a593Smuzhiyun 			       (t_void *)pioctl_req,
3364*4882a593Smuzhiyun 			       (t_void *)&cfg->param.ts_status);
3365*4882a593Smuzhiyun 
3366*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS)
3367*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
3368*4882a593Smuzhiyun 
3369*4882a593Smuzhiyun 	LEAVE();
3370*4882a593Smuzhiyun 	return ret;
3371*4882a593Smuzhiyun }
3372*4882a593Smuzhiyun #endif /* STA_SUPPORT */
3373*4882a593Smuzhiyun 
3374*4882a593Smuzhiyun /**
3375*4882a593Smuzhiyun  *  @brief This function prepares the command of WMM_PARAM_CONFIG
3376*4882a593Smuzhiyun  *
3377*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3378*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
3379*4882a593Smuzhiyun  *  @param cmd_action   cmd action.
3380*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
3381*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3382*4882a593Smuzhiyun  */
wlan_cmd_wmm_param_config(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u8 cmd_action,t_void * pdata_buf)3383*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_param_config(pmlan_private pmpriv,
3384*4882a593Smuzhiyun 				      HostCmd_DS_COMMAND *cmd, t_u8 cmd_action,
3385*4882a593Smuzhiyun 				      t_void *pdata_buf)
3386*4882a593Smuzhiyun {
3387*4882a593Smuzhiyun 	wmm_ac_parameters_t *ac_params = (wmm_ac_parameters_t *)pdata_buf;
3388*4882a593Smuzhiyun 	HostCmd_DS_WMM_PARAM_CONFIG *pcmd_cfg = &cmd->params.param_config;
3389*4882a593Smuzhiyun 	t_u8 i = 0;
3390*4882a593Smuzhiyun 
3391*4882a593Smuzhiyun 	ENTER();
3392*4882a593Smuzhiyun 
3393*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_PARAM_CONFIG);
3394*4882a593Smuzhiyun 	cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_PARAM_CONFIG) +
3395*4882a593Smuzhiyun 				     S_DS_GEN);
3396*4882a593Smuzhiyun 	cmd->result = 0;
3397*4882a593Smuzhiyun 
3398*4882a593Smuzhiyun 	pcmd_cfg->action = cmd_action;
3399*4882a593Smuzhiyun 	if (cmd_action == HostCmd_ACT_GEN_SET) {
3400*4882a593Smuzhiyun 		memcpy_ext(pmpriv->adapter, pcmd_cfg->ac_params, ac_params,
3401*4882a593Smuzhiyun 			   sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES,
3402*4882a593Smuzhiyun 			   sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
3403*4882a593Smuzhiyun 		for (i = 0; i < MAX_AC_QUEUES; i++) {
3404*4882a593Smuzhiyun 			pcmd_cfg->ac_params[i].tx_op_limit = wlan_cpu_to_le16(
3405*4882a593Smuzhiyun 				pcmd_cfg->ac_params[i].tx_op_limit);
3406*4882a593Smuzhiyun 		}
3407*4882a593Smuzhiyun 	}
3408*4882a593Smuzhiyun 	LEAVE();
3409*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3410*4882a593Smuzhiyun }
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun /**
3413*4882a593Smuzhiyun  *  @brief This function handles the command response of WMM_PARAM_CONFIG
3414*4882a593Smuzhiyun  *
3415*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3416*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
3417*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3418*4882a593Smuzhiyun  *
3419*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3420*4882a593Smuzhiyun  */
wlan_ret_wmm_param_config(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)3421*4882a593Smuzhiyun mlan_status wlan_ret_wmm_param_config(pmlan_private pmpriv,
3422*4882a593Smuzhiyun 				      const HostCmd_DS_COMMAND *resp,
3423*4882a593Smuzhiyun 				      mlan_ioctl_req *pioctl_buf)
3424*4882a593Smuzhiyun {
3425*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm = MNULL;
3426*4882a593Smuzhiyun 	HostCmd_DS_WMM_PARAM_CONFIG *pcfg =
3427*4882a593Smuzhiyun 		(HostCmd_DS_WMM_PARAM_CONFIG *)&resp->params.param_config;
3428*4882a593Smuzhiyun 	t_u8 i;
3429*4882a593Smuzhiyun 
3430*4882a593Smuzhiyun 	ENTER();
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun 	if (pioctl_buf) {
3433*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
3434*4882a593Smuzhiyun 		for (i = 0; i < MAX_AC_QUEUES; i++) {
3435*4882a593Smuzhiyun 			pcfg->ac_params[i].tx_op_limit = wlan_le16_to_cpu(
3436*4882a593Smuzhiyun 				pcfg->ac_params[i].tx_op_limit);
3437*4882a593Smuzhiyun 		}
3438*4882a593Smuzhiyun 		memcpy_ext(pmpriv->adapter, pwmm->param.ac_params,
3439*4882a593Smuzhiyun 			   pcfg->ac_params,
3440*4882a593Smuzhiyun 			   sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES,
3441*4882a593Smuzhiyun 			   sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
3442*4882a593Smuzhiyun 	}
3443*4882a593Smuzhiyun 
3444*4882a593Smuzhiyun 	LEAVE();
3445*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3446*4882a593Smuzhiyun }
3447*4882a593Smuzhiyun 
3448*4882a593Smuzhiyun /**
3449*4882a593Smuzhiyun  *  @brief This function prepares the command of WMM_QUEUE_CONFIG
3450*4882a593Smuzhiyun  *
3451*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3452*4882a593Smuzhiyun  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
3453*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
3454*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3455*4882a593Smuzhiyun  */
wlan_cmd_wmm_queue_config(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)3456*4882a593Smuzhiyun mlan_status wlan_cmd_wmm_queue_config(pmlan_private pmpriv,
3457*4882a593Smuzhiyun 				      HostCmd_DS_COMMAND *cmd,
3458*4882a593Smuzhiyun 				      t_void *pdata_buf)
3459*4882a593Smuzhiyun {
3460*4882a593Smuzhiyun 	mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *)pdata_buf;
3461*4882a593Smuzhiyun 	HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
3462*4882a593Smuzhiyun 
3463*4882a593Smuzhiyun 	ENTER();
3464*4882a593Smuzhiyun 
3465*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
3466*4882a593Smuzhiyun 	cmd->size = wlan_cpu_to_le16(
3467*4882a593Smuzhiyun 		sizeof(pcmd_qcfg->action) + sizeof(pcmd_qcfg->access_category) +
3468*4882a593Smuzhiyun 		sizeof(pcmd_qcfg->msdu_lifetime_expiry) + S_DS_GEN);
3469*4882a593Smuzhiyun 	cmd->result = 0;
3470*4882a593Smuzhiyun 
3471*4882a593Smuzhiyun 	pcmd_qcfg->action = pqcfg->action;
3472*4882a593Smuzhiyun 	pcmd_qcfg->access_category = pqcfg->access_category;
3473*4882a593Smuzhiyun 	pcmd_qcfg->msdu_lifetime_expiry =
3474*4882a593Smuzhiyun 		wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
3475*4882a593Smuzhiyun 
3476*4882a593Smuzhiyun 	LEAVE();
3477*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3478*4882a593Smuzhiyun }
3479*4882a593Smuzhiyun 
3480*4882a593Smuzhiyun /**
3481*4882a593Smuzhiyun  *  @brief This function handles the command response of WMM_QUEUE_CONFIG
3482*4882a593Smuzhiyun  *
3483*4882a593Smuzhiyun  *  @param pmpriv       A pointer to mlan_private structure
3484*4882a593Smuzhiyun  *  @param resp         A pointer to HostCmd_DS_COMMAND
3485*4882a593Smuzhiyun  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3486*4882a593Smuzhiyun  *
3487*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3488*4882a593Smuzhiyun  */
wlan_ret_wmm_queue_config(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)3489*4882a593Smuzhiyun mlan_status wlan_ret_wmm_queue_config(pmlan_private pmpriv,
3490*4882a593Smuzhiyun 				      const HostCmd_DS_COMMAND *resp,
3491*4882a593Smuzhiyun 				      mlan_ioctl_req *pioctl_buf)
3492*4882a593Smuzhiyun {
3493*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *pwmm = MNULL;
3494*4882a593Smuzhiyun 	const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg =
3495*4882a593Smuzhiyun 		&resp->params.queue_config;
3496*4882a593Smuzhiyun 
3497*4882a593Smuzhiyun 	ENTER();
3498*4882a593Smuzhiyun 
3499*4882a593Smuzhiyun 	if (pioctl_buf) {
3500*4882a593Smuzhiyun 		pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
3501*4882a593Smuzhiyun 		pwmm->param.q_cfg.action = wlan_le32_to_cpu(presp_qcfg->action);
3502*4882a593Smuzhiyun 		pwmm->param.q_cfg.access_category =
3503*4882a593Smuzhiyun 			wlan_le32_to_cpu(presp_qcfg->access_category);
3504*4882a593Smuzhiyun 		pwmm->param.q_cfg.msdu_lifetime_expiry =
3505*4882a593Smuzhiyun 			wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
3506*4882a593Smuzhiyun 	}
3507*4882a593Smuzhiyun 
3508*4882a593Smuzhiyun 	LEAVE();
3509*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3510*4882a593Smuzhiyun }
3511*4882a593Smuzhiyun 
3512*4882a593Smuzhiyun /**
3513*4882a593Smuzhiyun  *  @brief Set/Get a specified AC Queue's parameters
3514*4882a593Smuzhiyun  *
3515*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
3516*4882a593Smuzhiyun  *  @param pioctl_req   A pointer to ioctl request buffer
3517*4882a593Smuzhiyun  *
3518*4882a593Smuzhiyun  *  @return             MLAN_STATUS_PENDING --success, otherwise fail
3519*4882a593Smuzhiyun  */
wlan_wmm_ioctl_queue_config(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3520*4882a593Smuzhiyun static mlan_status wlan_wmm_ioctl_queue_config(pmlan_adapter pmadapter,
3521*4882a593Smuzhiyun 					       pmlan_ioctl_req pioctl_req)
3522*4882a593Smuzhiyun {
3523*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3524*4882a593Smuzhiyun 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
3525*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *cfg = MNULL;
3526*4882a593Smuzhiyun 
3527*4882a593Smuzhiyun 	ENTER();
3528*4882a593Smuzhiyun 	cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3529*4882a593Smuzhiyun 
3530*4882a593Smuzhiyun 	/* Send request to firmware */
3531*4882a593Smuzhiyun 	ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG, 0, 0,
3532*4882a593Smuzhiyun 			       (t_void *)pioctl_req,
3533*4882a593Smuzhiyun 			       (t_void *)&cfg->param.q_cfg);
3534*4882a593Smuzhiyun 
3535*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS)
3536*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
3537*4882a593Smuzhiyun 
3538*4882a593Smuzhiyun 	LEAVE();
3539*4882a593Smuzhiyun 	return ret;
3540*4882a593Smuzhiyun }
3541*4882a593Smuzhiyun 
3542*4882a593Smuzhiyun /**
3543*4882a593Smuzhiyun  *  @brief WMM configuration handler
3544*4882a593Smuzhiyun  *
3545*4882a593Smuzhiyun  *  @param pmadapter   A pointer to mlan_adapter structure
3546*4882a593Smuzhiyun  *  @param pioctl_req A pointer to ioctl request buffer
3547*4882a593Smuzhiyun  *
3548*4882a593Smuzhiyun  *  @return     MLAN_STATUS_SUCCESS --success, otherwise fail
3549*4882a593Smuzhiyun  */
wlan_wmm_cfg_ioctl(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)3550*4882a593Smuzhiyun mlan_status wlan_wmm_cfg_ioctl(pmlan_adapter pmadapter,
3551*4882a593Smuzhiyun 			       pmlan_ioctl_req pioctl_req)
3552*4882a593Smuzhiyun {
3553*4882a593Smuzhiyun 	mlan_status status = MLAN_STATUS_SUCCESS;
3554*4882a593Smuzhiyun 	mlan_ds_wmm_cfg *wmm = MNULL;
3555*4882a593Smuzhiyun 
3556*4882a593Smuzhiyun 	ENTER();
3557*4882a593Smuzhiyun 
3558*4882a593Smuzhiyun 	if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_cfg)) {
3559*4882a593Smuzhiyun 		PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
3560*4882a593Smuzhiyun 		pioctl_req->data_read_written = 0;
3561*4882a593Smuzhiyun 		pioctl_req->buf_len_needed = sizeof(mlan_ds_wmm_cfg);
3562*4882a593Smuzhiyun 		pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
3563*4882a593Smuzhiyun 		LEAVE();
3564*4882a593Smuzhiyun 		return MLAN_STATUS_RESOURCE;
3565*4882a593Smuzhiyun 	}
3566*4882a593Smuzhiyun 	wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
3567*4882a593Smuzhiyun 	switch (wmm->sub_command) {
3568*4882a593Smuzhiyun #ifdef STA_SUPPORT
3569*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_ENABLE:
3570*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
3571*4882a593Smuzhiyun 		break;
3572*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_QOS:
3573*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
3574*4882a593Smuzhiyun 		break;
3575*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_ADDTS:
3576*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
3577*4882a593Smuzhiyun 		break;
3578*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_DELTS:
3579*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
3580*4882a593Smuzhiyun 		break;
3581*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_QUEUE_STATS:
3582*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
3583*4882a593Smuzhiyun 		break;
3584*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_QUEUE_STATUS:
3585*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
3586*4882a593Smuzhiyun 		break;
3587*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_TS_STATUS:
3588*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
3589*4882a593Smuzhiyun 		break;
3590*4882a593Smuzhiyun #endif
3591*4882a593Smuzhiyun 	case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
3592*4882a593Smuzhiyun 		status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
3593*4882a593Smuzhiyun 		break;
3594*4882a593Smuzhiyun 	default:
3595*4882a593Smuzhiyun 		pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
3596*4882a593Smuzhiyun 		status = MLAN_STATUS_FAILURE;
3597*4882a593Smuzhiyun 		break;
3598*4882a593Smuzhiyun 	}
3599*4882a593Smuzhiyun 	LEAVE();
3600*4882a593Smuzhiyun 	return status;
3601*4882a593Smuzhiyun }
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun /**
3604*4882a593Smuzhiyun  *  @brief Get ralist info
3605*4882a593Smuzhiyun  *
3606*4882a593Smuzhiyun  *  @param priv         A pointer to mlan_private structure
3607*4882a593Smuzhiyun  *  @param buf          A pointer to ralist_info structure
3608*4882a593Smuzhiyun  *  @return             number of ralist entry
3609*4882a593Smuzhiyun  *
3610*4882a593Smuzhiyun  */
wlan_get_ralist_info(mlan_private * priv,ralist_info * buf)3611*4882a593Smuzhiyun int wlan_get_ralist_info(mlan_private *priv, ralist_info *buf)
3612*4882a593Smuzhiyun {
3613*4882a593Smuzhiyun 	ralist_info *plist = buf;
3614*4882a593Smuzhiyun 	mlan_list_head *ra_list_head = MNULL;
3615*4882a593Smuzhiyun 	raListTbl *ra_list;
3616*4882a593Smuzhiyun 	int i;
3617*4882a593Smuzhiyun 	int count = 0;
3618*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; i++) {
3619*4882a593Smuzhiyun 		ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
3620*4882a593Smuzhiyun 		ra_list =
3621*4882a593Smuzhiyun 			(raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
3622*4882a593Smuzhiyun 						    ra_list_head, MNULL, MNULL);
3623*4882a593Smuzhiyun 		while (ra_list && ra_list != (raListTbl *)ra_list_head) {
3624*4882a593Smuzhiyun 			if (ra_list->total_pkts) {
3625*4882a593Smuzhiyun 				plist->total_pkts = ra_list->total_pkts;
3626*4882a593Smuzhiyun 				plist->tid = i;
3627*4882a593Smuzhiyun 				plist->tx_pause = ra_list->tx_pause;
3628*4882a593Smuzhiyun 				memcpy_ext(priv->adapter, plist->ra,
3629*4882a593Smuzhiyun 					   ra_list->ra, MLAN_MAC_ADDR_LENGTH,
3630*4882a593Smuzhiyun 					   MLAN_MAC_ADDR_LENGTH);
3631*4882a593Smuzhiyun 				plist++;
3632*4882a593Smuzhiyun 				count++;
3633*4882a593Smuzhiyun 				if (count >= MLAN_MAX_RALIST_NUM)
3634*4882a593Smuzhiyun 					break;
3635*4882a593Smuzhiyun 			}
3636*4882a593Smuzhiyun 			ra_list = ra_list->pnext;
3637*4882a593Smuzhiyun 		}
3638*4882a593Smuzhiyun 	}
3639*4882a593Smuzhiyun 	LEAVE();
3640*4882a593Smuzhiyun 	return count;
3641*4882a593Smuzhiyun }
3642*4882a593Smuzhiyun 
3643*4882a593Smuzhiyun /**
3644*4882a593Smuzhiyun  *  @brief dump ralist info
3645*4882a593Smuzhiyun  *
3646*4882a593Smuzhiyun  *  @param priv         A pointer to mlan_private structure
3647*4882a593Smuzhiyun  *
3648*4882a593Smuzhiyun  *  @return             N/A
3649*4882a593Smuzhiyun  *
3650*4882a593Smuzhiyun  */
wlan_dump_ralist(mlan_private * priv)3651*4882a593Smuzhiyun void wlan_dump_ralist(mlan_private *priv)
3652*4882a593Smuzhiyun {
3653*4882a593Smuzhiyun 	mlan_list_head *ra_list_head = MNULL;
3654*4882a593Smuzhiyun 	raListTbl *ra_list;
3655*4882a593Smuzhiyun 	mlan_adapter *pmadapter = priv->adapter;
3656*4882a593Smuzhiyun 	int i;
3657*4882a593Smuzhiyun 	t_u32 tx_pkts_queued;
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 	tx_pkts_queued =
3660*4882a593Smuzhiyun 		util_scalar_read(pmadapter->pmoal_handle,
3661*4882a593Smuzhiyun 				 &priv->wmm.tx_pkts_queued, MNULL, MNULL);
3662*4882a593Smuzhiyun 	PRINTM(MERROR, "bss_index = %d, tx_pkts_queued = %d\n", priv->bss_index,
3663*4882a593Smuzhiyun 	       tx_pkts_queued);
3664*4882a593Smuzhiyun 	if (!tx_pkts_queued)
3665*4882a593Smuzhiyun 		return;
3666*4882a593Smuzhiyun 	for (i = 0; i < MAX_NUM_TID; i++) {
3667*4882a593Smuzhiyun 		ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
3668*4882a593Smuzhiyun 		ra_list =
3669*4882a593Smuzhiyun 			(raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
3670*4882a593Smuzhiyun 						    ra_list_head, MNULL, MNULL);
3671*4882a593Smuzhiyun 		while (ra_list && ra_list != (raListTbl *)ra_list_head) {
3672*4882a593Smuzhiyun 			if (ra_list->total_pkts) {
3673*4882a593Smuzhiyun 				PRINTM(MERROR,
3674*4882a593Smuzhiyun 				       "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
3675*4882a593Smuzhiyun 				       ra_list->ra[0], ra_list->ra[1],
3676*4882a593Smuzhiyun 				       ra_list->ra[2], ra_list->ra[3],
3677*4882a593Smuzhiyun 				       ra_list->ra[4], ra_list->ra[5], i,
3678*4882a593Smuzhiyun 				       ra_list->total_pkts, ra_list->tx_pause);
3679*4882a593Smuzhiyun 			}
3680*4882a593Smuzhiyun 			ra_list = ra_list->pnext;
3681*4882a593Smuzhiyun 		}
3682*4882a593Smuzhiyun 	}
3683*4882a593Smuzhiyun 	return;
3684*4882a593Smuzhiyun }
3685*4882a593Smuzhiyun 
3686*4882a593Smuzhiyun /**
3687*4882a593Smuzhiyun  *  @brief get tid down
3688*4882a593Smuzhiyun  *
3689*4882a593Smuzhiyun  *  @param priv         A pointer to mlan_private structure
3690*4882a593Smuzhiyun  * 	@param tid 			tid
3691*4882a593Smuzhiyun  *
3692*4882a593Smuzhiyun  *  @return             tid_down
3693*4882a593Smuzhiyun  *
3694*4882a593Smuzhiyun  */
wlan_get_wmm_tid_down(mlan_private * priv,int tid)3695*4882a593Smuzhiyun int wlan_get_wmm_tid_down(mlan_private *priv, int tid)
3696*4882a593Smuzhiyun {
3697*4882a593Smuzhiyun 	return wlan_wmm_downgrade_tid(priv, tid);
3698*4882a593Smuzhiyun }
3699