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