74ae5aba8126cce3ced92f74a25b117bd12f29f9
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / mt5931 / nic / que_mgt.c
1 /*
2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 $
3 */
4
5 /*! \file   "que_mgt.c"
6     \brief  TX/RX queues management
7
8     The main tasks of queue management include TC-based HIF TX flow control,
9     adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save
10     forwarding control, RX packet reordering, and RX BA agreement management.
11 */
12
13
14
15 /*
16 ** $Log: que_mgt.c $
17  *
18  * 03 02 2012 terry.wu
19  * NULL
20  * Sync CFG80211 modification from branch 2,2.
21  *
22  * 02 23 2012 eddie.chen
23  * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule
24  * Change the enqueue policy when ACM = 1.
25  *
26  * 11 22 2011 yuche.tsai
27  * NULL
28  * Code refine, remove one #if 0 code.
29  *
30  * 11 19 2011 eddie.chen
31  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
32  * Add xlog for tx
33  *
34  * 11 18 2011 yuche.tsai
35  * NULL
36  * CONFIG P2P support RSSI query, default turned off.
37  *
38  * 11 18 2011 eddie.chen
39  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
40  * Fix xlog format to hex format
41  *
42  * 11 17 2011 tsaiyuan.hsu
43  * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3.
44  * avoid deactivating staRec when changing state from 3 to 3.
45  *
46  * 11 11 2011 tsaiyuan.hsu
47  * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
48  * add debug msg for xlog.
49  *
50  * 11 11 2011 tsaiyuan.hsu
51  * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
52  * add debug counters of bb and ar for xlog.
53  *
54  * 11 10 2011 eddie.chen
55  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
56  * Use short name for xlog.
57  *
58  * 11 10 2011 eddie.chen
59  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
60  * Modify the QM xlog level and remove LOG_FUNC.
61  *
62  * 11 10 2011 chinglan.wang
63  * NULL
64  * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP.
65  *
66  * 11 09 2011 chinglan.wang
67  * NULL
68  * [WiFi direct]Can't make P2P connect via PBC.
69  *
70  * 11 08 2011 eddie.chen
71  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
72  * Add xlog function.
73  *
74  * 11 07 2011 tsaiyuan.hsu
75  * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
76  * add debug counters and periodically dump counters for debugging.
77  *
78  * 11 01 2011 chinglan.wang
79  * NULL
80  * Modify the Wi-Fi method of the flush TX queue when disconnect the AP.
81  * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to the AP..
82  *
83  * 10 25 2011 wh.su
84  * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check un-expect
85  * let the Rx BA accept even the sta not valid.
86  *
87  * 09 28 2011 tsaiyuan.hsu
88  * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
89  * enlarge window size only by 4.
90  *
91  * 09 01 2011 tsaiyuan.hsu
92  * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
93  * set rx window size as twice buffer size.
94  *
95  * 08 23 2011 yuche.tsai
96  * NULL
97  * Fix multicast address list issue.
98  *
99  * 08 03 2011 tsaiyuan.hsu
100  * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
101  * force window size at least 16.
102  *
103  * 08 02 2011 yuche.tsai
104  * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue.
105  * Fix GO send deauth frame issue.
106  *
107  * 07 26 2011 eddie.chen
108  * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter
109  * API for query the RX reorder queued packets counter.
110  *
111  * 07 07 2011 eddie.chen
112  * [WCXRP00000834] [MT6620 Wi-Fi][DRV]  Send 1x packet when peer STA is in PS.
113  * Add setEvent when free quota is updated.
114  *
115  * 07 05 2011 eddie.chen
116  * [WCXRP00000834] [MT6620 Wi-Fi][DRV]  Send 1x packet when peer STA is in PS.
117  * Send 1x when peer STA is in PS.
118  *
119  * 05 31 2011 eddie.chen
120  * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931
121  * Fix the QM quota in MT5931.
122  *
123  * 05 11 2011 eddie.chen
124  * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
125  * Fix dest type when GO packet copying.
126  *
127  * 05 09 2011 yuche.tsai
128  * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved)
129  * Deauthentication frame is not bound to network active status.
130  *
131  * 05 09 2011 eddie.chen
132  * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
133  * Check free number before copying broadcast packet.
134  *
135  * 04 14 2011 eddie.chen
136  * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
137  * Check the SW RFB free. Fix the compile warning..
138  *
139  * 04 12 2011 eddie.chen
140  * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
141  * Fix the sta index in processing security frame
142  * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4
143  * Add debug message.
144  *
145  * 04 11 2011 yuche.tsai
146  * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue.
147  * Fix kernel panic issue when MMPDU of P2P is pending in driver.
148  *
149  * 04 08 2011 eddie.chen
150  * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
151  * Fix for sigma
152  *
153  * 03 28 2011 eddie.chen
154  * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
155  * Fix Klockwork warning.
156  *
157  * 03 28 2011 eddie.chen
158  * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW
159  * Fix wmm parameters in beacon for BOW.
160  *
161  * 03 15 2011 eddie.chen
162  * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter
163  * Add sw debug counter for QM.
164  *
165  * 02 23 2011 eddie.chen
166  * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap
167  * Fix parsing WMM INFO and bmp delivery bitmap definition.
168  *
169  * 02 17 2011 eddie.chen
170  * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel
171  * 1) Chnage GetFrameAction decision when BSS is absent.
172  * 2) Check channel and resource in processing ProbeRequest
173  *
174  * 02 08 2011 eddie.chen
175  * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode
176  * Add event STA agint timeout
177  *
178  * 01 27 2011 tsaiyuan.hsu
179  * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support
180  * add roaming fsm
181  * 1. not support 11r, only use strength of signal to determine roaming.
182  * 2. not enable CFG_SUPPORT_ROAMING until completion of full test.
183  * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw
184  * 4. assume that change of link quality in smooth way.
185  *
186  * 01 25 2011 yuche.tsai
187  * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record.
188  * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role.
189  *
190  * 01 24 2011 eddie.chen
191  * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
192  * Remove comments.
193  *
194  * 01 24 2011 eddie.chen
195  * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
196  * Add destination decision in AP mode.
197  *
198  * 01 14 2011 wh.su
199  * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!!
200  * Allow 802.1x can be send even the net is not active due the drver / fw sync issue.
201  *
202  * 01 13 2011 eddie.chen
203  * [WCXRP00000322] Add WMM IE in beacon,
204 Add per station flow control when STA is in PS
205  * Fix typo and compile error.
206  *
207  * 01 12 2011 eddie.chen
208  * [WCXRP00000322] Add WMM IE in beacon,
209 Add per station flow control when STA is in PS
210  * Fix WMM parameter condition for STA
211  *
212  * 01 12 2011 eddie.chen
213  * [WCXRP00000322] Add WMM IE in beacon,
214 Add per station flow control when STA is in PS
215  * 1) Check Bss if support QoS before adding WMMIE
216  * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control
217  *
218  * 01 12 2011 george.huang
219  * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability
220  * Update MQM for WMM IE generation method
221  *
222  * 01 11 2011 eddie.chen
223  * [WCXRP00000322] Add WMM IE in beacon,
224 Add per station flow control when STA is in PS
225
226  * Add per STA flow control when STA is in PS mode
227  *
228  * 01 03 2011 george.huang
229  * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
230  * update prStaRec->fgIsUapsdSupported flag.
231  *
232  * 12 29 2010 eddie.chen
233  * [WCXRP00000322] Add WMM IE in beacon,
234 Add per station flow control when STA is in PS
235
236  * Add WMM parameter for broadcast.
237  *
238  * 12 29 2010 eddie.chen
239  * [WCXRP00000322] Add WMM IE in beacon,
240 Add per station flow control when STA is in PS
241
242  * 1) PS flow control event
243  *
244  * 2) WMM IE in beacon, assoc resp, probe resp
245  *
246  * 12 23 2010 george.huang
247  * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
248  * 1. update WMM IE parsing, with ASSOC REQ handling
249  * 2. extend U-APSD parameter passing from driver to FW
250  *
251  * 10 14 2010 wh.su
252  * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
253  * use the #14 and modify the add code for check MMPDU.
254  *
255  * 10 14 2010 wh.su
256  * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
257  * only MMPDU not check the netActive flag.
258  *
259  * 10 14 2010 wh.su
260  * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
261  * not check the netActive flag for mgmt .
262  *
263  * 10 04 2010 cp.wu
264  * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only
265  * remove ENUM_NETWORK_TYPE_T definitions
266  *
267  * 09 21 2010 kevin.huang
268  * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
269  * Eliminate Linux Compile Warning
270  *
271  * 08 30 2010 yarco.yang
272  * NULL
273  * Fixed klockwork error message
274  *
275  * 08 18 2010 yarco.yang
276  * NULL
277  * 1. Fixed HW checksum offload function not work under Linux issue.
278  * 2. Add debug message.
279  *
280  * 08 10 2010 yarco.yang
281  * NULL
282  * Code refine
283  *
284  * 08 06 2010 yarco.yang
285  * NULL
286  * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record  still can perform TX action
287  *
288  * 07 26 2010 cp.wu
289  *
290  * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet
291  * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found
292  *
293  * 07 20 2010 yarco.yang
294  *
295  * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake
296  *
297  * 07 16 2010 yarco.yang
298  *
299  * 1. Support BSS Absence/Presence Event
300  * 2. Support STA change PS mode Event
301  * 3. Support BMC forwarding for AP mode.
302  *
303  * 07 14 2010 yarco.yang
304  *
305  * 1. Remove CFG_MQM_MIGRATION
306  * 2. Add CMD_UPDATE_WMM_PARMS command
307  *
308  * 07 13 2010 yarco.yang
309  *
310  * [WPD00003849]
311  * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing
312  *
313  * 07 09 2010 yarco.yang
314  *
315  * [MT6620 and MT5931] SW Migration: Add ADDBA support
316  *
317  * 07 08 2010 cp.wu
318  *
319  * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
320  *
321  * 07 08 2010 yarco.yang
322  * [WPD00003837][MT6620]Data Path Refine
323  * .
324  *
325  * 07 06 2010 yarco.yang
326  * [WPD00003837][MT6620]Data Path Refine
327  * Use fgInUse instead of fgIsValid for De-queue judgement
328  *
329  * 07 06 2010 yarco.yang
330  * [WPD00003837][MT6620]Data Path Refine
331  * For MMPDU, STA_REC will be decided by caller module
332  *
333  * 07 06 2010 yarco.yang
334  * [WPD00003837][MT6620]Data Path Refine
335  * Add MGMT Packet type for HIF_TX_HEADER
336  *
337  * 06 29 2010 yarco.yang
338  * [WPD00003837][MT6620]Data Path Refine
339  * replace g_rQM with Adpater->rQM
340  *
341  * 06 25 2010 cp.wu
342  * [WPD00003833][MT6620 and MT5931] Driver migration
343  * add API in que_mgt to retrieve sta-rec index for security frames.
344  *
345  * 06 23 2010 yarco.yang
346  * [WPD00003837][MT6620]Data Path Refine
347  * Merge g_arStaRec[] into adapter->arStaRec[]
348  *
349  * 06 21 2010 yarco.yang
350  * [WPD00003837][MT6620]Data Path Refine
351  * Support CFG_MQM_MIGRATION flag
352  *
353  * 06 11 2010 cp.wu
354  * [WPD00003833][MT6620 and MT5931] Driver migration
355  * 1) migrate assoc.c.
356  * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness
357  * 3) add configuration options for CNM_MEM and RSN modules
358  * 4) add data path for management frames
359  * 5) eliminate rPacketInfo of MSDU_INFO_T
360  *
361  * 06 06 2010 kevin.huang
362  * [WPD00003832][MT6620 5931] Create driver base
363  * [MT6620 5931] Create driver base
364  *
365  * 03 31 2010 tehuang.liu
366  * [WPD00001943]Create WiFi test driver framework on WinXP
367  * Refined the debug msg
368  *
369  * 03 30 2010 cp.wu
370  * [WPD00001943]Create WiFi test driver framework on WinXP
371  * comment out one assertion which refer to undefined data member.
372  *
373  * 03 30 2010 tehuang.liu
374  * [WPD00001943]Create WiFi test driver framework on WinXP
375  * Enabled adaptive TC resource control
376  *
377  * 03 24 2010 jeffrey.chang
378  * [WPD00003826]Initial import for Linux port
379  * initial import for Linux port
380  *
381 * 03 17 2010 tehuang.liu
382  * [WPD00001943]Create WiFi test driver framework on WinXP
383  * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST)
384  *
385  * 03 11 2010 tehuang.liu
386  * [WPD00001943]Create WiFi test driver framework on WinXP
387  * Fixed buffer leak when processing BAR frames
388  *
389  * 03 02 2010 tehuang.liu
390  * [WPD00001943]Create WiFi test driver framework on WinXP
391  * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5
392  *
393  * 03 01 2010 tehuang.liu
394  * [WPD00001943]Create WiFi test driver framework on WinXP
395  * Fixed STA_REC index determination bug (fgIsValid shall be checked)
396  *
397  * 02 25 2010 tehuang.liu
398  * [WPD00001943]Create WiFi test driver framework on WinXP
399  * Refined function qmDetermineStaRecIndex() for BMCAST packets
400  *
401  * 02 25 2010 tehuang.liu
402  * [WPD00001943]Create WiFi test driver framework on WinXP
403  * Enabled multi-STA TX path with fairness
404  *
405  * 02 24 2010 tehuang.liu
406  * [WPD00001943]Create WiFi test driver framework on WinXP
407  * Enabled dynamically activating and deactivating STA_RECs
408  *
409  * 02 24 2010 tehuang.liu
410  * [WPD00001943]Create WiFi test driver framework on WinXP
411  * Added code for dynamic activating and deactivating STA_RECs.
412  *
413  * 01 13 2010 tehuang.liu
414  * [WPD00001943]Create WiFi test driver framework on WinXP
415  * Enabled the 802.1x path
416  *
417  * 01 13 2010 tehuang.liu
418  * [WPD00001943]Create WiFi test driver framework on WinXP
419  * Enabled the Burst_End Indication mechanism
420 **  \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468
421 **  Fixed casting for qmAddRxBaEntry()
422 **  \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752
423 **  remove SD1_SD3.. flag
424 **  \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468
425 **  Added RX buffer reordering functions
426 **  \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468
427 **  Modified Flush Queue function to let queues be reinitialized
428 **  \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468
429 **  Added flushing per-Type queues code
430 **  \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468
431 **  Added Debug msgs and fixed incorrect assert
432 **  \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468
433 **  Bug fixing (qmDequeueTxPackets local variable initialization)
434 **  \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752
435 **  correct and surpress PREfast warning
436 **  \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468
437 **  Used SD1_SD3_DATAPATH_INTEGRATION
438 **  \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468
439 **  Initial version
440 **
441 */
442
443 /*******************************************************************************
444 *                         C O M P I L E R   F L A G S
445 ********************************************************************************
446 */
447
448 /*******************************************************************************
449 *                    E X T E R N A L   R E F E R E N C E S
450 ********************************************************************************
451 */
452 #include "precomp.h"
453
454 /*******************************************************************************
455 *                              C O N S T A N T S
456 ********************************************************************************
457 */
458
459 /*******************************************************************************
460 *                             D A T A   T Y P E S
461 ********************************************************************************
462 */
463
464 /*******************************************************************************
465 *                            P U B L I C   D A T A
466 ********************************************************************************
467 */
468 OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM];
469 /*******************************************************************************
470 *                           P R I V A T E   D A T A
471 ********************************************************************************
472 */
473
474
475 /*******************************************************************************
476 *                                 M A C R O S
477 ********************************************************************************
478 */
479
480 /*******************************************************************************
481 *                   F U N C T I O N   D E C L A R A T I O N S
482 ********************************************************************************
483 */
484 __KAL_INLINE__ VOID
485 qmDetermineStaRecIndex(
486     IN P_ADAPTER_T   prAdapter,
487     IN P_MSDU_INFO_T prMsduInfo
488     );
489
490 __KAL_INLINE__ VOID
491 qmDequeueTxPacketsFromPerStaQueues(
492     IN P_ADAPTER_T  prAdapter,
493     OUT P_QUE_T prQue,
494     IN  UINT_8  ucTC,
495     IN  UINT_8  ucCurrentAvailableQuota,
496     IN  UINT_8  ucTotalQuota
497     );
498
499 __KAL_INLINE__ VOID
500 qmDequeueTxPacketsFromPerTypeQueues(
501     IN P_ADAPTER_T  prAdapter,
502     OUT P_QUE_T prQue,
503     IN  UINT_8  ucTC,
504     IN  UINT_8  ucMaxNum
505     );
506
507 /*******************************************************************************
508 *                              F U N C T I O N S
509 ********************************************************************************
510 */
511
512 /*----------------------------------------------------------------------------*/
513 /*!
514 * \brief Init Queue Managment for TX
515 *
516 * \param[in] (none)
517 *
518 * \return (none)
519 */
520 /*----------------------------------------------------------------------------*/
521 VOID
522 qmInit(
523     IN P_ADAPTER_T  prAdapter
524     )
525 {
526     UINT_32 u4QueArrayIdx;
527     UINT_32 i;
528
529     P_QUE_MGT_T prQM = &prAdapter->rQM;
530
531     //DbgPrint("QM: Enter qmInit()\n");
532 #if CFG_SUPPORT_QOS
533     prAdapter->rWifiVar.fgSupportQoS = TRUE;
534 #else
535     prAdapter->rWifiVar.fgSupportQoS = FALSE;
536 #endif
537
538 #if CFG_SUPPORT_AMPDU_RX
539     prAdapter->rWifiVar.fgSupportAmpduRx = TRUE;
540 #else
541     prAdapter->rWifiVar.fgSupportAmpduRx = FALSE;
542 #endif
543
544 #if CFG_SUPPORT_AMPDU_TX
545     prAdapter->rWifiVar.fgSupportAmpduTx = TRUE;
546 #else
547     prAdapter->rWifiVar.fgSupportAmpduTx = FALSE;
548 #endif
549
550 #if CFG_SUPPORT_TSPEC
551     prAdapter->rWifiVar.fgSupportTspec = TRUE;
552 #else
553     prAdapter->rWifiVar.fgSupportTspec = FALSE;
554 #endif
555
556 #if CFG_SUPPORT_UAPSD
557     prAdapter->rWifiVar.fgSupportUAPSD= TRUE;
558 #else
559     prAdapter->rWifiVar.fgSupportUAPSD = FALSE;
560 #endif
561
562 #if CFG_SUPPORT_UL_PSMP
563     prAdapter->rWifiVar.fgSupportULPSMP = TRUE;
564 #else
565     prAdapter->rWifiVar.fgSupportULPSMP = FALSE;
566 #endif
567
568     //4 <2> Initialize other TX queues (queues not in STA_RECs)
569     for(u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++){
570         QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx]));
571     }
572
573     //4 <3> Initialize the RX BA table and RX queues
574     /* Initialize the RX Reordering Parameters and Queues */
575     for(u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++){
576         prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE;
577         QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue));
578         prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF;
579         prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF;
580
581         prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE;
582
583     }
584     prQM->ucRxBaCount = 0;
585     kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout));
586
587 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
588     //4 <4> Initialize TC resource control variables
589     for(i = 0; i < TC_NUM; i++){
590         prQM->au4AverageQueLen[i] = 0;
591     }
592     prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC;
593     prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN;
594
595 //    ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen);
596
597     prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0;
598     prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1;
599     prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2;
600     prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3;
601     prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1)*/
602     prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5;
603
604     prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE;
605     prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE;
606     prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE;
607     prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE;
608     prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1)*/
609     prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE;
610
611
612     prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE;
613     prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE;
614     prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE;
615     prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE;
616     prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE;
617     prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE;
618
619     prQM->fgTcResourcePostAnnealing = FALSE;
620
621     ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64);
622 #endif
623
624 #if QM_TEST_MODE
625     prQM->u4PktCount = 0;
626
627 #if QM_TEST_FAIR_FORWARDING
628
629     prQM->u4CurrentStaRecIndexToEnqueue = 0;
630     {
631         UINT_8 aucMacAddr[MAC_ADDR_LEN];
632         P_STA_RECORD_T prStaRec;
633
634         /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
635         aucMacAddr[0] = 0x11;
636         aucMacAddr[1] = 0x22;
637         aucMacAddr[2] = 0xAA;
638         aucMacAddr[3] = 0xBB;
639         aucMacAddr[4] = 0xCC;
640         aucMacAddr[5] = 0xDD;
641
642         prStaRec = &prAdapter->arStaRec[1];
643         ASSERT(prStaRec);
644
645         prStaRec->fgIsValid      = TRUE;
646         prStaRec->fgIsQoS        = TRUE;
647         prStaRec->fgIsInPS        = FALSE;
648         prStaRec->ucPsSessionID  = 0xFF;
649         prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX;
650         prStaRec->fgIsAp         = TRUE;
651         COPY_MAC_ADDR((prStaRec)->aucMacAddr,aucMacAddr);
652
653     }
654
655 #endif
656
657 #endif
658
659 #if QM_FORWARDING_FAIRNESS
660 {
661     UINT_32 i;
662     for (i=0; i < NUM_OF_PER_STA_TX_QUEUES; i++){
663         prQM->au4ForwardCount[i] = 0;
664         prQM->au4HeadStaRecIndex[i] = 0;
665     }
666 }
667 #endif
668
669 }
670
671 #if QM_TEST_MODE
672 VOID
673 qmTestCases(
674     IN P_ADAPTER_T  prAdapter
675     )
676 {
677     P_QUE_MGT_T prQM = &prAdapter->rQM;
678
679     DbgPrint("QM: ** TEST MODE **\n");
680
681     if(QM_TEST_STA_REC_DETERMINATION){
682         if(prAdapter->arStaRec[0].fgIsValid){
683             prAdapter->arStaRec[0].fgIsValid = FALSE;
684             DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
685         }
686         else{
687             prAdapter->arStaRec[0].fgIsValid = TRUE;
688             DbgPrint("QM: (Test) Activate STA_REC[0]\n");
689         }
690     }
691
692     if(QM_TEST_STA_REC_DEACTIVATION){
693         /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */
694
695         if(prAdapter->arStaRec[0].fgIsValid){
696
697             DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
698             qmDeactivateStaRec(prAdapter,0);
699         }
700         else{
701
702             UINT_8 aucMacAddr[MAC_ADDR_LEN];
703
704             /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
705             aucMacAddr[0] = 0x11;
706             aucMacAddr[1] = 0x22;
707             aucMacAddr[2] = 0xAA;
708             aucMacAddr[3] = 0xBB;
709             aucMacAddr[4] = 0xCC;
710             aucMacAddr[5] = 0xDD;
711
712             DbgPrint("QM: (Test) Activate STA_REC[0]\n");
713             qmActivateStaRec(
714                 prAdapter,    /* Adapter pointer */
715                 0,                      /* STA_REC index from FW */
716                 TRUE,                   /* fgIsQoS */
717                 NETWORK_TYPE_AIS_INDEX, /* Network type */
718                 TRUE,                   /* fgIsAp */
719                 aucMacAddr              /* MAC address */
720             );
721         }
722     }
723
724     if(QM_TEST_FAIR_FORWARDING){
725         if(prAdapter->arStaRec[1].fgIsValid){
726             prQM->u4CurrentStaRecIndexToEnqueue ++;
727             prQM->u4CurrentStaRecIndexToEnqueue %= 2;
728             DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n", prQM->u4CurrentStaRecIndexToEnqueue);
729         }
730     }
731
732 }
733 #endif
734
735 /*----------------------------------------------------------------------------*/
736 /*!
737 * \brief Activate a STA_REC
738 *
739 * \param[in] prAdapter  Pointer to the Adapter instance
740 * \param[in] u4StaRecIdx The index of the STA_REC
741 * \param[in] fgIsQoS    Set to TRUE if this is a QoS STA
742 * \param[in] pucMacAddr The MAC address of the STA
743 *
744 * \return (none)
745 */
746 /*----------------------------------------------------------------------------*/
747 VOID
748 qmActivateStaRec(
749     IN P_ADAPTER_T prAdapter,
750     IN P_STA_RECORD_T  prStaRec
751     )
752 {
753
754     //4 <1> Deactivate first
755     ASSERT(prStaRec);
756
757     if(prStaRec->fgIsValid){ /* The STA_REC has been activated */
758         DBGLOG(QM, WARN, ("QM: (WARNING) Activating a STA_REC which has been activated \n"));
759         DBGLOG(QM, WARN, ("QM: (WARNING) Deactivating a STA_REC before re-activating \n"));
760         qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); // To flush TX/RX queues and del RX BA agreements
761     }
762
763     //4 <2> Activate the STA_REC
764     /* Init the STA_REC */
765     prStaRec->fgIsValid      = TRUE;
766     prStaRec->fgIsInPS       = FALSE;
767     prStaRec->ucPsSessionID  = 0xFF;
768     prStaRec->fgIsAp         = (IS_AP_STA(prStaRec)) ? TRUE : FALSE;;
769
770     /* Done in qmInit() or qmDeactivateStaRec() */
771 #if 0
772     /* At the beginning, no RX BA agreements have been established */
773     for(i =0; i<CFG_RX_MAX_BA_TID_NUM; i++){
774         (prStaRec->aprRxReorderParamRefTbl)[i] = NULL;
775     }
776 #endif
777
778     DBGLOG(QM, INFO, ("QM: +STA[%ld]\n", prStaRec->ucIndex));
779 }
780
781 /*----------------------------------------------------------------------------*/
782 /*!
783 * \brief Deactivate a STA_REC
784 *
785 * \param[in] prAdapter  Pointer to the Adapter instance
786 * \param[in] u4StaRecIdx The index of the STA_REC
787 *
788 * \return (none)
789 */
790 /*----------------------------------------------------------------------------*/
791 VOID
792 qmDeactivateStaRec(
793     IN P_ADAPTER_T prAdapter,
794     IN UINT_32 u4StaRecIdx
795     )
796 {
797     P_STA_RECORD_T prStaRec;
798     UINT_32 i;
799     P_MSDU_INFO_T prFlushedTxPacketList = NULL;
800
801     ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD);
802
803     prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
804     ASSERT(prStaRec);
805
806         //4<1> Flush TX queues
807     prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx);
808
809     if(prFlushedTxPacketList){
810         wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList);
811     }
812
813     //4 <2> Flush RX queues and delete RX BA agreements
814     for(i =0; i < CFG_RX_MAX_BA_TID_NUM; i++){
815         /* Delete the RX BA entry with TID = i */
816         qmDelRxBaEntry(prAdapter, (UINT_8)u4StaRecIdx, (UINT_8)i, FALSE);
817     }
818
819     //4 <3> Deactivate the STA_REC
820     prStaRec->fgIsValid = FALSE;
821     prStaRec->fgIsInPS = FALSE;
822
823     DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx));
824 }
825
826
827 /*----------------------------------------------------------------------------*/
828 /*!
829 * \brief Deactivate a STA_REC
830 *
831 * \param[in] prAdapter  Pointer to the Adapter instance
832 * \param[in] u4StaRecIdx The index of the network
833 *
834 * \return (none)
835 */
836 /*----------------------------------------------------------------------------*/
837
838 VOID
839 qmFreeAllByNetType(
840         IN P_ADAPTER_T prAdapter,
841         IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx
842         )
843 {
844
845     P_QUE_MGT_T prQM;
846     P_QUE_T     prQue;
847     QUE_T       rNeedToFreeQue;
848     QUE_T       rTempQue;
849     P_QUE_T     prNeedToFreeQue;
850     P_QUE_T     prTempQue;
851     P_MSDU_INFO_T prMsduInfo;
852
853
854     prQM = &prAdapter->rQM;
855     prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
856
857     QUEUE_INITIALIZE(&rNeedToFreeQue);
858     QUEUE_INITIALIZE(&rTempQue);
859
860     prNeedToFreeQue = &rNeedToFreeQue;
861     prTempQue = &rTempQue;
862
863     QUEUE_MOVE_ALL(prTempQue, prQue);
864
865     QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
866     while (prMsduInfo) {
867
868         if(prMsduInfo->ucNetworkType == eNetworkTypeIdx) {
869             QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T)prMsduInfo);
870         }
871         else {
872             QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo);
873         }
874
875         QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
876     }
877     if(QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) {
878         wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue));
879     }
880
881 }
882
883 /*----------------------------------------------------------------------------*/
884 /*!
885 * \brief Flush all TX queues
886 *
887 * \param[in] (none)
888 *
889 * \return The flushed packets (in a list of MSDU_INFOs)
890 */
891 /*----------------------------------------------------------------------------*/
892 P_MSDU_INFO_T
893 qmFlushTxQueues(
894         IN P_ADAPTER_T prAdapter
895         )
896 {
897     UINT_8 ucStaArrayIdx;
898     UINT_8 ucQueArrayIdx;
899
900     P_MSDU_INFO_T prMsduInfoListHead;
901     P_MSDU_INFO_T prMsduInfoListTail;
902
903     P_QUE_MGT_T prQM = &prAdapter->rQM;
904
905     DBGLOG(QM, TRACE, ("QM: Enter qmFlushTxQueues()\n"));
906
907     prMsduInfoListHead = NULL;
908     prMsduInfoListTail = NULL;
909
910     /* Concatenate all MSDU_INFOs in per-STA queues */
911     for(ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++){
912
913         /* Always check each STA_REC when flushing packets no matter it is inactive or active */
914         #if 0
915         if(!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid){
916             continue; /* Continue to check the next STA_REC */
917         }
918         #endif
919
920         for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++){
921             if(QUEUE_IS_EMPTY(&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))){
922                continue; /* Continue to check the next TX queue of the same STA */
923             }
924
925             if(!prMsduInfoListHead){
926
927                 /* The first MSDU_INFO is found */
928                 prMsduInfoListHead =(P_MSDU_INFO_T)
929                     QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]);
930                 prMsduInfoListTail =(P_MSDU_INFO_T)
931                     QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]);
932             }
933             else{
934                 /* Concatenate the MSDU_INFO list with the existing list */
935                 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
936                     QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]));
937
938                 prMsduInfoListTail = (P_MSDU_INFO_T)
939                     QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]);
940             }
941
942             QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]);
943         }
944     }
945
946     /* Flush per-Type queues */
947     for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++){
948
949         if(QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))){
950            continue; /* Continue to check the next TX queue of the same STA */
951         }
952
953         if(!prMsduInfoListHead){
954
955             /* The first MSDU_INFO is found */
956             prMsduInfoListHead =(P_MSDU_INFO_T)
957                 QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]);
958             prMsduInfoListTail =(P_MSDU_INFO_T)
959                 QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]);
960         }
961         else{
962             /* Concatenate the MSDU_INFO list with the existing list */
963             QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
964                 QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]));
965
966             prMsduInfoListTail = (P_MSDU_INFO_T)
967                 QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]);
968         }
969
970         QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]);
971
972     }
973
974     if(prMsduInfoListTail){
975         /* Terminate the MSDU_INFO list with a NULL pointer */
976         QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL);
977     }
978
979     return prMsduInfoListHead;
980 }
981
982
983 /*----------------------------------------------------------------------------*/
984 /*!
985 * \brief Flush TX packets for a particular STA
986 *
987 * \param[in] u4StaRecIdx STA_REC index
988 *
989 * \return The flushed packets (in a list of MSDU_INFOs)
990 */
991 /*----------------------------------------------------------------------------*/
992 P_MSDU_INFO_T
993 qmFlushStaTxQueues(
994     IN P_ADAPTER_T prAdapter,
995         IN UINT_32 u4StaRecIdx
996         )
997 {
998     UINT_8 ucQueArrayIdx;
999     P_MSDU_INFO_T prMsduInfoListHead;
1000     P_MSDU_INFO_T prMsduInfoListTail;
1001     P_STA_RECORD_T prStaRec;
1002
1003     DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx));
1004
1005     ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD);
1006
1007     prMsduInfoListHead = NULL;
1008     prMsduInfoListTail = NULL;
1009
1010     prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
1011     ASSERT(prStaRec);
1012
1013     /* No matter whether this is an activated STA_REC, do flush */
1014 #if 0
1015     if(!prStaRec->fgIsValid){
1016         return NULL;
1017     }
1018 #endif
1019
1020     /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */
1021     for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++){
1022         if(QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))){
1023             continue;
1024         }
1025
1026         if(!prMsduInfoListHead){
1027             /* The first MSDU_INFO is found */
1028             prMsduInfoListHead =(P_MSDU_INFO_T)
1029                 QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]);
1030             prMsduInfoListTail =(P_MSDU_INFO_T)
1031                 QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]);        }
1032         else{
1033             /* Concatenate the MSDU_INFO list with the existing list */
1034             QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
1035                 QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]));
1036
1037             prMsduInfoListTail =
1038                 (P_MSDU_INFO_T)QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]);
1039         }
1040
1041         QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]);
1042
1043     }
1044
1045 #if 0
1046     if(prMsduInfoListTail){
1047         /* Terminate the MSDU_INFO list with a NULL pointer */
1048         QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, nicGetPendingStaMMPDU(prAdapter, (UINT_8)u4StaRecIdx));
1049     }
1050     else {
1051         prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8)u4StaRecIdx);
1052     }
1053 #endif
1054
1055     return prMsduInfoListHead;
1056
1057 }
1058
1059 /*----------------------------------------------------------------------------*/
1060 /*!
1061 * \brief Flush RX packets
1062 *
1063 * \param[in] (none)
1064 *
1065 * \return The flushed packets (in a list of SW_RFBs)
1066 */
1067 /*----------------------------------------------------------------------------*/
1068 P_SW_RFB_T
1069 qmFlushRxQueues(
1070         IN P_ADAPTER_T  prAdapter
1071         )
1072 {
1073     UINT_32 i;
1074     P_SW_RFB_T prSwRfbListHead;
1075     P_SW_RFB_T prSwRfbListTail;
1076     P_QUE_MGT_T prQM = &prAdapter->rQM;
1077
1078     prSwRfbListHead = prSwRfbListTail = NULL;
1079
1080     DBGLOG(QM, TRACE, ("QM: Enter qmFlushRxQueues()\n"));
1081
1082     for(i =0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
1083         if(QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))){
1084             if(!prSwRfbListHead){
1085
1086                 /* The first MSDU_INFO is found */
1087                 prSwRfbListHead =(P_SW_RFB_T)
1088                     QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue));
1089                 prSwRfbListTail =(P_SW_RFB_T)
1090                     QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue));
1091             }
1092             else{
1093                 /* Concatenate the MSDU_INFO list with the existing list */
1094                 QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail,
1095                     QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue)));
1096
1097                 prSwRfbListTail = (P_SW_RFB_T)
1098                     QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue));
1099             }
1100
1101             QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue));
1102
1103         }
1104         else{
1105             continue;
1106         }
1107     }
1108
1109     if(prSwRfbListTail){
1110         /* Terminate the MSDU_INFO list with a NULL pointer */
1111         QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1112     }
1113     return prSwRfbListHead;
1114
1115 }
1116
1117
1118 /*----------------------------------------------------------------------------*/
1119 /*!
1120 * \brief Flush RX packets with respect to a particular STA
1121 *
1122 * \param[in] u4StaRecIdx STA_REC index
1123 * \param[in] u4Tid TID
1124 *
1125 * \return The flushed packets (in a list of SW_RFBs)
1126 */
1127 /*----------------------------------------------------------------------------*/
1128 P_SW_RFB_T
1129 qmFlushStaRxQueue(
1130     IN P_ADAPTER_T prAdapter,
1131         IN UINT_32 u4StaRecIdx,
1132         IN UINT_32 u4Tid
1133         )
1134 {
1135     //UINT_32 i;
1136     P_SW_RFB_T prSwRfbListHead;
1137     P_SW_RFB_T prSwRfbListTail;
1138     P_RX_BA_ENTRY_T prReorderQueParm;
1139     P_STA_RECORD_T prStaRec;
1140
1141     DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx));
1142
1143     prSwRfbListHead = prSwRfbListTail = NULL;
1144
1145     prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
1146     ASSERT(prStaRec);
1147
1148     /* No matter whether this is an activated STA_REC, do flush */
1149 #if 0
1150     if(!prStaRec->fgIsValid){
1151         return NULL;
1152     }
1153 #endif
1154
1155     /* Obtain the RX BA Entry pointer */
1156     prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]);
1157
1158     /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */
1159     if(prReorderQueParm){
1160
1161         if(QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))){
1162
1163             prSwRfbListHead =(P_SW_RFB_T)
1164                 QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue));
1165             prSwRfbListTail =(P_SW_RFB_T)
1166                 QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue));
1167
1168
1169             QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue));
1170
1171         }
1172     }
1173
1174     if(prSwRfbListTail){
1175         /* Terminate the MSDU_INFO list with a NULL pointer */
1176         QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1177     }
1178     return prSwRfbListHead;
1179
1180
1181 }
1182
1183
1184 /*----------------------------------------------------------------------------*/
1185 /*!
1186 * \brief Enqueue TX packets
1187 *
1188 * \param[in] prMsduInfoListHead Pointer to the list of TX packets
1189 *
1190 * \return The freed packets, which are not enqueued
1191 */
1192 /*----------------------------------------------------------------------------*/
1193 P_MSDU_INFO_T
1194 qmEnqueueTxPackets(
1195     IN P_ADAPTER_T   prAdapter,
1196         IN P_MSDU_INFO_T prMsduInfoListHead
1197         )
1198 {
1199     P_MSDU_INFO_T   prMsduInfoReleaseList;
1200     P_MSDU_INFO_T   prCurrentMsduInfo;
1201     P_MSDU_INFO_T   prNextMsduInfo;
1202
1203     P_STA_RECORD_T  prStaRec;
1204     P_QUE_T         prTxQue;
1205     QUE_T           rNotEnqueuedQue;
1206
1207
1208     UINT_8          ucPacketType;
1209     UINT_8          ucTC;
1210     P_QUE_MGT_T prQM = &prAdapter->rQM;
1211     UINT_8 aucNextUP[WMM_AC_INDEX_NUM] = { 1 /* BEtoBK*/, 1 /*na*/, 0/*VItoBE*/ , 4 /*VOtoVI*/};
1212
1213     DBGLOG(QM, LOUD, ("Enter qmEnqueueTxPackets\n"));
1214
1215     ASSERT(prMsduInfoListHead);
1216
1217 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
1218         {
1219                 //UINT_32         i;
1220         //4 <0> Update TC resource control related variables
1221         /* Keep track of the queue length */
1222         if (--prQM->u4TimeToUpdateQueLen == 0){
1223             prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN;
1224             qmUpdateAverageTxQueLen(prAdapter);
1225         }
1226         }
1227 #endif
1228
1229     /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */
1230     prStaRec = NULL;
1231     prMsduInfoReleaseList = NULL;
1232     prCurrentMsduInfo = NULL;
1233     QUEUE_INITIALIZE(&rNotEnqueuedQue);
1234     prNextMsduInfo = prMsduInfoListHead;
1235
1236     do{
1237         P_BSS_INFO_T prBssInfo;
1238         BOOLEAN      fgCheckACMAgain;
1239         ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX;
1240         prCurrentMsduInfo = prNextMsduInfo;
1241         prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo);
1242         ucTC = TC1_INDEX;
1243
1244         //4 <1> Lookup the STA_REC index
1245         /* The ucStaRecIndex will be set in this function */
1246         qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo);
1247         ucPacketType = HIF_TX_PACKET_TYPE_DATA;
1248
1249         DBGLOG(QM, LOUD , ("***** ucStaRecIndex = %d *****\n",
1250                prCurrentMsduInfo->ucStaRecIndex));
1251
1252
1253         prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]);
1254
1255         if(IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) {
1256
1257             switch (prCurrentMsduInfo->ucStaRecIndex){
1258                 case STA_REC_INDEX_BMCAST:
1259                     prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
1260                     ucTC = TC5_INDEX;
1261 #if 0
1262                     if(prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX
1263                             && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT
1264                             ) {
1265                         if(LINK_IS_EMPTY(&prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].rStaRecOfClientList)) {
1266                             prTxQue = &rNotEnqueuedQue;
1267                             TX_INC_CNT(&prAdapter->rTxCtrl,TX_AP_BORADCAST_DROP);
1268                         }
1269                     }
1270 #endif
1271
1272                     QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23);
1273                     break;
1274
1275                 case STA_REC_INDEX_NOT_FOUND:
1276                     ucTC = TC5_INDEX;
1277
1278                     if(prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1279
1280                         /* if the packet is the forward type. the packet should be freed */
1281                         DBGLOG(QM, TRACE, ("Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"));
1282                         //prTxQue = &rNotEnqueuedQue;
1283                     }
1284                     prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC];
1285                     QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24);
1286
1287                     break;
1288
1289                 default:
1290                     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prCurrentMsduInfo->ucStaRecIndex);
1291
1292                     ASSERT(prStaRec);
1293                     ASSERT(prStaRec->fgIsValid);
1294
1295                     if(prCurrentMsduInfo->ucUserPriority < 8) {
1296                         QM_DBG_CNT_INC(prQM, prCurrentMsduInfo->ucUserPriority + 15);
1297                         /* QM_DBG_CNT_15 */ /* QM_DBG_CNT_16 */ /* QM_DBG_CNT_17 */ /* QM_DBG_CNT_18 */
1298                         /* QM_DBG_CNT_19 */ /* QM_DBG_CNT_20 */ /* QM_DBG_CNT_21 */ /* QM_DBG_CNT_22 */
1299                     }
1300
1301                     eAci = WMM_AC_BE_INDEX;
1302                     do {
1303                         fgCheckACMAgain = FALSE;
1304                     if (prStaRec->fgIsQoS){
1305                         switch(prCurrentMsduInfo->ucUserPriority){
1306                         case 1:
1307                         case 2:
1308                             prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC0];
1309                             ucTC = TC0_INDEX;
1310                                     eAci = WMM_AC_BK_INDEX;
1311                             break;
1312                         case 0:
1313                         case 3:
1314                             prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1];
1315                             ucTC = TC1_INDEX;
1316                                     eAci = WMM_AC_BE_INDEX;
1317                             break;
1318                         case 4:
1319                         case 5:
1320                             prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC2];
1321                             ucTC = TC2_INDEX;
1322                                     eAci = WMM_AC_VI_INDEX;
1323                             break;
1324                         case 6:
1325                         case 7:
1326                             prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC3];
1327                             ucTC = TC3_INDEX;
1328                                     eAci = WMM_AC_VO_INDEX;
1329                             break;
1330                         default:
1331                             prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1];
1332                             ucTC = TC1_INDEX;
1333                                     eAci = WMM_AC_BE_INDEX;
1334                             ASSERT(0);
1335                             break;
1336                         }
1337                             if(prBssInfo->arACQueParms[eAci].fgIsACMSet && eAci != WMM_AC_BK_INDEX) {
1338                                 prCurrentMsduInfo->ucUserPriority = aucNextUP[eAci];
1339                                 fgCheckACMAgain = TRUE;
1340                             }
1341                     }
1342                     else{
1343                         prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1];
1344                         ucTC = TC1_INDEX;
1345                     }
1346                     }
1347                     while(fgCheckACMAgain);
1348
1349                      //LOG_FUNC ("QoS %u UP %u TC %u",prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC);
1350
1351                     break; /*default */
1352              } /* switch (prCurrentMsduInfo->ucStaRecIndex) */
1353
1354              if(prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1355                 if(prTxQue->u4NumElem > 32) {
1356                     DBGLOG(QM, INFO, ("Drop the Packet for full Tx queue (forwarding) Bss %u\n", prCurrentMsduInfo->ucNetworkType));
1357                      prTxQue = &rNotEnqueuedQue;
1358                      TX_INC_CNT(&prAdapter->rTxCtrl,TX_FORWARD_OVERFLOW_DROP);
1359                 }
1360              }
1361
1362         }
1363         else {
1364
1365             DBGLOG(QM, INFO, ("Drop the Packet for inactive Bss %u\n", prCurrentMsduInfo->ucNetworkType));
1366             QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31);
1367             prTxQue = &rNotEnqueuedQue;
1368             TX_INC_CNT(&prAdapter->rTxCtrl,TX_INACTIVE_BSS_DROP);
1369         }
1370
1371         //4 <3> Fill the MSDU_INFO for constructing HIF TX header
1372
1373         /* TODO: Fill MSDU_INFO according to the network type,
1374         *  EtherType, and STA status (for PS forwarding control).
1375         */
1376
1377         /* Note that the Network Type Index and STA_REC index are determined in
1378         *  qmDetermineStaRecIndex(prCurrentMsduInfo).
1379         */
1380         QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(
1381             prCurrentMsduInfo,                          /* MSDU_INFO ptr */
1382             ucTC,                                       /* TC tag */
1383             ucPacketType,                               /* Packet Type */
1384             0,                                          /* Format ID */
1385             prCurrentMsduInfo->fgIs802_1x,              /* Flag 802.1x */
1386             prCurrentMsduInfo->fgIs802_11,              /* Flag 802.11 */
1387             0,                                          /* PAL LLH */
1388             0,                                          /* ACL SN */
1389             PS_FORWARDING_TYPE_NON_PS,                  /* PS Forwarding Type */
1390             0                                           /* PS Session ID */
1391         );
1392
1393         //4 <4> Enqueue the packet
1394         QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T)prCurrentMsduInfo);
1395
1396
1397 #if QM_TEST_MODE
1398         if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT){
1399             prQM->u4PktCount = 0;
1400             qmTestCases(prAdapter);
1401         }
1402
1403 #endif
1404
1405         DBGLOG(QM, LOUD, ("Current queue length = %u\n", prTxQue->u4NumElem));
1406     }while(prNextMsduInfo);
1407
1408     if(  QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue) ) {
1409         QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL);
1410         prMsduInfoReleaseList =  (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rNotEnqueuedQue);
1411     }
1412
1413
1414     return prMsduInfoReleaseList;
1415 }
1416
1417 /*----------------------------------------------------------------------------*/
1418 /*!
1419 * \brief Determine the STA_REC index for a packet
1420 *
1421 * \param[in] prMsduInfo Pointer to the packet
1422 *
1423 * \return (none)
1424 */
1425 /*----------------------------------------------------------------------------*/
1426 static VOID
1427 qmDetermineStaRecIndex(
1428     IN P_ADAPTER_T   prAdapter,
1429         IN P_MSDU_INFO_T prMsduInfo
1430         )
1431 {
1432     UINT_32 i;
1433
1434     P_STA_RECORD_T prTempStaRec;
1435     //P_QUE_MGT_T prQM = &prAdapter->rQM;
1436
1437     prTempStaRec = NULL;
1438
1439     ASSERT(prMsduInfo);
1440
1441     //4 <1> DA = BMCAST
1442     if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)){
1443         /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP.
1444         *  FW shall take care of this. The host driver is not able to distinguish these cases. */
1445         prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST;
1446         DBGLOG(QM, LOUD, ("TX with DA = BMCAST\n"));
1447         return;
1448     }
1449
1450
1451     //4 <2> Check if an AP STA is present
1452     for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
1453         prTempStaRec = &(prAdapter->arStaRec[i]);
1454
1455         if((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType)
1456                 && (prTempStaRec->fgIsAp)
1457                 && (prTempStaRec->fgIsValid)){
1458             prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex;
1459             return;
1460         }
1461     }
1462
1463
1464
1465
1466     //4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client)
1467     for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
1468         prTempStaRec = &(prAdapter->arStaRec[i]);
1469         if (prTempStaRec->fgIsValid){
1470             if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)){
1471                 prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex;
1472                 return;
1473             }
1474         }
1475     }
1476
1477
1478     //4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW
1479     prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND;
1480     DBGLOG(QM, LOUD, ("QM: TX with STA_REC_INDEX_NOT_FOUND\n"));
1481
1482
1483 #if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING)
1484     prMsduInfo->ucStaRecIndex = (UINT_8)prQM->u4CurrentStaRecIndexToEnqueue;
1485 #endif
1486 }
1487
1488 /*----------------------------------------------------------------------------*/
1489 /*!
1490 * \brief Dequeue TX packets from a STA_REC for a particular TC
1491 *
1492 * \param[out] prQue The queue to put the dequeued packets
1493 * \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX)
1494 * \param[in] ucMaxNum The maximum amount of dequeued packets
1495 *
1496 * \return (none)
1497 */
1498 /*----------------------------------------------------------------------------*/
1499 static VOID
1500 qmDequeueTxPacketsFromPerStaQueues(
1501     IN P_ADAPTER_T   prAdapter,
1502     OUT P_QUE_T prQue,
1503     IN  UINT_8  ucTC,
1504     IN  UINT_8  ucCurrentQuota,
1505     IN  UINT_8  ucTotalQuota
1506     )
1507 {
1508
1509 #if QM_FORWARDING_FAIRNESS
1510     UINT_32         i;  /* Loop for */
1511
1512     PUINT_32        pu4HeadStaRecIndex;         /* The Head STA index */
1513     PUINT_32        pu4HeadStaRecForwardCount;  /* The total forwarded packets for the head STA */
1514
1515     P_STA_RECORD_T  prStaRec;           /* The current focused STA */
1516     P_BSS_INFO_T    prBssInfo;          /* The Bss for current focused STA */
1517     P_QUE_T         prCurrQueue;        /* The current TX queue to dequeue */
1518     P_MSDU_INFO_T   prDequeuedPkt;      /* The dequeued packet */
1519
1520     UINT_32         u4ForwardCount;     /* To remember the total forwarded packets for a STA */
1521     UINT_32         u4MaxForwardCount;  /* The maximum number of packets a STA can forward */
1522     UINT_32         u4Resource;         /* The TX resource amount */
1523
1524     BOOLEAN         fgChangeHeadSta;    /* Whether a new head STA shall be determined at the end of the function */
1525     P_QUE_MGT_T prQM = &prAdapter->rQM;
1526
1527     PUINT_8         pucFreeQuota;
1528
1529     DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC));
1530
1531     ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX ||
1532            ucTC == TC2_INDEX || ucTC == TC3_INDEX ||
1533            ucTC == TC4_INDEX
1534            );
1535
1536     if(!ucCurrentQuota){
1537         DBGLOG(TX, LOUD, ("@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n",
1538         ucTC, ucCurrentQuota));
1539         return;
1540     }
1541
1542     u4Resource = ucCurrentQuota;
1543
1544     //4 <1> Determine the head STA
1545     /* The head STA shall be an active STA */
1546
1547     pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]);
1548     pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]);
1549
1550     DBGLOG(QM, LOUD, ("(Fairness) TID = %u Init Head STA = %u Resource = %u\n",
1551         ucTC, *pu4HeadStaRecIndex, u4Resource));
1552
1553
1554     /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */
1555     for (i=0; i < CFG_NUM_OF_STA_RECORD + 1; i++){
1556         prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)];
1557         ASSERT(prStaRec);
1558
1559         /* Only Data frame (1x was not included) will be queued in */
1560         if (prStaRec->fgIsValid){
1561
1562               prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
1563
1564               ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1565
1566                 /* Determine how many packets the head STA is allowed to send in a round */
1567
1568                     QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25);
1569                     u4MaxForwardCount = ucTotalQuota;
1570 #if CFG_ENABLE_WIFI_DIRECT
1571
1572                     pucFreeQuota = NULL;
1573                     if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) {
1574                         // TODO: Change the threshold in coorperation with the PS forwarding mechanism
1575                         // u4MaxForwardCount = ucTotalQuota;
1576                         /* Per STA flow control when STA in PS mode */
1577                         /* The PHASE 1: only update from ucFreeQuota (now) */
1578                         /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1579                         /* NOTE: other method to set u4Resource */
1580
1581                         if(prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
1582                               /*  && prAdapter->rWifiVar.fgSupportQoS
1583                                 && prAdapter->rWifiVar.fgSupportUAPSD*/) {
1584
1585                             if( prStaRec->ucBmpTriggerAC & BIT(ucTC)) {
1586                                 u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery;
1587                                 pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery;
1588                             }
1589                             else {
1590                                 u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1591                                 pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1592                             }
1593
1594                         }
1595                         else {
1596                             ASSERT(prStaRec->ucFreeQuotaForDelivery == 0);
1597                             u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1598                             pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1599                         }
1600
1601                     } /* fgIsInPS */
1602 #endif /* CFG_ENABLE_WIFI_DIRECT */
1603
1604 #if CFG_ENABLE_WIFI_DIRECT
1605                     if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) {
1606                         if(u4MaxForwardCount > prBssInfo->ucBssFreeQuota) {
1607                             u4MaxForwardCount = prBssInfo->ucBssFreeQuota;
1608                         }
1609                     }
1610
1611 #endif /* CFG_ENABLE_WIFI_DIRECT */
1612
1613                     /* Determine whether the head STA can continue to forward packets in this round */
1614                     if((*pu4HeadStaRecForwardCount) < u4MaxForwardCount){
1615                         break;
1616                     }
1617
1618         } /* prStaRec->fgIsValid */
1619         else{
1620             /* The current Head STA has been deactivated, so search for a new head STA */
1621             prStaRec = NULL;
1622             prBssInfo = NULL;
1623             (*pu4HeadStaRecIndex) ++;
1624             (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD;
1625
1626             /* Reset the forwarding count before searching (since this is for a new selected STA) */
1627             (*pu4HeadStaRecForwardCount) = 0;
1628         }
1629     } /* i < CFG_NUM_OF_STA_RECORD + 1 */
1630
1631     /* All STA_RECs are inactive, so exit */
1632     if (!prStaRec){
1633         /* Under concurrent, it is possible that there is no candidcated STA.*/
1634         //DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n"));
1635         return;
1636     }
1637
1638     DBGLOG(QM, LOUD, ("(Fairness) TID = %u Round Head STA = %lu\n",
1639         ucTC, *pu4HeadStaRecIndex));
1640
1641     //4 <2> Dequeue packets from the head STA
1642
1643     prCurrQueue = &prStaRec->arTxQueue[ucTC];
1644     prDequeuedPkt = NULL;
1645     fgChangeHeadSta = FALSE;
1646
1647     while(prCurrQueue){
1648
1649
1650 #if QM_DEBUG_COUNTER
1651
1652         if(ucTC <= TC4_INDEX) {
1653             if(QUEUE_IS_EMPTY(prCurrQueue)) {
1654                 QM_DBG_CNT_INC(prQM, ucTC);
1655                 /* QM_DBG_CNT_00 */ /* QM_DBG_CNT_01 */ /* QM_DBG_CNT_02 */ /* QM_DBG_CNT_03 */ /* QM_DBG_CNT_04 */
1656             }
1657             if(u4Resource == 0) {
1658                 QM_DBG_CNT_INC(prQM, ucTC + 5);
1659                 /* QM_DBG_CNT_05 */ /* QM_DBG_CNT_06 */ /* QM_DBG_CNT_07 */ /* QM_DBG_CNT_08 */ /* QM_DBG_CNT_09 */
1660             }
1661             if(((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) {
1662                 QM_DBG_CNT_INC(prQM, ucTC + 10);
1663                 /* QM_DBG_CNT_10 */ /* QM_DBG_CNT_11 */ /* QM_DBG_CNT_12 */ /* QM_DBG_CNT_13 */ /* QM_DBG_CNT_14 */
1664             }
1665         }
1666 #endif
1667
1668
1669         /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1670         if (QUEUE_IS_EMPTY(prCurrQueue) || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)){
1671             fgChangeHeadSta = TRUE;
1672             break;
1673         }
1674         else if (u4Resource == 0){
1675             break;
1676         }
1677         else{
1678
1679             QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1680 #if DBG && 0
1681             LOG_FUNC("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1682                     prDequeuedPkt->ucTC,
1683                     prCurrQueue->u4NumElem,
1684                     prDequeuedPkt->ucNetworkType,
1685                     prDequeuedPkt->ucMacHeaderLength,
1686                     prDequeuedPkt->u2FrameLength,
1687                     prDequeuedPkt->ucPacketType,
1688                     prDequeuedPkt->fgIs802_1x,
1689                     prDequeuedPkt->fgIs802_11 );
1690
1691             LOG_FUNC("Dest Mac: " MACSTR "\n",
1692                     MAC2STR(prDequeuedPkt->aucEthDestAddr));
1693
1694 #if LINUX
1695             {
1696                 struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket;
1697                 dumpMemory8((PUINT_8)prSkb->data,prSkb->len);
1698             }
1699 #endif
1700
1701 #endif
1702
1703             ASSERT(prDequeuedPkt->ucTC == ucTC);
1704
1705             if(!QUEUE_IS_EMPTY(prCurrQueue)) {
1706                 /* XXX: check all queues for STA */
1707                 prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED;
1708             }
1709
1710             QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt);
1711             u4Resource--;
1712             (*pu4HeadStaRecForwardCount) ++;
1713
1714
1715 #if CFG_ENABLE_WIFI_DIRECT
1716             /* XXX The PHASE 2: decrease from  aucFreeQuotaPerQueue[] */
1717             if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) {
1718                 ASSERT(pucFreeQuota);
1719                 ASSERT(*pucFreeQuota>0);
1720                 if(*pucFreeQuota>0) {
1721                     *pucFreeQuota = *pucFreeQuota - 1;
1722                 }
1723             }
1724 #endif  /* CFG_ENABLE_WIFI_DIRECT */
1725
1726 #if CFG_ENABLE_WIFI_DIRECT
1727                 if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) {
1728                     if(prBssInfo->ucBssFreeQuota>0) {
1729                         prBssInfo->ucBssFreeQuota--;
1730                     }
1731                 }
1732 #endif  /* CFG_ENABLE_WIFI_DIRECT */
1733
1734         }
1735     }
1736
1737    if (*pu4HeadStaRecForwardCount){
1738         DBGLOG(QM, LOUD, ("TC = %u Round Head STA = %lu, u4HeadStaRecForwardCount = %lu\n", ucTC, *pu4HeadStaRecIndex, (*pu4HeadStaRecForwardCount)));
1739    }
1740
1741 #if QM_BURST_END_INFO_ENABLED
1742     /* Let FW know which packet is the last one dequeued from the STA */
1743     if (prDequeuedPkt){
1744         prDequeuedPkt->fgIsBurstEnd = TRUE;
1745     }
1746 #endif
1747
1748
1749     //4 <3> Dequeue from the other STAs if there is residual TX resource
1750
1751     /* Check all of the STAs to continue forwarding packets (including the head STA) */
1752     for (i= 0; i< CFG_NUM_OF_STA_RECORD; i++){
1753         /* Break in case no reasource is available */
1754         if (u4Resource == 0){
1755             break;
1756         }
1757
1758         /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */
1759         prStaRec = &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD];
1760         ASSERT(prStaRec);
1761
1762        if (prStaRec->fgIsValid) {
1763
1764               prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
1765                 ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1766
1767                 DBGLOG(QM, LOUD, ("(Fairness) TID = %u Sharing STA = %u Resource = %lu\n",
1768                 ucTC, prStaRec->ucIndex, u4Resource));
1769
1770                 prCurrQueue = &prStaRec->arTxQueue[ucTC];
1771                 u4ForwardCount = 0;
1772                 u4MaxForwardCount = ucTotalQuota;
1773
1774 #if CFG_ENABLE_WIFI_DIRECT
1775                 pucFreeQuota = NULL;
1776                 if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) {
1777                     // TODO: Change the threshold in coorperation with the PS forwarding mechanism
1778                     // u4MaxForwardCount = ucTotalQuota;
1779                     /* Per STA flow control when STA in PS mode */
1780                     /* The PHASE 1: only update from ucFreeQuota (now) */
1781                     /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1782                     /* NOTE: other method to set u4Resource */
1783                     if(prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
1784                           /*  && prAdapter->rWifiVar.fgSupportQoS
1785                             && prAdapter->rWifiVar.fgSupportUAPSD*/) {
1786
1787                         if( prStaRec->ucBmpTriggerAC & BIT(ucTC)) {
1788                             u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery;
1789                             pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery;
1790                         }
1791                         else {
1792                             u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1793                             pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1794                         }
1795
1796                     }
1797                     else {
1798                         ASSERT(prStaRec->ucFreeQuotaForDelivery == 0);
1799                         u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1800                         pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1801                     }
1802
1803                 }
1804 #endif /* CFG_ENABLE_WIFI_DIRECT */
1805 #if CFG_ENABLE_WIFI_DIRECT
1806                 if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) {
1807                     if(u4MaxForwardCount > prBssInfo->ucBssFreeQuota) {
1808                         u4MaxForwardCount = prBssInfo->ucBssFreeQuota;
1809                     }
1810                 }
1811
1812 #endif /* CFG_ENABLE_WIFI_DIRECT */
1813         } /* prStaRec->fgIsValid */
1814         else{
1815             prBssInfo = NULL;
1816             /* Invalid STA, so check the next STA */
1817             continue;
1818         }
1819
1820         while(prCurrQueue){
1821             /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1822             if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue) || (u4ForwardCount >= u4MaxForwardCount)){
1823                 break;
1824             }
1825             else{
1826
1827                 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1828
1829 #if DBG && 0
1830                 DBGLOG(QM, LOUD, ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1831                     prDequeuedPkt->ucTC,
1832                     prCurrQueue->u4NumElem,
1833                         prDequeuedPkt->ucNetworkType,
1834                         prDequeuedPkt->ucMacHeaderLength,
1835                     prDequeuedPkt->u2FrameLength,
1836                     prDequeuedPkt->ucPacketType,
1837                     prDequeuedPkt->fgIs802_1x,
1838                     prDequeuedPkt->fgIs802_11 ));
1839
1840                 DBGLOG(QM, LOUD,("Dest Mac: " MACSTR "\n",
1841                         MAC2STR(prDequeuedPkt->aucEthDestAddr)));
1842
1843 #if LINUX
1844                 {
1845                     struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket;
1846                     dumpMemory8((PUINT_8)prSkb->data,prSkb->len);
1847                 }
1848 #endif
1849
1850 #endif
1851
1852
1853                 ASSERT(prDequeuedPkt->ucTC == ucTC);
1854
1855                 if(!QUEUE_IS_EMPTY(prCurrQueue)) {
1856                     prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED;
1857                 }
1858
1859                 QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt);
1860                 u4Resource--;
1861                 u4ForwardCount ++;
1862
1863 #if CFG_ENABLE_WIFI_DIRECT
1864                 /* XXX The PHASE 2: decrease from  aucFreeQuotaPerQueue[] */
1865                 if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) {
1866                     ASSERT(pucFreeQuota);
1867                     ASSERT(*pucFreeQuota>0);
1868                     if(*pucFreeQuota>0) {
1869                         *pucFreeQuota = *pucFreeQuota - 1;
1870                     }
1871                 }
1872 #endif  /* CFG_ENABLE_WIFI_DIRECT */
1873
1874
1875 #if CFG_ENABLE_WIFI_DIRECT
1876                 ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1877                 if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) {
1878                     if(prBssInfo->ucBssFreeQuota>0) {
1879                         prBssInfo->ucBssFreeQuota--;
1880                     }
1881                 }
1882 #endif  /* CFG_ENABLE_WIFI_DIRECT */
1883
1884             }
1885         }
1886
1887 #if QM_BURST_END_INFO_ENABLED
1888         /* Let FW know which packet is the last one dequeued from the STA */
1889         if (u4ForwardCount){
1890             prDequeuedPkt->fgIsBurstEnd = TRUE;
1891         }
1892 #endif
1893     }
1894
1895
1896     if (fgChangeHeadSta){
1897         (*pu4HeadStaRecIndex) ++;
1898         (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD;
1899         (*pu4HeadStaRecForwardCount) = 0;
1900         DBGLOG(QM, LOUD, ("(Fairness) TID = %u Scheduled Head STA = %lu Left Resource = %lu\n",
1901             ucTC, (*pu4HeadStaRecIndex),  u4Resource));
1902     }
1903
1904
1905 /***************************************************************************************/
1906 #else
1907     UINT_8          ucStaRecIndex;
1908     P_STA_RECORD_T  prStaRec;
1909     P_QUE_T         prCurrQueue;
1910     UINT_8          ucPktCount;
1911     P_MSDU_INFO_T   prDequeuedPkt;
1912
1913     DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC));
1914
1915     if (ucCurrentQuota == 0){
1916         return;
1917     }
1918
1919     //4 <1> Determine the queue index and the head STA
1920
1921     /* The head STA */
1922     ucStaRecIndex = 0;  /* TODO: Get the current head STA */
1923     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex);
1924     ASSERT(prStaRec);
1925
1926     if(prStaRec == NULL) {
1927         return;
1928     }
1929
1930     /* The queue to pull out packets */
1931     ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX ||
1932            ucTC == TC2_INDEX || ucTC == TC3_INDEX ||
1933            ucTC == TC4_INDEX
1934            );
1935     prCurrQueue = &prStaRec->arTxQueue[ucTC];
1936
1937     ucPktCount = ucCurrentQuota;
1938     prDequeuedPkt = NULL;
1939
1940     //4 <2> Dequeue packets for the head STA
1941     while(TRUE){
1942         if (!(prStaRec->fgIsValid) || ucPktCount ==0 || QUEUE_IS_EMPTY(prCurrQueue)){
1943             break;
1944
1945         }
1946         else{
1947
1948             QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1949             //DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC);
1950             ASSERT(prDequeuedPkt->ucTC == ucTC);
1951
1952             QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt);
1953             ucPktCount--;
1954         }
1955     }
1956
1957     //DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem);
1958
1959 #if QM_BURST_END_INFO_ENABLED
1960     if (prDequeuedPkt){
1961         prDequeuedPkt->fgIsBurstEnd = TRUE;
1962     }
1963
1964 #endif
1965
1966     //4 <3> Update scheduling info
1967     /* TODO */
1968
1969     //4 <4> Utilize the remainaing TX opportunities for non-head STAs
1970     /* TODO */
1971 #endif
1972 }
1973
1974
1975 /*----------------------------------------------------------------------------*/
1976 /*!
1977 * \brief Dequeue TX packets from a per-Type-based Queue for a particular TC
1978 *
1979 * \param[out] prQue The queue to put the dequeued packets
1980 * \param[in] ucTC The TC index (Shall always be TC5_INDEX)
1981 * \param[in] ucMaxNum The maximum amount of dequeued packets
1982 *
1983 * \return (none)
1984 */
1985 /*----------------------------------------------------------------------------*/
1986 static VOID
1987 qmDequeueTxPacketsFromPerTypeQueues(
1988     IN P_ADAPTER_T   prAdapter,
1989     OUT P_QUE_T prQue,
1990     IN  UINT_8  ucTC,
1991     IN  UINT_8  ucMaxNum
1992     )
1993 {
1994     //UINT_8          ucQueIndex;
1995     //UINT_8          ucStaRecIndex;
1996     P_BSS_INFO_T prBssInfo;
1997     P_BSS_INFO_T parBssInfo;
1998     P_QUE_T         prCurrQueue;
1999     UINT_8          ucPktCount;
2000     P_MSDU_INFO_T   prDequeuedPkt;
2001     P_MSDU_INFO_T   prBurstEndPkt;
2002     QUE_T           rMergeQue;
2003     P_QUE_T         prMergeQue;
2004     P_QUE_MGT_T     prQM;
2005
2006     DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum));
2007
2008     /* TC5: Broadcast/Multicast data packets */
2009     ASSERT(ucTC == TC5_INDEX);
2010
2011     if (ucMaxNum == 0){
2012         return;
2013     }
2014
2015     prQM = &prAdapter->rQM;
2016     //4 <1> Determine the queue
2017
2018     prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
2019     ucPktCount = ucMaxNum;
2020     prDequeuedPkt = NULL;
2021     prBurstEndPkt = NULL;
2022
2023     parBssInfo = prAdapter->rWifiVar.arBssInfo;
2024
2025     QUEUE_INITIALIZE(&rMergeQue);
2026     prMergeQue = &rMergeQue;
2027
2028     //4 <2> Dequeue packets
2029     while(TRUE){
2030         if(ucPktCount ==0 || QUEUE_IS_EMPTY(prCurrQueue)){
2031             break;
2032         }
2033         else{
2034             QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
2035             ASSERT(prDequeuedPkt->ucTC == ucTC);
2036
2037             ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM);
2038
2039             prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType];
2040
2041             if(IS_BSS_ACTIVE(prBssInfo)) {
2042                 if(  !prBssInfo->fgIsNetAbsent){
2043                     QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt);
2044                     prBurstEndPkt = prDequeuedPkt;
2045                     ucPktCount--;
2046                     QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26);
2047 #if DBG && 0
2048                     LOG_FUNC("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
2049                         prDequeuedPkt->ucTC,
2050                         prCurrQueue->u4NumElem,
2051                             prDequeuedPkt->ucNetworkType,
2052                             prDequeuedPkt->ucMacHeaderLength,
2053                         prDequeuedPkt->u2FrameLength,
2054                         prDequeuedPkt->ucPacketType,
2055                         prDequeuedPkt->fgIs802_1x,
2056                         prDequeuedPkt->fgIs802_11 );
2057
2058                     LOG_FUNC("Dest Mac: " MACSTR "\n",
2059                             MAC2STR(prDequeuedPkt->aucEthDestAddr));
2060
2061 #if LINUX
2062                     {
2063                         struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket;
2064                         dumpMemory8((PUINT_8)prSkb->data,prSkb->len);
2065                     }
2066 #endif
2067
2068 #endif
2069                 }
2070                 else {
2071                     QUEUE_INSERT_TAIL(prMergeQue,(P_QUE_ENTRY_T)prDequeuedPkt);
2072                 }
2073             }
2074             else {
2075                 QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL);
2076                 wlanProcessQueuedMsduInfo(prAdapter,prDequeuedPkt);
2077             }
2078         }
2079     }
2080
2081     if(QUEUE_IS_NOT_EMPTY(prMergeQue)) {
2082         QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue);
2083         QUEUE_MOVE_ALL(prCurrQueue, prMergeQue);
2084         QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(prCurrQueue), NULL);
2085     }
2086
2087 #if QM_BURST_END_INFO_ENABLED
2088     if (prBurstEndPkt){
2089         prBurstEndPkt->fgIsBurstEnd = TRUE;
2090     }
2091 #endif
2092 } /* qmDequeueTxPacketsFromPerTypeQueues */
2093
2094
2095
2096
2097 /*----------------------------------------------------------------------------*/
2098 /*!
2099 * \brief Dequeue TX packets to send to HIF TX
2100 *
2101 * \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2102 *
2103 * \return The list of dequeued TX packets
2104 */
2105 /*----------------------------------------------------------------------------*/
2106 P_MSDU_INFO_T
2107 qmDequeueTxPackets(
2108     IN P_ADAPTER_T   prAdapter,
2109         IN P_TX_TCQ_STATUS_T prTcqStatus
2110         )
2111 {
2112
2113     INT_32 i;
2114     P_MSDU_INFO_T prReturnedPacketListHead;
2115     QUE_T rReturnedQue;
2116
2117     DBGLOG(QM, LOUD, ("Enter qmDequeueTxPackets\n"));
2118
2119     QUEUE_INITIALIZE(&rReturnedQue);
2120
2121     prReturnedPacketListHead = NULL;
2122
2123     /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */
2124     for(i = TC4_INDEX; i >= TC0_INDEX; i--){
2125         DBGLOG(QM, LOUD, ("Dequeue packets from Per-STA queue[%u]\n", i));
2126
2127         qmDequeueTxPacketsFromPerStaQueues(
2128             prAdapter,
2129             &rReturnedQue,
2130             (UINT_8)i,
2131             prTcqStatus->aucFreeBufferCount[i],
2132             prTcqStatus->aucMaxNumOfBuffer[i]
2133             );
2134
2135         /* The aggregate number of dequeued packets */
2136         DBGLOG(QM, LOUD, ("DQA)[%u](%lu)\n", i, rReturnedQue.u4NumElem));
2137     }
2138
2139
2140     /* TC5 (BMCAST or STA-NOT-FOUND packets) */
2141     qmDequeueTxPacketsFromPerTypeQueues(
2142             prAdapter,
2143             &rReturnedQue,
2144             TC5_INDEX,
2145             prTcqStatus->aucFreeBufferCount[TC5_INDEX]
2146             );
2147
2148     DBGLOG(QM, LOUD, ("Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem));
2149
2150     if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)){
2151         prReturnedPacketListHead = (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rReturnedQue);
2152         QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(&rReturnedQue), NULL);
2153     }
2154
2155     return prReturnedPacketListHead;
2156 }
2157
2158 /*----------------------------------------------------------------------------*/
2159 /*!
2160 * \brief Adjust the TC quotas according to traffic demands
2161 *
2162 * \param[out] prTcqAdjust The resulting adjustment
2163 * \param[in] prTcqStatus Info about the current TC quotas and counters
2164 *
2165 * \return (none)
2166 */
2167 /*----------------------------------------------------------------------------*/
2168 VOID
2169 qmAdjustTcQuotas (
2170     IN P_ADAPTER_T  prAdapter,
2171     OUT P_TX_TCQ_ADJUST_T prTcqAdjust,
2172     IN P_TX_TCQ_STATUS_T prTcqStatus
2173         )
2174 {
2175 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2176     UINT_32 i;
2177     P_QUE_MGT_T prQM = &prAdapter->rQM;
2178
2179     /* Must initialize */
2180     for (i = 0; i < TC_NUM; i++){
2181         prTcqAdjust->acVariation[i]= 0;
2182     }
2183
2184     //4 <1> If TC resource is not just adjusted, exit directly
2185     if (!prQM->fgTcResourcePostAnnealing){
2186         return;
2187     }
2188
2189     //4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource
2190     else{
2191         INT_32 i4TotalExtraQuota = 0;
2192         INT_32 ai4ExtraQuota[TC_NUM];
2193         BOOLEAN fgResourceRedistributed = TRUE;
2194
2195         /* Obtain the free-to-distribute resource */
2196         for (i = 0; i < TC_NUM; i++){
2197             ai4ExtraQuota[i] = (INT_32)prTcqStatus->aucMaxNumOfBuffer[i] - (INT_32)prQM->au4CurrentTcResource[i];
2198
2199             if (ai4ExtraQuota[i] > 0){ /* The resource shall be reallocated to other TCs */
2200                 if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]){
2201                     ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i];
2202                     fgResourceRedistributed = FALSE;
2203                 }
2204
2205                 i4TotalExtraQuota += ai4ExtraQuota[i];
2206                 prTcqAdjust->acVariation[i] = (INT_8)(-ai4ExtraQuota[i]);
2207             }
2208         }
2209
2210         /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */
2211         for (i = 0; i < TC_NUM; i++){
2212             if (ai4ExtraQuota[i] < 0){
2213                 if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota){
2214                     ai4ExtraQuota[i] = (-i4TotalExtraQuota);
2215                     fgResourceRedistributed = FALSE;
2216                 }
2217
2218                 i4TotalExtraQuota += ai4ExtraQuota[i];
2219                 prTcqAdjust->acVariation[i] = (INT_8)(-ai4ExtraQuota[i]);
2220             }
2221         }
2222
2223         /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2224         prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed);
2225
2226 #if QM_PRINT_TC_RESOURCE_CTRL
2227         DBGLOG(QM, LOUD, ("QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n",
2228             prTcqStatus->aucFreeBufferCount[0],
2229             prTcqStatus->aucFreeBufferCount[1],
2230             prTcqStatus->aucFreeBufferCount[2],
2231             prTcqStatus->aucFreeBufferCount[3],
2232             prTcqStatus->aucFreeBufferCount[4],
2233             prTcqStatus->aucFreeBufferCount[5]
2234             ));        
2235 #endif
2236     }
2237
2238 #else
2239     UINT_32 i;
2240     for (i = 0; i < TC_NUM; i++){
2241         prTcqAdjust->acVariation[i]= 0;
2242     }
2243
2244 #endif
2245 }
2246
2247 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2248 /*----------------------------------------------------------------------------*/
2249 /*!
2250 * \brief Update the average TX queue length for the TC resource control mechanism
2251 *
2252 * \param (none)
2253 *
2254 * \return (none)
2255 */
2256 /*----------------------------------------------------------------------------*/
2257 VOID
2258 qmUpdateAverageTxQueLen(
2259     IN P_ADAPTER_T   prAdapter
2260     )
2261 {
2262     INT_32 u4CurrQueLen, i, k;
2263     P_STA_RECORD_T prStaRec;
2264     P_QUE_MGT_T prQM = &prAdapter->rQM;
2265
2266     //4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */
2267     for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++){
2268         u4CurrQueLen = 0;
2269
2270         for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++){
2271             prStaRec = &prAdapter->arStaRec[k];
2272             ASSERT(prStaRec);
2273
2274             /* If the STA is activated, get the queue length */
2275             if (prStaRec->fgIsValid &&
2276                     (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent)
2277                     )
2278             {
2279
2280                 u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem);
2281             }
2282         }
2283
2284         if (prQM->au4AverageQueLen[i] == 0){
2285             prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR);
2286         }
2287         else{
2288             prQM->au4AverageQueLen[i] -= (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR);
2289             prQM->au4AverageQueLen[i] += (u4CurrQueLen);
2290         }
2291
2292     }
2293
2294     /* Update the queue length for TC5 (BMCAST) */
2295     u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem;
2296
2297     if (prQM->au4AverageQueLen[TC_NUM-1] == 0){
2298         prQM->au4AverageQueLen[TC_NUM-1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR);
2299     }
2300     else{
2301         prQM->au4AverageQueLen[TC_NUM-1] -= (prQM->au4AverageQueLen[TC_NUM-1] >> QM_QUE_LEN_MOVING_AVE_FACTOR);
2302         prQM->au4AverageQueLen[TC_NUM-1] += (u4CurrQueLen);
2303     }
2304
2305
2306     //4 <2> Adjust TC resource assignment
2307     /* Check whether it is time to adjust the TC resource assignment */
2308     if (--prQM->u4TimeToAdjustTcResource == 0){
2309        /* The last assignment has not been completely applied */
2310        if (prQM->fgTcResourcePostAnnealing){
2311             /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */
2312             prQM->u4TimeToAdjustTcResource = 1;
2313        }
2314
2315        /* The last assignment has been applied */
2316        else{
2317             prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC;
2318             qmReassignTcResource(prAdapter);
2319        }
2320     }
2321
2322     /* Debug */
2323 #if QM_PRINT_TC_RESOURCE_CTRL
2324         for (i=0; i<TC_NUM; i++){
2325             if(QM_GET_TX_QUEUE_LEN(prAdapter, i) >= 100){
2326                 DBGLOG(QM, LOUD, ("QM: QueLen [%ld %ld %ld %ld %ld %ld]\n",
2327                     QM_GET_TX_QUEUE_LEN(prAdapter, 0),
2328                     QM_GET_TX_QUEUE_LEN(prAdapter, 1),
2329                     QM_GET_TX_QUEUE_LEN(prAdapter, 2),
2330                     QM_GET_TX_QUEUE_LEN(prAdapter, 3),
2331                     QM_GET_TX_QUEUE_LEN(prAdapter, 4),
2332                     QM_GET_TX_QUEUE_LEN(prAdapter, 5)
2333                     ));
2334                 break;
2335             }
2336         }
2337 #endif
2338
2339 }
2340
2341
2342
2343 /*----------------------------------------------------------------------------*/
2344 /*!
2345 * \brief Assign TX resource for each TC according to TX queue length and current assignment
2346 *
2347 * \param (none)
2348 *
2349 * \return (none)
2350 */
2351 /*----------------------------------------------------------------------------*/
2352 VOID
2353 qmReassignTcResource(
2354     IN P_ADAPTER_T   prAdapter
2355     )
2356 {
2357     INT_32 i4TotalResourceDemand = 0;
2358     UINT_32 u4ResidualResource = 0;
2359     UINT_32 i;
2360     INT_32 ai4PerTcResourceDemand[TC_NUM];
2361     UINT_32 u4ShareCount = 0;
2362     UINT_32 u4Share = 0 ;
2363     P_QUE_MGT_T prQM = &prAdapter->rQM;
2364
2365     /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to
2366     *  start the TC-quota adjusting procedure, which will be invoked upon every TX Done
2367     */
2368
2369     //4 <1> Determine the demands
2370     /* Determine the amount of extra resource to fulfill all of the demands */
2371     for (i=0; i<TC_NUM; i++){
2372         /* Skip TC4, which is not adjustable */
2373         if (i == TC4_INDEX) {
2374             continue;
2375         }
2376
2377         /* Define: extra_demand = que_length + min_reserved_quota - current_quota */
2378         ai4PerTcResourceDemand[i] =
2379             ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + prQM->au4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]);
2380
2381         /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */
2382         if (QM_GET_TX_QUEUE_LEN(prAdapter, i)){
2383             ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY;
2384         }
2385
2386         i4TotalResourceDemand += ai4PerTcResourceDemand[i];
2387     }
2388
2389     //4 <2> Case 1: Demand <= Total Resource
2390     if (i4TotalResourceDemand <= 0){
2391         //4 <2.1> Satisfy every TC
2392         for (i = 0; i < TC_NUM; i++){
2393             /* Skip TC4 (not adjustable) */
2394             if (i == TC4_INDEX) {
2395                 continue;
2396             }
2397
2398             prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i];
2399         }
2400
2401         //4 <2.2> Share the residual resource evenly
2402         u4ShareCount= (TC_NUM - 1); /* excluding TC4 */
2403         u4ResidualResource = (UINT_32)(-i4TotalResourceDemand);
2404         u4Share = (u4ResidualResource/u4ShareCount);
2405
2406         for (i=0; i<TC_NUM; i++){
2407             /* Skip TC4 (not adjustable) */
2408             if (i == TC4_INDEX) {
2409                 continue;
2410             }
2411
2412             prQM->au4CurrentTcResource[i] += u4Share;
2413
2414             /* Every TC is fully satisfied */
2415             ai4PerTcResourceDemand[i] = 0;
2416
2417             /* The left resource will be allocated to TC3 */
2418             u4ResidualResource -= u4Share;
2419         }
2420
2421         //4 <2.3> Allocate the left resource to TC3 (VO)
2422         prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource);
2423
2424     }
2425
2426     //4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC
2427     else{
2428         u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE;
2429
2430         //4 <3.1> Allocated resouce amount  = minimum of (guaranteed, total demand)
2431         for (i=0; i<TC_NUM; i++){
2432             /* Skip TC4 (not adjustable) */
2433             if (i == TC4_INDEX) {
2434                 continue;
2435             }
2436
2437             /* The demand can be fulfilled with the guaranteed resource amount */
2438             if (prQM->au4CurrentTcResource[i] + ai4PerTcResourceDemand[i] < prQM->au4GuaranteedTcResource[i]){
2439                 prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i];
2440                 u4ResidualResource += (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]);
2441                 ai4PerTcResourceDemand[i] = 0;
2442             }
2443
2444             /* The demand can not be fulfilled with the guaranteed resource amount */
2445             else{
2446                 ai4PerTcResourceDemand[i] -= (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]);
2447                 prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i];
2448                 u4ShareCount++;
2449             }
2450         }
2451
2452         //4 <3.2> Allocate the residual resource
2453         do{
2454             /* If there is no resource left, exit directly */
2455             if (u4ResidualResource == 0){
2456                 break;
2457             }
2458
2459             /* This shall not happen */
2460             if  (u4ShareCount == 0){
2461                 prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource;
2462                 DBGLOG(QM, ERROR, ("QM: (Error) u4ShareCount = 0\n"));
2463                 break;
2464             }
2465
2466             /* Share the residual resource evenly */
2467             u4Share = (u4ResidualResource / u4ShareCount);
2468             if(u4Share){
2469                 for (i=0; i<TC_NUM; i++){
2470                     /* Skip TC4 (not adjustable) */
2471                     if (i == TC4_INDEX) {
2472                         continue;
2473                     }
2474
2475                     if (ai4PerTcResourceDemand[i]){
2476                         if (ai4PerTcResourceDemand[i] - u4Share){
2477                             prQM->au4CurrentTcResource[i] += u4Share;
2478                             u4ResidualResource -= u4Share;
2479                             ai4PerTcResourceDemand[i] -= u4Share;
2480                         }
2481                         else{
2482                             prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i];
2483                             u4ResidualResource -= ai4PerTcResourceDemand[i];
2484                             ai4PerTcResourceDemand[i] = 0;
2485                         }
2486                     }
2487                 }
2488             }
2489
2490             /* By priority, allocate the left resource that is not divisible by u4Share */
2491             if (u4ResidualResource == 0){
2492                 break;
2493             }
2494
2495             if (ai4PerTcResourceDemand[TC3_INDEX]){      /* VO */
2496                 prQM->au4CurrentTcResource[TC3_INDEX]++;
2497                 if (--u4ResidualResource == 0) {
2498                     break;
2499                 }
2500             }
2501
2502             if (ai4PerTcResourceDemand[TC2_INDEX]){      /* VI */
2503                 prQM->au4CurrentTcResource[TC2_INDEX]++;
2504                 if (--u4ResidualResource == 0) {
2505                     break;
2506                 }
2507             }
2508
2509             if (ai4PerTcResourceDemand[TC5_INDEX]){      /* BMCAST */
2510                 prQM->au4CurrentTcResource[TC5_INDEX]++;
2511                 if (--u4ResidualResource == 0) {
2512                     break;
2513                 }
2514             }
2515
2516             if (ai4PerTcResourceDemand[TC1_INDEX]){      /* BE */
2517                 prQM->au4CurrentTcResource[TC1_INDEX]++;
2518                 if (--u4ResidualResource == 0) {
2519                     break;
2520                 }
2521             }
2522
2523             if (ai4PerTcResourceDemand[TC0_INDEX]){      /* BK */
2524                 prQM->au4CurrentTcResource[TC0_INDEX]++;
2525                 if (--u4ResidualResource == 0) {
2526                     break;
2527                 }
2528             }
2529
2530             /* Allocate the left resource */
2531             prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource;
2532
2533         }while(FALSE);
2534     }
2535
2536     prQM->fgTcResourcePostAnnealing = TRUE;
2537
2538 #if QM_PRINT_TC_RESOURCE_CTRL
2539     /* Debug print */
2540     DBGLOG(QM, LOUD, ("QM: TC Rsc %ld %ld %ld %ld %ld %ld\n",
2541         prQM->au4CurrentTcResource[0],
2542         prQM->au4CurrentTcResource[1],
2543         prQM->au4CurrentTcResource[2],
2544         prQM->au4CurrentTcResource[3],
2545         prQM->au4CurrentTcResource[4],
2546         prQM->au4CurrentTcResource[5]
2547         ));
2548 #endif
2549
2550 }
2551
2552 #endif
2553
2554
2555 /*----------------------------------------------------------------------------*/
2556 /* RX-Related Queue Management                                                */
2557 /*----------------------------------------------------------------------------*/
2558 /*----------------------------------------------------------------------------*/
2559 /*!
2560 * \brief Init Queue Managment for RX
2561 *
2562 * \param[in] (none)
2563 *
2564 * \return (none)
2565 */
2566 /*----------------------------------------------------------------------------*/
2567 VOID
2568 qmInitRxQueues(
2569     IN P_ADAPTER_T   prAdapter
2570     )
2571 {
2572     //DbgPrint("QM: Enter qmInitRxQueues()\n");
2573     /* TODO */
2574 }
2575
2576 /*----------------------------------------------------------------------------*/
2577 /*!
2578 * \brief Handle RX packets (buffer reordering)
2579 *
2580 * \param[in] prSwRfbListHead The list of RX packets
2581 *
2582 * \return The list of packets which are not buffered for reordering
2583 */
2584 /*----------------------------------------------------------------------------*/
2585 P_SW_RFB_T
2586 qmHandleRxPackets(
2587     IN P_ADAPTER_T   prAdapter,
2588     IN P_SW_RFB_T prSwRfbListHead
2589     )
2590 {
2591
2592 #if CFG_RX_REORDERING_ENABLED
2593     //UINT_32 i;
2594     P_SW_RFB_T          prCurrSwRfb;
2595     P_SW_RFB_T          prNextSwRfb;
2596     P_HIF_RX_HEADER_T   prHifRxHdr;
2597     QUE_T               rReturnedQue;
2598     PUINT_8             pucEthDestAddr;
2599
2600     //DbgPrint("QM: Enter qmHandleRxPackets()\n");
2601
2602     DEBUGFUNC("qmHandleRxPackets");
2603
2604     ASSERT(prSwRfbListHead);
2605
2606     QUEUE_INITIALIZE(&rReturnedQue);
2607     prNextSwRfb = prSwRfbListHead;
2608
2609     do{
2610         prCurrSwRfb = prNextSwRfb;
2611         prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb);
2612
2613         prHifRxHdr = prCurrSwRfb->prHifRxHdr; // TODO: (Tehuang) Use macro to obtain the pointer
2614
2615         /* TODO: (Tehuang) Check if relaying */
2616         prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST;
2617
2618         /* Decide the Destination */
2619 #if CFG_RX_PKTS_DUMP
2620         if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) {
2621             DBGLOG(SW4, INFO, ("QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n",
2622                     HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr),
2623                     prHifRxHdr->ucStaRecIdx,
2624                     prCurrSwRfb->ucWlanIdx,
2625                     HIF_RX_HDR_GET_SN(prHifRxHdr),  /* The new SN of the frame */
2626                     HIF_RX_HDR_GET_TID(prHifRxHdr),
2627                     prCurrSwRfb->ucPacketType,
2628                     HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)));
2629
2630             DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prCurrSwRfb->pvHeader, prCurrSwRfb->u2PacketLen);
2631         }
2632 #endif
2633         // DBGLOG(RX, TRACE, ("SN=%d, TID=%d\n", HIF_RX_HDR_GET_SN(prHifRxHdr), HIF_RX_HDR_GET_TID(prHifRxHdr)));
2634
2635         if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){
2636
2637             UINT_8 ucNetTypeIdx;
2638             P_BSS_INFO_T prBssInfo;
2639
2640             pucEthDestAddr = prCurrSwRfb->pvHeader;
2641             ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr);
2642
2643             prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]);
2644             //DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16);
2645             //
2646
2647             if( prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem
2648                     > (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM)  ) {
2649
2650                 if(IS_BSS_ACTIVE(prBssInfo)) {
2651                     if(OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) {
2652                         if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)){
2653                             prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD;
2654                         }
2655                         else if(UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr,pucEthDestAddr)) {
2656                             prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD;
2657                             /* TODO : need to check the dst mac is valid */
2658                             /* If src mac is invalid, the packet will be freed in fw */
2659                         }
2660                     } /* OP_MODE_ACCESS_POINT */
2661                 }
2662                 else {
2663                     DBGLOG(QM, TRACE, ("Mark NULL the Packet for inactive Bss %u\n",ucNetTypeIdx));
2664                     prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2665                     QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb);
2666                     continue;
2667                 }
2668
2669             }
2670             else {
2671                     /* Dont not occupy other SW RFB */
2672                     DBGLOG(QM, TRACE, ("Mark NULL the Packet for less Free Sw Rfb\n"));
2673                     prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2674                     QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb);
2675                     continue;
2676             }
2677
2678         }
2679
2680         /* BAR frame */
2681         if(HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)){
2682             prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2683             qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue);
2684         }
2685         /* Reordering is not required for this packet, return it without buffering */
2686         else if(!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr)){
2687 #if 0
2688             if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){
2689                 UINT_8 ucNetTypeIdx;
2690                 P_BSS_INFO_T prBssInfo;
2691
2692                 pucEthDestAddr = prCurrSwRfb->pvHeader;
2693                 ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr);
2694
2695                 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]);
2696
2697                 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)){
2698                     prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD;
2699                 }
2700             }
2701 #endif
2702             QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb);
2703         }
2704         /* Reordering is required for this packet */
2705         else{
2706             /* If this packet should dropped or indicated to the host immediately,
2707             *  it should be enqueued into the rReturnedQue with specific flags. If
2708             *  this packet should be buffered for reordering, it should be enqueued
2709             *  into the reordering queue in the STA_REC rather than into the
2710             *  rReturnedQue.
2711             */
2712             qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue);
2713
2714         }
2715     }while(prNextSwRfb);
2716
2717
2718     /* The returned list of SW_RFBs must end with a NULL pointer */
2719     if(QUEUE_IS_NOT_EMPTY(&rReturnedQue)){
2720         QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T)QUEUE_GET_TAIL(&rReturnedQue), NULL);
2721     }
2722
2723     return (P_SW_RFB_T)QUEUE_GET_HEAD(&rReturnedQue);
2724
2725 #else
2726
2727     //DbgPrint("QM: Enter qmHandleRxPackets()\n");
2728     return prSwRfbListHead;
2729
2730 #endif
2731
2732 }
2733
2734 /*----------------------------------------------------------------------------*/
2735 /*!
2736 * \brief Reorder the received packet
2737 *
2738 * \param[in] prSwRfb The RX packet to process
2739 * \param[out] prReturnedQue The queue for indicating packets
2740 *
2741 * \return (none)
2742 */
2743 /*----------------------------------------------------------------------------*/
2744 VOID
2745 qmProcessPktWithReordering(
2746     IN P_ADAPTER_T   prAdapter,
2747     IN P_SW_RFB_T prSwRfb,
2748     OUT P_QUE_T prReturnedQue
2749     )
2750 {
2751
2752
2753     P_STA_RECORD_T prStaRec;
2754     P_HIF_RX_HEADER_T   prHifRxHdr;
2755     P_RX_BA_ENTRY_T prReorderQueParm;
2756
2757     UINT_32 u4SeqNo;
2758     UINT_32 u4WinStart;
2759     UINT_32 u4WinEnd;
2760     P_QUE_T prReorderQue;
2761     //P_SW_RFB_T prReorderedSwRfb;
2762
2763     DEBUGFUNC("qmProcessPktWithReordering");
2764
2765     ASSERT(prSwRfb);
2766     ASSERT(prReturnedQue);
2767     ASSERT(prSwRfb->prHifRxHdr);
2768
2769     prHifRxHdr = prSwRfb->prHifRxHdr;
2770     prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
2771     prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr);  /* The new SN of the frame */
2772     prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr));
2773     //prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
2774
2775     /* Incorrect STA_REC index */
2776     if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
2777         prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2778         QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2779         DBGLOG(QM, WARN,("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
2780             prSwRfb->ucStaRecIdx));
2781         //ASSERT(0);
2782         return;
2783     }
2784
2785     /* Check whether the STA_REC is activated */
2786     prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
2787     ASSERT(prStaRec);
2788
2789 #if 0
2790     if(!(prStaRec->fgIsValid)){
2791         /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2792         prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2793         QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2794         DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC \n"));
2795         //ASSERT(0);
2796         return;
2797     }
2798 #endif
2799
2800     /* Check whether the BA agreement exists */
2801     prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
2802     if(!prReorderQueParm){
2803         /* TODO: (Tehuang) Handle the Host-FW sync issue.*/
2804         prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2805         QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2806         DBGLOG(QM, WARN,("Reordering for a NULL ReorderQueParm \n"));
2807         //ASSERT(0);
2808         return;
2809     }
2810
2811
2812
2813     /* Start to reorder packets */
2814     u4SeqNo = (UINT_32)(prSwRfb->u2SSN);
2815     prReorderQue = &(prReorderQueParm->rReOrderQue);
2816     u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart);
2817     u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd);
2818
2819     /* Debug */
2820     //DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
2821
2822     /* Case 1: Fall within */
2823     if  /* 0 - start - sn - end - 4095 */
2824         (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd))
2825         /* 0 - end - start - sn - 4095 */
2826         || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo))
2827         /* 0 - sn - end - start - 4095 */
2828         || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))){
2829
2830         qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
2831
2832 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2833         if(prReorderQueParm->fgIsWaitingForPktWithSsn){
2834             /* Let the first received packet pass the reorder check */
2835             DBGLOG(QM, LOUD, ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd));
2836
2837             prReorderQueParm->u2WinStart = (UINT_16)u4SeqNo;
2838             prReorderQueParm->u2WinEnd =
2839                 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT;
2840             prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
2841        }
2842 #endif
2843
2844
2845         qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue);
2846     }
2847     /* Case 2: Fall ahead */
2848     else if
2849         /* 0 - start - end - sn - (start+2048) - 4095 */
2850         (((u4WinStart < u4WinEnd)
2851             && (u4WinEnd < u4SeqNo)
2852             && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT)))
2853         /* 0 - sn - (start+2048) - start - end - 4095 */
2854         || ((u4SeqNo < u4WinStart)
2855             && (u4WinStart < u4WinEnd)
2856             && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))
2857         /* 0 - end - sn - (start+2048) - start - 4095 */
2858         || ((u4WinEnd < u4SeqNo)
2859             && (u4SeqNo < u4WinStart)
2860             && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))){
2861
2862
2863 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2864         if(prReorderQueParm->fgIsWaitingForPktWithSsn){
2865             prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
2866         }
2867 #endif
2868
2869         qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
2870
2871         /* Advance the window after inserting a new tail */
2872         prReorderQueParm->u2WinEnd = (UINT_16)u4SeqNo;
2873         prReorderQueParm->u2WinStart =
2874             (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1)
2875             % MAX_SEQ_NO_COUNT);
2876
2877         qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
2878
2879     }
2880     /* Case 3: Fall behind */
2881     else{
2882
2883 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2884     #if QM_RX_INIT_FALL_BEHIND_PASS
2885         if(prReorderQueParm->fgIsWaitingForPktWithSsn){
2886             //?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
2887             QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2888             //DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
2889             return;
2890         }
2891     #endif
2892 #endif
2893
2894         /* An erroneous packet */
2895         prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2896         QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2897         //DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
2898         return;
2899     }
2900
2901     return;
2902
2903 }
2904
2905
2906 VOID
2907 qmProcessBarFrame(
2908     IN P_ADAPTER_T   prAdapter,
2909     IN P_SW_RFB_T prSwRfb,
2910     OUT P_QUE_T prReturnedQue
2911     )
2912 {
2913
2914     P_STA_RECORD_T prStaRec;
2915     P_HIF_RX_HEADER_T   prHifRxHdr;
2916     P_RX_BA_ENTRY_T prReorderQueParm;
2917
2918     UINT_32 u4SSN;
2919     UINT_32 u4WinStart;
2920     UINT_32 u4WinEnd;
2921     P_QUE_T prReorderQue;
2922     //P_SW_RFB_T prReorderedSwRfb;
2923
2924     ASSERT(prSwRfb);
2925     ASSERT(prReturnedQue);
2926     ASSERT(prSwRfb->prHifRxHdr);
2927
2928     prHifRxHdr = prSwRfb->prHifRxHdr;
2929     prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
2930     prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */
2931     prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr));
2932
2933     prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2934     QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
2935
2936     /* Incorrect STA_REC index */
2937     if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
2938         DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
2939             prSwRfb->ucStaRecIdx));
2940         //ASSERT(0);
2941         return;
2942     }
2943
2944     /* Check whether the STA_REC is activated */
2945     prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
2946     ASSERT(prStaRec);
2947
2948 #if 0
2949     if(!(prStaRec->fgIsValid)){
2950         /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2951         DbgPrint("QM: (Warning) BAR for an invalid STA_REC \n");
2952         //ASSERT(0);
2953         return;
2954     }
2955 #endif
2956
2957     /* Check whether the BA agreement exists */
2958     prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
2959     if(!prReorderQueParm){
2960         /* TODO: (Tehuang) Handle the Host-FW sync issue.*/
2961         DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm \n"));
2962         //ASSERT(0);
2963         return;
2964     }
2965
2966
2967     u4SSN = (UINT_32)(prSwRfb->u2SSN);
2968     prReorderQue = &(prReorderQueParm->rReOrderQue);
2969     u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart);
2970     u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd);
2971
2972     if(qmCompareSnIsLessThan(u4WinStart,u4SSN)){
2973         prReorderQueParm->u2WinStart = (UINT_16)u4SSN;
2974         prReorderQueParm->u2WinEnd =
2975             ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT;
2976         DBGLOG(QM, TRACE, ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));        
2977         qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
2978     }
2979     else{
2980         DBGLOG(QM, TRACE, ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd));
2981     }
2982 }
2983
2984
2985
2986 VOID
2987 qmInsertFallWithinReorderPkt(
2988     IN P_SW_RFB_T prSwRfb,
2989     IN P_RX_BA_ENTRY_T prReorderQueParm,
2990     OUT P_QUE_T prReturnedQue
2991     )
2992 {
2993     P_SW_RFB_T prExaminedQueuedSwRfb;
2994     P_QUE_T prReorderQue;
2995     ASSERT(prSwRfb);
2996     ASSERT(prReorderQueParm);
2997     ASSERT(prReturnedQue);
2998
2999     prReorderQue = &(prReorderQueParm->rReOrderQue);
3000     prExaminedQueuedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3001
3002     /* There are no packets queued in the Reorder Queue */
3003     if(prExaminedQueuedSwRfb == NULL){
3004         ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL;
3005         ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3006         prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3007         prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb;
3008         prReorderQue->u4NumElem ++;
3009     }
3010
3011     /* Determine the insert position */
3012     else{
3013         do{
3014             /* Case 1: Terminate. A duplicate packet */
3015             if(((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))){
3016                 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3017                 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3018                 return;
3019             }
3020
3021             /* Case 2: Terminate. The insert point is found */
3022             else if(qmCompareSnIsLessThan(
3023                         (prSwRfb->u2SSN),(prExaminedQueuedSwRfb->u2SSN))){
3024                 break;
3025             }
3026
3027             /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3028             else{
3029                 prExaminedQueuedSwRfb =
3030                     (P_SW_RFB_T)(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prNext);
3031             }
3032         }while(prExaminedQueuedSwRfb);
3033
3034         /* Update the Reorder Queue Parameters according to the found insert position */
3035         if(prExaminedQueuedSwRfb == NULL){
3036             /* The received packet shall be placed at the tail */
3037             ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail;
3038             ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3039             (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb);
3040             prReorderQue->prTail = (P_QUE_ENTRY_T)(prSwRfb);
3041         }
3042         else{
3043             ((P_QUE_ENTRY_T)prSwRfb)->prPrev = ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev;
3044             ((P_QUE_ENTRY_T)prSwRfb)->prNext = (P_QUE_ENTRY_T)prExaminedQueuedSwRfb;
3045             if(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb) == (prReorderQue->prHead)){
3046                 /* The received packet will become the head */
3047                 prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3048             }
3049             else{
3050                 (((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T)prSwRfb;
3051             }
3052             ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T)prSwRfb;
3053         }
3054
3055         prReorderQue->u4NumElem ++;
3056
3057     }
3058
3059 }
3060
3061
3062 VOID
3063 qmInsertFallAheadReorderPkt(
3064     IN P_SW_RFB_T prSwRfb,
3065     IN P_RX_BA_ENTRY_T prReorderQueParm,
3066     OUT P_QUE_T prReturnedQue
3067     )
3068 {
3069     P_QUE_T prReorderQue;
3070     ASSERT(prSwRfb);
3071     ASSERT(prReorderQueParm);
3072     ASSERT(prReturnedQue);
3073
3074     prReorderQue = &(prReorderQueParm->rReOrderQue);
3075
3076     /* There are no packets queued in the Reorder Queue */
3077     if(QUEUE_IS_EMPTY(prReorderQue)){
3078         ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL;
3079         ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3080         prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3081     }
3082     else{
3083         ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail;
3084         ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3085         (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb);
3086     }
3087     prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb;
3088     prReorderQue->u4NumElem ++;
3089
3090 }
3091
3092
3093 VOID
3094 qmPopOutDueToFallWithin(
3095     IN P_RX_BA_ENTRY_T prReorderQueParm,
3096     OUT P_QUE_T prReturnedQue
3097     )
3098 {
3099     P_SW_RFB_T prReorderedSwRfb;
3100     P_QUE_T prReorderQue;
3101     BOOLEAN fgDequeuHead, fgMissing;
3102     OS_SYSTIME rCurrentTime, *prMissTimeout;
3103
3104     prReorderQue = &(prReorderQueParm->rReOrderQue);
3105     fgMissing = FALSE;
3106     rCurrentTime = 0;
3107     prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]);
3108     if (*prMissTimeout) {
3109         fgMissing = TRUE;
3110         GET_CURRENT_SYSTIME(&rCurrentTime);
3111     }
3112
3113     /* Check whether any packet can be indicated to the higher layer */
3114     while(TRUE){
3115         if(QUEUE_IS_EMPTY(prReorderQue)){
3116             break;
3117         }
3118
3119         /* Always examine the head packet */
3120         prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3121         fgDequeuHead = FALSE;
3122
3123         /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3124         if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){
3125
3126             fgDequeuHead = TRUE;
3127             prReorderQueParm->u2WinStart =
3128                 (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT);
3129         }
3130         /* SN > WinStart, break to update WinEnd */
3131         else{
3132            if (TRUE == fgMissing &&
3133                CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout), 
3134                                   //MSEC_TO_SEC(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3135                                   MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3136                 DBGLOG(QM, TRACE, ("RX BA timeout, next tid %d, SSN %d\n", 
3137                         prReorderQueParm->ucTid, prReorderedSwRfb->u2SSN));
3138                 fgDequeuHead = TRUE;
3139                 prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3140                 fgMissing = FALSE;
3141              
3142            }
3143            else {
3144               break;
3145            }
3146         }
3147
3148
3149         /* Dequeue the head packet */
3150         if(fgDequeuHead){
3151
3152             if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){
3153                 prReorderQue->prHead = NULL;
3154                 prReorderQue->prTail = NULL;
3155             }
3156             else{
3157                 prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext;
3158                 (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL;
3159             }
3160             prReorderQue->u4NumElem --;
3161             //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN);
3162             QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb);
3163         }
3164     }
3165
3166     if (QUEUE_IS_EMPTY(prReorderQue)) {
3167          *prMissTimeout = 0;
3168     }
3169     else {
3170         if (FALSE == fgMissing) {
3171            GET_CURRENT_SYSTIME(prMissTimeout);
3172         }
3173     }
3174     /* After WinStart has been determined, update the WinEnd */
3175     prReorderQueParm->u2WinEnd =
3176         (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1 )% MAX_SEQ_NO_COUNT);
3177
3178 }
3179
3180 VOID
3181 qmPopOutDueToFallAhead(
3182     IN P_RX_BA_ENTRY_T prReorderQueParm,
3183     OUT P_QUE_T prReturnedQue
3184     )
3185 {
3186     P_SW_RFB_T prReorderedSwRfb;
3187     P_QUE_T prReorderQue;
3188     BOOLEAN fgDequeuHead;
3189
3190     prReorderQue = &(prReorderQueParm->rReOrderQue);
3191
3192     /* Check whether any packet can be indicated to the higher layer */
3193     while(TRUE){
3194         if(QUEUE_IS_EMPTY(prReorderQue)){
3195             break;
3196         }
3197
3198         /* Always examine the head packet */
3199         prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3200         fgDequeuHead = FALSE;
3201
3202         /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3203         if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){
3204
3205             fgDequeuHead = TRUE;
3206             prReorderQueParm->u2WinStart =
3207                 (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT);
3208         }
3209
3210         /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3211         else if(qmCompareSnIsLessThan(
3212                 (UINT_32)(prReorderedSwRfb->u2SSN),
3213                 (UINT_32)(prReorderQueParm->u2WinStart))){
3214
3215             fgDequeuHead = TRUE;
3216
3217         }
3218
3219         /* SN > WinStart, break to update WinEnd */
3220         else{
3221             break;
3222         }
3223
3224
3225         /* Dequeue the head packet */
3226         if(fgDequeuHead){
3227
3228             if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){
3229                 prReorderQue->prHead = NULL;
3230                 prReorderQue->prTail = NULL;
3231             }
3232             else{
3233                 prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext;
3234                 (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL;
3235             }
3236             prReorderQue->u4NumElem --;
3237             //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN);
3238             QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb);
3239         }
3240     }
3241
3242     /* After WinStart has been determined, update the WinEnd */
3243     prReorderQueParm->u2WinEnd =
3244         (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1)% MAX_SEQ_NO_COUNT);
3245
3246 }
3247
3248 BOOLEAN
3249 qmCompareSnIsLessThan(
3250     IN UINT_32 u4SnLess,
3251     IN UINT_32 u4SnGreater
3252     )
3253 {
3254     /* 0 <--->  SnLess   <--(gap>2048)--> SnGreater : SnLess > SnGreater */
3255     if((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater){ /* Shall be <= */
3256         return FALSE;
3257     }
3258
3259     /* 0 <---> SnGreater <--(gap>2048)--> SnLess    : SnLess < SnGreater */
3260     else if((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess){
3261         return TRUE;
3262     }
3263
3264     /* 0 <---> SnGreater <--(gap<2048)--> SnLess    : SnLess > SnGreater */
3265     /* 0 <--->  SnLess   <--(gap<2048)--> SnGreater : SnLess < SnGreater */
3266     else{
3267         return (u4SnLess < u4SnGreater);
3268     }
3269 }
3270
3271
3272 /*----------------------------------------------------------------------------*/
3273 /*!
3274 * \brief Handle Mailbox RX messages
3275 *
3276 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
3277 *
3278 * \return (none)
3279 */
3280 /*----------------------------------------------------------------------------*/
3281 VOID
3282 qmHandleMailboxRxMessage(
3283         IN MAILBOX_MSG_T prMailboxRxMsg
3284         )
3285 {
3286     //DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n");
3287     /* TODO */
3288 }
3289
3290
3291 /*----------------------------------------------------------------------------*/
3292 /*!
3293 * \brief Handle ADD RX BA Event from the FW
3294 *
3295 * \param[in] prAdapter Adapter pointer
3296 * \param[in] prEvent The event packet from the FW
3297 *
3298 * \return (none)
3299 */
3300 /*----------------------------------------------------------------------------*/
3301 VOID
3302 qmHandleEventRxAddBa(
3303     IN P_ADAPTER_T prAdapter,
3304     IN P_WIFI_EVENT_T prEvent
3305     )
3306 {
3307     P_EVENT_RX_ADDBA_T prEventRxAddBa;
3308     P_STA_RECORD_T prStaRec;
3309     UINT_32 u4Tid;
3310     UINT_32 u4WinSize;
3311
3312     DBGLOG(QM, INFO, ("QM:Event +RxBa\n"));    
3313
3314     prEventRxAddBa = (P_EVENT_RX_ADDBA_T)prEvent;
3315     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx);
3316
3317     if(!prStaRec){
3318         /* Invalid STA_REC index, discard the event packet */
3319         //ASSERT(0);
3320         DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
3321         return;
3322     }
3323
3324 #if 0
3325     if(!(prStaRec->fgIsValid)){
3326         /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3327         DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
3328         //ASSERT(0);
3329         //return;
3330     }
3331 #endif
3332
3333     u4Tid = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_TID_MASK)
3334             >> BA_PARAM_SET_TID_MASK_OFFSET);
3335
3336     u4WinSize = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_BUFFER_SIZE_MASK)
3337             >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
3338
3339     if(!qmAddRxBaEntry(
3340         prAdapter,
3341         prStaRec->ucIndex,
3342         (UINT_8)u4Tid,
3343         (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN),
3344         (UINT_16)u4WinSize)){
3345
3346         /* FW shall ensure the availabiilty of the free-to-use BA entry */
3347         DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n"));
3348         ASSERT(0);
3349     }
3350
3351 }
3352
3353 /*----------------------------------------------------------------------------*/
3354 /*!
3355 * \brief Handle DEL RX BA Event from the FW
3356 *
3357 * \param[in] prAdapter Adapter pointer
3358 * \param[in] prEvent The event packet from the FW
3359 *
3360 * \return (none)
3361 */
3362 /*----------------------------------------------------------------------------*/
3363 VOID
3364 qmHandleEventRxDelBa(
3365     IN P_ADAPTER_T prAdapter,
3366     IN P_WIFI_EVENT_T prEvent
3367     )
3368 {
3369     P_EVENT_RX_DELBA_T prEventRxDelBa;
3370     P_STA_RECORD_T prStaRec;
3371
3372     //DbgPrint("QM:Event -RxBa\n");
3373
3374     prEventRxDelBa = (P_EVENT_RX_DELBA_T)prEvent;
3375     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx);
3376
3377     if(!prStaRec){
3378         /* Invalid STA_REC index, discard the event packet */
3379         //ASSERT(0);
3380         return;
3381     }
3382
3383 #if 0
3384     if(!(prStaRec->fgIsValid)){
3385         /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3386         //ASSERT(0);
3387         return;
3388     }
3389 #endif
3390
3391     qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE);
3392
3393 }
3394
3395 P_RX_BA_ENTRY_T
3396 qmLookupRxBaEntry(
3397     IN P_ADAPTER_T prAdapter,
3398     UINT_8 ucStaRecIdx,
3399     UINT_8 ucTid
3400     )
3401 {
3402     int i;
3403     P_QUE_MGT_T prQM = &prAdapter->rQM;
3404
3405     //DbgPrint("QM: Enter qmLookupRxBaEntry()\n");
3406
3407     for(i=0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
3408         if(prQM->arRxBaTable[i].fgIsValid){
3409             if((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) &&
3410                 (prQM->arRxBaTable[i].ucTid == ucTid)){
3411                 return &prQM->arRxBaTable[i];
3412             }
3413         }
3414     }
3415     return NULL;
3416 }
3417
3418 BOOL
3419 qmAddRxBaEntry(
3420     IN P_ADAPTER_T prAdapter,
3421     IN UINT_8  ucStaRecIdx,
3422     IN UINT_8  ucTid,
3423     IN UINT_16 u2WinStart,
3424     IN UINT_16 u2WinSize
3425     )
3426 {
3427     int i;
3428     P_RX_BA_ENTRY_T prRxBaEntry = NULL;
3429     P_STA_RECORD_T prStaRec;
3430     P_QUE_MGT_T prQM = &prAdapter->rQM;
3431
3432     ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3433
3434     if(ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
3435         /* Invalid STA_REC index, discard the event packet */
3436         DBGLOG(QM, WARN, ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx));
3437         return FALSE;
3438     }
3439
3440     prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3441     ASSERT(prStaRec);
3442
3443     //if(!(prStaRec->fgIsValid)){
3444     //    DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA \n");
3445     //    return FALSE;
3446     //}
3447
3448     //4 <1> Delete before adding
3449     /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3450     if(qmLookupRxBaEntry(prAdapter, ucStaRecIdx,ucTid)){
3451         qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */
3452     }
3453
3454     //4 <2> Add a new BA entry
3455     /* No available entry to store the BA agreement info. Retrun FALSE. */
3456     if(prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS){
3457         DBGLOG(QM, ERROR, ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3458         return FALSE;
3459     }
3460     else{
3461        /* Find the free-to-use BA entry */
3462         for(i=0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
3463             if(!prQM->arRxBaTable[i].fgIsValid){
3464                 prRxBaEntry = &(prQM->arRxBaTable[i]);
3465                 prQM->ucRxBaCount++;
3466                 DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount));
3467                 break;
3468             }
3469         }
3470
3471         /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
3472         u2WinSize += CFG_RX_BA_INC_SIZE;
3473         if(prRxBaEntry){
3474             prRxBaEntry->ucStaRecIdx = ucStaRecIdx;
3475             prRxBaEntry->ucTid = ucTid;
3476             prRxBaEntry->u2WinStart = u2WinStart;
3477             prRxBaEntry->u2WinSize= u2WinSize;
3478             prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT);
3479             prRxBaEntry->fgIsValid = TRUE;
3480             prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE;
3481             
3482             g_arMissTimeout[ucStaRecIdx][ucTid] = 0;
3483
3484             DBGLOG(QM, INFO, ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
3485                 ucStaRecIdx, ucTid,
3486                 prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize));
3487
3488             /* Update the BA entry reference table for per-packet lookup */
3489             prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry;
3490         }
3491         else{
3492             /* This shall not happen because FW should keep track of the usage of RX BA entries */
3493             DBGLOG(QM, ERROR, ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3494             return FALSE;
3495         }
3496     }
3497
3498     return TRUE;
3499 }
3500 VOID
3501 qmDelRxBaEntry(
3502     IN P_ADAPTER_T prAdapter,
3503     IN UINT_8 ucStaRecIdx,
3504     IN UINT_8 ucTid,
3505     IN BOOLEAN fgFlushToHost
3506     )
3507 {
3508     P_RX_BA_ENTRY_T prRxBaEntry;
3509     P_STA_RECORD_T prStaRec;
3510     P_SW_RFB_T prFlushedPacketList = NULL;
3511     P_QUE_MGT_T prQM = &prAdapter->rQM;
3512
3513     ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3514
3515     prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3516     ASSERT(prStaRec);
3517
3518 #if 0
3519     if(!(prStaRec->fgIsValid)){
3520         DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA \n");
3521         return;
3522     }
3523 #endif
3524
3525     /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3526     prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid];
3527
3528     if(prRxBaEntry){
3529
3530         prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid);
3531
3532         if(prFlushedPacketList){
3533
3534             if(fgFlushToHost) {
3535                 wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList);
3536             }
3537             else {
3538
3539                 P_SW_RFB_T prSwRfb;
3540                 P_SW_RFB_T prNextSwRfb;
3541                 prSwRfb =  prFlushedPacketList;
3542
3543                 do {
3544                     prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prSwRfb);
3545                     nicRxReturnRFB(prAdapter, prSwRfb);
3546                     prSwRfb = prNextSwRfb;
3547                 } while(prSwRfb);
3548
3549             }
3550
3551
3552         }
3553 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
3554         /* Update RX BA entry state. Note that RX queue flush is not done here */
3555         prRxBaEntry->fgIsValid = FALSE;
3556         prQM->ucRxBaCount--;
3557
3558                 /* Debug */
3559                 #if 0
3560         DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount);
3561                 #endif
3562
3563         /* Update STA RX BA table */
3564         prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL;
3565 #endif
3566
3567         DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid));
3568
3569     }
3570
3571
3572         /* Debug */
3573         #if CFG_HIF_RX_STARVATION_WARNING
3574     {
3575         P_RX_CTRL_T prRxCtrl;
3576         prRxCtrl = &prAdapter->rRxCtrl;
3577         DBGLOG(QM, TRACE, ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, prRxCtrl->u4DequeuedCnt));
3578     }
3579         #endif
3580 }
3581
3582
3583 /*----------------------------------------------------------------------------*/
3584 /*!
3585 * \brief To process WMM related IEs in ASSOC_RSP
3586 *
3587 * \param[in] prAdapter Adapter pointer
3588 * \param[in] prSwRfb            The received frame
3589 * \param[in] pucIE              The pointer to the first IE in the frame
3590 * \param[in] u2IELength         The total length of IEs in the frame
3591 *
3592 * \return none
3593 */
3594 /*----------------------------------------------------------------------------*/
3595 VOID
3596 mqmProcessAssocReq (
3597     IN P_ADAPTER_T prAdapter,
3598     IN P_SW_RFB_T  prSwRfb,
3599     IN PUINT_8     pucIE,
3600     IN UINT_16     u2IELength
3601     )
3602 {
3603     P_STA_RECORD_T      prStaRec;
3604     UINT_16             u2Offset;
3605     PUINT_8             pucIEStart;
3606     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3607     P_IE_WMM_INFO_T prIeWmmInfo;
3608
3609     DEBUGFUNC("mqmProcessAssocReq");
3610
3611     ASSERT(prSwRfb);
3612     ASSERT(pucIE);
3613
3614     prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3615     ASSERT(prStaRec);
3616
3617     if(prStaRec == NULL) {
3618         return;
3619     }
3620
3621     prStaRec->fgIsQoS = FALSE;
3622     prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
3623
3624     pucIEStart = pucIE;
3625
3626     /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/
3627     if (!prAdapter->rWifiVar.fgSupportQoS) {
3628         return;
3629     }
3630
3631
3632     /* Determine whether QoS is enabled with the association */
3633     else{
3634         IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3635             switch (IE_ID(pucIE)) {
3636             case ELEM_ID_WMM:
3637
3638             if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3639                 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
3640
3641                     switch(WMM_IE_OUI_SUBTYPE(pucIE)){
3642                     case VENDOR_OUI_SUBTYPE_WMM_INFO:
3643                         {
3644
3645                             UINT_8 ucQosInfo;
3646                             UINT_8 ucQosInfoAC;
3647                             UINT_8 ucBmpAC;
3648                         if(IE_LEN(pucIE) != 7){
3649                             break; /* WMM Info IE with a wrong length */
3650                         }
3651                         prStaRec->fgIsQoS = TRUE;
3652                         prStaRec->fgIsWmmSupported = TRUE;
3653
3654                         prIeWmmInfo = (P_IE_WMM_INFO_T)pucIE;
3655                             ucQosInfo = prIeWmmInfo->ucQosInfo;
3656                             ucQosInfoAC = ucQosInfo & BITS(0, 3);
3657
3658                             prStaRec->fgIsUapsdSupported = ((ucQosInfoAC)? TRUE: FALSE) &
3659                                                 prAdapter->rWifiVar.fgSupportUAPSD;
3660
3661                             ucBmpAC = 0;
3662
3663                             if( ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) {
3664                                     ucBmpAC |= BIT(ACI_VO);
3665                             }
3666                             if( ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) {
3667                                     ucBmpAC |= BIT(ACI_VI);
3668                             }
3669                             if( ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) {
3670                                     ucBmpAC |= BIT(ACI_BE);
3671                             }
3672                             if( ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) {
3673                                     ucBmpAC |= BIT(ACI_BK);
3674                             }
3675
3676                             prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC;
3677
3678                             prStaRec->ucUapsdSp = (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5;
3679
3680                         }
3681                         break;
3682
3683                     default:
3684                         /* Other WMM QoS IEs. Ignore any */
3685                         break;
3686                     }
3687                 }
3688                 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3689
3690                 break;
3691
3692             case ELEM_ID_HT_CAP:
3693                 /* Some client won't put the WMM IE if client is 802.11n */
3694                 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
3695                     prStaRec->fgIsQoS = TRUE;
3696                 }
3697                 break;
3698                 default:
3699                 break;
3700             }
3701         }
3702
3703         DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
3704
3705     }
3706 }
3707
3708
3709 /*----------------------------------------------------------------------------*/
3710 /*!
3711 * \brief To process WMM related IEs in ASSOC_RSP
3712 *
3713 * \param[in] prAdapter Adapter pointer
3714 * \param[in] prSwRfb            The received frame
3715 * \param[in] pucIE              The pointer to the first IE in the frame
3716 * \param[in] u2IELength         The total length of IEs in the frame
3717 *
3718 * \return none
3719 */
3720 /*----------------------------------------------------------------------------*/
3721 VOID
3722 mqmProcessAssocRsp (
3723     IN P_ADAPTER_T prAdapter,
3724     IN P_SW_RFB_T  prSwRfb,
3725     IN PUINT_8     pucIE,
3726     IN UINT_16     u2IELength
3727     )
3728 {
3729     P_STA_RECORD_T      prStaRec;
3730     UINT_16             u2Offset;
3731     PUINT_8             pucIEStart;
3732     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3733
3734     DEBUGFUNC("mqmProcessAssocRsp");
3735
3736     ASSERT(prSwRfb);
3737     ASSERT(pucIE);
3738
3739     prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3740     ASSERT(prStaRec);
3741
3742     if(prStaRec == NULL) {
3743         return;
3744     }
3745
3746     prStaRec->fgIsQoS = FALSE;
3747
3748     pucIEStart = pucIE;
3749
3750     DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
3751         prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS));
3752
3753     /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/
3754     //if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported))
3755     if((!prAdapter->rWifiVar.fgSupportQoS))
3756     {
3757         return;
3758     }
3759
3760     /* Determine whether QoS is enabled with the association */
3761     else{
3762         IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3763             switch (IE_ID(pucIE)) {
3764             case ELEM_ID_WMM:
3765                     if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3766                         (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
3767
3768                             switch(WMM_IE_OUI_SUBTYPE(pucIE)){
3769                             case VENDOR_OUI_SUBTYPE_WMM_PARAM:
3770                                 if(IE_LEN(pucIE) != 24){
3771                                     break; /* WMM Info IE with a wrong length */
3772                                 }
3773                                 prStaRec->fgIsQoS = TRUE;
3774                                 break;
3775
3776                             case VENDOR_OUI_SUBTYPE_WMM_INFO:
3777                                 if(IE_LEN(pucIE) != 7){
3778                                     break; /* WMM Info IE with a wrong length */
3779                                 }
3780                                 prStaRec->fgIsQoS = TRUE;
3781                                 break;
3782
3783                             default:
3784                                 /* Other WMM QoS IEs. Ignore any */
3785                                 break;
3786                             }
3787                         }
3788                         /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3789                     break;
3790
3791              case ELEM_ID_HT_CAP:
3792                 /* Some AP won't put the WMM IE if client is 802.11n */ 
3793                 if ( IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
3794                     prStaRec->fgIsQoS = TRUE;
3795                 }
3796                 break;
3797             default:
3798                 break;
3799             }
3800         }
3801
3802         /* Parse AC parameters and write to HW CRs */
3803         if((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)){
3804             mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE);
3805         }
3806
3807         DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
3808         if(prStaRec->fgIsWmmSupported) {
3809             nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex);
3810         }
3811     }
3812 }
3813
3814
3815 /*----------------------------------------------------------------------------*/
3816 /*!
3817 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
3818 *
3819 * \param[in] prAdapter          Adapter pointer
3820 * \param[in] prSwRfb            The received frame
3821 * \param[in] pucIE              The pointer to the first IE in the frame
3822 * \param[in] u2IELength         The total length of IEs in the frame
3823 * \param[in] fgForceOverride    TRUE: If EDCA parameters are found, always set to HW CRs.
3824 *
3825 * \return none
3826 */
3827 /*----------------------------------------------------------------------------*/
3828 VOID
3829 mqmParseEdcaParameters (
3830     IN P_ADAPTER_T prAdapter,
3831     IN P_SW_RFB_T  prSwRfb,
3832     IN PUINT_8     pucIE,
3833     IN UINT_16     u2IELength,
3834     IN BOOLEAN     fgForceOverride
3835     )
3836 {
3837     P_STA_RECORD_T      prStaRec;
3838     UINT_16             u2Offset;
3839     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3840     P_BSS_INFO_T prBssInfo;
3841
3842     DEBUGFUNC("mqmParseEdcaParameters");
3843
3844     ASSERT(prSwRfb);
3845     ASSERT(pucIE);
3846
3847     prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3848     ASSERT(prStaRec);
3849
3850     if(prStaRec == NULL) {
3851         return;
3852     }
3853
3854     DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
3855         prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS));
3856
3857     if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)){
3858         return;
3859     }
3860
3861     prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
3862
3863     /* Goal: Obtain the EDCA parameters */
3864     IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3865         switch (IE_ID(pucIE)) {
3866         case ELEM_ID_WMM:
3867
3868             if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3869                 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
3870
3871                 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
3872                 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
3873                     if(IE_LEN(pucIE) != 24){
3874                         break; /* WMM Param IE with a wrong length */
3875                     }
3876                     else{
3877                         P_AC_QUE_PARMS_T prAcQueParams;
3878                         P_IE_WMM_PARAM_T prIeWmmParam;
3879                         ENUM_WMM_ACI_T eAci;
3880                         PUINT_8 pucWmmParamSetCount;
3881                         //int i;
3882
3883                         pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount);
3884
3885                         prIeWmmParam = (P_IE_WMM_PARAM_T)pucIE;
3886
3887                         /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
3888                         if(!fgForceOverride){
3889                             if(*pucWmmParamSetCount == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)){
3890                                 break; /* Ignore the IE without updating HW CRs */
3891                             }
3892                         }
3893
3894                         /* Update Parameter Set Count */
3895                         *pucWmmParamSetCount = (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT);
3896
3897                         /* Update EDCA parameters */
3898                         for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){
3899
3900                             prAcQueParams = &prBssInfo->arACQueParms[eAci];
3901                             mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams);
3902
3903                             prAcQueParams->fgIsACMSet =
3904                                     (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE;
3905                             prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN;
3906
3907                             DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
3908                                 eAci, prAcQueParams->fgIsACMSet,
3909                                 prAcQueParams->u2Aifsn, prAcQueParams->u2CWmin,
3910                                 prAcQueParams->u2CWmax, prAcQueParams->u2TxopLimit));
3911                             }
3912                     }
3913                     break;
3914
3915                 default:
3916                     /* Other WMM QoS IEs. Ignore */
3917                     break;
3918                 }
3919
3920             }
3921             /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
3922             break;
3923         default:
3924             break;
3925         }
3926     }
3927 }
3928
3929
3930 /*----------------------------------------------------------------------------*/
3931 /*!
3932 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
3933 *
3934 * \param[in] prAdapter           Adapter pointer
3935 * \param[in] prIeWmmParam        The pointer to the WMM Parameter IE
3936 * \param[in] u4AcOffset          The offset specifying the AC queue for parsing
3937 * \param[in] prHwAcParams        The parameter structure used to configure the HW CRs
3938 *
3939 * \return none
3940 */
3941 /*----------------------------------------------------------------------------*/
3942 VOID
3943 mqmFillAcQueParam(
3944     IN  P_IE_WMM_PARAM_T prIeWmmParam,
3945     IN  UINT_32 u4AcOffset,
3946     OUT P_AC_QUE_PARMS_T prAcQueParams
3947     )
3948 {
3949     prAcQueParams->u2Aifsn = *((PUINT_8)(&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4));
3950
3951     prAcQueParams->u2CWmax =
3952         BIT(((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK)
3953         >> WMM_ECW_WMAX_OFFSET)-1;
3954
3955     prAcQueParams->u2CWmin =
3956         BIT((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK)-1;
3957
3958     WLAN_GET_FIELD_16(((PUINT_8)(&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)),&(prAcQueParams->u2TxopLimit));
3959
3960     prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME;
3961
3962
3963 }
3964
3965
3966 /*----------------------------------------------------------------------------*/
3967 /*!
3968 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
3969 *
3970 * \param[in] prAdapter       Adapter pointer
3971 * \param[in]  prScanResult   The scan result which shall be parsed to obtain needed info
3972 * \param[out] prStaRec       The obtained info is stored in the STA_REC
3973 *
3974 * \return none
3975 */
3976 /*----------------------------------------------------------------------------*/
3977 VOID
3978 mqmProcessScanResult(
3979     IN P_ADAPTER_T prAdapter,
3980     IN P_BSS_DESC_T prScanResult,
3981     OUT P_STA_RECORD_T prStaRec
3982     )
3983 {
3984     PUINT_8     pucIE;
3985     UINT_16     u2IELength;
3986     UINT_16     u2Offset;
3987     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3988
3989     DEBUGFUNC("mqmProcessScanResult");
3990
3991     ASSERT(prScanResult);
3992     ASSERT(prStaRec);
3993
3994     /* Reset the flag before parsing */
3995     prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
3996
3997     if (!prAdapter->rWifiVar.fgSupportQoS){
3998         return;
3999     }
4000
4001     u2IELength = prScanResult->u2IELength;
4002     pucIE = prScanResult->aucIEBuf;
4003
4004     /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */
4005     IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4006         switch (IE_ID(pucIE)) {
4007         case ELEM_ID_WMM:
4008             if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4009                 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
4010
4011                 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
4012                 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4013                     if(IE_LEN(pucIE) != 24){
4014                         break; /* WMM Param IE with a wrong length */
4015                     }
4016                     else{
4017                         prStaRec->fgIsWmmSupported = TRUE;
4018                         prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_PARAM_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE);
4019                     }
4020                     break;
4021
4022                 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4023                     if(IE_LEN(pucIE) != 7){
4024                         break; /* WMM Info IE with a wrong length */
4025                     }
4026                     else{
4027                         prStaRec->fgIsWmmSupported = TRUE;
4028                         prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_INFO_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE);
4029                     }
4030                     break;
4031
4032                 default:
4033                     /* A WMM QoS IE that doesn't matter. Ignore it. */
4034                     break;
4035                 }
4036             }
4037             /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4038
4039             break;
4040
4041         default:
4042             /* A WMM IE that doesn't matter. Ignore it. */
4043             break;
4044         }
4045     }
4046     DBGLOG(QM, LOUD, ("MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n",
4047         prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported));
4048
4049 }
4050
4051 UINT_8
4052 qmGetStaRecIdx(
4053     IN P_ADAPTER_T                  prAdapter,
4054     IN PUINT_8                      pucEthDestAddr,
4055     IN ENUM_NETWORK_TYPE_INDEX_T    eNetworkType
4056     )
4057 {
4058     UINT_32 i;
4059     P_STA_RECORD_T prTempStaRec;
4060
4061     prTempStaRec = NULL;
4062
4063     ASSERT(prAdapter);
4064
4065     //4 <1> DA = BMCAST
4066     if(IS_BMCAST_MAC_ADDR(pucEthDestAddr)){
4067         return STA_REC_INDEX_BMCAST;
4068     }
4069
4070
4071     //4 <2> Check if an AP STA is present
4072     for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
4073         prTempStaRec = &(prAdapter->arStaRec[i]);
4074         if((prTempStaRec->ucNetTypeIndex == eNetworkType)
4075                 && (prTempStaRec->fgIsAp)
4076                 && (prTempStaRec->fgIsValid)){
4077             return prTempStaRec->ucIndex;
4078         }
4079     }
4080
4081     //4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client)
4082     for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
4083         prTempStaRec = &(prAdapter->arStaRec[i]);
4084         if(prTempStaRec->fgIsValid){
4085             if(EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)){
4086                 return prTempStaRec->ucIndex;
4087             }
4088         }
4089     }
4090
4091
4092     //4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW
4093     return STA_REC_INDEX_NOT_FOUND;
4094 }
4095
4096
4097 /*----------------------------------------------------------------------------*/
4098 /*!
4099 * @brief Generate the WMM Info IE
4100 *
4101 * \param[in] prAdapter  Adapter pointer
4102 * @param prMsduInfo The TX MMPDU
4103 *
4104 * @return (none)
4105 */
4106 /*----------------------------------------------------------------------------*/
4107 VOID
4108 mqmGenerateWmmInfoIE (
4109     IN P_ADAPTER_T          prAdapter,
4110     IN P_MSDU_INFO_T        prMsduInfo
4111     )
4112 {
4113     P_IE_WMM_INFO_T prIeWmmInfo;
4114     UINT_32 ucUapsd[] = {
4115         WMM_QOS_INFO_BE_UAPSD,
4116         WMM_QOS_INFO_BK_UAPSD,
4117         WMM_QOS_INFO_VI_UAPSD,
4118         WMM_QOS_INFO_VO_UAPSD
4119     };
4120     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4121
4122     P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo;
4123     P_BSS_INFO_T prBssInfo;
4124     P_STA_RECORD_T prStaRec;
4125
4126     DEBUGFUNC("mqmGenerateWmmInfoIE");
4127
4128     ASSERT(prMsduInfo);
4129
4130     /* In case QoS is not turned off, exit directly */
4131     if(!prAdapter->rWifiVar.fgSupportQoS){
4132         return;
4133     }
4134
4135     prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4136     ASSERT(prStaRec);
4137
4138     if(prStaRec == NULL) {
4139         return;
4140     }
4141
4142     if(!prStaRec->fgIsWmmSupported) {
4143         return;
4144     }
4145
4146     prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
4147
4148     prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
4149
4150     prIeWmmInfo = (P_IE_WMM_INFO_T)
4151             ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4152
4153     prIeWmmInfo->ucId = ELEM_ID_WMM;
4154     prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4155
4156     /* WMM-2.2.1 WMM Information Element Field Values */
4157     prIeWmmInfo->aucOui[0] = aucWfaOui[0];
4158     prIeWmmInfo->aucOui[1] = aucWfaOui[1];
4159     prIeWmmInfo->aucOui[2] = aucWfaOui[2];
4160     prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
4161     prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
4162
4163     prIeWmmInfo->ucVersion = VERSION_WMM;
4164     prIeWmmInfo->ucQosInfo = 0;
4165
4166     /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4167 //    if(prAdapter->rWifiVar.fgSupportUAPSD){
4168     if(prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported){
4169
4170         UINT_8 ucQosInfo = 0;
4171         UINT_8 i;
4172
4173
4174         /* Static U-APSD setting */
4175         for(i = ACI_BE; i <= ACI_VO; i++){
4176             if (prPmProfSetupInfo->ucBmpDeliveryAC &  prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)){
4177                 ucQosInfo |= (UINT_8)ucUapsd[i];
4178             }
4179         }
4180
4181
4182         if (prPmProfSetupInfo->ucBmpDeliveryAC &  prPmProfSetupInfo->ucBmpTriggerAC) {
4183             switch (prPmProfSetupInfo->ucUapsdSp) {
4184            case WMM_MAX_SP_LENGTH_ALL:
4185                ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
4186                break;
4187
4188            case WMM_MAX_SP_LENGTH_2:
4189                ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4190                break;
4191
4192            case WMM_MAX_SP_LENGTH_4:
4193                ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
4194                break;
4195
4196            case WMM_MAX_SP_LENGTH_6:
4197                ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
4198                break;
4199
4200            default:
4201             DBGLOG(QM, INFO, ("MQM: Incorrect SP length \n"));
4202                ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4203                break;
4204            }
4205         }
4206         prIeWmmInfo->ucQosInfo = ucQosInfo;
4207
4208     }
4209
4210     /* Increment the total IE length for the Element ID and Length fields. */
4211     prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo);
4212
4213 }
4214
4215
4216 #if 0
4217 /*----------------------------------------------------------------------------*/
4218 /*!
4219 * @brief log2 calculation for CW
4220 *
4221 * @param[in] val value
4222 *
4223 * @return log2(val)
4224 */
4225 /*----------------------------------------------------------------------------*/
4226
4227 UINT_32 cwlog2(UINT_32 val) {
4228
4229      UINT_32 n;
4230      n=0;
4231
4232      while (val >= 512) {  n+= 9; val = val >> 9; }
4233      while (val >= 16) { n+= 4; val >>= 4; }
4234      while (val >= 2) { n+= 1; val >>= 1; }
4235      return n;
4236 }
4237 #endif
4238
4239
4240 /*----------------------------------------------------------------------------*/
4241 /*!
4242 * @brief Generate the WMM Param IE
4243 *
4244 * \param[in] prAdapter  Adapter pointer
4245 * @param prMsduInfo The TX MMPDU
4246 *
4247 * @return (none)
4248 */
4249 /*----------------------------------------------------------------------------*/
4250 VOID
4251 mqmGenerateWmmParamIE (
4252     IN P_ADAPTER_T          prAdapter,
4253     IN P_MSDU_INFO_T        prMsduInfo
4254     )
4255 {
4256     P_IE_WMM_PARAM_T prIeWmmParam;
4257
4258     UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4259
4260     UINT_8 aucACI[] = {
4261         WMM_ACI_AC_BE,
4262         WMM_ACI_AC_BK,
4263         WMM_ACI_AC_VI,
4264         WMM_ACI_AC_VO
4265     };
4266
4267     P_BSS_INFO_T prBssInfo;
4268     P_STA_RECORD_T prStaRec;
4269     ENUM_WMM_ACI_T eAci;
4270
4271     DEBUGFUNC("mqmGenerateWmmParamIE");
4272     DBGLOG(QM, LOUD,("\n"));
4273
4274     ASSERT(prMsduInfo);
4275
4276     /* In case QoS is not turned off, exit directly */
4277     if(!prAdapter->rWifiVar.fgSupportQoS){
4278         return;
4279     }
4280
4281     prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4282
4283     if(prStaRec) {
4284         if(!prStaRec->fgIsQoS) {
4285             return;
4286         }
4287     }
4288
4289     prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]);
4290
4291     if(!prBssInfo->fgIsQBSS) { return; }
4292
4293 #if 0  // 20120220 frog: update beacon content & change OP mode is a separate event for P2P network.
4294     if( prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT &&
4295          prBssInfo->eCurrentOPMode != OP_MODE_BOW)
4296     {
4297         return;
4298     }
4299 #endif
4300
4301     prIeWmmParam = (P_IE_WMM_PARAM_T)
4302             ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4303
4304     prIeWmmParam->ucId = ELEM_ID_WMM;
4305     prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
4306
4307     /* WMM-2.2.1 WMM Information Element Field Values */
4308     prIeWmmParam->aucOui[0] = aucWfaOui[0];
4309     prIeWmmParam->aucOui[1] = aucWfaOui[1];
4310     prIeWmmParam->aucOui[2] = aucWfaOui[2];
4311     prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
4312     prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
4313
4314     prIeWmmParam->ucVersion = VERSION_WMM;
4315     prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
4316
4317     /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4318     if(prAdapter->rWifiVar.fgSupportUAPSD){
4319
4320         prIeWmmParam->ucQosInfo |=  WMM_QOS_INFO_UAPSD;
4321
4322     }
4323
4324     /* EDCA parameter */
4325
4326     for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){
4327
4328         //DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
4329         //           eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ,
4330         //           prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn,
4331         //           prBssInfo->arACQueParmsForBcast[eAci].u2CWmin,
4332         //           prBssInfo->arACQueParmsForBcast[eAci].u2CWmax,
4333         //           prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit));
4334
4335        *( ((PUINT_8)(&prIeWmmParam->ucAciAifsn_BE)) + (eAci <<2) ) = (UINT_8) (aucACI[eAci]
4336                                    | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM:0 )
4337                                    | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN)));
4338 #if 1
4339         *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4340                         | (((prBssInfo->aucCWminLog2ForBcast[eAci] )) & WMM_ECW_WMIN_MASK)
4341                         | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci] )) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4342                         );
4343 #else
4344        *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4345                         | (cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmin + 1)) & WMM_ECW_WMIN_MASK)
4346                         | ((cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmax + 1)) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4347                         );
4348 #endif
4349
4350        WLAN_SET_FIELD_16( ((PUINT_8)(prIeWmmParam->aucTxopLimit_BE)) + (eAci<<2)
4351                         , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
4352
4353     }
4354
4355     /* Increment the total IE length for the Element ID and Length fields. */
4356     prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam);
4357
4358 }
4359
4360
4361
4362
4363 ENUM_FRAME_ACTION_T
4364 qmGetFrameAction(
4365     IN P_ADAPTER_T                  prAdapter,
4366     IN ENUM_NETWORK_TYPE_INDEX_T    eNetworkType,
4367     IN UINT_8                       ucStaRecIdx,
4368     IN P_MSDU_INFO_T                prMsduInfo,
4369     IN ENUM_FRAME_TYPE_IN_CMD_Q_T   eFrameType
4370 )
4371 {
4372     P_BSS_INFO_T   prBssInfo;
4373     P_STA_RECORD_T prStaRec;
4374     P_WLAN_MAC_HEADER_T prWlanFrame;
4375     UINT_16        u2TxFrameCtrl;
4376
4377     DEBUGFUNC("qmGetFrameAction");
4378
4379 #if (NIC_TX_BUFF_COUNT_TC4 > 2)
4380 #define QM_MGMT_QUUEUD_THRESHOLD 2
4381 #else
4382 #define QM_MGMT_QUUEUD_THRESHOLD 1
4383 #endif
4384
4385     DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4));
4386     DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD  > 0);
4387
4388     prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]);
4389     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx);
4390
4391     /* XXX Check BOW P2P AIS time ot set active */
4392     if (!IS_BSS_ACTIVE(prBssInfo)) {
4393         if (eFrameType == FRAME_TYPE_MMPDU) {
4394             prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4395             u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM
4396             if ((u2TxFrameCtrl == MAC_FRAME_DEAUTH) && (prMsduInfo->pfTxDoneHandler == NULL)) {
4397                 return FRAME_ACTION_TX_PKT;
4398             }
4399
4400         }
4401
4402         DBGLOG(QM, INFO, ("Drop packets Action (Inactive %u).\n",prBssInfo->ucNetTypeIndex));
4403         TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP);
4404         return FRAME_ACTION_DROP_PKT;
4405     }
4406
4407     /* TODO Handle disconnect issue */
4408
4409     /* P2P probe Request frame */
4410     do {
4411         if(eFrameType == FRAME_TYPE_MMPDU) {
4412              ASSERT(prMsduInfo!=NULL);
4413              prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4414              u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM
4415
4416              if (u2TxFrameCtrl == MAC_FRAME_BEACON ) {
4417                  if( prBssInfo->fgIsNetAbsent) {
4418                      return FRAME_ACTION_DROP_PKT;
4419                  }
4420              }
4421              else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) {
4422                  if( prBssInfo->fgIsNetAbsent) {
4423                      break;
4424                  }
4425             }
4426             else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) {
4427                 if( prBssInfo->fgIsNetAbsent) {
4428                     break;
4429                 }
4430                 DBGLOG(P2P, LOUD, ("Sending DEAUTH Frame\n"));
4431                 return FRAME_ACTION_TX_PKT;
4432             }
4433             /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */
4434             else if(u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ
4435                      || u2TxFrameCtrl == MAC_FRAME_AUTH
4436                      || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ
4437                      || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ
4438                      || u2TxFrameCtrl == MAC_FRAME_ACTION) {
4439
4440                 if(prStaRec){
4441                     if(prStaRec->fgIsInPS) {
4442                        if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) {
4443                             return FRAME_ACTION_TX_PKT;
4444                        }
4445                        else {
4446                             return FRAME_ACTION_QUEUE_PKT;
4447                         }
4448                     }
4449                 }
4450                 return FRAME_ACTION_TX_PKT;
4451              }
4452
4453             if (!prStaRec){
4454                 return FRAME_ACTION_TX_PKT;
4455             }
4456              else {
4457                 if (!prStaRec->fgIsInUse) {
4458                     return FRAME_ACTION_DROP_PKT;
4459                 }
4460             }
4461
4462         } /* FRAME_TYPE_MMPDU */
4463         else if ((eFrameType == FRAME_TYPE_802_1X)){
4464
4465             if (!prStaRec){
4466                 return FRAME_ACTION_TX_PKT;
4467             }
4468             else {
4469                 if (!prStaRec->fgIsInUse) {
4470                     return FRAME_ACTION_DROP_PKT;
4471                 }
4472                 if(prStaRec->fgIsInPS) {
4473                    if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) {
4474                         return FRAME_ACTION_TX_PKT;
4475                    }
4476                    else {
4477                         return FRAME_ACTION_QUEUE_PKT;
4478                     }
4479                 }
4480             }
4481
4482         } /* FRAME_TYPE_802_1X */
4483         else if ((!IS_BSS_ACTIVE(prBssInfo))
4484                 || (!prStaRec)
4485                 || (!prStaRec->fgIsInUse)){
4486             return FRAME_ACTION_DROP_PKT;
4487         }
4488     }while(0);
4489
4490     if (prBssInfo->fgIsNetAbsent){
4491         DBGLOG(QM, LOUD, ("Queue packets (Absent %u).\n",prBssInfo->ucNetTypeIndex));
4492         return FRAME_ACTION_QUEUE_PKT;
4493     }
4494
4495     if (prStaRec && prStaRec->fgIsInPS){
4496         DBGLOG(QM, LOUD, ("Queue packets (PS %u).\n",prStaRec->fgIsInPS));
4497         return FRAME_ACTION_QUEUE_PKT;
4498     }
4499     else {
4500         switch (eFrameType){
4501             case FRAME_TYPE_802_1X:
4502                 if (!prStaRec->fgIsValid){
4503                     return FRAME_ACTION_QUEUE_PKT;
4504                 }
4505                 break;
4506
4507             case FRAME_TYPE_MMPDU:
4508                 break;
4509
4510             default:
4511                 ASSERT(0);
4512         }
4513     }
4514
4515     return FRAME_ACTION_TX_PKT;
4516 }
4517
4518
4519 /*----------------------------------------------------------------------------*/
4520 /*!
4521 * \brief Handle BSS change operation Event from the FW
4522 *
4523 * \param[in] prAdapter Adapter pointer
4524 * \param[in] prEvent The event packet from the FW
4525 *
4526 * \return (none)
4527 */
4528 /*----------------------------------------------------------------------------*/
4529 VOID
4530 qmHandleEventBssAbsencePresence(
4531     IN P_ADAPTER_T prAdapter,
4532     IN P_WIFI_EVENT_T prEvent
4533     )
4534 {
4535     P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus;
4536     P_BSS_INFO_T prBssInfo;
4537     BOOLEAN fgIsNetAbsentOld;
4538
4539     prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T)prEvent;
4540     prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]);
4541     fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent;
4542     prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent;
4543     prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota;
4544
4545     //DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n",
4546     //    prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota));
4547
4548     DBGLOG(QM, TRACE, ("NAF=%d,%d,%d\n",
4549         prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota));
4550
4551     if(!prBssInfo->fgIsNetAbsent) {
4552           QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_27);
4553     }
4554     else {
4555           QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_28);
4556     }
4557     /* From Absent to Present */
4558     if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)){
4559         kalSetEvent(prAdapter->prGlueInfo);
4560     }
4561 }
4562
4563
4564 /*----------------------------------------------------------------------------*/
4565 /*!
4566 * \brief Handle STA change PS mode Event from the FW
4567 *
4568 * \param[in] prAdapter Adapter pointer
4569 * \param[in] prEvent The event packet from the FW
4570 *
4571 * \return (none)
4572 */
4573 /*----------------------------------------------------------------------------*/
4574 VOID
4575 qmHandleEventStaChangePsMode(
4576     IN P_ADAPTER_T prAdapter,
4577     IN P_WIFI_EVENT_T prEvent
4578     )
4579 {
4580     P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode;
4581     P_STA_RECORD_T prStaRec;
4582     BOOLEAN fgIsInPSOld;
4583
4584     //DbgPrint("QM:Event -RxBa\n");
4585
4586     prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T)prEvent;
4587     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx);
4588     ASSERT(prStaRec);
4589
4590     if(prStaRec) {
4591
4592         fgIsInPSOld = prStaRec->fgIsInPS;
4593         prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs;
4594
4595         qmUpdateFreeQuota(
4596                     prAdapter,
4597                     prStaRec,
4598                      prEventStaChangePsMode->ucUpdateMode,
4599                      prEventStaChangePsMode->ucFreeQuota);
4600
4601         //DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n",
4602         //    prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
4603
4604
4605         //DBGLOG(QM, TRACE, ("PS=%d,%d\n",
4606         //    prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
4607
4608         /* From PS to Awake */
4609         if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)){
4610             kalSetEvent(prAdapter->prGlueInfo);
4611         }
4612     }
4613 }
4614
4615 /*----------------------------------------------------------------------------*/
4616 /*!
4617 * \brief Update STA free quota Event from FW
4618 *
4619 * \param[in] prAdapter Adapter pointer
4620 * \param[in] prEvent The event packet from the FW
4621 *
4622 * \return (none)
4623 */
4624 /*----------------------------------------------------------------------------*/
4625 VOID
4626 qmHandleEventStaUpdateFreeQuota(
4627     IN P_ADAPTER_T prAdapter,
4628     IN P_WIFI_EVENT_T prEvent
4629     )
4630 {
4631     P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota;
4632     P_STA_RECORD_T prStaRec;
4633
4634
4635     prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T)prEvent;
4636     prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx);
4637     ASSERT(prStaRec);
4638
4639     if(prStaRec) {
4640         if(prStaRec->fgIsInPS) {
4641             qmUpdateFreeQuota(
4642                     prAdapter,
4643                     prStaRec,
4644                      prEventStaUpdateFreeQuota->ucUpdateMode,
4645                      prEventStaUpdateFreeQuota->ucFreeQuota);
4646
4647             kalSetEvent(prAdapter->prGlueInfo);
4648         }
4649 #if 0
4650         DBGLOG(QM, TRACE, ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
4651             prEventStaUpdateFreeQuota->ucStaRecIdx,
4652             prEventStaUpdateFreeQuota->ucUpdateMode,
4653             prEventStaUpdateFreeQuota->ucFreeQuota));
4654 #endif
4655
4656         DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n",
4657             prEventStaUpdateFreeQuota->ucStaRecIdx,
4658             prEventStaUpdateFreeQuota->ucUpdateMode,
4659             prEventStaUpdateFreeQuota->ucFreeQuota));
4660
4661
4662     }
4663
4664 }
4665
4666
4667 /*----------------------------------------------------------------------------*/
4668 /*!
4669 * \brief Update STA free quota
4670 *
4671 * \param[in] prStaRec the STA
4672 * \param[in] ucUpdateMode the method to update free quota
4673 * \param[in] ucFreeQuota  the value for update
4674 *
4675 * \return (none)
4676 */
4677 /*----------------------------------------------------------------------------*/
4678 VOID
4679 qmUpdateFreeQuota(
4680     IN P_ADAPTER_T prAdapter,
4681     IN P_STA_RECORD_T prStaRec,
4682     IN UINT_8 ucUpdateMode,
4683     IN UINT_8 ucFreeQuota
4684     )
4685 {
4686
4687     UINT_8 ucFreeQuotaForNonDelivery;
4688     UINT_8 ucFreeQuotaForDelivery;
4689
4690     ASSERT(prStaRec);
4691     DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
4692         prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota ));
4693
4694     if(!prStaRec->fgIsInPS)return;
4695
4696     switch (ucUpdateMode) {
4697         case FREE_QUOTA_UPDATE_MODE_INIT:
4698         case FREE_QUOTA_UPDATE_MODE_OVERWRITE:
4699                 prStaRec->ucFreeQuota = ucFreeQuota;
4700                 break;
4701         case FREE_QUOTA_UPDATE_MODE_INCREASE:
4702                 prStaRec->ucFreeQuota += ucFreeQuota;
4703                 break;
4704         case FREE_QUOTA_UPDATE_MODE_DECREASE:
4705                 prStaRec->ucFreeQuota -= ucFreeQuota;
4706                 break;
4707         default:
4708             ASSERT(0);
4709     }
4710
4711     DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n",
4712         prStaRec->ucFreeQuota ));
4713
4714     ucFreeQuota = prStaRec->ucFreeQuota;
4715
4716     ucFreeQuotaForNonDelivery = 0;
4717     ucFreeQuotaForDelivery = 0;
4718
4719     if(ucFreeQuota > 0) {
4720         if( prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
4721                /* && prAdapter->rWifiVar.fgSupportQoS
4722                 && prAdapter->rWifiVar.fgSupportUAPSD*/) {
4723         /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]  */
4724
4725             if(prStaRec->ucFreeQuotaForNonDelivery > 0  && prStaRec->ucFreeQuotaForDelivery > 0) {
4726                 ucFreeQuotaForNonDelivery = ucFreeQuota>>1;
4727                 ucFreeQuotaForDelivery =  ucFreeQuota - ucFreeQuotaForNonDelivery;
4728             }
4729             else if(prStaRec->ucFreeQuotaForNonDelivery == 0  && prStaRec->ucFreeQuotaForDelivery == 0) {
4730                   ucFreeQuotaForNonDelivery =  ucFreeQuota>>1;
4731                   ucFreeQuotaForDelivery =  ucFreeQuota - ucFreeQuotaForNonDelivery;
4732             }
4733             else if(prStaRec->ucFreeQuotaForNonDelivery > 0) {
4734                 /* NonDelivery is not busy */
4735                 if(ucFreeQuota >= 3  ) {
4736                     ucFreeQuotaForNonDelivery = 2;
4737                     ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery ;
4738                 }
4739                 else {
4740                     ucFreeQuotaForDelivery = ucFreeQuota;
4741                     ucFreeQuotaForNonDelivery = 0;
4742                 }
4743             }
4744             else if(prStaRec->ucFreeQuotaForDelivery > 0) {
4745                 /* Delivery is not busy */
4746                 if(ucFreeQuota >= 3 ) {
4747                     ucFreeQuotaForDelivery = 2;
4748                     ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery;
4749                 }
4750                 else {
4751                     ucFreeQuotaForNonDelivery = ucFreeQuota;
4752                     ucFreeQuotaForDelivery = 0;
4753                 }
4754             }
4755
4756         }
4757         else {
4758             /* !prStaRec->fgIsUapsdSupported */
4759             ucFreeQuotaForNonDelivery = ucFreeQuota;
4760             ucFreeQuotaForDelivery = 0;
4761         }
4762     } /* ucFreeQuota > 0 */
4763
4764     prStaRec->ucFreeQuotaForDelivery =  ucFreeQuotaForDelivery;
4765     prStaRec->ucFreeQuotaForNonDelivery =  ucFreeQuotaForNonDelivery;
4766
4767     DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d  QuotaForNonDelivery = %d\n",
4768         prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery ));
4769
4770 }
4771
4772 /*----------------------------------------------------------------------------*/
4773 /*!
4774 * \brief Return the reorder queued RX packets
4775 *
4776 * \param[in] (none)
4777 *
4778 * \return The number of queued RX packets
4779 */
4780 /*----------------------------------------------------------------------------*/
4781 UINT_32
4782 qmGetRxReorderQueuedBufferCount(
4783         IN P_ADAPTER_T  prAdapter
4784         )
4785 {
4786     UINT_32 i, u4Total;
4787     P_QUE_MGT_T prQM = &prAdapter->rQM;
4788     u4Total = 0;
4789     /* XXX The summation may impact the performance */
4790     for(i =0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
4791         u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem;
4792 #if DBG && 0
4793         if(QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))){
4794             ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0);
4795         }
4796 #endif
4797     }
4798     ASSERT(u4Total <=( CFG_NUM_OF_QM_RX_PKT_NUM*2));
4799    return u4Total;
4800 }
4801
4802