1 /** @file mlan_wmm.c
2  *
3  *  @brief  This file provides functions for WMM
4  *
5  *  Copyright 2008-2024 NXP
6  *
7  *  SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 /********************************************************
12 Change log:
13     10/24/2008: initial version
14 ********************************************************/
15 
16 #include <mlan_api.h>
17 
18 /* Additional WMSDK header files */
19 #include <wmerrno.h>
20 #include <osa.h>
21 #if CONFIG_TX_RX_ZERO_COPY
22 #include <wm_net.h>
23 #endif
24 /* Always keep this include at the end of all include files */
25 #include <mlan_remap_mem_operations.h>
26 /********************************************************
27     Local Variables
28 ********************************************************/
29 
30 /** Maximum value FW can accept for driver delay in packet transmission */
31 #define DRV_PKT_DELAY_TO_FW_MAX 512
32 
33 /*
34  * Upper and Lower threshold for packet queuing in the driver
35 
36  *    - When the number of packets queued reaches the upper limit,
37  *      the driver will stop the net queue in the app/kernel space.
38 
39  *    - When the number of packets drops beneath the lower limit after
40  *      having reached the upper limit, the driver will restart the net
41  *      queue.
42  */
43 
44 /** Lower threshold for packet queuing in the driver.
45  * When the number of packets drops beneath the lower limit after having
46  * reached the upper limit, the driver will restart the net queue.
47  */
48 #define WMM_QUEUED_PACKET_LOWER_LIMIT 180
49 
50 /** Upper threshold for packet queuing in the driver.
51  * When the number of packets queued reaches the upper limit, the driver
52  * will stop the net queue in the app/kernel space.
53  */
54 #define WMM_QUEUED_PACKET_UPPER_LIMIT 200
55 
56 /** Offset for TOS field in the IP header */
57 #define IPTOS_OFFSET 5
58 
59 /** WMM information IE */
60 static const t_u8 wmm_info_ie[] = {(t_u8)WMM_IE, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
61 
62 /** Type enumeration of WMM AC_QUEUES */
63 typedef MLAN_PACK_START enum _wmm_ac_e { AC_BE, AC_BK, AC_VI, AC_VO } MLAN_PACK_END wmm_ac_e;
64 
65 /**
66  * This table will be used to store the tid values based on ACs.
67  * It is initialized to default values per TID.
68  */
69 static t_u8 tos_to_tid[] = {
70     /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
71     0x01, /* 0 1 0 AC_BK */
72     0x02, /* 0 0 0 AC_BK */
73     0x00, /* 0 0 1 AC_BE */
74     0x03, /* 0 1 1 AC_BE */
75     0x04, /* 1 0 0 AC_VI */
76     0x05, /* 1 0 1 AC_VI */
77     0x06, /* 1 1 0 AC_VO */
78     0x07  /* 1 1 1 AC_VO */
79 };
80 
81 /**
82  * This table will provide the tid value for given ac. This table does not
83  * change and will be used to copy back the default values to tos_to_tid in
84  * case of disconnect.
85  */
86 static const t_u8 ac_to_tid[4][2] = {{1, 2}, {0, 3}, {4, 5}, {6, 7}};
87 raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 *ra_addr);
88 /********************************************************
89     Local Functions
90 ********************************************************/
91 #ifdef DEBUG_LEVEL2
92 /**
93  *  @brief Debug print function to display the priority parameters for a WMM AC
94  *
95  *  @param pac_param	Pointer to the AC parameters to display
96  *
97  *  @return		N/A
98  */
wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)99 static void wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t *pac_param)
100 {
101     const char *ac_str[] = {"BK", "BE", "VI", "VO"};
102 
103     ENTER();
104 
105     PRINTM(MINFO,
106            "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
107            "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
108            ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]], pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
109            pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min, pac_param->ecw.ecw_max,
110            wlan_le16_to_cpu(pac_param->tx_op_limit));
111 
112     LEAVE();
113 }
114 
115 /** Print the WMM AC for debug purpose */
116 #define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
117 #else
118 /** Print the WMM AC for debug purpose */
119 #define PRINTM_AC(pac_param)
120 #endif
121 
122 /**
123  *  @brief  This function cleans Tx/Rx queues
124  *
125  *  @param priv		A pointer to mlan_private
126  *
127  *  @return		N/A
128  */
wlan_clean_txrx(pmlan_private priv)129 t_void wlan_clean_txrx(pmlan_private priv)
130 {
131     mlan_adapter *pmadapter = priv->adapter;
132 
133     ENTER();
134 
135 #if CONFIG_WMM
136     wlan_cleanup_bypass_txq(GET_BSS_ROLE(priv));
137 #endif
138 
139     wlan_11n_cleanup_reorder_tbl(priv);
140 
141     (void)pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
142     wlan_11n_deleteall_txbastream_tbl(priv);
143 #ifdef SDIO_MULTI_PORT_TX_AGGR
144     MP_TX_AGGR_BUF_RESET(priv->adapter);
145 #endif
146 #ifdef SDIO_MULTI_PORT_RX_AGGR_FOR_REF
147     MP_RX_AGGR_BUF_RESET(priv->adapter);
148 #endif
149 #if CONFIG_WMM
150     wlan_ralist_del_all_enh(priv);
151 #endif /* CONFIG_WMM */
152     (void)__memcpy(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
153 
154 #if defined(UAP_SUPPORT)
155     priv->num_drop_pkts = 0;
156 #endif
157     (void)pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
158 
159     LEAVE();
160 }
161 
162 /**
163  *  @brief Set the WMM queue priorities to their default values
164  *
165  *  @param priv     Pointer to the mlan_private driver data struct
166  *
167  *  @return         N/A
168  */
wlan_wmm_default_queue_priorities(pmlan_private priv)169 void wlan_wmm_default_queue_priorities(pmlan_private priv)
170 {
171     ENTER();
172 
173     /* Default queue priorities: VO->VI->BE->BK */
174     priv->wmm.queue_priority[0] = (t_u8)WMM_AC_VO;
175     priv->wmm.queue_priority[1] = (t_u8)WMM_AC_VI;
176     priv->wmm.queue_priority[2] = (t_u8)WMM_AC_BE;
177     priv->wmm.queue_priority[3] = (t_u8)WMM_AC_BK;
178 
179     LEAVE();
180 }
181 
182 /**
183  *  @brief Initialize the WMM parameter.
184  *
185  *  @param pmadapter  Pointer to the mlan_adapter data structure
186  *
187  *  @return         N/A
188  */
wlan_init_wmm_param(pmlan_adapter pmadapter)189 t_void wlan_init_wmm_param(pmlan_adapter pmadapter)
190 {
191     /* Reuse the same structure of WmmAcParameters_t for configuration
192      * purpose here. the definition of acm bit is changed to ucm (user
193      * configuration mode) FW will take the setting of
194      * aifsn,ecw_max,ecw_min, tx_op_limit only when ucm is set to 1.
195      * othewise the default setting/behavoir in firmware will be used.
196      */
197 #ifdef RW610
198     pmadapter->ac_params[AC_BE].aci_aifsn.acm   = 0;
199     pmadapter->ac_params[AC_BE].aci_aifsn.aci   = AC_BE;
200     pmadapter->ac_params[AC_BE].aci_aifsn.aifsn = 5;
201     pmadapter->ac_params[AC_BE].ecw.ecw_max     = 6;
202     pmadapter->ac_params[AC_BE].ecw.ecw_min     = 4;
203     pmadapter->ac_params[AC_BE].tx_op_limit     = 0;
204 
205     pmadapter->ac_params[AC_BK].aci_aifsn.acm   = 0;
206     pmadapter->ac_params[AC_BK].aci_aifsn.aci   = AC_BK;
207     pmadapter->ac_params[AC_BK].aci_aifsn.aifsn = 9;
208     pmadapter->ac_params[AC_BK].ecw.ecw_max     = 10;
209     pmadapter->ac_params[AC_BK].ecw.ecw_min     = 4;
210     pmadapter->ac_params[AC_BK].tx_op_limit     = 0;
211 
212     pmadapter->ac_params[AC_VI].aci_aifsn.acm   = 0;
213     pmadapter->ac_params[AC_VI].aci_aifsn.aci   = AC_VI;
214     pmadapter->ac_params[AC_VI].aci_aifsn.aifsn = 3;
215     pmadapter->ac_params[AC_VI].ecw.ecw_max     = 4;
216     pmadapter->ac_params[AC_VI].ecw.ecw_min     = 3;
217     pmadapter->ac_params[AC_VI].tx_op_limit     = 94;
218 
219     pmadapter->ac_params[AC_VO].aci_aifsn.acm   = 0;
220     pmadapter->ac_params[AC_VO].aci_aifsn.aci   = AC_VO;
221     pmadapter->ac_params[AC_VO].aci_aifsn.aifsn = 3;
222     pmadapter->ac_params[AC_VO].ecw.ecw_max     = 3;
223     pmadapter->ac_params[AC_VO].ecw.ecw_min     = 2;
224     pmadapter->ac_params[AC_VO].tx_op_limit     = 47;
225 #else
226     pmadapter->ac_params[AC_BE].aci_aifsn.acm   = 0;
227     pmadapter->ac_params[AC_BE].aci_aifsn.aci   = AC_BE;
228     pmadapter->ac_params[AC_BE].aci_aifsn.aifsn = 3;
229     pmadapter->ac_params[AC_BE].ecw.ecw_max     = 10;
230     pmadapter->ac_params[AC_BE].ecw.ecw_min     = 4;
231     pmadapter->ac_params[AC_BE].tx_op_limit     = 0;
232 
233     pmadapter->ac_params[AC_BK].aci_aifsn.acm   = 0;
234     pmadapter->ac_params[AC_BK].aci_aifsn.aci   = AC_BK;
235     pmadapter->ac_params[AC_BK].aci_aifsn.aifsn = 7;
236     pmadapter->ac_params[AC_BK].ecw.ecw_max     = 10;
237     pmadapter->ac_params[AC_BK].ecw.ecw_min     = 4;
238     pmadapter->ac_params[AC_BK].tx_op_limit     = 0;
239 
240     pmadapter->ac_params[AC_VI].aci_aifsn.acm   = 0;
241     pmadapter->ac_params[AC_VI].aci_aifsn.aci   = AC_VI;
242     pmadapter->ac_params[AC_VI].aci_aifsn.aifsn = 2;
243     pmadapter->ac_params[AC_VI].ecw.ecw_max     = 4;
244     pmadapter->ac_params[AC_VI].ecw.ecw_min     = 3;
245     pmadapter->ac_params[AC_VI].tx_op_limit     = 188;
246 
247     pmadapter->ac_params[AC_VO].aci_aifsn.acm   = 0;
248     pmadapter->ac_params[AC_VO].aci_aifsn.aci   = AC_VO;
249     pmadapter->ac_params[AC_VO].aci_aifsn.aifsn = 2;
250     pmadapter->ac_params[AC_VO].ecw.ecw_max     = 3;
251     pmadapter->ac_params[AC_VO].ecw.ecw_min     = 2;
252     pmadapter->ac_params[AC_VO].tx_op_limit     = 102;
253 #endif
254 }
255 
256 /**
257  *  @brief Initialize the WMM state information and the WMM data path queues.
258  *
259  *  @param pmadapter  Pointer to the mlan_adapter data structure
260  *
261  *  @return         N/A
262  */
wlan_wmm_init(pmlan_adapter pmadapter)263 t_void wlan_wmm_init(pmlan_adapter pmadapter)
264 {
265     t_u8 i, j;
266     pmlan_private priv;
267 
268     ENTER();
269 
270     for (j = 0; j < pmadapter->priv_num; ++j)
271     {
272         priv = pmadapter->priv[j];
273         if (priv != MNULL)
274         {
275             for (i = 0; i < MAX_NUM_TID; ++i)
276             {
277                 priv->wmm.pkts_queued[i]              = 0;
278                 priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
279             }
280 
281             priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
282 #ifdef STA_SUPPORT
283             if (priv->bss_type == MLAN_BSS_TYPE_STA)
284             {
285                 priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
286                 priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
287             }
288 #endif
289 #ifdef UAP_SUPPORT
290             if (priv->bss_type == MLAN_BSS_TYPE_UAP
291 #ifdef WIFI_DIRECT_SUPPORT
292                 || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
293 #endif
294             )
295             {
296                 priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
297                 priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
298             }
299 #endif
300             priv->add_ba_param.tx_amsdu = MTRUE;
301             priv->add_ba_param.rx_amsdu = MTRUE;
302             (void)__memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
303             wlan_wmm_default_queue_priorities(priv);
304         }
305     }
306 
307     LEAVE();
308 }
309 
310 /**
311  *   @brief Get ralist node
312  *
313  *   @param priv     Pointer to the mlan_private driver data struct
314  *   @param tid      TID
315  *   @param ra_addr  Pointer to the route address
316  *
317  *   @return         ra_list or MNULL
318  */
wlan_wmm_get_ralist_node(pmlan_private priv,t_u8 tid,t_u8 * ra_addr)319 raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 *ra_addr)
320 {
321     raListTbl *ra_list;
322     ENTER();
323     ra_list =
324         (raListTbl *)util_peek_list(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[tid].ra_list, MNULL, MNULL);
325     while (ra_list && (ra_list != (raListTbl *)&priv->wmm.tid_tbl_ptr[tid].ra_list))
326     {
327         if (!__memcmp(priv->adapter, ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH))
328         {
329             LEAVE();
330             return ra_list;
331         }
332         ra_list = ra_list->pnext;
333     }
334     LEAVE();
335     return MNULL;
336 }
337 
338 #ifdef STA_SUPPORT
339 /**
340  *  @brief Call back from the command module to allow insertion of a WMM TLV
341  *
342  *  If the BSS we are associating to supports WMM, add the required WMM
343  *    Information IE to the association request command buffer in the form
344  *    of a NXP extended IEEE IE.
345  *
346  *  @param priv        Pointer to the mlan_private driver data struct
347  *  @param ppAssocBuf  Output parameter: Pointer to the TLV output buffer,
348  *                     modified on return to point after the appended WMM TLV
349  *  @param pWmmIE      Pointer to the WMM IE for the BSS we are joining
350  *  @param pHTCap      Pointer to the HT IE for the BSS we are joining
351  *
352  *  @return Length of data appended to the association tlv buffer
353  */
wlan_wmm_process_association_req(pmlan_private priv,t_u8 ** ppAssocBuf,IEEEtypes_WmmParameter_t * pWmmIE,IEEEtypes_HTCap_t * pHTCap)354 t_u32 wlan_wmm_process_association_req(pmlan_private priv,
355                                        t_u8 **ppAssocBuf,
356                                        IEEEtypes_WmmParameter_t *pWmmIE,
357                                        IEEEtypes_HTCap_t *pHTCap)
358 {
359     MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
360     t_u32 ret_len = 0;
361 
362     ENTER();
363 
364     /* Null checks */
365     if (ppAssocBuf == MNULL)
366     {
367         LEAVE();
368         return 0;
369     }
370     if ((*ppAssocBuf) == MNULL)
371     {
372         LEAVE();
373         return 0;
374     }
375 
376     if (pWmmIE == MNULL)
377     {
378         LEAVE();
379         return 0;
380     }
381 
382     PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n", pWmmIE->vend_hdr.element_id);
383 
384     if ((priv->wmm_required || ((pHTCap != MNULL) && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY) &&
385                                 (priv->config_bands & BAND_GN || priv->config_bands & BAND_AN))) &&
386         pWmmIE->vend_hdr.element_id == WMM_IE)
387     {
388         pwmm_tlv              = (MrvlIEtypes_WmmParamSet_t *)(void *)*ppAssocBuf;
389         pwmm_tlv->header.type = (t_u16)wmm_info_ie[0];
390         pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
391         pwmm_tlv->header.len  = (t_u16)wmm_info_ie[1];
392         (void)__memcpy(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2], pwmm_tlv->header.len);
393         if (pWmmIE->qos_info.qos_uapsd != 0U)
394         {
395             (void)__memcpy(priv->adapter, (t_u8 *)(pwmm_tlv->wmm_ie + pwmm_tlv->header.len - sizeof(priv->wmm_qosinfo)),
396                            &priv->wmm_qosinfo, sizeof(priv->wmm_qosinfo));
397         }
398 
399         ret_len              = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
400         pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
401 
402         HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *)pwmm_tlv, ret_len);
403         *ppAssocBuf += ret_len;
404     }
405 
406     LEAVE();
407     return ret_len;
408 }
409 #endif /* STA_SUPPORT */
410 
411 #if CONFIG_WMM
412 /**
413  *  @brief This function prepares the command of WMM_PARAM_CONFIG
414  *
415  *  @param pmpriv       A pointer to mlan_private structure
416  *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
417  *  @param cmd_action   cmd action.
418  *  @param pdata_buf    A pointer to data buffer
419  *  @return             MLAN_STATUS_SUCCESS
420  */
wlan_cmd_wmm_param_config(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u8 cmd_action,t_void * pdata_buf)421 mlan_status wlan_cmd_wmm_param_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u8 cmd_action, t_void *pdata_buf)
422 {
423     wmm_ac_parameters_t *ac_params        = (wmm_ac_parameters_t *)pdata_buf;
424     HostCmd_DS_WMM_PARAM_CONFIG *pcmd_cfg = &cmd->params.param_config;
425     t_u8 i                                = 0;
426 
427     ENTER();
428 
429     cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_PARAM_CONFIG);
430     cmd->size    = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_PARAM_CONFIG) + S_DS_GEN);
431     cmd->result  = 0;
432 
433     pcmd_cfg->action = cmd_action;
434     if (cmd_action == HostCmd_ACT_GEN_SET)
435     {
436         (void)__memcpy(pmpriv->adapter, pcmd_cfg->ac_params, ac_params, sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
437         for (i = 0; i < MAX_AC_QUEUES; i++)
438         {
439             pcmd_cfg->ac_params[i].tx_op_limit = wlan_cpu_to_le16(pcmd_cfg->ac_params[i].tx_op_limit);
440         }
441     }
442     LEAVE();
443     return MLAN_STATUS_SUCCESS;
444 }
445 
446 /**
447  *  @brief This function handles the command response of WMM_PARAM_CONFIG
448  *
449  *  @param pmpriv       A pointer to mlan_private structure
450  *  @param resp         A pointer to HostCmd_DS_COMMAND
451  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
452  *
453  *  @return             MLAN_STATUS_SUCCESS
454  */
wlan_ret_wmm_param_config(pmlan_private pmpriv,const HostCmd_DS_COMMAND * resp,mlan_ioctl_req * pioctl_buf)455 mlan_status wlan_ret_wmm_param_config(pmlan_private pmpriv, const HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf)
456 {
457     mlan_ds_wmm_cfg *pwmm             = MNULL;
458     HostCmd_DS_WMM_PARAM_CONFIG *pcfg = (HostCmd_DS_WMM_PARAM_CONFIG *)&resp->params.param_config;
459     t_u8 i;
460 
461     ENTER();
462 
463     if (pioctl_buf)
464     {
465         pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
466         for (i = 0; i < MAX_AC_QUEUES; i++)
467         {
468             pcfg->ac_params[i].tx_op_limit = wlan_le16_to_cpu(pcfg->ac_params[i].tx_op_limit);
469         }
470         (void)__memcpy(pmpriv->adapter, pwmm->param.ac_params, pcfg->ac_params,
471                        sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
472     }
473 
474     LEAVE();
475     return MLAN_STATUS_SUCCESS;
476 }
477 #endif
478 
479 #if CONFIG_WMM
480 #if CONFIG_WMM_DEBUG
481 #define MAX_HISTORY_RA_LIST_NUM 32
482 
wlan_ralist_get_history(mlan_private * priv,t_u8 * ra,t_u8 ac)483 static raListTbl *wlan_ralist_get_history(mlan_private *priv, t_u8 *ra, t_u8 ac)
484 {
485     raListTbl *ra_list = (raListTbl *)util_peek_list(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], MNULL, MNULL);
486 
487     if (ra_list == MNULL)
488         return MNULL;
489 
490     while (ra_list && ra_list != (raListTbl *)&priv->wmm.hist_ra[ac])
491     {
492         if (!memcmp(priv->adapter, ra, ra_list->ra, MLAN_MAC_ADDR_LENGTH))
493             return ra_list;
494 
495         ra_list = ra_list->pnext;
496     }
497     return MNULL;
498 }
499 
500 /* restore ralist to history list for debug */
wlan_ralist_restore_history(mlan_private * priv,raListTbl * ra_list,t_u8 ac)501 static void wlan_ralist_restore_history(mlan_private *priv, raListTbl *ra_list, t_u8 ac)
502 {
503     raListTbl *tmp = MNULL;
504 
505     /* history lists has same ra, update stats and insert to tail */
506     tmp = wlan_ralist_get_history(priv, ra_list->ra, ac);
507     if (tmp != MNULL)
508     {
509         util_unlink_list(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], (mlan_linked_list *)tmp, MNULL, MNULL);
510         ra_list->drop_count += tmp->drop_count;
511         util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], (mlan_linked_list *)ra_list, MNULL,
512                                MNULL);
513         goto FREE_TMP;
514     }
515 
516     /* history ralist count reaches max, dequeue the earliest ralist */
517     if (priv->wmm.hist_ra_count[ac] >= MAX_HISTORY_RA_LIST_NUM)
518     {
519         tmp = (raListTbl *)util_dequeue_list(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], MNULL, MNULL);
520         if (tmp == MNULL)
521         {
522             wifi_e("%s error history ralist count %hhu", priv->wmm.hist_ra_count[ac]);
523             goto FREE_IN;
524         }
525 
526         util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], (mlan_linked_list *)ra_list, MNULL,
527                                MNULL);
528         goto FREE_TMP;
529     }
530     else
531     {
532         util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->wmm.hist_ra[ac], (mlan_linked_list *)ra_list, MNULL,
533                                MNULL);
534         priv->wmm.hist_ra_count[ac]++;
535     }
536 
537     return;
538 FREE_TMP:
539     priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle, &tmp->buf_head.plock);
540     priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, (t_u8 *)tmp);
541     return;
542 FREE_IN:
543     priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
544     priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, (t_u8 *)ra_list);
545     return;
546 }
547 #endif
548 
549 /*
550  *  transfer destination address to receive address
551  *  consider 802.3 DA as RA
552  *  for broadcast and multicast, consider RA as broadcast mac address
553  */
wifi_wmm_da_to_ra(uint8_t * da,uint8_t * ra)554 void wifi_wmm_da_to_ra(uint8_t *da, uint8_t *ra)
555 {
556     if ((da[0] & 0x01) == 1)
557         (void)__memset(mlan_adap, ra, 0xff, MLAN_MAC_ADDR_LENGTH);
558     else
559         (void)__memcpy(mlan_adap, ra, da, MLAN_MAC_ADDR_LENGTH);
560 }
561 
562 /*
563  *  check ra tx_pause status
564  *  1. STA mode: check priv->tx_pause
565  *  2. UAP mode:
566  *      a. broadcast/multicast ra: check in ralists
567  *      b. unicast ra: check in ampdu_stat_array for quick access
568  */
wifi_wmm_is_tx_pause(const uint8_t interface,mlan_wmm_ac_e queue,uint8_t * ra)569 static uint8_t wifi_wmm_is_tx_pause(const uint8_t interface, mlan_wmm_ac_e queue, uint8_t *ra)
570 {
571     t_u8 is_tx_pause   = MFALSE;
572     raListTbl *ra_list = MNULL;
573 
574     if (interface == MLAN_BSS_TYPE_STA)
575     {
576         is_tx_pause = mlan_adap->priv[0]->tx_pause;
577     }
578     else if (interface == MLAN_BSS_TYPE_UAP)
579     {
580         if (mlan_adap->priv[1]->tx_pause == MTRUE)
581         {
582             is_tx_pause = MTRUE;
583         }
584         else
585         {
586             mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle,
587                                                     &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
588 
589             ra_list = wlan_wmm_get_ralist_node(mlan_adap->priv[interface], queue, ra);
590             if (ra_list != MNULL)
591                 is_tx_pause = ra_list->tx_pause;
592 
593             mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
594                                                     &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
595         }
596     }
597 
598     return is_tx_pause;
599 }
600 
601 /*
602  *  find the alternative buffer paused in txqueue and replace it,
603  *  priv->tx_pause 1: replace any ra node's oldest packet
604  *  tx_pause 1: replace the same ra node's oldest packet
605  *  tx_pause 0: replace any other tx_paused ra node's oldest packet
606  */
wifi_wmm_get_alter_buf_from_txqueue(const uint8_t interface,t_u8 * ra,t_u8 queue,t_u8 tx_pause)607 static outbuf_t *wifi_wmm_get_alter_buf_from_txqueue(const uint8_t interface, t_u8 *ra, t_u8 queue, t_u8 tx_pause)
608 {
609     raListTbl *ra_list_head = MNULL;
610     raListTbl *ra_list      = MNULL;
611     outbuf_t *buf           = MNULL;
612 
613     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle,
614                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
615 
616     if (mlan_adap->priv[interface]->wmm.pkts_queued[queue] == 0)
617         goto FAIL;
618 
619     ra_list_head = (raListTbl *)&mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list;
620     ra_list      = (raListTbl *)util_peek_list(mlan_adap->pmoal_handle, (mlan_list_head *)ra_list_head, MNULL, MNULL);
621 
622     while (ra_list && ra_list != ra_list_head)
623     {
624         mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
625         if (__memcmp(mlan_adap, ra, ra_list->ra, MLAN_MAC_ADDR_LENGTH) && ra_list->tx_pause == MTRUE &&
626             ra_list->total_pkts != 0)
627         {
628             buf = (outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &ra_list->buf_head, MNULL, MNULL);
629             if (buf != MNULL)
630                 goto SUCC;
631         }
632         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
633         ra_list = ra_list->pnext;
634     }
635 
636 FAIL:
637     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
638                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
639     return MNULL;
640 SUCC:
641     mlan_adap->priv[interface]->wmm.pkts_queued[queue]--;
642     ra_list->total_pkts--;
643     ra_list->drop_count++;
644 #if CONFIG_TX_RX_ZERO_COPY
645     /* Before replacement, need free the buffer from stack first */
646     net_stack_buffer_free(buf->buffer);
647 #endif
648 
649     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
650 
651     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
652                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
653 
654     wifi_wmm_drop_pause_replaced(interface);
655     return buf;
656 }
657 
658 /* wmm enhance get free buffer */
wifi_wmm_get_outbuf_enh(uint32_t * outbuf_len,mlan_wmm_ac_e queue,const uint8_t interface,uint8_t * ra,bool * is_tx_pause)659 uint8_t *wifi_wmm_get_outbuf_enh(
660     uint32_t *outbuf_len, mlan_wmm_ac_e queue, const uint8_t interface, uint8_t *ra, bool *is_tx_pause)
661 {
662     t_u8 i;
663     outbuf_t *buf = MNULL;
664     t_u8 tx_pause;
665 
666     buf = wifi_wmm_buf_get();
667     if (buf != MNULL)
668         goto SUCC;
669 
670     /* check tx_pause */
671     tx_pause     = wifi_wmm_is_tx_pause(interface, queue, ra);
672     *is_tx_pause = (tx_pause == MTRUE) ? true : false;
673 
674     /* loop tid_tbl to find buf to replace in wmm ralists */
675     if (tx_pause == MFALSE)
676     {
677         for (i = 0; i < MAX_AC_QUEUES; i++)
678         {
679             buf = wifi_wmm_get_alter_buf_from_txqueue(interface, ra, i, tx_pause);
680             if (buf != MNULL)
681                 goto SUCC;
682         }
683     }
684 
685     *outbuf_len = 0;
686     return MNULL;
687 SUCC:
688     *outbuf_len = OUTBUF_WMM_LEN;
689     return (uint8_t *)buf;
690 }
691 
692 /*
693  *  get RA list for tx enqueue,
694  *  check add broadcast RA list,
695  *  drop unknown RA packets in UAP mode
696  */
wlan_wmm_get_queue_raptr_enh(pmlan_private priv,t_u8 ac,t_u8 * ra_addr)697 static raListTbl *wlan_wmm_get_queue_raptr_enh(pmlan_private priv, t_u8 ac, t_u8 *ra_addr)
698 {
699     raListTbl *ra_list = MNULL;
700     t_u8 bcast_addr[]  = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
701 
702     ra_list = wlan_wmm_get_ralist_node(priv, ac, ra_addr);
703     if (ra_list != MNULL)
704         return ra_list;
705 
706 #if CONFIG_WIFI_NM_WPA_SUPPLICANT
707     if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
708          (0 != memcmp(ra_addr, bcast_addr, sizeof(bcast_addr))))
709     {
710         if (MNULL == wlan_get_station_entry(priv, ra_addr))
711         {
712             PRINTM(MERROR, "Drop packets to unknow station " MACSTR "\n",  MAC2STR(ra_addr));
713             LEAVE();
714             return MNULL;
715         }
716     }
717 #else
718     if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP && __memcmp(priv->adapter, ra_addr, bcast_addr, MLAN_MAC_ADDR_LENGTH))
719         return MNULL;
720 #endif
721 
722     /* wlan_ralist_add_enh will hold wmm lock, so need to unlock first */
723     priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[ac].ra_list.plock);
724 
725     wlan_ralist_add_enh(priv, ra_addr);
726 
727     priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[ac].ra_list.plock);
728 
729     ra_list = wlan_wmm_get_ralist_node(priv, ac, ra_addr);
730     return ra_list;
731 }
732 
733 /* wmm enhance enqueue tx buffer */
wlan_wmm_add_buf_txqueue_enh(const uint8_t interface,const uint8_t * buffer,const uint16_t len,uint8_t pkt_prio)734 int wlan_wmm_add_buf_txqueue_enh(const uint8_t interface, const uint8_t *buffer, const uint16_t len, uint8_t pkt_prio)
735 {
736     mlan_private *priv            = MNULL;
737     t_u8 ra[MLAN_MAC_ADDR_LENGTH] = {0x0};
738     raListTbl *ralist             = MNULL;
739 
740     if (interface == MLAN_BSS_TYPE_STA)
741         priv = mlan_adap->priv[0];
742     else
743         priv = mlan_adap->priv[1];
744 
745         /* refer to low_level_output payload memcpy */
746 #if CONFIG_TX_RX_ZERO_COPY
747     wifi_wmm_da_to_ra(&((outbuf_t *)buffer)->eth_header[0], ra);
748 #else
749     wifi_wmm_da_to_ra(&((outbuf_t *)buffer)->data[0], ra);
750 #endif
751     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
752 
753     ralist = wlan_wmm_get_queue_raptr_enh(priv, pkt_prio, ra);
754     if (ralist == MNULL)
755     {
756         /* drop for unknown ra when enqueue */
757         wifi_wmm_buf_put((outbuf_t *)buffer);
758         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
759                                                 &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
760         return MLAN_STATUS_FAILURE;
761     }
762 
763     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &ralist->buf_head.plock);
764 
765     util_enqueue_list_tail(mlan_adap->pmoal_handle, &ralist->buf_head, (mlan_linked_list *)buffer, MNULL, MNULL);
766     ralist->total_pkts++;
767     priv->wmm.pkts_queued[pkt_prio]++;
768 
769     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ralist->buf_head.plock);
770 
771     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
772 
773     return MLAN_STATUS_SUCCESS;
774 }
775 
776 /* wmm enhance buffer pool management */
777 /* return NULL if wmm free list is empty */
wifi_wmm_buf_get(void)778 outbuf_t *wifi_wmm_buf_get(void)
779 {
780     outbuf_t *buf = MNULL;
781 
782     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
783 
784     assert(mlan_adap->outbuf_pool.free_cnt >= 0);
785 
786     if (mlan_adap->outbuf_pool.free_cnt == 0)
787     {
788         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
789         return MNULL;
790     }
791 
792     buf = (outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MNULL, MNULL);
793     assert(buf != MNULL);
794     mlan_adap->outbuf_pool.free_cnt--;
795 
796     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
797     return buf;
798 }
799 
wifi_wmm_buf_put(outbuf_t * buf)800 void wifi_wmm_buf_put(outbuf_t *buf)
801 {
802     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
803 
804     assert(mlan_adap->outbuf_pool.free_cnt < MAX_WMM_BUF_NUM);
805 
806 #if CONFIG_TX_RX_ZERO_COPY
807     /* Free driver's reference count for network buffer */
808     net_stack_buffer_free(buf->buffer);
809 #endif
810 
811     util_enqueue_list_tail(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, &buf->entry, MNULL, MNULL);
812     mlan_adap->outbuf_pool.free_cnt++;
813 
814     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
815 }
816 
817 /* init free list, insert all buffers to free list */
wifi_wmm_buf_pool_init(uint8_t * pool)818 int wifi_wmm_buf_pool_init(uint8_t *pool)
819 {
820     int i;
821     outbuf_t *buf = MNULL;
822 
823     __memset(mlan_adap, &mlan_adap->outbuf_pool, 0x00, sizeof(outbuf_pool_t));
824 
825     util_init_list_head(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MFALSE, MNULL);
826 
827     if (mlan_adap->callbacks.moal_init_semaphore(mlan_adap->pmoal_handle, "wmm_buf_pool_sem",
828                                                  &mlan_adap->outbuf_pool.free_list.plock) != MLAN_STATUS_SUCCESS)
829         return WM_E_NOMEM;
830 
831     for (i = 0; i < MAX_WMM_BUF_NUM; i++)
832     {
833         /* TODO: where to put buffer pool mgmt codes */
834         // buf = (outbuf_t *)&outbuf_arr[i][0];
835         buf = (outbuf_t *)(pool + (i * OUTBUF_WMM_LEN));
836         util_init_list(&buf->entry);
837         util_enqueue_list_tail(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, &buf->entry, MNULL, MNULL);
838     }
839     mlan_adap->outbuf_pool.free_cnt = MAX_WMM_BUF_NUM;
840 
841     return WM_SUCCESS;
842 }
843 
844 /* deinit free list, should be called after all buffers are put back */
wifi_wmm_buf_pool_deinit(void)845 void wifi_wmm_buf_pool_deinit(void)
846 {
847     mlan_adap->outbuf_pool.free_cnt = 0;
848 
849     mlan_adap->callbacks.moal_free_semaphore(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
850 
851     util_free_list_head(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MNULL);
852 
853     __memset(mlan_adap, &mlan_adap->outbuf_pool, 0x00, sizeof(outbuf_pool_t));
854 }
855 
856 /* wmm enhance ralist operation */
857 /* should be called inside wmm tid_tbl_ptr ra_list lock */
wlan_ralist_pkts_free_enh(mlan_private * priv,raListTbl * ra_list,t_u8 ac)858 void wlan_ralist_pkts_free_enh(mlan_private *priv, raListTbl *ra_list, t_u8 ac)
859 {
860     outbuf_t *buff = MNULL;
861 
862     priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
863 
864     while ((buff = (outbuf_t *)util_peek_list(priv->adapter->pmoal_handle, &ra_list->buf_head, MNULL, MNULL)))
865     {
866         util_unlink_list(priv->adapter->pmoal_handle, &ra_list->buf_head, &buff->entry, MNULL, MNULL);
867         wifi_wmm_buf_put(buff);
868 
869         priv->wmm.pkts_queued[ac]--;
870         wifi_wmm_drop_no_media(priv->bss_index);
871         ra_list->drop_count++;
872     }
873     ra_list->total_pkts = 0;
874 
875     priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
876 }
877 
878 /* should be called inside wmm tid_tbl_ptr ra_list lock */
wlan_ralist_free_enh(mlan_private * priv,raListTbl * ra_list,t_u8 ac)879 static void wlan_ralist_free_enh(mlan_private *priv, raListTbl *ra_list, t_u8 ac)
880 {
881 #if CONFIG_WMM_DEBUG
882     wlan_ralist_restore_history(priv, ra_list, ac);
883 #else
884     priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
885 #if !CONFIG_MEM_POOLS
886 
887     priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, (t_u8 *)ra_list);
888 #else
889     OSA_MemoryPoolFree(buf_128_MemoryPool, ra_list);
890 #endif
891 #endif
892 }
893 
wlan_ralist_alloc_enh(pmlan_adapter pmadapter,t_u8 * ra)894 static raListTbl *wlan_ralist_alloc_enh(pmlan_adapter pmadapter, t_u8 *ra)
895 {
896     mlan_status ret;
897     raListTbl *ra_list = MNULL;
898 
899 #if !CONFIG_MEM_POOLS
900     ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF, (t_u8 **)&ra_list);
901     if (ret != MLAN_STATUS_SUCCESS || ra_list == MNULL)
902         return MNULL;
903 #else
904     ra_list = OSA_MemoryPoolAllocate(buf_128_MemoryPool);
905     if (ra_list == MNULL)
906     {
907         return MNULL;
908     }
909 
910 #endif
911 
912     util_init_list((pmlan_linked_list)ra_list);
913     util_init_list_head((t_void *)pmadapter->pmoal_handle, &ra_list->buf_head, MFALSE, MNULL);
914 
915     ret = pmadapter->callbacks.moal_init_semaphore(pmadapter->pmoal_handle, "buf_head_sem", &ra_list->buf_head.plock);
916     if (ret != MLAN_STATUS_SUCCESS)
917     {
918         pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *)ra_list);
919         return MNULL;
920     }
921 
922     (void)__memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
923 
924     ra_list->total_pkts = 0;
925     ra_list->tx_pause   = 0;
926     ra_list->drop_count = 0;
927 
928     wifi_d("RAList: Allocating buffers for TID %p\n", ra_list);
929 
930     return ra_list;
931 }
932 
wlan_ralist_add_enh(mlan_private * priv,t_u8 * ra)933 void wlan_ralist_add_enh(mlan_private *priv, t_u8 *ra)
934 {
935     int i;
936     raListTbl *ra_list      = MNULL;
937     pmlan_adapter pmadapter = priv->adapter;
938 
939     for (i = 0; i < MAX_AC_QUEUES; i++)
940     {
941         if ((ra_list = wlan_wmm_get_ralist_node(priv, i, ra)))
942             continue;
943 
944         ra_list = wlan_ralist_alloc_enh(pmadapter, ra);
945         wifi_d("Creating RA List %p for tid %d\n", ra_list, i);
946         if (ra_list == MNULL)
947         {
948             wifi_e("Creating RA List for tid %d fail", i);
949             break;
950         }
951 
952         pmadapter->callbacks.moal_semaphore_get(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
953 
954         util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list,
955                                MNULL, MNULL);
956 
957         if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == MNULL)
958             priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
959 
960         pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
961     }
962 }
963 
wlan_ralist_update_enh(mlan_private * priv,t_u8 * old_ra,t_u8 * new_ra)964 int wlan_ralist_update_enh(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra)
965 {
966     int i;
967     int update_count   = 0;
968     raListTbl *ra_list = MNULL;
969 #if CONFIG_WMM_DEBUG
970     raListTbl *hist_ra_list = MNULL;
971 #endif
972 
973     for (i = 0; i < MAX_AC_QUEUES; i++)
974     {
975         priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle,
976                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
977 
978         ra_list = wlan_wmm_get_ralist_node(priv, i, old_ra);
979         if (ra_list == MNULL)
980         {
981             priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
982                                                         &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
983             continue;
984         }
985 
986         update_count++;
987 
988         wlan_ralist_pkts_free_enh(priv, ra_list, i);
989         ra_list->tx_pause = MFALSE;
990 
991         (void)__memcpy(priv->adapter, ra_list->ra, new_ra, MLAN_MAC_ADDR_LENGTH);
992 
993 #if CONFIG_WMM_DEBUG
994         hist_ra_list = wlan_ralist_alloc_enh(priv->adapter, old_ra);
995         if (hist_ra_list != MNULL)
996         {
997             hist_ra_list->drop_count = ra_list->drop_count;
998             wlan_ralist_free_enh(priv, hist_ra_list, i);
999         }
1000 #endif
1001 
1002         priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
1003                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1004     }
1005 
1006     return update_count;
1007 }
1008 
wlan_ralist_del_enh(mlan_private * priv,t_u8 * ra)1009 void wlan_ralist_del_enh(mlan_private *priv, t_u8 *ra)
1010 {
1011     int i;
1012     pmlan_adapter pmadapter = priv->adapter;
1013     raListTbl *ra_list      = MNULL;
1014 
1015     for (i = 0; i < MAX_AC_QUEUES; i++)
1016     {
1017         pmadapter->callbacks.moal_semaphore_get(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1018 
1019         ra_list = wlan_wmm_get_ralist_node(priv, i, ra);
1020         if (ra_list == MNULL)
1021         {
1022             pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1023             continue;
1024         }
1025 
1026         wlan_ralist_pkts_free_enh(priv, ra_list, i);
1027 
1028         util_unlink_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list, MNULL,
1029                          MNULL);
1030 
1031         if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
1032             priv->wmm.tid_tbl_ptr[i].ra_list_curr = (raListTbl *)&priv->wmm.tid_tbl_ptr[i].ra_list;
1033 
1034         wlan_ralist_free_enh(priv, ra_list, i);
1035 
1036         pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1037     }
1038 }
1039 
wlan_ralist_del_all_enh(mlan_private * priv)1040 void wlan_ralist_del_all_enh(mlan_private *priv)
1041 {
1042     int i;
1043     raListTbl *ra_list      = MNULL;
1044     pmlan_adapter pmadapter = priv->adapter;
1045 
1046     for (i = 0; i < MAX_AC_QUEUES; i++)
1047     {
1048         priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle,
1049                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1050 
1051         while ((ra_list = (raListTbl *)util_peek_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL,
1052                                                       MNULL)))
1053         {
1054             util_unlink_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list,
1055                              MNULL, MNULL);
1056 
1057             wlan_ralist_pkts_free_enh(priv, ra_list, i);
1058 
1059             wlan_ralist_free_enh(priv, ra_list, i);
1060         }
1061 
1062         /* do not reinit list lock, so use util_init_list instead of util_init_list_head */
1063         util_init_list((pmlan_linked_list)&priv->wmm.tid_tbl_ptr[i].ra_list);
1064         priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
1065         priv->wmm.pkts_queued[i]              = 0;
1066 
1067         priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
1068                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1069     }
1070 }
1071 
wlan_ralist_deinit_enh(mlan_private * priv)1072 void wlan_ralist_deinit_enh(mlan_private *priv)
1073 {
1074     int i;
1075 
1076     /* already del all ralists in wlan_clean_txrx */
1077     // wlan_ralist_del_all_enh(priv);
1078 
1079     for (i = 0; i < MAX_AC_QUEUES; i++)
1080     {
1081         /* free ralist lock */
1082         priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle,
1083                                                      &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1084 
1085         /* deinit ralists table */
1086         util_free_list_head(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL);
1087     }
1088 }
1089 
1090 /* debug statistics */
wifi_wmm_drop_err_mem(const uint8_t interface)1091 void wifi_wmm_drop_err_mem(const uint8_t interface)
1092 {
1093     if (interface == MLAN_BSS_TYPE_STA)
1094         mlan_adap->priv[0]->driver_error_cnt.tx_err_mem++;
1095     else if (interface == MLAN_BSS_TYPE_UAP)
1096         mlan_adap->priv[1]->driver_error_cnt.tx_err_mem++;
1097 }
1098 
wifi_wmm_drop_no_media(const uint8_t interface)1099 void wifi_wmm_drop_no_media(const uint8_t interface)
1100 {
1101     if (interface == MLAN_BSS_TYPE_STA)
1102         mlan_adap->priv[0]->driver_error_cnt.tx_no_media++;
1103     else if (interface == MLAN_BSS_TYPE_UAP)
1104         mlan_adap->priv[1]->driver_error_cnt.tx_no_media++;
1105 }
1106 
wifi_wmm_drop_retried_drop(const uint8_t interface)1107 void wifi_wmm_drop_retried_drop(const uint8_t interface)
1108 {
1109     if (interface == MLAN_BSS_TYPE_STA)
1110         mlan_adap->priv[0]->driver_error_cnt.tx_wmm_retried_drop++;
1111     else if (interface == MLAN_BSS_TYPE_UAP)
1112         mlan_adap->priv[1]->driver_error_cnt.tx_wmm_retried_drop++;
1113 }
1114 
wifi_wmm_drop_pause_drop(const uint8_t interface)1115 void wifi_wmm_drop_pause_drop(const uint8_t interface)
1116 {
1117     if (interface == MLAN_BSS_TYPE_STA)
1118         mlan_adap->priv[0]->driver_error_cnt.tx_wmm_pause_drop++;
1119     else if (interface == MLAN_BSS_TYPE_UAP)
1120         mlan_adap->priv[1]->driver_error_cnt.tx_wmm_pause_drop++;
1121 }
1122 
wifi_wmm_drop_pause_replaced(const uint8_t interface)1123 void wifi_wmm_drop_pause_replaced(const uint8_t interface)
1124 {
1125     if (interface == MLAN_BSS_TYPE_STA)
1126         mlan_adap->priv[0]->driver_error_cnt.tx_wmm_pause_replaced++;
1127     else if (interface == MLAN_BSS_TYPE_UAP)
1128         mlan_adap->priv[1]->driver_error_cnt.tx_wmm_pause_replaced++;
1129 }
1130 
wlan_get_bypass_lock(uint8_t interface)1131 void wlan_get_bypass_lock(uint8_t interface)
1132 {
1133     pmlan_private priv = mlan_adap->priv[interface];
1134 
1135     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1136 }
1137 
wlan_put_bypass_lock(uint8_t interface)1138 void wlan_put_bypass_lock(uint8_t interface)
1139 {
1140     pmlan_private priv = mlan_adap->priv[interface];
1141 
1142     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1143 }
1144 
wlan_add_buf_bypass_txq(const uint8_t * buffer,const uint8_t interface)1145 void wlan_add_buf_bypass_txq(const uint8_t *buffer, const uint8_t interface)
1146 {
1147     pmlan_private priv = mlan_adap->priv[interface];
1148 
1149     wlan_get_bypass_lock(interface);
1150 
1151     util_enqueue_list_tail(mlan_adap->pmoal_handle, &priv->bypass_txq, (mlan_linked_list *)buffer, MNULL, MNULL);
1152     priv->bypass_txq_cnt++;
1153 
1154     wlan_put_bypass_lock(interface);
1155 }
1156 
wlan_bypass_txq_empty(uint8_t interface)1157 t_u8 wlan_bypass_txq_empty(uint8_t interface)
1158 {
1159     return (mlan_adap->priv[interface]->bypass_txq_cnt) ? MFALSE : MTRUE;
1160 }
1161 
wifi_bypass_txq_init(void)1162 int wifi_bypass_txq_init(void)
1163 {
1164     pmlan_private priv = NULL;
1165     int i;
1166 
1167     for (i = 0; i < mlan_adap->priv_num; ++i)
1168     {
1169         priv = mlan_adap->priv[i];
1170         if (priv != MNULL)
1171         {
1172             /* Initialize bypass_txq */
1173             util_init_list_head((t_void *)mlan_adap->pmoal_handle, &priv->bypass_txq, MFALSE, MNULL);
1174             priv->bypass_txq_cnt = 0;
1175 
1176             if (mlan_adap->callbacks.moal_init_semaphore(mlan_adap->pmoal_handle, "bypass_txq_sem",
1177                                                          &priv->bypass_txq.plock) != MLAN_STATUS_SUCCESS)
1178                 return WM_E_NOMEM;
1179         }
1180     }
1181 
1182     return WM_SUCCESS;
1183 }
1184 
wlan_cleanup_bypass_txq(uint8_t interface)1185 void wlan_cleanup_bypass_txq(uint8_t interface)
1186 {
1187     bypass_outbuf_t *buf;
1188     pmlan_private priv = mlan_adap->priv[interface];
1189 
1190     /*Free hold buff*/
1191     while (!wlan_bypass_txq_empty(interface))
1192     {
1193         wlan_get_bypass_lock(interface);
1194 
1195         buf = (bypass_outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &priv->bypass_txq, MNULL, MNULL);
1196         priv->bypass_txq_cnt--;
1197 #if !CONFIG_MEM_POOLS
1198         OSA_MemoryFree(buf);
1199 #else
1200         OSA_MemoryPoolFree(buf_1536_MemoryPool, buf);
1201 #endif
1202 
1203         wlan_put_bypass_lock(interface);
1204     }
1205 }
1206 
wifi_bypass_txq_deinit(void)1207 void wifi_bypass_txq_deinit(void)
1208 {
1209     pmlan_private priv = NULL;
1210     int i;
1211 
1212     for (i = 0; i < mlan_adap->priv_num; ++i)
1213     {
1214         priv = mlan_adap->priv[i];
1215         if (priv != MNULL)
1216         {
1217             wlan_cleanup_bypass_txq(i);
1218 
1219             mlan_adap->callbacks.moal_free_semaphore(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1220             /* Deinit bypass_txq */
1221             util_free_list_head(mlan_adap->pmoal_handle, &priv->bypass_txq, MNULL);
1222             priv->bypass_txq_cnt = 0;
1223         }
1224     }
1225 }
1226 #endif /* CONFIG_WMM */
1227