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