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 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 #if 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 #if UAP_SUPPORT
573     raListTbl *ra_list = MNULL;
574 #endif
575 
576     if (interface == MLAN_BSS_TYPE_STA)
577     {
578         is_tx_pause = mlan_adap->priv[0]->tx_pause;
579     }
580 #if UAP_SUPPORT
581     else if (interface == MLAN_BSS_TYPE_UAP)
582     {
583         if (mlan_adap->priv[1]->tx_pause == MTRUE)
584         {
585             is_tx_pause = MTRUE;
586         }
587         else
588         {
589             mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle,
590                                                     &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
591 
592             ra_list = wlan_wmm_get_ralist_node(mlan_adap->priv[interface], queue, ra);
593             if (ra_list != MNULL)
594                 is_tx_pause = ra_list->tx_pause;
595 
596             mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
597                                                     &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
598         }
599     }
600 #else
601     (void)queue;
602     (void)ra;
603 #endif
604 
605     return is_tx_pause;
606 }
607 
608 /*
609  *  find the alternative buffer paused in txqueue and replace it,
610  *  priv->tx_pause 1: replace any ra node's oldest packet
611  *  tx_pause 1: replace the same ra node's oldest packet
612  *  tx_pause 0: replace any other tx_paused ra node's oldest packet
613  */
wifi_wmm_get_alter_buf_from_txqueue(const uint8_t interface,t_u8 * ra,t_u8 queue,t_u8 tx_pause)614 static outbuf_t *wifi_wmm_get_alter_buf_from_txqueue(const uint8_t interface, t_u8 *ra, t_u8 queue, t_u8 tx_pause)
615 {
616     raListTbl *ra_list_head = MNULL;
617     raListTbl *ra_list      = MNULL;
618     outbuf_t *buf           = MNULL;
619 
620     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle,
621                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
622 
623     if (mlan_adap->priv[interface]->wmm.pkts_queued[queue] == 0)
624         goto FAIL;
625 
626     ra_list_head = (raListTbl *)&mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list;
627     ra_list      = (raListTbl *)util_peek_list(mlan_adap->pmoal_handle, (mlan_list_head *)ra_list_head, MNULL, MNULL);
628 
629     while (ra_list && ra_list != ra_list_head)
630     {
631         mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
632         if (__memcmp(mlan_adap, ra, ra_list->ra, MLAN_MAC_ADDR_LENGTH) && ra_list->tx_pause == MTRUE &&
633             ra_list->total_pkts != 0)
634         {
635             buf = (outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &ra_list->buf_head, MNULL, MNULL);
636             if (buf != MNULL)
637                 goto SUCC;
638         }
639         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
640         ra_list = ra_list->pnext;
641     }
642 
643 FAIL:
644     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
645                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
646     return MNULL;
647 SUCC:
648     mlan_adap->priv[interface]->wmm.pkts_queued[queue]--;
649     ra_list->total_pkts--;
650     ra_list->drop_count++;
651 #if CONFIG_TX_RX_ZERO_COPY
652     /* Before replacement, need free the buffer from stack first */
653     net_stack_buffer_free(buf->buffer);
654 #endif
655 
656     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ra_list->buf_head.plock);
657 
658     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
659                                             &mlan_adap->priv[interface]->wmm.tid_tbl_ptr[queue].ra_list.plock);
660 
661     wifi_wmm_drop_pause_replaced(interface);
662     return buf;
663 }
664 
665 /* 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)666 uint8_t *wifi_wmm_get_outbuf_enh(
667     uint32_t *outbuf_len, mlan_wmm_ac_e queue, const uint8_t interface, uint8_t *ra, bool *is_tx_pause)
668 {
669     t_u8 i;
670     outbuf_t *buf = MNULL;
671     t_u8 tx_pause;
672 
673     buf = wifi_wmm_buf_get();
674     if (buf != MNULL)
675         goto SUCC;
676 
677     /* check tx_pause */
678     tx_pause     = wifi_wmm_is_tx_pause(interface, queue, ra);
679     *is_tx_pause = (tx_pause == MTRUE) ? true : false;
680 
681     /* loop tid_tbl to find buf to replace in wmm ralists */
682     if (tx_pause == MFALSE)
683     {
684         for (i = 0; i < MAX_AC_QUEUES; i++)
685         {
686             buf = wifi_wmm_get_alter_buf_from_txqueue(interface, ra, i, tx_pause);
687             if (buf != MNULL)
688                 goto SUCC;
689         }
690     }
691 
692     *outbuf_len = 0;
693     return MNULL;
694 SUCC:
695     *outbuf_len = OUTBUF_WMM_LEN;
696     return (uint8_t *)buf;
697 }
698 
699 /*
700  *  get RA list for tx enqueue,
701  *  check add broadcast RA list,
702  *  drop unknown RA packets in UAP mode
703  */
wlan_wmm_get_queue_raptr_enh(pmlan_private priv,t_u8 ac,t_u8 * ra_addr)704 static raListTbl *wlan_wmm_get_queue_raptr_enh(pmlan_private priv, t_u8 ac, t_u8 *ra_addr)
705 {
706     raListTbl *ra_list = MNULL;
707     t_u8 bcast_addr[]  = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
708 
709     ra_list = wlan_wmm_get_ralist_node(priv, ac, ra_addr);
710     if (ra_list != MNULL)
711         return ra_list;
712 
713 #if CONFIG_WIFI_NM_WPA_SUPPLICANT
714     if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
715          (0 != memcmp(ra_addr, bcast_addr, sizeof(bcast_addr))))
716     {
717         if (MNULL == wlan_get_station_entry(priv, ra_addr))
718         {
719             PRINTM(MERROR, "Drop packets to unknow station " MACSTR "\n",  MAC2STR(ra_addr));
720             LEAVE();
721             return MNULL;
722         }
723     }
724 #else
725     if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP && __memcmp(priv->adapter, ra_addr, bcast_addr, MLAN_MAC_ADDR_LENGTH))
726         return MNULL;
727 #endif
728 
729     /* wlan_ralist_add_enh will hold wmm lock, so need to unlock first */
730     priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[ac].ra_list.plock);
731 
732     wlan_ralist_add_enh(priv, ra_addr);
733 
734     priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[ac].ra_list.plock);
735 
736     ra_list = wlan_wmm_get_ralist_node(priv, ac, ra_addr);
737     return ra_list;
738 }
739 
740 /* 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)741 int wlan_wmm_add_buf_txqueue_enh(const uint8_t interface, const uint8_t *buffer, const uint16_t len, uint8_t pkt_prio)
742 {
743     mlan_private *priv            = MNULL;
744     t_u8 ra[MLAN_MAC_ADDR_LENGTH] = {0x0};
745     raListTbl *ralist             = MNULL;
746 
747     CHECK_BSS_TYPE(interface, MLAN_STATUS_FAILURE);
748     priv = mlan_adap->priv[interface];
749 
750     /* refer to low_level_output payload memcpy */
751 #if CONFIG_TX_RX_ZERO_COPY
752     wifi_wmm_da_to_ra(&((outbuf_t *)buffer)->eth_header[0], ra);
753 #else
754     wifi_wmm_da_to_ra(&((outbuf_t *)buffer)->data[0], ra);
755 #endif
756     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
757 
758     ralist = wlan_wmm_get_queue_raptr_enh(priv, pkt_prio, ra);
759     if (ralist == MNULL)
760     {
761         /* drop for unknown ra when enqueue */
762         wifi_wmm_buf_put((outbuf_t *)buffer);
763         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle,
764                                                 &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
765         return MLAN_STATUS_FAILURE;
766     }
767 
768     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &ralist->buf_head.plock);
769 
770     util_enqueue_list_tail(mlan_adap->pmoal_handle, &ralist->buf_head, (mlan_linked_list *)buffer, MNULL, MNULL);
771     ralist->total_pkts++;
772     priv->wmm.pkts_queued[pkt_prio]++;
773 
774     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &ralist->buf_head.plock);
775 
776     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &priv->wmm.tid_tbl_ptr[pkt_prio].ra_list.plock);
777 
778     return MLAN_STATUS_SUCCESS;
779 }
780 
781 /* wmm enhance buffer pool management */
782 /* return NULL if wmm free list is empty */
wifi_wmm_buf_get(void)783 outbuf_t *wifi_wmm_buf_get(void)
784 {
785     outbuf_t *buf = MNULL;
786 
787     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
788 
789     assert(mlan_adap->outbuf_pool.free_cnt >= 0);
790 
791     if (mlan_adap->outbuf_pool.free_cnt == 0)
792     {
793         mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
794         return MNULL;
795     }
796 
797     buf = (outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MNULL, MNULL);
798     assert(buf != MNULL);
799     mlan_adap->outbuf_pool.free_cnt--;
800 
801     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
802     return buf;
803 }
804 
wifi_wmm_buf_put(outbuf_t * buf)805 void wifi_wmm_buf_put(outbuf_t *buf)
806 {
807     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
808 
809     assert(mlan_adap->outbuf_pool.free_cnt < MAX_WMM_BUF_NUM);
810 
811 #if CONFIG_TX_RX_ZERO_COPY
812     /* Free driver's reference count for network buffer */
813     net_stack_buffer_free(buf->buffer);
814 #endif
815 
816     util_enqueue_list_tail(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, &buf->entry, MNULL, MNULL);
817     mlan_adap->outbuf_pool.free_cnt++;
818 
819     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
820 }
821 
822 /* init free list, insert all buffers to free list */
wifi_wmm_buf_pool_init(uint8_t * pool)823 int wifi_wmm_buf_pool_init(uint8_t *pool)
824 {
825     int i;
826     outbuf_t *buf = MNULL;
827 
828     __memset(mlan_adap, &mlan_adap->outbuf_pool, 0x00, sizeof(outbuf_pool_t));
829 
830     util_init_list_head(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MFALSE, MNULL);
831 
832     if (mlan_adap->callbacks.moal_init_semaphore(mlan_adap->pmoal_handle, "wmm_buf_pool_sem",
833                                                  &mlan_adap->outbuf_pool.free_list.plock) != MLAN_STATUS_SUCCESS)
834         return WM_E_NOMEM;
835 
836     for (i = 0; i < MAX_WMM_BUF_NUM; i++)
837     {
838         /* TODO: where to put buffer pool mgmt codes */
839         // buf = (outbuf_t *)&outbuf_arr[i][0];
840         buf = (outbuf_t *)(pool + (i * OUTBUF_WMM_LEN));
841         util_init_list(&buf->entry);
842         util_enqueue_list_tail(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, &buf->entry, MNULL, MNULL);
843     }
844     mlan_adap->outbuf_pool.free_cnt = MAX_WMM_BUF_NUM;
845 
846     return WM_SUCCESS;
847 }
848 
849 /* deinit free list, should be called after all buffers are put back */
wifi_wmm_buf_pool_deinit(void)850 void wifi_wmm_buf_pool_deinit(void)
851 {
852     mlan_adap->outbuf_pool.free_cnt = 0;
853 
854     mlan_adap->callbacks.moal_free_semaphore(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list.plock);
855 
856     util_free_list_head(mlan_adap->pmoal_handle, &mlan_adap->outbuf_pool.free_list, MNULL);
857 
858     __memset(mlan_adap, &mlan_adap->outbuf_pool, 0x00, sizeof(outbuf_pool_t));
859 }
860 
861 /* wmm enhance ralist operation */
862 /* 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)863 void wlan_ralist_pkts_free_enh(mlan_private *priv, raListTbl *ra_list, t_u8 ac)
864 {
865     outbuf_t *buff = MNULL;
866 
867     priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
868 
869     while ((buff = (outbuf_t *)util_peek_list(priv->adapter->pmoal_handle, &ra_list->buf_head, MNULL, MNULL)))
870     {
871         util_unlink_list(priv->adapter->pmoal_handle, &ra_list->buf_head, &buff->entry, MNULL, MNULL);
872         wifi_wmm_buf_put(buff);
873 
874         priv->wmm.pkts_queued[ac]--;
875         wifi_wmm_drop_no_media(priv->bss_index);
876         ra_list->drop_count++;
877     }
878     ra_list->total_pkts = 0;
879 
880     priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
881 }
882 
883 /* should be called inside wmm tid_tbl_ptr ra_list lock */
wlan_ralist_free_enh(mlan_private * priv,raListTbl * ra_list,t_u8 ac)884 static void wlan_ralist_free_enh(mlan_private *priv, raListTbl *ra_list, t_u8 ac)
885 {
886 #if CONFIG_WMM_DEBUG
887     wlan_ralist_restore_history(priv, ra_list, ac);
888 #else
889     priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle, &ra_list->buf_head.plock);
890 #if !CONFIG_MEM_POOLS
891 
892     priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle, (t_u8 *)ra_list);
893 #else
894     OSA_MemoryPoolFree(buf_128_MemoryPool, ra_list);
895 #endif
896 #endif
897 }
898 
wlan_ralist_alloc_enh(pmlan_adapter pmadapter,t_u8 * ra)899 static raListTbl *wlan_ralist_alloc_enh(pmlan_adapter pmadapter, t_u8 *ra)
900 {
901     mlan_status ret;
902     raListTbl *ra_list = MNULL;
903 
904 #if !CONFIG_MEM_POOLS
905     ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF, (t_u8 **)&ra_list);
906     if (ret != MLAN_STATUS_SUCCESS || ra_list == MNULL)
907         return MNULL;
908 #else
909     ra_list = OSA_MemoryPoolAllocate(buf_128_MemoryPool);
910     if (ra_list == MNULL)
911     {
912         return MNULL;
913     }
914 
915 #endif
916 
917     util_init_list((pmlan_linked_list)ra_list);
918     util_init_list_head((t_void *)pmadapter->pmoal_handle, &ra_list->buf_head, MFALSE, MNULL);
919 
920     ret = pmadapter->callbacks.moal_init_semaphore(pmadapter->pmoal_handle, "buf_head_sem", &ra_list->buf_head.plock);
921     if (ret != MLAN_STATUS_SUCCESS)
922     {
923         pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *)ra_list);
924         return MNULL;
925     }
926 
927     (void)__memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
928 
929     ra_list->total_pkts = 0;
930     ra_list->tx_pause   = 0;
931     ra_list->drop_count = 0;
932 
933     wifi_d("RAList: Allocating buffers for TID %p\n", ra_list);
934 
935     return ra_list;
936 }
937 
wlan_ralist_add_enh(mlan_private * priv,t_u8 * ra)938 void wlan_ralist_add_enh(mlan_private *priv, t_u8 *ra)
939 {
940     int i;
941     raListTbl *ra_list      = MNULL;
942     pmlan_adapter pmadapter = priv->adapter;
943 
944     for (i = 0; i < MAX_AC_QUEUES; i++)
945     {
946         if ((ra_list = wlan_wmm_get_ralist_node(priv, i, ra)))
947             continue;
948 
949         ra_list = wlan_ralist_alloc_enh(pmadapter, ra);
950         wifi_d("Creating RA List %p for tid %d\n", ra_list, i);
951         if (ra_list == MNULL)
952         {
953             wifi_e("Creating RA List for tid %d fail", i);
954             break;
955         }
956 
957         pmadapter->callbacks.moal_semaphore_get(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
958 
959         util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list,
960                                MNULL, MNULL);
961 
962         if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == MNULL)
963             priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
964 
965         pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
966     }
967 }
968 
wlan_ralist_update_enh(mlan_private * priv,t_u8 * old_ra,t_u8 * new_ra)969 int wlan_ralist_update_enh(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra)
970 {
971     int i;
972     int update_count   = 0;
973     raListTbl *ra_list = MNULL;
974 #if CONFIG_WMM_DEBUG
975     raListTbl *hist_ra_list = MNULL;
976 #endif
977 
978     for (i = 0; i < MAX_AC_QUEUES; i++)
979     {
980         priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle,
981                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
982 
983         ra_list = wlan_wmm_get_ralist_node(priv, i, old_ra);
984         if (ra_list == MNULL)
985         {
986             priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
987                                                         &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
988             continue;
989         }
990 
991         update_count++;
992 
993         wlan_ralist_pkts_free_enh(priv, ra_list, i);
994         ra_list->tx_pause = MFALSE;
995 
996         (void)__memcpy(priv->adapter, ra_list->ra, new_ra, MLAN_MAC_ADDR_LENGTH);
997 
998 #if CONFIG_WMM_DEBUG
999         hist_ra_list = wlan_ralist_alloc_enh(priv->adapter, old_ra);
1000         if (hist_ra_list != MNULL)
1001         {
1002             hist_ra_list->drop_count = ra_list->drop_count;
1003             wlan_ralist_free_enh(priv, hist_ra_list, i);
1004         }
1005 #endif
1006 
1007         priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
1008                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1009     }
1010 
1011     return update_count;
1012 }
1013 
wlan_ralist_del_enh(mlan_private * priv,t_u8 * ra)1014 void wlan_ralist_del_enh(mlan_private *priv, t_u8 *ra)
1015 {
1016     int i;
1017     pmlan_adapter pmadapter = priv->adapter;
1018     raListTbl *ra_list      = MNULL;
1019 
1020     for (i = 0; i < MAX_AC_QUEUES; i++)
1021     {
1022         pmadapter->callbacks.moal_semaphore_get(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1023 
1024         ra_list = wlan_wmm_get_ralist_node(priv, i, ra);
1025         if (ra_list == MNULL)
1026         {
1027             pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1028             continue;
1029         }
1030 
1031         wlan_ralist_pkts_free_enh(priv, ra_list, i);
1032 
1033         util_unlink_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list, MNULL,
1034                          MNULL);
1035 
1036         if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
1037             priv->wmm.tid_tbl_ptr[i].ra_list_curr = (raListTbl *)&priv->wmm.tid_tbl_ptr[i].ra_list;
1038 
1039         wlan_ralist_free_enh(priv, ra_list, i);
1040 
1041         pmadapter->callbacks.moal_semaphore_put(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1042     }
1043 }
1044 
wlan_ralist_del_all_enh(mlan_private * priv)1045 void wlan_ralist_del_all_enh(mlan_private *priv)
1046 {
1047     int i;
1048     raListTbl *ra_list      = MNULL;
1049     pmlan_adapter pmadapter = priv->adapter;
1050 
1051     for (i = 0; i < MAX_AC_QUEUES; i++)
1052     {
1053         priv->adapter->callbacks.moal_semaphore_get(priv->adapter->pmoal_handle,
1054                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1055 
1056         while ((ra_list = (raListTbl *)util_peek_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL,
1057                                                       MNULL)))
1058         {
1059             util_unlink_list(pmadapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, (pmlan_linked_list)ra_list,
1060                              MNULL, MNULL);
1061 
1062             wlan_ralist_pkts_free_enh(priv, ra_list, i);
1063 
1064             wlan_ralist_free_enh(priv, ra_list, i);
1065         }
1066 
1067         /* do not reinit list lock, so use util_init_list instead of util_init_list_head */
1068         util_init_list((pmlan_linked_list)&priv->wmm.tid_tbl_ptr[i].ra_list);
1069         priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
1070         priv->wmm.pkts_queued[i]              = 0;
1071 
1072         priv->adapter->callbacks.moal_semaphore_put(priv->adapter->pmoal_handle,
1073                                                     &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1074     }
1075 }
1076 
wlan_ralist_deinit_enh(mlan_private * priv)1077 void wlan_ralist_deinit_enh(mlan_private *priv)
1078 {
1079     int i;
1080 
1081     /* already del all ralists in wlan_clean_txrx */
1082     // wlan_ralist_del_all_enh(priv);
1083 
1084     for (i = 0; i < MAX_AC_QUEUES; i++)
1085     {
1086         /* free ralist lock */
1087         priv->adapter->callbacks.moal_free_semaphore(priv->adapter->pmoal_handle,
1088                                                      &priv->wmm.tid_tbl_ptr[i].ra_list.plock);
1089 
1090         /* deinit ralists table */
1091         util_free_list_head(priv->adapter->pmoal_handle, &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL);
1092     }
1093 }
1094 
1095 /* debug statistics */
wifi_wmm_drop_err_mem(const uint8_t interface)1096 void wifi_wmm_drop_err_mem(const uint8_t interface)
1097 {
1098     CHECK_BSS_TYPE_RET_VOID(interface);
1099     mlan_adap->priv[interface]->driver_error_cnt.tx_err_mem++;
1100 }
1101 
wifi_wmm_drop_no_media(const uint8_t interface)1102 void wifi_wmm_drop_no_media(const uint8_t interface)
1103 {
1104     CHECK_BSS_TYPE_RET_VOID(interface);
1105     mlan_adap->priv[interface]->driver_error_cnt.tx_no_media++;
1106 }
1107 
wifi_wmm_drop_retried_drop(const uint8_t interface)1108 void wifi_wmm_drop_retried_drop(const uint8_t interface)
1109 {
1110     CHECK_BSS_TYPE_RET_VOID(interface);
1111     mlan_adap->priv[interface]->driver_error_cnt.tx_wmm_retried_drop++;
1112 }
1113 
wifi_wmm_drop_pause_drop(const uint8_t interface)1114 void wifi_wmm_drop_pause_drop(const uint8_t interface)
1115 {
1116     CHECK_BSS_TYPE_RET_VOID(interface);
1117     mlan_adap->priv[interface]->driver_error_cnt.tx_wmm_pause_drop++;
1118 }
1119 
wifi_wmm_drop_pause_replaced(const uint8_t interface)1120 void wifi_wmm_drop_pause_replaced(const uint8_t interface)
1121 {
1122     CHECK_BSS_TYPE_RET_VOID(interface);
1123     mlan_adap->priv[interface]->driver_error_cnt.tx_wmm_pause_replaced++;
1124 }
1125 
wlan_get_bypass_lock(uint8_t interface)1126 void wlan_get_bypass_lock(uint8_t interface)
1127 {
1128     pmlan_private priv = mlan_adap->priv[interface];
1129 
1130     mlan_adap->callbacks.moal_semaphore_get(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1131 }
1132 
wlan_put_bypass_lock(uint8_t interface)1133 void wlan_put_bypass_lock(uint8_t interface)
1134 {
1135     pmlan_private priv = mlan_adap->priv[interface];
1136 
1137     mlan_adap->callbacks.moal_semaphore_put(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1138 }
1139 
wlan_add_buf_bypass_txq(const uint8_t * buffer,const uint8_t interface)1140 void wlan_add_buf_bypass_txq(const uint8_t *buffer, const uint8_t interface)
1141 {
1142     pmlan_private priv = mlan_adap->priv[interface];
1143 
1144     wlan_get_bypass_lock(interface);
1145 
1146     util_enqueue_list_tail(mlan_adap->pmoal_handle, &priv->bypass_txq, (mlan_linked_list *)buffer, MNULL, MNULL);
1147     priv->bypass_txq_cnt++;
1148 
1149     wlan_put_bypass_lock(interface);
1150 }
1151 
wlan_bypass_txq_empty(uint8_t interface)1152 t_u8 wlan_bypass_txq_empty(uint8_t interface)
1153 {
1154     return (mlan_adap->priv[interface]->bypass_txq_cnt) ? MFALSE : MTRUE;
1155 }
1156 
wifi_bypass_txq_init(void)1157 int wifi_bypass_txq_init(void)
1158 {
1159     pmlan_private priv = NULL;
1160     int i;
1161 
1162     for (i = 0; i < mlan_adap->priv_num; ++i)
1163     {
1164         priv = mlan_adap->priv[i];
1165         if (priv != MNULL)
1166         {
1167             /* Initialize bypass_txq */
1168             util_init_list_head((t_void *)mlan_adap->pmoal_handle, &priv->bypass_txq, MFALSE, MNULL);
1169             priv->bypass_txq_cnt = 0;
1170 
1171             if (mlan_adap->callbacks.moal_init_semaphore(mlan_adap->pmoal_handle, "bypass_txq_sem",
1172                                                          &priv->bypass_txq.plock) != MLAN_STATUS_SUCCESS)
1173                 return WM_E_NOMEM;
1174         }
1175     }
1176 
1177     return WM_SUCCESS;
1178 }
1179 
wlan_cleanup_bypass_txq(uint8_t interface)1180 void wlan_cleanup_bypass_txq(uint8_t interface)
1181 {
1182     bypass_outbuf_t *buf;
1183     pmlan_private priv = mlan_adap->priv[interface];
1184 
1185     CHECK_BSS_TYPE_RET_VOID(interface);
1186 
1187     /*Free hold buff*/
1188     while (!wlan_bypass_txq_empty(interface))
1189     {
1190         wlan_get_bypass_lock(interface);
1191 
1192         buf = (bypass_outbuf_t *)util_dequeue_list(mlan_adap->pmoal_handle, &priv->bypass_txq, MNULL, MNULL);
1193         priv->bypass_txq_cnt--;
1194 #if !CONFIG_MEM_POOLS
1195         OSA_MemoryFree(buf);
1196 #else
1197         OSA_MemoryPoolFree(buf_1536_MemoryPool, buf);
1198 #endif
1199 
1200         wlan_put_bypass_lock(interface);
1201     }
1202 }
1203 
wifi_bypass_txq_deinit(void)1204 void wifi_bypass_txq_deinit(void)
1205 {
1206     pmlan_private priv = NULL;
1207     int i;
1208 
1209     for (i = 0; i < mlan_adap->priv_num; ++i)
1210     {
1211         priv = mlan_adap->priv[i];
1212         if (priv != MNULL)
1213         {
1214             wlan_cleanup_bypass_txq(i);
1215 
1216             mlan_adap->callbacks.moal_free_semaphore(mlan_adap->pmoal_handle, &priv->bypass_txq.plock);
1217             /* Deinit bypass_txq */
1218             util_free_list_head(mlan_adap->pmoal_handle, &priv->bypass_txq, MNULL);
1219             priv->bypass_txq_cnt = 0;
1220         }
1221     }
1222 }
1223 #endif /* CONFIG_WMM */
1224