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