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