2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 $
6 \brief TX/RX queues management
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.
20 * Sync CFG80211 modification from branch 2,2.
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.
26 * 11 22 2011 yuche.tsai
28 * Code refine, remove one #if 0 code.
30 * 11 19 2011 eddie.chen
31 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
34 * 11 18 2011 yuche.tsai
36 * CONFIG P2P support RSSI query, default turned off.
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
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.
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.
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.
54 * 11 10 2011 eddie.chen
55 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
56 * Use short name for xlog.
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.
62 * 11 10 2011 chinglan.wang
64 * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP.
66 * 11 09 2011 chinglan.wang
68 * [WiFi direct]Can't make P2P connect via PBC.
70 * 11 08 2011 eddie.chen
71 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
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.
78 * 11 01 2011 chinglan.wang
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..
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.
87 * 09 28 2011 tsaiyuan.hsu
88 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
89 * enlarge window size only by 4.
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.
95 * 08 23 2011 yuche.tsai
97 * Fix multicast address list issue.
99 * 08 03 2011 tsaiyuan.hsu
100 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
101 * force window size at least 16.
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.
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.
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.
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.
119 * 05 31 2011 eddie.chen
120 * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931
121 * Fix the QM quota in MT5931.
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.
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.
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.
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..
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
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.
149 * 04 08 2011 eddie.chen
150 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
153 * 03 28 2011 eddie.chen
154 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
155 * Fix Klockwork warning.
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.
161 * 03 15 2011 eddie.chen
162 * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter
163 * Add sw debug counter for QM.
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.
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
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
178 * 01 27 2011 tsaiyuan.hsu
179 * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support
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.
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.
190 * 01 24 2011 eddie.chen
191 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
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.
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.
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.
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
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
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
222 * 01 11 2011 eddie.chen
223 * [WCXRP00000322] Add WMM IE in beacon,
224 Add per station flow control when STA is in PS
226 * Add per STA flow control when STA is in PS mode
228 * 01 03 2011 george.huang
229 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
230 * update prStaRec->fgIsUapsdSupported flag.
232 * 12 29 2010 eddie.chen
233 * [WCXRP00000322] Add WMM IE in beacon,
234 Add per station flow control when STA is in PS
236 * Add WMM parameter for broadcast.
238 * 12 29 2010 eddie.chen
239 * [WCXRP00000322] Add WMM IE in beacon,
240 Add per station flow control when STA is in PS
242 * 1) PS flow control event
244 * 2) WMM IE in beacon, assoc resp, probe resp
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
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.
256 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
257 * only MMPDU not check the netActive flag.
260 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
261 * not check the netActive flag for mgmt .
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
267 * 09 21 2010 kevin.huang
268 * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
269 * Eliminate Linux Compile Warning
271 * 08 30 2010 yarco.yang
273 * Fixed klockwork error message
275 * 08 18 2010 yarco.yang
277 * 1. Fixed HW checksum offload function not work under Linux issue.
278 * 2. Add debug message.
280 * 08 10 2010 yarco.yang
284 * 08 06 2010 yarco.yang
286 * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action
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
293 * 07 20 2010 yarco.yang
295 * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake
297 * 07 16 2010 yarco.yang
299 * 1. Support BSS Absence/Presence Event
300 * 2. Support STA change PS mode Event
301 * 3. Support BMC forwarding for AP mode.
303 * 07 14 2010 yarco.yang
305 * 1. Remove CFG_MQM_MIGRATION
306 * 2. Add CMD_UPDATE_WMM_PARMS command
308 * 07 13 2010 yarco.yang
311 * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing
313 * 07 09 2010 yarco.yang
315 * [MT6620 and MT5931] SW Migration: Add ADDBA support
319 * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
321 * 07 08 2010 yarco.yang
322 * [WPD00003837][MT6620]Data Path Refine
325 * 07 06 2010 yarco.yang
326 * [WPD00003837][MT6620]Data Path Refine
327 * Use fgInUse instead of fgIsValid for De-queue judgement
329 * 07 06 2010 yarco.yang
330 * [WPD00003837][MT6620]Data Path Refine
331 * For MMPDU, STA_REC will be decided by caller module
333 * 07 06 2010 yarco.yang
334 * [WPD00003837][MT6620]Data Path Refine
335 * Add MGMT Packet type for HIF_TX_HEADER
337 * 06 29 2010 yarco.yang
338 * [WPD00003837][MT6620]Data Path Refine
339 * replace g_rQM with Adpater->rQM
342 * [WPD00003833][MT6620 and MT5931] Driver migration
343 * add API in que_mgt to retrieve sta-rec index for security frames.
345 * 06 23 2010 yarco.yang
346 * [WPD00003837][MT6620]Data Path Refine
347 * Merge g_arStaRec[] into adapter->arStaRec[]
349 * 06 21 2010 yarco.yang
350 * [WPD00003837][MT6620]Data Path Refine
351 * Support CFG_MQM_MIGRATION flag
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
361 * 06 06 2010 kevin.huang
362 * [WPD00003832][MT6620 5931] Create driver base
363 * [MT6620 5931] Create driver base
365 * 03 31 2010 tehuang.liu
366 * [WPD00001943]Create WiFi test driver framework on WinXP
367 * Refined the debug msg
370 * [WPD00001943]Create WiFi test driver framework on WinXP
371 * comment out one assertion which refer to undefined data member.
373 * 03 30 2010 tehuang.liu
374 * [WPD00001943]Create WiFi test driver framework on WinXP
375 * Enabled adaptive TC resource control
377 * 03 24 2010 jeffrey.chang
378 * [WPD00003826]Initial import for Linux port
379 * initial import for Linux port
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)
385 * 03 11 2010 tehuang.liu
386 * [WPD00001943]Create WiFi test driver framework on WinXP
387 * Fixed buffer leak when processing BAR frames
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
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)
397 * 02 25 2010 tehuang.liu
398 * [WPD00001943]Create WiFi test driver framework on WinXP
399 * Refined function qmDetermineStaRecIndex() for BMCAST packets
401 * 02 25 2010 tehuang.liu
402 * [WPD00001943]Create WiFi test driver framework on WinXP
403 * Enabled multi-STA TX path with fairness
405 * 02 24 2010 tehuang.liu
406 * [WPD00001943]Create WiFi test driver framework on WinXP
407 * Enabled dynamically activating and deactivating STA_RECs
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.
413 * 01 13 2010 tehuang.liu
414 * [WPD00001943]Create WiFi test driver framework on WinXP
415 * Enabled the 802.1x path
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
443 /*******************************************************************************
444 * C O M P I L E R F L A G S
445 ********************************************************************************
448 /*******************************************************************************
449 * E X T E R N A L R E F E R E N C E S
450 ********************************************************************************
454 /*******************************************************************************
456 ********************************************************************************
459 /*******************************************************************************
461 ********************************************************************************
464 /*******************************************************************************
465 * P U B L I C D A T A
466 ********************************************************************************
468 OS_SYSTIME g_arMissTimeout
[CFG_STA_REC_NUM
][CFG_RX_MAX_BA_TID_NUM
];
470 /*******************************************************************************
471 * P R I V A T E D A T A
472 ********************************************************************************
476 /*******************************************************************************
478 ********************************************************************************
481 /*******************************************************************************
482 * F U N C T I O N D E C L A R A T I O N S
483 ********************************************************************************
485 __KAL_INLINE__ VOID
qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
);
488 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter
,
491 IN UINT_8 ucCurrentAvailableQuota
, IN UINT_8 ucTotalQuota
);
494 qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter
,
495 OUT P_QUE_T prQue
, IN UINT_8 ucTC
, IN UINT_8 ucMaxNum
);
497 /*******************************************************************************
499 ********************************************************************************
502 /*----------------------------------------------------------------------------*/
504 * \brief Init Queue Managment for TX
510 /*----------------------------------------------------------------------------*/
511 VOID
qmInit(IN P_ADAPTER_T prAdapter
)
513 UINT_32 u4QueArrayIdx
;
516 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
518 /* DbgPrint("QM: Enter qmInit()\n"); */
520 prAdapter
->rWifiVar
.fgSupportQoS
= TRUE
;
522 prAdapter
->rWifiVar
.fgSupportQoS
= FALSE
;
525 #if CFG_SUPPORT_AMPDU_RX
526 prAdapter
->rWifiVar
.fgSupportAmpduRx
= TRUE
;
528 prAdapter
->rWifiVar
.fgSupportAmpduRx
= FALSE
;
531 #if CFG_SUPPORT_AMPDU_TX
532 prAdapter
->rWifiVar
.fgSupportAmpduTx
= TRUE
;
534 prAdapter
->rWifiVar
.fgSupportAmpduTx
= FALSE
;
537 #if CFG_SUPPORT_TSPEC
538 prAdapter
->rWifiVar
.fgSupportTspec
= TRUE
;
540 prAdapter
->rWifiVar
.fgSupportTspec
= FALSE
;
543 #if CFG_SUPPORT_UAPSD
544 prAdapter
->rWifiVar
.fgSupportUAPSD
= TRUE
;
546 prAdapter
->rWifiVar
.fgSupportUAPSD
= FALSE
;
549 #if CFG_SUPPORT_UL_PSMP
550 prAdapter
->rWifiVar
.fgSupportULPSMP
= TRUE
;
552 prAdapter
->rWifiVar
.fgSupportULPSMP
= FALSE
;
555 /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */
556 for (u4QueArrayIdx
= 0; u4QueArrayIdx
< NUM_OF_PER_TYPE_TX_QUEUES
; u4QueArrayIdx
++) {
557 QUEUE_INITIALIZE(&(prQM
->arTxQueue
[u4QueArrayIdx
]));
560 /* 4 <3> Initialize the RX BA table and RX queues */
561 /* Initialize the RX Reordering Parameters and Queues */
562 for (u4QueArrayIdx
= 0; u4QueArrayIdx
< CFG_NUM_OF_RX_BA_AGREEMENTS
; u4QueArrayIdx
++) {
563 prQM
->arRxBaTable
[u4QueArrayIdx
].fgIsValid
= FALSE
;
564 QUEUE_INITIALIZE(&(prQM
->arRxBaTable
[u4QueArrayIdx
].rReOrderQue
));
565 prQM
->arRxBaTable
[u4QueArrayIdx
].u2WinStart
= 0xFFFF;
566 prQM
->arRxBaTable
[u4QueArrayIdx
].u2WinEnd
= 0xFFFF;
568 prQM
->arRxBaTable
[u4QueArrayIdx
].fgIsWaitingForPktWithSsn
= FALSE
;
571 prQM
->ucRxBaCount
= 0;
573 kalMemSet(&g_arMissTimeout
, 0, sizeof(g_arMissTimeout
));
575 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
576 /* 4 <4> Initialize TC resource control variables */
577 for (i
= 0; i
< TC_NUM
; i
++) {
578 prQM
->au4AverageQueLen
[i
] = 0;
580 prQM
->u4TimeToAdjustTcResource
= QM_INIT_TIME_TO_ADJUST_TC_RSC
;
581 prQM
->u4TimeToUpdateQueLen
= QM_INIT_TIME_TO_UPDATE_QUE_LEN
;
583 /* ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); */
585 prQM
->au4CurrentTcResource
[TC0_INDEX
] = NIC_TX_BUFF_COUNT_TC0
;
586 prQM
->au4CurrentTcResource
[TC1_INDEX
] = NIC_TX_BUFF_COUNT_TC1
;
587 prQM
->au4CurrentTcResource
[TC2_INDEX
] = NIC_TX_BUFF_COUNT_TC2
;
588 prQM
->au4CurrentTcResource
[TC3_INDEX
] = NIC_TX_BUFF_COUNT_TC3
;
589 prQM
->au4CurrentTcResource
[TC4_INDEX
] = NIC_TX_BUFF_COUNT_TC4
; /* Not adjustable (TX port 1) */
590 prQM
->au4CurrentTcResource
[TC5_INDEX
] = NIC_TX_BUFF_COUNT_TC5
;
592 prQM
->au4MinReservedTcResource
[TC0_INDEX
] = QM_MIN_RESERVED_TC0_RESOURCE
;
593 prQM
->au4MinReservedTcResource
[TC1_INDEX
] = QM_MIN_RESERVED_TC1_RESOURCE
;
594 prQM
->au4MinReservedTcResource
[TC2_INDEX
] = QM_MIN_RESERVED_TC2_RESOURCE
;
595 prQM
->au4MinReservedTcResource
[TC3_INDEX
] = QM_MIN_RESERVED_TC3_RESOURCE
;
596 prQM
->au4MinReservedTcResource
[TC4_INDEX
] = QM_MIN_RESERVED_TC4_RESOURCE
; /* Not adjustable (TX port 1) */
597 prQM
->au4MinReservedTcResource
[TC5_INDEX
] = QM_MIN_RESERVED_TC5_RESOURCE
;
600 prQM
->au4GuaranteedTcResource
[TC0_INDEX
] = QM_GUARANTEED_TC0_RESOURCE
;
601 prQM
->au4GuaranteedTcResource
[TC1_INDEX
] = QM_GUARANTEED_TC1_RESOURCE
;
602 prQM
->au4GuaranteedTcResource
[TC2_INDEX
] = QM_GUARANTEED_TC2_RESOURCE
;
603 prQM
->au4GuaranteedTcResource
[TC3_INDEX
] = QM_GUARANTEED_TC3_RESOURCE
;
604 prQM
->au4GuaranteedTcResource
[TC4_INDEX
] = QM_GUARANTEED_TC4_RESOURCE
;
605 prQM
->au4GuaranteedTcResource
[TC5_INDEX
] = QM_GUARANTEED_TC5_RESOURCE
;
607 prQM
->fgTcResourcePostAnnealing
= FALSE
;
609 ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE
< 64);
613 prQM
->u4PktCount
= 0;
615 #if QM_TEST_FAIR_FORWARDING
617 prQM
->u4CurrentStaRecIndexToEnqueue
= 0;
619 UINT_8 aucMacAddr
[MAC_ADDR_LEN
];
620 P_STA_RECORD_T prStaRec
;
622 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
623 aucMacAddr
[0] = 0x11;
624 aucMacAddr
[1] = 0x22;
625 aucMacAddr
[2] = 0xAA;
626 aucMacAddr
[3] = 0xBB;
627 aucMacAddr
[4] = 0xCC;
628 aucMacAddr
[5] = 0xDD;
630 prStaRec
= &prAdapter
->arStaRec
[1];
633 prStaRec
->fgIsValid
= TRUE
;
634 prStaRec
->fgIsQoS
= TRUE
;
635 prStaRec
->fgIsInPS
= FALSE
;
636 prStaRec
->ucPsSessionID
= 0xFF;
637 prStaRec
->ucNetTypeIndex
= NETWORK_TYPE_AIS_INDEX
;
638 prStaRec
->fgIsAp
= TRUE
;
639 COPY_MAC_ADDR((prStaRec
)->aucMacAddr
, aucMacAddr
);
647 #if QM_FORWARDING_FAIRNESS
650 for (i
= 0; i
< NUM_OF_PER_STA_TX_QUEUES
; i
++) {
651 prQM
->au4ForwardCount
[i
] = 0;
652 prQM
->au4HeadStaRecIndex
[i
] = 0;
660 VOID
qmTestCases(IN P_ADAPTER_T prAdapter
)
662 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
664 DbgPrint("QM: ** TEST MODE **\n");
666 if (QM_TEST_STA_REC_DETERMINATION
) {
667 if (prAdapter
->arStaRec
[0].fgIsValid
) {
668 prAdapter
->arStaRec
[0].fgIsValid
= FALSE
;
669 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
671 prAdapter
->arStaRec
[0].fgIsValid
= TRUE
;
672 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
676 if (QM_TEST_STA_REC_DEACTIVATION
) {
677 /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */
679 if (prAdapter
->arStaRec
[0].fgIsValid
) {
681 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
682 qmDeactivateStaRec(prAdapter
, 0);
685 UINT_8 aucMacAddr
[MAC_ADDR_LEN
];
687 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
688 aucMacAddr
[0] = 0x11;
689 aucMacAddr
[1] = 0x22;
690 aucMacAddr
[2] = 0xAA;
691 aucMacAddr
[3] = 0xBB;
692 aucMacAddr
[4] = 0xCC;
693 aucMacAddr
[5] = 0xDD;
695 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
696 qmActivateStaRec(prAdapter
, /* Adapter pointer */
697 0, /* STA_REC index from FW */
699 NETWORK_TYPE_AIS_INDEX
, /* Network type */
701 aucMacAddr
/* MAC address */
706 if (QM_TEST_FAIR_FORWARDING
) {
707 if (prAdapter
->arStaRec
[1].fgIsValid
) {
708 prQM
->u4CurrentStaRecIndexToEnqueue
++;
709 prQM
->u4CurrentStaRecIndexToEnqueue
%= 2;
710 DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n",
711 prQM
->u4CurrentStaRecIndexToEnqueue
);
718 /*----------------------------------------------------------------------------*/
720 * \brief Activate a STA_REC
722 * \param[in] prAdapter Pointer to the Adapter instance
723 * \param[in] u4StaRecIdx The index of the STA_REC
724 * \param[in] fgIsQoS Set to TRUE if this is a QoS STA
725 * \param[in] pucMacAddr The MAC address of the STA
729 /*----------------------------------------------------------------------------*/
730 VOID
qmActivateStaRec(IN P_ADAPTER_T prAdapter
, IN P_STA_RECORD_T prStaRec
)
733 /* 4 <1> Deactivate first */
736 if (prStaRec
->fgIsValid
) { /* The STA_REC has been activated */
738 ("QM: (WARNING) Activating a STA_REC which has been activated\n"));
739 DBGLOG(QM
, WARN
, ("QM: (WARNING) Deactivating a STA_REC before re-activating\n"));
740 qmDeactivateStaRec(prAdapter
, prStaRec
->ucIndex
); /* To flush TX/RX queues and del RX BA agreements */
742 /* 4 <2> Activate the STA_REC */
743 /* Init the STA_REC */
744 prStaRec
->fgIsValid
= TRUE
;
745 prStaRec
->fgIsInPS
= FALSE
;
746 prStaRec
->ucPsSessionID
= 0xFF;
747 prStaRec
->fgIsAp
= (IS_AP_STA(prStaRec
)) ? TRUE
: FALSE
;
749 /* Done in qmInit() or qmDeactivateStaRec() */
751 /* At the beginning, no RX BA agreements have been established */
752 for (i
= 0; i
< CFG_RX_MAX_BA_TID_NUM
; i
++) {
753 (prStaRec
->aprRxReorderParamRefTbl
)[i
] = NULL
;
757 DBGLOG(QM
, INFO
, ("QM: +STA[%ld]\n", prStaRec
->ucIndex
));
760 /*----------------------------------------------------------------------------*/
762 * \brief Deactivate a STA_REC
764 * \param[in] prAdapter Pointer to the Adapter instance
765 * \param[in] u4StaRecIdx The index of the STA_REC
769 /*----------------------------------------------------------------------------*/
770 VOID
qmDeactivateStaRec(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StaRecIdx
)
772 P_STA_RECORD_T prStaRec
;
774 P_MSDU_INFO_T prFlushedTxPacketList
= NULL
;
776 ASSERT(u4StaRecIdx
< CFG_NUM_OF_STA_RECORD
);
778 prStaRec
= &prAdapter
->arStaRec
[u4StaRecIdx
];
781 /* 4<1> Flush TX queues */
782 prFlushedTxPacketList
= qmFlushStaTxQueues(prAdapter
, u4StaRecIdx
);
784 if (prFlushedTxPacketList
) {
785 wlanProcessQueuedMsduInfo(prAdapter
, prFlushedTxPacketList
);
787 /* 4 <2> Flush RX queues and delete RX BA agreements */
788 for (i
= 0; i
< CFG_RX_MAX_BA_TID_NUM
; i
++) {
789 /* Delete the RX BA entry with TID = i */
790 qmDelRxBaEntry(prAdapter
, (UINT_8
) u4StaRecIdx
, (UINT_8
) i
, FALSE
);
793 /* 4 <3> Deactivate the STA_REC */
794 prStaRec
->fgIsValid
= FALSE
;
795 prStaRec
->fgIsInPS
= FALSE
;
797 DBGLOG(QM
, INFO
, ("QM: -STA[%ld]\n", u4StaRecIdx
));
801 /*----------------------------------------------------------------------------*/
803 * \brief Deactivate a STA_REC
805 * \param[in] prAdapter Pointer to the Adapter instance
806 * \param[in] u4StaRecIdx The index of the network
810 /*----------------------------------------------------------------------------*/
812 VOID
qmFreeAllByNetType(IN P_ADAPTER_T prAdapter
, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx
)
817 QUE_T rNeedToFreeQue
;
819 P_QUE_T prNeedToFreeQue
;
821 P_MSDU_INFO_T prMsduInfo
;
824 prQM
= &prAdapter
->rQM
;
825 prQue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
827 QUEUE_INITIALIZE(&rNeedToFreeQue
);
828 QUEUE_INITIALIZE(&rTempQue
);
830 prNeedToFreeQue
= &rNeedToFreeQue
;
831 prTempQue
= &rTempQue
;
833 QUEUE_MOVE_ALL(prTempQue
, prQue
);
835 QUEUE_REMOVE_HEAD(prTempQue
, prMsduInfo
, P_MSDU_INFO_T
);
838 if (prMsduInfo
->ucNetworkType
== eNetworkTypeIdx
) {
839 QUEUE_INSERT_TAIL(prNeedToFreeQue
, (P_QUE_ENTRY_T
) prMsduInfo
);
841 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prMsduInfo
);
844 QUEUE_REMOVE_HEAD(prTempQue
, prMsduInfo
, P_MSDU_INFO_T
);
846 if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue
)) {
847 wlanProcessQueuedMsduInfo(prAdapter
,
848 (P_MSDU_INFO_T
) QUEUE_GET_HEAD(prNeedToFreeQue
));
853 /*----------------------------------------------------------------------------*/
855 * \brief Flush all TX queues
859 * \return The flushed packets (in a list of MSDU_INFOs)
861 /*----------------------------------------------------------------------------*/
862 P_MSDU_INFO_T
qmFlushTxQueues(IN P_ADAPTER_T prAdapter
)
864 UINT_8 ucStaArrayIdx
;
865 UINT_8 ucQueArrayIdx
;
867 P_MSDU_INFO_T prMsduInfoListHead
;
868 P_MSDU_INFO_T prMsduInfoListTail
;
870 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
872 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushTxQueues()\n"));
874 prMsduInfoListHead
= NULL
;
875 prMsduInfoListTail
= NULL
;
877 /* Concatenate all MSDU_INFOs in per-STA queues */
878 for (ucStaArrayIdx
= 0; ucStaArrayIdx
< CFG_NUM_OF_STA_RECORD
; ucStaArrayIdx
++) {
880 /* Always check each STA_REC when flushing packets no matter it is inactive or active */
882 if (!prAdapter
->arStaRec
[ucStaArrayIdx
].fgIsValid
) {
883 continue; /* Continue to check the next STA_REC */
887 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_STA_TX_QUEUES
; ucQueArrayIdx
++) {
889 (&(prAdapter
->arStaRec
[ucStaArrayIdx
].arTxQueue
[ucQueArrayIdx
]))) {
890 continue; /* Continue to check the next TX queue of the same STA */
893 if (!prMsduInfoListHead
) {
895 /* The first MSDU_INFO is found */
896 prMsduInfoListHead
= (P_MSDU_INFO_T
)
897 QUEUE_GET_HEAD(&prAdapter
->arStaRec
[ucStaArrayIdx
].
898 arTxQueue
[ucQueArrayIdx
]);
899 prMsduInfoListTail
= (P_MSDU_INFO_T
)
900 QUEUE_GET_TAIL(&prAdapter
->arStaRec
[ucStaArrayIdx
].
901 arTxQueue
[ucQueArrayIdx
]);
903 /* Concatenate the MSDU_INFO list with the existing list */
904 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
905 QUEUE_GET_HEAD(&prAdapter
->
906 arStaRec
[ucStaArrayIdx
].
907 arTxQueue
[ucQueArrayIdx
]));
909 prMsduInfoListTail
= (P_MSDU_INFO_T
)
910 QUEUE_GET_TAIL(&prAdapter
->arStaRec
[ucStaArrayIdx
].
911 arTxQueue
[ucQueArrayIdx
]);
914 QUEUE_INITIALIZE(&prAdapter
->arStaRec
[ucStaArrayIdx
].
915 arTxQueue
[ucQueArrayIdx
]);
919 /* Flush per-Type queues */
920 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_TYPE_TX_QUEUES
; ucQueArrayIdx
++) {
922 if (QUEUE_IS_EMPTY(&(prQM
->arTxQueue
[ucQueArrayIdx
]))) {
923 continue; /* Continue to check the next TX queue of the same STA */
926 if (!prMsduInfoListHead
) {
928 /* The first MSDU_INFO is found */
929 prMsduInfoListHead
= (P_MSDU_INFO_T
)
930 QUEUE_GET_HEAD(&prQM
->arTxQueue
[ucQueArrayIdx
]);
931 prMsduInfoListTail
= (P_MSDU_INFO_T
)
932 QUEUE_GET_TAIL(&prQM
->arTxQueue
[ucQueArrayIdx
]);
934 /* Concatenate the MSDU_INFO list with the existing list */
935 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
936 QUEUE_GET_HEAD(&prQM
->arTxQueue
[ucQueArrayIdx
]));
938 prMsduInfoListTail
= (P_MSDU_INFO_T
)
939 QUEUE_GET_TAIL(&prQM
->arTxQueue
[ucQueArrayIdx
]);
942 QUEUE_INITIALIZE(&prQM
->arTxQueue
[ucQueArrayIdx
]);
946 if (prMsduInfoListTail
) {
947 /* Terminate the MSDU_INFO list with a NULL pointer */
948 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
, NULL
);
951 return prMsduInfoListHead
;
955 /*----------------------------------------------------------------------------*/
957 * \brief Flush TX packets for a particular STA
959 * \param[in] u4StaRecIdx STA_REC index
961 * \return The flushed packets (in a list of MSDU_INFOs)
963 /*----------------------------------------------------------------------------*/
964 P_MSDU_INFO_T
qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StaRecIdx
)
966 UINT_8 ucQueArrayIdx
;
967 P_MSDU_INFO_T prMsduInfoListHead
;
968 P_MSDU_INFO_T prMsduInfoListTail
;
969 P_STA_RECORD_T prStaRec
;
971 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx
));
973 ASSERT(u4StaRecIdx
< CFG_NUM_OF_STA_RECORD
);
975 prMsduInfoListHead
= NULL
;
976 prMsduInfoListTail
= NULL
;
978 prStaRec
= &prAdapter
->arStaRec
[u4StaRecIdx
];
981 /* No matter whether this is an activated STA_REC, do flush */
983 if (!prStaRec
->fgIsValid
) {
988 /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */
989 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_STA_TX_QUEUES
; ucQueArrayIdx
++) {
990 if (QUEUE_IS_EMPTY(&(prStaRec
->arTxQueue
[ucQueArrayIdx
]))) {
994 if (!prMsduInfoListHead
) {
995 /* The first MSDU_INFO is found */
996 prMsduInfoListHead
= (P_MSDU_INFO_T
)
997 QUEUE_GET_HEAD(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
998 prMsduInfoListTail
= (P_MSDU_INFO_T
)
999 QUEUE_GET_TAIL(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1001 /* Concatenate the MSDU_INFO list with the existing list */
1002 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1003 QUEUE_GET_HEAD(&prStaRec
->
1004 arTxQueue
[ucQueArrayIdx
]));
1006 prMsduInfoListTail
=
1007 (P_MSDU_INFO_T
) QUEUE_GET_TAIL(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1010 QUEUE_INITIALIZE(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1015 if (prMsduInfoListTail
) {
1016 /* Terminate the MSDU_INFO list with a NULL pointer */
1017 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1018 nicGetPendingStaMMPDU(prAdapter
, (UINT_8
) u4StaRecIdx
));
1020 prMsduInfoListHead
= nicGetPendingStaMMPDU(prAdapter
, (UINT_8
) u4StaRecIdx
);
1024 return prMsduInfoListHead
;
1028 /*----------------------------------------------------------------------------*/
1030 * \brief Flush RX packets
1034 * \return The flushed packets (in a list of SW_RFBs)
1036 /*----------------------------------------------------------------------------*/
1037 P_SW_RFB_T
qmFlushRxQueues(IN P_ADAPTER_T prAdapter
)
1040 P_SW_RFB_T prSwRfbListHead
;
1041 P_SW_RFB_T prSwRfbListTail
;
1042 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1044 prSwRfbListHead
= prSwRfbListTail
= NULL
;
1046 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushRxQueues()\n"));
1048 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
1049 if (QUEUE_IS_NOT_EMPTY(&(prQM
->arRxBaTable
[i
].rReOrderQue
))) {
1050 if (!prSwRfbListHead
) {
1052 /* The first MSDU_INFO is found */
1053 prSwRfbListHead
= (P_SW_RFB_T
)
1054 QUEUE_GET_HEAD(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1055 prSwRfbListTail
= (P_SW_RFB_T
)
1056 QUEUE_GET_TAIL(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1058 /* Concatenate the MSDU_INFO list with the existing list */
1059 QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail
,
1061 (prQM
->arRxBaTable
[i
].
1064 prSwRfbListTail
= (P_SW_RFB_T
)
1065 QUEUE_GET_TAIL(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1068 QUEUE_INITIALIZE(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1075 if (prSwRfbListTail
) {
1076 /* Terminate the MSDU_INFO list with a NULL pointer */
1077 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail
, NULL
);
1079 return prSwRfbListHead
;
1084 /*----------------------------------------------------------------------------*/
1086 * \brief Flush RX packets with respect to a particular STA
1088 * \param[in] u4StaRecIdx STA_REC index
1089 * \param[in] u4Tid TID
1091 * \return The flushed packets (in a list of SW_RFBs)
1093 /*----------------------------------------------------------------------------*/
1094 P_SW_RFB_T
qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StaRecIdx
, IN UINT_32 u4Tid
)
1097 P_SW_RFB_T prSwRfbListHead
;
1098 P_SW_RFB_T prSwRfbListTail
;
1099 P_RX_BA_ENTRY_T prReorderQueParm
;
1100 P_STA_RECORD_T prStaRec
;
1102 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx
));
1104 prSwRfbListHead
= prSwRfbListTail
= NULL
;
1106 prStaRec
= &prAdapter
->arStaRec
[u4StaRecIdx
];
1109 /* No matter whether this is an activated STA_REC, do flush */
1111 if (!prStaRec
->fgIsValid
) {
1116 /* Obtain the RX BA Entry pointer */
1117 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[u4Tid
]);
1119 /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */
1120 if (prReorderQueParm
) {
1122 if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm
->rReOrderQue
))) {
1124 prSwRfbListHead
= (P_SW_RFB_T
)
1125 QUEUE_GET_HEAD(&(prReorderQueParm
->rReOrderQue
));
1126 prSwRfbListTail
= (P_SW_RFB_T
)
1127 QUEUE_GET_TAIL(&(prReorderQueParm
->rReOrderQue
));
1130 QUEUE_INITIALIZE(&(prReorderQueParm
->rReOrderQue
));
1135 if (prSwRfbListTail
) {
1136 /* Terminate the MSDU_INFO list with a NULL pointer */
1137 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail
, NULL
);
1139 return prSwRfbListHead
;
1145 /*----------------------------------------------------------------------------*/
1147 * \brief Enqueue TX packets
1149 * \param[in] prMsduInfoListHead Pointer to the list of TX packets
1151 * \return The freed packets, which are not enqueued
1153 /*----------------------------------------------------------------------------*/
1154 P_MSDU_INFO_T
qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfoListHead
)
1156 P_MSDU_INFO_T prMsduInfoReleaseList
;
1157 P_MSDU_INFO_T prCurrentMsduInfo
;
1158 P_MSDU_INFO_T prNextMsduInfo
;
1160 P_STA_RECORD_T prStaRec
;
1162 QUE_T rNotEnqueuedQue
;
1165 UINT_8 ucPacketType
;
1167 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1168 UINT_8 aucNextUP
[WMM_AC_INDEX_NUM
] =
1169 { 1 /* BEtoBK */ , 1 /*na */ , 0 /*VItoBE */ , 4 /*VOtoVI */ };
1171 DBGLOG(QM
, LOUD
, ("Enter qmEnqueueTxPackets\n"));
1173 ASSERT(prMsduInfoListHead
);
1175 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
1178 /* 4 <0> Update TC resource control related variables */
1179 /* Keep track of the queue length */
1180 if (--prQM
->u4TimeToUpdateQueLen
== 0) {
1181 prQM
->u4TimeToUpdateQueLen
= QM_INIT_TIME_TO_UPDATE_QUE_LEN
;
1182 qmUpdateAverageTxQueLen(prAdapter
);
1187 /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */
1189 prMsduInfoReleaseList
= NULL
;
1190 prCurrentMsduInfo
= NULL
;
1191 QUEUE_INITIALIZE(&rNotEnqueuedQue
);
1192 prNextMsduInfo
= prMsduInfoListHead
;
1195 P_BSS_INFO_T prBssInfo
;
1196 BOOLEAN fgCheckACMAgain
;
1197 ENUM_WMM_ACI_T eAci
= WMM_AC_BE_INDEX
;
1198 prCurrentMsduInfo
= prNextMsduInfo
;
1199 prNextMsduInfo
= QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo
);
1202 /* 4 <1> Lookup the STA_REC index */
1203 /* The ucStaRecIndex will be set in this function */
1204 qmDetermineStaRecIndex(prAdapter
, prCurrentMsduInfo
);
1205 ucPacketType
= HIF_TX_PACKET_TYPE_DATA
;
1207 DBGLOG(QM
, LOUD
, ("***** ucStaRecIndex = %d *****\n",
1208 prCurrentMsduInfo
->ucStaRecIndex
));
1211 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prCurrentMsduInfo
->ucNetworkType
]);
1213 if (IS_NET_ACTIVE(prAdapter
, prCurrentMsduInfo
->ucNetworkType
)) {
1215 switch (prCurrentMsduInfo
->ucStaRecIndex
) {
1216 case STA_REC_INDEX_BMCAST
:
1217 prTxQue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
1220 if (prCurrentMsduInfo
->ucNetworkType
== NETWORK_TYPE_P2P_INDEX
1221 && prCurrentMsduInfo
->eSrc
!= TX_PACKET_MGMT
) {
1223 (&prAdapter
->rWifiVar
.arBssInfo
[NETWORK_TYPE_P2P_INDEX
].
1224 rStaRecOfClientList
)) {
1225 prTxQue
= &rNotEnqueuedQue
;
1226 TX_INC_CNT(&prAdapter
->rTxCtrl
,
1227 TX_AP_BORADCAST_DROP
);
1232 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_23
);
1235 case STA_REC_INDEX_NOT_FOUND
:
1238 if (prCurrentMsduInfo
->eSrc
== TX_PACKET_FORWARDING
) {
1240 /* if the packet is the forward type. the packet should be freed */
1242 ("Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"));
1243 /* prTxQue = &rNotEnqueuedQue; */
1245 prTxQue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_NO_STA_REC
];
1246 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_24
);
1252 QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
,
1253 prCurrentMsduInfo
->ucStaRecIndex
);
1256 ASSERT(prStaRec
->fgIsValid
);
1258 if (prCurrentMsduInfo
->ucUserPriority
< 8) {
1259 QM_DBG_CNT_INC(prQM
,
1260 prCurrentMsduInfo
->ucUserPriority
+ 15);
1261 /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */
1262 /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */
1265 eAci
= WMM_AC_BE_INDEX
;
1267 fgCheckACMAgain
= FALSE
;
1268 if (prStaRec
->fgIsQoS
) {
1269 switch (prCurrentMsduInfo
->ucUserPriority
) {
1274 arTxQueue
[TX_QUEUE_INDEX_AC0
];
1276 eAci
= WMM_AC_BK_INDEX
;
1282 arTxQueue
[TX_QUEUE_INDEX_AC1
];
1284 eAci
= WMM_AC_BE_INDEX
;
1290 arTxQueue
[TX_QUEUE_INDEX_AC2
];
1292 eAci
= WMM_AC_VI_INDEX
;
1298 arTxQueue
[TX_QUEUE_INDEX_AC3
];
1300 eAci
= WMM_AC_VO_INDEX
;
1305 arTxQueue
[TX_QUEUE_INDEX_AC1
];
1307 eAci
= WMM_AC_BE_INDEX
;
1311 if (prBssInfo
->arACQueParms
[eAci
].fgIsACMSet
1312 && eAci
!= WMM_AC_BK_INDEX
) {
1313 prCurrentMsduInfo
->ucUserPriority
=
1315 fgCheckACMAgain
= TRUE
;
1318 prTxQue
= &prStaRec
->arTxQueue
[TX_QUEUE_INDEX_AC1
];
1322 while (fgCheckACMAgain
);
1324 /* LOG_FUNC ("QoS %u UP %u TC %u",prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); */
1327 } /* switch (prCurrentMsduInfo->ucStaRecIndex) */
1329 if (prCurrentMsduInfo
->eSrc
== TX_PACKET_FORWARDING
) {
1330 if (prTxQue
->u4NumElem
> 32) {
1332 ("Drop the Packet for full Tx queue (forwarding) Bss %u\n",
1333 prCurrentMsduInfo
->ucNetworkType
));
1334 prTxQue
= &rNotEnqueuedQue
;
1335 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_FORWARD_OVERFLOW_DROP
);
1342 ("Drop the Packet for inactive Bss %u\n",
1343 prCurrentMsduInfo
->ucNetworkType
));
1344 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_31
);
1345 prTxQue
= &rNotEnqueuedQue
;
1346 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_INACTIVE_BSS_DROP
);
1349 /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */
1351 /* TODO: Fill MSDU_INFO according to the network type,
1352 * EtherType, and STA status (for PS forwarding control).
1355 /* Note that the Network Type Index and STA_REC index are determined in
1356 * qmDetermineStaRecIndex(prCurrentMsduInfo).
1358 QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(prCurrentMsduInfo
, /* MSDU_INFO ptr */
1360 ucPacketType
, /* Packet Type */
1362 prCurrentMsduInfo
->fgIs802_1x
, /* Flag 802.1x */
1363 prCurrentMsduInfo
->fgIs802_11
, /* Flag 802.11 */
1366 PS_FORWARDING_TYPE_NON_PS
, /* PS Forwarding Type */
1367 0 /* PS Session ID */
1370 /* 4 <4> Enqueue the packet */
1371 QUEUE_INSERT_TAIL(prTxQue
, (P_QUE_ENTRY_T
) prCurrentMsduInfo
);
1375 if (++prQM
->u4PktCount
== QM_TEST_TRIGGER_TX_COUNT
) {
1376 prQM
->u4PktCount
= 0;
1377 qmTestCases(prAdapter
);
1381 DBGLOG(QM
, LOUD
, ("Current queue length = %u\n", prTxQue
->u4NumElem
));
1382 } while (prNextMsduInfo
);
1384 if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue
)) {
1385 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(&rNotEnqueuedQue
), NULL
);
1386 prMsduInfoReleaseList
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(&rNotEnqueuedQue
);
1390 return prMsduInfoReleaseList
;
1393 /*----------------------------------------------------------------------------*/
1395 * \brief Determine the STA_REC index for a packet
1397 * \param[in] prMsduInfo Pointer to the packet
1401 /*----------------------------------------------------------------------------*/
1402 static VOID
qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
1406 P_STA_RECORD_T prTempStaRec
;
1407 /* P_QUE_MGT_T prQM = &prAdapter->rQM; */
1409 prTempStaRec
= NULL
;
1413 /* 4 <1> DA = BMCAST */
1414 if (IS_BMCAST_MAC_ADDR(prMsduInfo
->aucEthDestAddr
)) {
1415 /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP.
1416 * FW shall take care of this. The host driver is not able to distinguish these cases. */
1417 prMsduInfo
->ucStaRecIndex
= STA_REC_INDEX_BMCAST
;
1418 DBGLOG(QM
, LOUD
, ("TX with DA = BMCAST\n"));
1422 /* 4 <2> Check if an AP STA is present */
1423 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
1424 prTempStaRec
= &(prAdapter
->arStaRec
[i
]);
1426 if ((prTempStaRec
->ucNetTypeIndex
== prMsduInfo
->ucNetworkType
)
1427 && (prTempStaRec
->fgIsAp
)
1428 && (prTempStaRec
->fgIsValid
)) {
1429 prMsduInfo
->ucStaRecIndex
= prTempStaRec
->ucIndex
;
1437 /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */
1438 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
1439 prTempStaRec
= &(prAdapter
->arStaRec
[i
]);
1440 if (prTempStaRec
->fgIsValid
) {
1441 if (EQUAL_MAC_ADDR(prTempStaRec
->aucMacAddr
, prMsduInfo
->aucEthDestAddr
)) {
1442 prMsduInfo
->ucStaRecIndex
= prTempStaRec
->ucIndex
;
1449 /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */
1450 prMsduInfo
->ucStaRecIndex
= STA_REC_INDEX_NOT_FOUND
;
1451 DBGLOG(QM
, LOUD
, ("QM: TX with STA_REC_INDEX_NOT_FOUND\n"));
1454 #if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING)
1455 prMsduInfo
->ucStaRecIndex
= (UINT_8
) prQM
->u4CurrentStaRecIndexToEnqueue
;
1459 /*----------------------------------------------------------------------------*/
1461 * \brief Dequeue TX packets from a STA_REC for a particular TC
1463 * \param[out] prQue The queue to put the dequeued packets
1464 * \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX)
1465 * \param[in] ucMaxNum The maximum amount of dequeued packets
1469 /*----------------------------------------------------------------------------*/
1471 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter
,
1473 IN UINT_8 ucTC
, IN UINT_8 ucCurrentQuota
, IN UINT_8 ucTotalQuota
)
1476 #if QM_FORWARDING_FAIRNESS
1477 UINT_32 i
; /* Loop for */
1479 PUINT_32 pu4HeadStaRecIndex
; /* The Head STA index */
1480 PUINT_32 pu4HeadStaRecForwardCount
; /* The total forwarded packets for the head STA */
1482 P_STA_RECORD_T prStaRec
; /* The current focused STA */
1483 P_BSS_INFO_T prBssInfo
; /* The Bss for current focused STA */
1484 P_QUE_T prCurrQueue
; /* The current TX queue to dequeue */
1485 P_MSDU_INFO_T prDequeuedPkt
; /* The dequeued packet */
1487 UINT_32 u4ForwardCount
; /* To remember the total forwarded packets for a STA */
1488 UINT_32 u4MaxForwardCount
; /* The maximum number of packets a STA can forward */
1489 UINT_32 u4Resource
; /* The TX resource amount */
1491 BOOLEAN fgChangeHeadSta
; /* Whether a new head STA shall be determined at the end of the function */
1492 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1494 PUINT_8 pucFreeQuota
;
1496 DBGLOG(QM
, LOUD
, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC
));
1498 ASSERT(ucTC
== TC0_INDEX
|| ucTC
== TC1_INDEX
||
1499 ucTC
== TC2_INDEX
|| ucTC
== TC3_INDEX
|| ucTC
== TC4_INDEX
);
1501 if (!ucCurrentQuota
) {
1502 DBGLOG(TX
, LOUD
, ("@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n",
1503 ucTC
, ucCurrentQuota
));
1507 u4Resource
= ucCurrentQuota
;
1509 /* 4 <1> Determine the head STA */
1510 /* The head STA shall be an active STA */
1512 pu4HeadStaRecIndex
= &(prQM
->au4HeadStaRecIndex
[ucTC
]);
1513 pu4HeadStaRecForwardCount
= &(prQM
->au4ForwardCount
[ucTC
]);
1515 DBGLOG(QM
, LOUD
, ("(Fairness) TID = %u Init Head STA = %u Resource = %u\n",
1516 ucTC
, *pu4HeadStaRecIndex
, u4Resource
));
1519 /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */
1520 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
+ 1; i
++) {
1521 prStaRec
= &prAdapter
->arStaRec
[(*pu4HeadStaRecIndex
)];
1524 /* Only Data frame (1x was not included) will be queued in */
1525 if (prStaRec
->fgIsValid
) {
1527 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prStaRec
->ucNetTypeIndex
]);
1529 ASSERT(prBssInfo
->ucNetTypeIndex
== prStaRec
->ucNetTypeIndex
);
1531 /* Determine how many packets the head STA is allowed to send in a round */
1533 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_25
);
1534 u4MaxForwardCount
= ucTotalQuota
;
1535 #if CFG_ENABLE_WIFI_DIRECT
1537 pucFreeQuota
= NULL
;
1538 if (prStaRec
->fgIsInPS
&& (ucTC
!= TC4_INDEX
)) {
1539 /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */
1540 /* u4MaxForwardCount = ucTotalQuota; */
1541 /* Per STA flow control when STA in PS mode */
1542 /* The PHASE 1: only update from ucFreeQuota (now) */
1543 /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1544 /* NOTE: other method to set u4Resource */
1546 if (prStaRec
->fgIsQoS
&& prStaRec
->fgIsUapsdSupported
1547 /* && prAdapter->rWifiVar.fgSupportQoS
1548 && prAdapter->rWifiVar.fgSupportUAPSD */) {
1550 if (prStaRec
->ucBmpTriggerAC
& BIT(ucTC
)) {
1552 prStaRec
->ucFreeQuotaForDelivery
;
1553 pucFreeQuota
= &prStaRec
->ucFreeQuotaForDelivery
;
1556 prStaRec
->ucFreeQuotaForNonDelivery
;
1557 pucFreeQuota
= &prStaRec
->ucFreeQuotaForNonDelivery
;
1561 ASSERT(prStaRec
->ucFreeQuotaForDelivery
== 0);
1562 u4MaxForwardCount
= prStaRec
->ucFreeQuotaForNonDelivery
;
1563 pucFreeQuota
= &prStaRec
->ucFreeQuotaForNonDelivery
;
1567 #endif /* CFG_ENABLE_WIFI_DIRECT */
1569 #if CFG_ENABLE_WIFI_DIRECT
1570 if (prBssInfo
->fgIsNetAbsent
&& (ucTC
!= TC4_INDEX
)) {
1571 if (u4MaxForwardCount
> prBssInfo
->ucBssFreeQuota
) {
1572 u4MaxForwardCount
= prBssInfo
->ucBssFreeQuota
;
1575 #endif /* CFG_ENABLE_WIFI_DIRECT */
1577 /* Determine whether the head STA can continue to forward packets in this round */
1578 if ((*pu4HeadStaRecForwardCount
) < u4MaxForwardCount
) {
1582 } /* prStaRec->fgIsValid */
1584 /* The current Head STA has been deactivated, so search for a new head STA */
1587 (*pu4HeadStaRecIndex
)++;
1588 (*pu4HeadStaRecIndex
) %= CFG_NUM_OF_STA_RECORD
;
1590 /* Reset the forwarding count before searching (since this is for a new selected STA) */
1591 (*pu4HeadStaRecForwardCount
) = 0;
1593 } /* i < CFG_NUM_OF_STA_RECORD + 1 */
1595 /* All STA_RECs are inactive, so exit */
1597 /* Under concurrent, it is possible that there is no candidcated STA. */
1598 /* DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); */
1602 DBGLOG(QM
, LOUD
, ("(Fairness) TID = %u Round Head STA = %lu\n", ucTC
, *pu4HeadStaRecIndex
));
1604 /* 4 <2> Dequeue packets from the head STA */
1606 prCurrQueue
= &prStaRec
->arTxQueue
[ucTC
];
1607 prDequeuedPkt
= NULL
;
1608 fgChangeHeadSta
= FALSE
;
1610 while (prCurrQueue
) {
1613 #if QM_DEBUG_COUNTER
1615 if (ucTC
<= TC4_INDEX
) {
1616 if (QUEUE_IS_EMPTY(prCurrQueue
)) {
1617 QM_DBG_CNT_INC(prQM
, ucTC
);
1618 /* QM_DBG_CNT_00 *//* QM_DBG_CNT_01 *//* QM_DBG_CNT_02 *//* QM_DBG_CNT_03 *//* QM_DBG_CNT_04 */
1620 if (u4Resource
== 0) {
1621 QM_DBG_CNT_INC(prQM
, ucTC
+ 5);
1622 /* QM_DBG_CNT_05 *//* QM_DBG_CNT_06 *//* QM_DBG_CNT_07 *//* QM_DBG_CNT_08 *//* QM_DBG_CNT_09 */
1624 if (((*pu4HeadStaRecForwardCount
) >= u4MaxForwardCount
)) {
1625 QM_DBG_CNT_INC(prQM
, ucTC
+ 10);
1626 /* QM_DBG_CNT_10 *//* QM_DBG_CNT_11 *//* QM_DBG_CNT_12 *//* QM_DBG_CNT_13 *//* QM_DBG_CNT_14 */
1632 /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1633 if (QUEUE_IS_EMPTY(prCurrQueue
)
1634 || ((*pu4HeadStaRecForwardCount
) >= u4MaxForwardCount
)) {
1635 fgChangeHeadSta
= TRUE
;
1637 } else if (u4Resource
== 0) {
1641 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
, P_MSDU_INFO_T
);
1644 ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1645 prDequeuedPkt
->ucTC
, prCurrQueue
->u4NumElem
,
1646 prDequeuedPkt
->ucNetworkType
, prDequeuedPkt
->ucMacHeaderLength
,
1647 prDequeuedPkt
->u2FrameLength
, prDequeuedPkt
->ucPacketType
,
1648 prDequeuedPkt
->fgIs802_1x
, prDequeuedPkt
->fgIs802_11
);
1650 LOG_FUNC("Dest Mac: " MACSTR
"\n", MAC2STR(prDequeuedPkt
->aucEthDestAddr
));
1654 struct sk_buff
*prSkb
= (struct sk_buff
*)prDequeuedPkt
->prPacket
;
1655 dumpMemory8((PUINT_8
) prSkb
->data
, prSkb
->len
);
1661 ASSERT(prDequeuedPkt
->ucTC
== ucTC
);
1663 if (!QUEUE_IS_EMPTY(prCurrQueue
)) {
1664 /* XXX: check all queues for STA */
1665 prDequeuedPkt
->ucPsForwardingType
= PS_FORWARDING_MORE_DATA_ENABLED
;
1668 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
1670 (*pu4HeadStaRecForwardCount
)++;
1673 #if CFG_ENABLE_WIFI_DIRECT
1674 /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */
1675 if (prStaRec
->fgIsInPS
&& (ucTC
!= TC4_INDEX
)) {
1676 ASSERT(pucFreeQuota
);
1677 ASSERT(*pucFreeQuota
> 0);
1678 if (*pucFreeQuota
> 0) {
1679 *pucFreeQuota
= *pucFreeQuota
- 1;
1682 #endif /* CFG_ENABLE_WIFI_DIRECT */
1684 #if CFG_ENABLE_WIFI_DIRECT
1685 if (prBssInfo
->fgIsNetAbsent
&& (ucTC
!= TC4_INDEX
)) {
1686 if (prBssInfo
->ucBssFreeQuota
> 0) {
1687 prBssInfo
->ucBssFreeQuota
--;
1690 #endif /* CFG_ENABLE_WIFI_DIRECT */
1695 if (*pu4HeadStaRecForwardCount
) {
1697 ("TC = %u Round Head STA = %lu, u4HeadStaRecForwardCount = %lu\n", ucTC
,
1698 *pu4HeadStaRecIndex
, (*pu4HeadStaRecForwardCount
)));
1700 #if QM_BURST_END_INFO_ENABLED
1701 /* Let FW know which packet is the last one dequeued from the STA */
1702 if (prDequeuedPkt
) {
1703 prDequeuedPkt
->fgIsBurstEnd
= TRUE
;
1708 /* 4 <3> Dequeue from the other STAs if there is residual TX resource */
1710 /* Check all of the STAs to continue forwarding packets (including the head STA) */
1711 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
1712 /* Break in case no reasource is available */
1713 if (u4Resource
== 0) {
1717 /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */
1719 &prAdapter
->arStaRec
[((*pu4HeadStaRecIndex
) + i
+ 1) % CFG_NUM_OF_STA_RECORD
];
1722 if (prStaRec
->fgIsValid
) {
1724 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prStaRec
->ucNetTypeIndex
]);
1725 ASSERT(prBssInfo
->ucNetTypeIndex
== prStaRec
->ucNetTypeIndex
);
1727 DBGLOG(QM
, LOUD
, ("(Fairness) TID = %u Sharing STA = %u Resource = %lu\n",
1728 ucTC
, prStaRec
->ucIndex
, u4Resource
));
1730 prCurrQueue
= &prStaRec
->arTxQueue
[ucTC
];
1732 u4MaxForwardCount
= ucTotalQuota
;
1734 #if CFG_ENABLE_WIFI_DIRECT
1735 pucFreeQuota
= NULL
;
1736 if (prStaRec
->fgIsInPS
&& (ucTC
!= TC4_INDEX
)) {
1737 /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */
1738 /* u4MaxForwardCount = ucTotalQuota; */
1739 /* Per STA flow control when STA in PS mode */
1740 /* The PHASE 1: only update from ucFreeQuota (now) */
1741 /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1742 /* NOTE: other method to set u4Resource */
1743 if (prStaRec
->fgIsQoS
&& prStaRec
->fgIsUapsdSupported
1744 /* && prAdapter->rWifiVar.fgSupportQoS
1745 && prAdapter->rWifiVar.fgSupportUAPSD */) {
1747 if (prStaRec
->ucBmpTriggerAC
& BIT(ucTC
)) {
1749 prStaRec
->ucFreeQuotaForDelivery
;
1750 pucFreeQuota
= &prStaRec
->ucFreeQuotaForDelivery
;
1753 prStaRec
->ucFreeQuotaForNonDelivery
;
1754 pucFreeQuota
= &prStaRec
->ucFreeQuotaForNonDelivery
;
1758 ASSERT(prStaRec
->ucFreeQuotaForDelivery
== 0);
1759 u4MaxForwardCount
= prStaRec
->ucFreeQuotaForNonDelivery
;
1760 pucFreeQuota
= &prStaRec
->ucFreeQuotaForNonDelivery
;
1764 #endif /* CFG_ENABLE_WIFI_DIRECT */
1765 #if CFG_ENABLE_WIFI_DIRECT
1766 if (prBssInfo
->fgIsNetAbsent
&& (ucTC
!= TC4_INDEX
)) {
1767 if (u4MaxForwardCount
> prBssInfo
->ucBssFreeQuota
) {
1768 u4MaxForwardCount
= prBssInfo
->ucBssFreeQuota
;
1771 #endif /* CFG_ENABLE_WIFI_DIRECT */
1772 } /* prStaRec->fgIsValid */
1775 /* Invalid STA, so check the next STA */
1779 while (prCurrQueue
) {
1780 /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1781 if ((u4Resource
== 0) || QUEUE_IS_EMPTY(prCurrQueue
)
1782 || (u4ForwardCount
>= u4MaxForwardCount
)) {
1786 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
, P_MSDU_INFO_T
);
1790 ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1791 prDequeuedPkt
->ucTC
, prCurrQueue
->u4NumElem
,
1792 prDequeuedPkt
->ucNetworkType
,
1793 prDequeuedPkt
->ucMacHeaderLength
,
1794 prDequeuedPkt
->u2FrameLength
, prDequeuedPkt
->ucPacketType
,
1795 prDequeuedPkt
->fgIs802_1x
, prDequeuedPkt
->fgIs802_11
));
1797 DBGLOG(QM
, LOUD
, ("Dest Mac: " MACSTR
"\n",
1798 MAC2STR(prDequeuedPkt
->aucEthDestAddr
)));
1802 struct sk_buff
*prSkb
=
1803 (struct sk_buff
*)prDequeuedPkt
->prPacket
;
1804 dumpMemory8((PUINT_8
) prSkb
->data
, prSkb
->len
);
1811 ASSERT(prDequeuedPkt
->ucTC
== ucTC
);
1813 if (!QUEUE_IS_EMPTY(prCurrQueue
)) {
1814 prDequeuedPkt
->ucPsForwardingType
=
1815 PS_FORWARDING_MORE_DATA_ENABLED
;
1818 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
1822 #if CFG_ENABLE_WIFI_DIRECT
1823 /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */
1824 if (prStaRec
->fgIsInPS
&& (ucTC
!= TC4_INDEX
)) {
1825 ASSERT(pucFreeQuota
);
1826 ASSERT(*pucFreeQuota
> 0);
1827 if (*pucFreeQuota
> 0) {
1828 *pucFreeQuota
= *pucFreeQuota
- 1;
1831 #endif /* CFG_ENABLE_WIFI_DIRECT */
1834 #if CFG_ENABLE_WIFI_DIRECT
1835 ASSERT(prBssInfo
->ucNetTypeIndex
== prStaRec
->ucNetTypeIndex
);
1836 if (prBssInfo
->fgIsNetAbsent
&& (ucTC
!= TC4_INDEX
)) {
1837 if (prBssInfo
->ucBssFreeQuota
> 0) {
1838 prBssInfo
->ucBssFreeQuota
--;
1841 #endif /* CFG_ENABLE_WIFI_DIRECT */
1846 #if QM_BURST_END_INFO_ENABLED
1847 /* Let FW know which packet is the last one dequeued from the STA */
1848 if (u4ForwardCount
) {
1849 prDequeuedPkt
->fgIsBurstEnd
= TRUE
;
1855 if (fgChangeHeadSta
) {
1856 (*pu4HeadStaRecIndex
)++;
1857 (*pu4HeadStaRecIndex
) %= CFG_NUM_OF_STA_RECORD
;
1858 (*pu4HeadStaRecForwardCount
) = 0;
1860 ("(Fairness) TID = %u Scheduled Head STA = %lu Left Resource = %lu\n", ucTC
,
1861 (*pu4HeadStaRecIndex
), u4Resource
));
1865 /***************************************************************************************/
1867 UINT_8 ucStaRecIndex
;
1868 P_STA_RECORD_T prStaRec
;
1869 P_QUE_T prCurrQueue
;
1871 P_MSDU_INFO_T prDequeuedPkt
;
1873 DBGLOG(QM
, LOUD
, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC
));
1875 if (ucCurrentQuota
== 0) {
1878 /* 4 <1> Determine the queue index and the head STA */
1881 ucStaRecIndex
= 0; /* TODO: Get the current head STA */
1882 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, ucStaRecIndex
);
1885 if (prStaRec
== NULL
) {
1889 /* The queue to pull out packets */
1890 ASSERT(ucTC
== TC0_INDEX
|| ucTC
== TC1_INDEX
||
1891 ucTC
== TC2_INDEX
|| ucTC
== TC3_INDEX
|| ucTC
== TC4_INDEX
);
1892 prCurrQueue
= &prStaRec
->arTxQueue
[ucTC
];
1894 ucPktCount
= ucCurrentQuota
;
1895 prDequeuedPkt
= NULL
;
1897 /* 4 <2> Dequeue packets for the head STA */
1899 if (!(prStaRec
->fgIsValid
) || ucPktCount
== 0 || QUEUE_IS_EMPTY(prCurrQueue
)) {
1904 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
, P_MSDU_INFO_T
);
1905 /* DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); */
1906 ASSERT(prDequeuedPkt
->ucTC
== ucTC
);
1908 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
1913 /* DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); */
1915 #if QM_BURST_END_INFO_ENABLED
1916 if (prDequeuedPkt
) {
1917 prDequeuedPkt
->fgIsBurstEnd
= TRUE
;
1921 /* 4 <3> Update scheduling info */
1924 /* 4 <4> Utilize the remainaing TX opportunities for non-head STAs */
1930 /*----------------------------------------------------------------------------*/
1932 * \brief Dequeue TX packets from a per-Type-based Queue for a particular TC
1934 * \param[out] prQue The queue to put the dequeued packets
1935 * \param[in] ucTC The TC index (Shall always be TC5_INDEX)
1936 * \param[in] ucMaxNum The maximum amount of dequeued packets
1940 /*----------------------------------------------------------------------------*/
1942 qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter
,
1943 OUT P_QUE_T prQue
, IN UINT_8 ucTC
, IN UINT_8 ucMaxNum
)
1945 /* UINT_8 ucQueIndex; */
1946 /* UINT_8 ucStaRecIndex; */
1947 P_BSS_INFO_T prBssInfo
;
1948 P_BSS_INFO_T parBssInfo
;
1949 P_QUE_T prCurrQueue
;
1951 P_MSDU_INFO_T prDequeuedPkt
;
1952 P_MSDU_INFO_T prBurstEndPkt
;
1958 ("Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC
, ucMaxNum
));
1960 /* TC5: Broadcast/Multicast data packets */
1961 ASSERT(ucTC
== TC5_INDEX
);
1963 if (ucMaxNum
== 0) {
1967 prQM
= &prAdapter
->rQM
;
1968 /* 4 <1> Determine the queue */
1970 prCurrQueue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
1971 ucPktCount
= ucMaxNum
;
1972 prDequeuedPkt
= NULL
;
1973 prBurstEndPkt
= NULL
;
1975 parBssInfo
= prAdapter
->rWifiVar
.arBssInfo
;
1977 QUEUE_INITIALIZE(&rMergeQue
);
1978 prMergeQue
= &rMergeQue
;
1980 /* 4 <2> Dequeue packets */
1982 if (ucPktCount
== 0 || QUEUE_IS_EMPTY(prCurrQueue
)) {
1985 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
, P_MSDU_INFO_T
);
1986 ASSERT(prDequeuedPkt
->ucTC
== ucTC
);
1988 ASSERT(prDequeuedPkt
->ucNetworkType
< NETWORK_TYPE_INDEX_NUM
);
1990 prBssInfo
= &parBssInfo
[prDequeuedPkt
->ucNetworkType
];
1992 if (IS_BSS_ACTIVE(prBssInfo
)) {
1993 if (!prBssInfo
->fgIsNetAbsent
) {
1994 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
1995 prBurstEndPkt
= prDequeuedPkt
;
1997 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_26
);
2000 ("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
2001 prDequeuedPkt
->ucTC
, prCurrQueue
->u4NumElem
,
2002 prDequeuedPkt
->ucNetworkType
,
2003 prDequeuedPkt
->ucMacHeaderLength
,
2004 prDequeuedPkt
->u2FrameLength
,
2005 prDequeuedPkt
->ucPacketType
, prDequeuedPkt
->fgIs802_1x
,
2006 prDequeuedPkt
->fgIs802_11
);
2008 LOG_FUNC("Dest Mac: " MACSTR
"\n",
2009 MAC2STR(prDequeuedPkt
->aucEthDestAddr
));
2013 struct sk_buff
*prSkb
=
2014 (struct sk_buff
*)prDequeuedPkt
->prPacket
;
2015 dumpMemory8((PUINT_8
) prSkb
->data
, prSkb
->len
);
2021 QUEUE_INSERT_TAIL(prMergeQue
,
2022 (P_QUE_ENTRY_T
) prDequeuedPkt
);
2025 QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt
, NULL
);
2026 wlanProcessQueuedMsduInfo(prAdapter
, prDequeuedPkt
);
2031 if (QUEUE_IS_NOT_EMPTY(prMergeQue
)) {
2032 QUEUE_CONCATENATE_QUEUES(prMergeQue
, prCurrQueue
);
2033 QUEUE_MOVE_ALL(prCurrQueue
, prMergeQue
);
2034 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(prCurrQueue
), NULL
);
2036 #if QM_BURST_END_INFO_ENABLED
2037 if (prBurstEndPkt
) {
2038 prBurstEndPkt
->fgIsBurstEnd
= TRUE
;
2041 } /* qmDequeueTxPacketsFromPerTypeQueues */
2046 /*----------------------------------------------------------------------------*/
2048 * \brief Dequeue TX packets to send to HIF TX
2050 * \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2052 * \return The list of dequeued TX packets
2054 /*----------------------------------------------------------------------------*/
2055 P_MSDU_INFO_T
qmDequeueTxPackets(IN P_ADAPTER_T prAdapter
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2059 P_MSDU_INFO_T prReturnedPacketListHead
;
2062 DBGLOG(QM
, LOUD
, ("Enter qmDequeueTxPackets\n"));
2064 QUEUE_INITIALIZE(&rReturnedQue
);
2066 prReturnedPacketListHead
= NULL
;
2068 /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */
2069 for (i
= TC4_INDEX
; i
>= TC0_INDEX
; i
--) {
2070 DBGLOG(QM
, LOUD
, ("Dequeue packets from Per-STA queue[%u]\n", i
));
2072 qmDequeueTxPacketsFromPerStaQueues(prAdapter
,
2075 prTcqStatus
->aucFreeBufferCount
[i
],
2076 prTcqStatus
->aucMaxNumOfBuffer
[i
]
2079 /* The aggregate number of dequeued packets */
2080 DBGLOG(QM
, LOUD
, ("DQA)[%u](%lu)\n", i
, rReturnedQue
.u4NumElem
));
2084 /* TC5 (BMCAST or STA-NOT-FOUND packets) */
2085 qmDequeueTxPacketsFromPerTypeQueues(prAdapter
,
2087 TC5_INDEX
, prTcqStatus
->aucFreeBufferCount
[TC5_INDEX
]
2091 ("Current total number of dequeued packets = %u\n", rReturnedQue
.u4NumElem
));
2093 if (QUEUE_IS_NOT_EMPTY(&rReturnedQue
)) {
2094 prReturnedPacketListHead
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(&rReturnedQue
);
2095 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(&rReturnedQue
), NULL
);
2098 return prReturnedPacketListHead
;
2101 /*----------------------------------------------------------------------------*/
2103 * \brief Adjust the TC quotas according to traffic demands
2105 * \param[out] prTcqAdjust The resulting adjustment
2106 * \param[in] prTcqStatus Info about the current TC quotas and counters
2110 /*----------------------------------------------------------------------------*/
2112 qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter
,
2113 OUT P_TX_TCQ_ADJUST_T prTcqAdjust
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2115 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2117 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2119 /* Must initialize */
2120 for (i
= 0; i
< TC_NUM
; i
++) {
2121 prTcqAdjust
->acVariation
[i
] = 0;
2124 /* 4 <1> If TC resource is not just adjusted, exit directly */
2125 if (!prQM
->fgTcResourcePostAnnealing
) {
2128 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2130 INT_32 i4TotalExtraQuota
= 0;
2131 INT_32 ai4ExtraQuota
[TC_NUM
];
2132 BOOLEAN fgResourceRedistributed
= TRUE
;
2134 /* Obtain the free-to-distribute resource */
2135 for (i
= 0; i
< TC_NUM
; i
++) {
2137 (INT_32
) prTcqStatus
->aucMaxNumOfBuffer
[i
] -
2138 (INT_32
) prQM
->au4CurrentTcResource
[i
];
2140 if (ai4ExtraQuota
[i
] > 0) { /* The resource shall be reallocated to other TCs */
2141 if (ai4ExtraQuota
[i
] > prTcqStatus
->aucFreeBufferCount
[i
]) {
2142 ai4ExtraQuota
[i
] = prTcqStatus
->aucFreeBufferCount
[i
];
2143 fgResourceRedistributed
= FALSE
;
2146 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2147 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2151 /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */
2152 for (i
= 0; i
< TC_NUM
; i
++) {
2153 if (ai4ExtraQuota
[i
] < 0) {
2154 if ((-ai4ExtraQuota
[i
]) > i4TotalExtraQuota
) {
2155 ai4ExtraQuota
[i
] = (-i4TotalExtraQuota
);
2156 fgResourceRedistributed
= FALSE
;
2159 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2160 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2164 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2165 prQM
->fgTcResourcePostAnnealing
= (!fgResourceRedistributed
);
2167 #if QM_PRINT_TC_RESOURCE_CTRL
2168 DBGLOG(QM
, LOUD
, ("QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n",
2169 prTcqStatus
->aucFreeBufferCount
[0],
2170 prTcqStatus
->aucFreeBufferCount
[1],
2171 prTcqStatus
->aucFreeBufferCount
[2],
2172 prTcqStatus
->aucFreeBufferCount
[3],
2173 prTcqStatus
->aucFreeBufferCount
[4],
2174 prTcqStatus
->aucFreeBufferCount
[5]
2181 for (i
= 0; i
< TC_NUM
; i
++) {
2182 prTcqAdjust
->acVariation
[i
] = 0;
2188 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2189 /*----------------------------------------------------------------------------*/
2191 * \brief Update the average TX queue length for the TC resource control mechanism
2197 /*----------------------------------------------------------------------------*/
2198 VOID
qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter
)
2200 INT_32 u4CurrQueLen
, i
, k
;
2201 P_STA_RECORD_T prStaRec
;
2202 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2204 /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ */
2205 for (i
= 0; i
< NUM_OF_PER_STA_TX_QUEUES
- 1; i
++) {
2208 for (k
= 0; k
< CFG_NUM_OF_STA_RECORD
; k
++) {
2209 prStaRec
= &prAdapter
->arStaRec
[k
];
2212 /* If the STA is activated, get the queue length */
2213 if (prStaRec
->fgIsValid
&&
2214 (!prAdapter
->rWifiVar
.arBssInfo
[prStaRec
->ucNetTypeIndex
].fgIsNetAbsent
)
2217 u4CurrQueLen
+= (prStaRec
->arTxQueue
[i
].u4NumElem
);
2221 if (prQM
->au4AverageQueLen
[i
] == 0) {
2222 prQM
->au4AverageQueLen
[i
] = (u4CurrQueLen
<< QM_QUE_LEN_MOVING_AVE_FACTOR
);
2224 prQM
->au4AverageQueLen
[i
] -=
2225 (prQM
->au4AverageQueLen
[i
] >> QM_QUE_LEN_MOVING_AVE_FACTOR
);
2226 prQM
->au4AverageQueLen
[i
] += (u4CurrQueLen
);
2231 /* Update the queue length for TC5 (BMCAST) */
2232 u4CurrQueLen
= prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
].u4NumElem
;
2234 if (prQM
->au4AverageQueLen
[TC_NUM
- 1] == 0) {
2235 prQM
->au4AverageQueLen
[TC_NUM
- 1] = (u4CurrQueLen
<< QM_QUE_LEN_MOVING_AVE_FACTOR
);
2237 prQM
->au4AverageQueLen
[TC_NUM
- 1] -=
2238 (prQM
->au4AverageQueLen
[TC_NUM
- 1] >> QM_QUE_LEN_MOVING_AVE_FACTOR
);
2239 prQM
->au4AverageQueLen
[TC_NUM
- 1] += (u4CurrQueLen
);
2243 /* 4 <2> Adjust TC resource assignment */
2244 /* Check whether it is time to adjust the TC resource assignment */
2245 if (--prQM
->u4TimeToAdjustTcResource
== 0) {
2246 /* The last assignment has not been completely applied */
2247 if (prQM
->fgTcResourcePostAnnealing
) {
2248 /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */
2249 prQM
->u4TimeToAdjustTcResource
= 1;
2252 /* The last assignment has been applied */
2254 prQM
->u4TimeToAdjustTcResource
= QM_INIT_TIME_TO_ADJUST_TC_RSC
;
2255 qmReassignTcResource(prAdapter
);
2260 #if QM_PRINT_TC_RESOURCE_CTRL
2261 for (i
= 0; i
< TC_NUM
; i
++) {
2262 if (QM_GET_TX_QUEUE_LEN(prAdapter
, i
) >= 100) {
2263 DBGLOG(QM
, LOUD
, ("QM: QueLen [%ld %ld %ld %ld %ld %ld]\n",
2264 QM_GET_TX_QUEUE_LEN(prAdapter
, 0),
2265 QM_GET_TX_QUEUE_LEN(prAdapter
, 1),
2266 QM_GET_TX_QUEUE_LEN(prAdapter
, 2),
2267 QM_GET_TX_QUEUE_LEN(prAdapter
, 3),
2268 QM_GET_TX_QUEUE_LEN(prAdapter
, 4),
2269 QM_GET_TX_QUEUE_LEN(prAdapter
, 5)
2280 /*----------------------------------------------------------------------------*/
2282 * \brief Assign TX resource for each TC according to TX queue length and current assignment
2288 /*----------------------------------------------------------------------------*/
2289 VOID
qmReassignTcResource(IN P_ADAPTER_T prAdapter
)
2291 INT_32 i4TotalResourceDemand
= 0;
2292 UINT_32 u4ResidualResource
= 0;
2294 INT_32 ai4PerTcResourceDemand
[TC_NUM
];
2295 UINT_32 u4ShareCount
= 0;
2296 UINT_32 u4Share
= 0;
2297 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2299 /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to
2300 * start the TC-quota adjusting procedure, which will be invoked upon every TX Done
2303 /* 4 <1> Determine the demands */
2304 /* Determine the amount of extra resource to fulfill all of the demands */
2305 for (i
= 0; i
< TC_NUM
; i
++) {
2306 /* Skip TC4, which is not adjustable */
2307 if (i
== TC4_INDEX
) {
2311 /* Define: extra_demand = que_length + min_reserved_quota - current_quota */
2312 ai4PerTcResourceDemand
[i
] =
2313 ((UINT_32
) (QM_GET_TX_QUEUE_LEN(prAdapter
, i
)) +
2314 prQM
->au4MinReservedTcResource
[i
] - prQM
->au4CurrentTcResource
[i
]);
2316 /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */
2317 if (QM_GET_TX_QUEUE_LEN(prAdapter
, i
)) {
2318 ai4PerTcResourceDemand
[i
] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY
;
2321 i4TotalResourceDemand
+= ai4PerTcResourceDemand
[i
];
2324 /* 4 <2> Case 1: Demand <= Total Resource */
2325 if (i4TotalResourceDemand
<= 0) {
2326 /* 4 <2.1> Satisfy every TC */
2327 for (i
= 0; i
< TC_NUM
; i
++) {
2328 /* Skip TC4 (not adjustable) */
2329 if (i
== TC4_INDEX
) {
2333 prQM
->au4CurrentTcResource
[i
] += ai4PerTcResourceDemand
[i
];
2336 /* 4 <2.2> Share the residual resource evenly */
2337 u4ShareCount
= (TC_NUM
- 1); /* excluding TC4 */
2338 u4ResidualResource
= (UINT_32
) (-i4TotalResourceDemand
);
2339 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2341 for (i
= 0; i
< TC_NUM
; i
++) {
2342 /* Skip TC4 (not adjustable) */
2343 if (i
== TC4_INDEX
) {
2347 prQM
->au4CurrentTcResource
[i
] += u4Share
;
2349 /* Every TC is fully satisfied */
2350 ai4PerTcResourceDemand
[i
] = 0;
2352 /* The left resource will be allocated to TC3 */
2353 u4ResidualResource
-= u4Share
;
2356 /* 4 <2.3> Allocate the left resource to TC3 (VO) */
2357 prQM
->au4CurrentTcResource
[TC3_INDEX
] += (u4ResidualResource
);
2360 /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */
2362 u4ResidualResource
= QM_INITIAL_RESIDUAL_TC_RESOURCE
;
2364 /* 4 <3.1> Allocated resouce amount = minimum of (guaranteed, total demand) */
2365 for (i
= 0; i
< TC_NUM
; i
++) {
2366 /* Skip TC4 (not adjustable) */
2367 if (i
== TC4_INDEX
) {
2371 /* The demand can be fulfilled with the guaranteed resource amount */
2372 if (prQM
->au4CurrentTcResource
[i
] + ai4PerTcResourceDemand
[i
] <
2373 prQM
->au4GuaranteedTcResource
[i
]) {
2374 prQM
->au4CurrentTcResource
[i
] += ai4PerTcResourceDemand
[i
];
2375 u4ResidualResource
+=
2376 (prQM
->au4GuaranteedTcResource
[i
] -
2377 prQM
->au4CurrentTcResource
[i
]);
2378 ai4PerTcResourceDemand
[i
] = 0;
2381 /* The demand can not be fulfilled with the guaranteed resource amount */
2383 ai4PerTcResourceDemand
[i
] -=
2384 (prQM
->au4GuaranteedTcResource
[i
] -
2385 prQM
->au4CurrentTcResource
[i
]);
2386 prQM
->au4CurrentTcResource
[i
] = prQM
->au4GuaranteedTcResource
[i
];
2391 /* 4 <3.2> Allocate the residual resource */
2393 /* If there is no resource left, exit directly */
2394 if (u4ResidualResource
== 0) {
2398 /* This shall not happen */
2399 if (u4ShareCount
== 0) {
2400 prQM
->au4CurrentTcResource
[TC1_INDEX
] += u4ResidualResource
;
2401 DBGLOG(QM
, ERROR
, ("QM: (Error) u4ShareCount = 0\n"));
2405 /* Share the residual resource evenly */
2406 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2408 for (i
= 0; i
< TC_NUM
; i
++) {
2409 /* Skip TC4 (not adjustable) */
2410 if (i
== TC4_INDEX
) {
2414 if (ai4PerTcResourceDemand
[i
]) {
2415 if (ai4PerTcResourceDemand
[i
] - u4Share
) {
2416 prQM
->au4CurrentTcResource
[i
] += u4Share
;
2417 u4ResidualResource
-= u4Share
;
2418 ai4PerTcResourceDemand
[i
] -= u4Share
;
2420 prQM
->au4CurrentTcResource
[i
] +=
2421 ai4PerTcResourceDemand
[i
];
2422 u4ResidualResource
-=
2423 ai4PerTcResourceDemand
[i
];
2424 ai4PerTcResourceDemand
[i
] = 0;
2430 /* By priority, allocate the left resource that is not divisible by u4Share */
2431 if (u4ResidualResource
== 0) {
2435 if (ai4PerTcResourceDemand
[TC3_INDEX
]) { /* VO */
2436 prQM
->au4CurrentTcResource
[TC3_INDEX
]++;
2437 if (--u4ResidualResource
== 0) {
2442 if (ai4PerTcResourceDemand
[TC2_INDEX
]) { /* VI */
2443 prQM
->au4CurrentTcResource
[TC2_INDEX
]++;
2444 if (--u4ResidualResource
== 0) {
2449 if (ai4PerTcResourceDemand
[TC5_INDEX
]) { /* BMCAST */
2450 prQM
->au4CurrentTcResource
[TC5_INDEX
]++;
2451 if (--u4ResidualResource
== 0) {
2456 if (ai4PerTcResourceDemand
[TC1_INDEX
]) { /* BE */
2457 prQM
->au4CurrentTcResource
[TC1_INDEX
]++;
2458 if (--u4ResidualResource
== 0) {
2463 if (ai4PerTcResourceDemand
[TC0_INDEX
]) { /* BK */
2464 prQM
->au4CurrentTcResource
[TC0_INDEX
]++;
2465 if (--u4ResidualResource
== 0) {
2470 /* Allocate the left resource */
2471 prQM
->au4CurrentTcResource
[TC3_INDEX
] += u4ResidualResource
;
2476 prQM
->fgTcResourcePostAnnealing
= TRUE
;
2478 #if QM_PRINT_TC_RESOURCE_CTRL
2480 DBGLOG(QM
, LOUD
, ("QM: TC Rsc %ld %ld %ld %ld %ld %ld\n",
2481 prQM
->au4CurrentTcResource
[0],
2482 prQM
->au4CurrentTcResource
[1],
2483 prQM
->au4CurrentTcResource
[2],
2484 prQM
->au4CurrentTcResource
[3],
2485 prQM
->au4CurrentTcResource
[4], prQM
->au4CurrentTcResource
[5]
2494 /*----------------------------------------------------------------------------*/
2495 /* RX-Related Queue Management */
2496 /*----------------------------------------------------------------------------*/
2497 /*----------------------------------------------------------------------------*/
2499 * \brief Init Queue Managment for RX
2505 /*----------------------------------------------------------------------------*/
2506 VOID
qmInitRxQueues(IN P_ADAPTER_T prAdapter
)
2508 /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */
2512 /*----------------------------------------------------------------------------*/
2514 * \brief Handle RX packets (buffer reordering)
2516 * \param[in] prSwRfbListHead The list of RX packets
2518 * \return The list of packets which are not buffered for reordering
2520 /*----------------------------------------------------------------------------*/
2521 P_SW_RFB_T
qmHandleRxPackets(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfbListHead
)
2524 #if CFG_RX_REORDERING_ENABLED
2526 P_SW_RFB_T prCurrSwRfb
;
2527 P_SW_RFB_T prNextSwRfb
;
2528 P_HIF_RX_HEADER_T prHifRxHdr
;
2530 PUINT_8 pucEthDestAddr
;
2533 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
2535 DEBUGFUNC("qmHandleRxPackets");
2537 ASSERT(prSwRfbListHead
);
2539 QUEUE_INITIALIZE(&rReturnedQue
);
2540 prNextSwRfb
= prSwRfbListHead
;
2543 prCurrSwRfb
= prNextSwRfb
;
2544 prNextSwRfb
= QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb
);
2546 prHifRxHdr
= prCurrSwRfb
->prHifRxHdr
; /* TODO: (Tehuang) Use macro to obtain the pointer */
2548 /* TODO: (Tehuang) Check if relaying */
2549 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_HOST
;
2551 /* Decide the Destination */
2552 #if CFG_RX_PKTS_DUMP
2553 if (prAdapter
->rRxCtrl
.u4RxPktsDumpTypeMask
& BIT(HIF_RX_PKT_TYPE_DATA
)) {
2554 DBGLOG(SW4
, INFO
, ("QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr
), prHifRxHdr
->ucStaRecIdx
, prCurrSwRfb
->ucWlanIdx
, HIF_RX_HDR_GET_SN(prHifRxHdr
), /* The new SN of the frame */
2555 HIF_RX_HDR_GET_TID(prHifRxHdr
),
2556 prCurrSwRfb
->ucPacketType
,
2557 HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr
)));
2559 DBGLOG_MEM8(SW4
, TRACE
, (PUINT_8
) prCurrSwRfb
->pvHeader
,
2560 prCurrSwRfb
->u2PacketLen
);
2565 if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr
)) {
2567 UINT_8 ucNetTypeIdx
;
2568 P_BSS_INFO_T prBssInfo
;
2570 pucEthDestAddr
= prCurrSwRfb
->pvHeader
;
2571 ucNetTypeIdx
= HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr
);
2573 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[ucNetTypeIdx
]);
2574 /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */
2577 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr
)
2578 && (OP_MODE_ACCESS_POINT
!= prBssInfo
->eCurrentOPMode
)) {
2582 if (prAdapter
->rRxCtrl
.rFreeSwRfbList
.u4NumElem
2583 > (CFG_RX_MAX_PKT_NUM
- CFG_NUM_OF_QM_RX_PKT_NUM
)) {
2585 if (IS_BSS_ACTIVE(prBssInfo
)) {
2586 if (OP_MODE_ACCESS_POINT
== prBssInfo
->eCurrentOPMode
) {
2587 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr
)) {
2589 RX_PKT_DESTINATION_HOST_WITH_FORWARD
;
2591 if (UNEQUAL_MAC_ADDR
2592 (prBssInfo
->aucOwnMacAddr
,
2595 RX_PKT_DESTINATION_FORWARD
;
2596 /* TODO : need to check the dst mac is valid */
2597 /* If src mac is invalid, the packet will be freed in fw */
2599 } /* OP_MODE_ACCESS_POINT */
2602 ("Mark NULL the Packet for inactive Bss %u\n",
2604 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2605 QUEUE_INSERT_TAIL(&rReturnedQue
,
2606 (P_QUE_ENTRY_T
) prCurrSwRfb
);
2611 /* Dont not occupy other SW RFB */
2612 DBGLOG(QM
, TRACE
, ("Mark NULL the Packet for less Free Sw Rfb\n"));
2613 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2614 QUEUE_INSERT_TAIL(&rReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
2621 if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr
)) {
2622 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2623 qmProcessBarFrame(prAdapter
, prCurrSwRfb
, &rReturnedQue
);
2625 /* Reordering is not required for this packet, return it without buffering */
2626 else if (!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr
) || fgIsBMC
) {
2628 if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr
)) {
2629 UINT_8 ucNetTypeIdx
;
2630 P_BSS_INFO_T prBssInfo
;
2632 pucEthDestAddr
= prCurrSwRfb
->pvHeader
;
2633 ucNetTypeIdx
= HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr
);
2635 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[ucNetTypeIdx
]);
2637 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr
)
2638 && (OP_MODE_ACCESS_POINT
== prBssInfo
->eCurrentOPMode
)) {
2639 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_HOST_WITH_FORWARD
;
2643 QUEUE_INSERT_TAIL(&rReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
2645 /* Reordering is required for this packet */
2647 /* If this packet should dropped or indicated to the host immediately,
2648 * it should be enqueued into the rReturnedQue with specific flags. If
2649 * this packet should be buffered for reordering, it should be enqueued
2650 * into the reordering queue in the STA_REC rather than into the
2653 qmProcessPktWithReordering(prAdapter
, prCurrSwRfb
, &rReturnedQue
);
2656 } while (prNextSwRfb
);
2659 /* The returned list of SW_RFBs must end with a NULL pointer */
2660 if (QUEUE_IS_NOT_EMPTY(&rReturnedQue
)) {
2661 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T
) QUEUE_GET_TAIL(&rReturnedQue
), NULL
);
2664 return (P_SW_RFB_T
) QUEUE_GET_HEAD(&rReturnedQue
);
2668 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
2669 return prSwRfbListHead
;
2675 /*----------------------------------------------------------------------------*/
2677 * \brief Reorder the received packet
2679 * \param[in] prSwRfb The RX packet to process
2680 * \param[out] prReturnedQue The queue for indicating packets
2684 /*----------------------------------------------------------------------------*/
2686 qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter
,
2687 IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
2691 P_STA_RECORD_T prStaRec
;
2692 P_HIF_RX_HEADER_T prHifRxHdr
;
2693 P_RX_BA_ENTRY_T prReorderQueParm
;
2698 P_QUE_T prReorderQue
;
2699 /* P_SW_RFB_T prReorderedSwRfb; */
2701 DEBUGFUNC("qmProcessPktWithReordering");
2704 ASSERT(prReturnedQue
);
2705 ASSERT(prSwRfb
->prHifRxHdr
);
2707 prHifRxHdr
= prSwRfb
->prHifRxHdr
;
2708 prSwRfb
->ucStaRecIdx
= prHifRxHdr
->ucStaRecIdx
;
2709 prSwRfb
->u2SSN
= HIF_RX_HDR_GET_SN(prHifRxHdr
); /* The new SN of the frame */
2710 prSwRfb
->ucTid
= (UINT_8
) (HIF_RX_HDR_GET_TID(prHifRxHdr
));
2711 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
2713 /* Incorrect STA_REC index */
2714 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
2715 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2716 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2717 DBGLOG(QM
, WARN
, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
2718 prSwRfb
->ucStaRecIdx
));
2723 /* Check whether the STA_REC is activated */
2724 prStaRec
= &(prAdapter
->arStaRec
[prSwRfb
->ucStaRecIdx
]);
2728 if (!(prStaRec
->fgIsValid
)) {
2729 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2730 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2731 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2732 DBGLOG(QM
, WARN
, ("Reordering for an invalid STA_REC\n"));
2738 /* Check whether the BA agreement exists */
2739 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
2740 if (!prReorderQueParm
) {
2741 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2742 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2743 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2744 DBGLOG(QM
, WARN
, ("Reordering for a NULL ReorderQueParm\n"));
2751 /* Start to reorder packets */
2752 u4SeqNo
= (UINT_32
) (prSwRfb
->u2SSN
);
2753 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
2754 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
2755 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
2758 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2760 /* Case 1: Fall within */
2761 if /* 0 - start - sn - end - 4095 */
2762 (((u4WinStart
<= u4SeqNo
) && (u4SeqNo
<= u4WinEnd
))
2763 /* 0 - end - start - sn - 4095 */
2764 || ((u4WinEnd
< u4WinStart
) && (u4WinStart
<= u4SeqNo
))
2765 /* 0 - sn - end - start - 4095 */
2766 || ((u4SeqNo
<= u4WinEnd
) && (u4WinEnd
< u4WinStart
))) {
2768 qmInsertFallWithinReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
2770 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2771 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
2772 /* Let the first received packet pass the reorder check */
2774 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SeqNo
, u4WinStart
,
2777 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SeqNo
;
2778 prReorderQueParm
->u2WinEnd
=
2779 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
2780 1) % MAX_SEQ_NO_COUNT
;
2781 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
2786 qmPopOutDueToFallWithin(prReorderQueParm
, prReturnedQue
);
2788 /* Case 2: Fall ahead */
2790 /* 0 - start - end - sn - (start+2048) - 4095 */
2791 (((u4WinStart
< u4WinEnd
)
2792 && (u4WinEnd
< u4SeqNo
)
2793 && (u4SeqNo
< (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
2794 /* 0 - sn - (start+2048) - start - end - 4095 */
2795 || ((u4SeqNo
< u4WinStart
)
2796 && (u4WinStart
< u4WinEnd
)
2797 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
2798 /* 0 - end - sn - (start+2048) - start - 4095 */
2799 || ((u4WinEnd
< u4SeqNo
)
2800 && (u4SeqNo
< u4WinStart
)
2801 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))) {
2804 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2805 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
2806 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
2810 qmInsertFallAheadReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
2812 /* Advance the window after inserting a new tail */
2813 prReorderQueParm
->u2WinEnd
= (UINT_16
) u4SeqNo
;
2814 prReorderQueParm
->u2WinStart
=
2815 (((prReorderQueParm
->u2WinEnd
) - (prReorderQueParm
->u2WinSize
) +
2816 MAX_SEQ_NO_COUNT
+ 1)
2817 % MAX_SEQ_NO_COUNT
);
2819 qmPopOutDueToFallAhead(prReorderQueParm
, prReturnedQue
);
2822 /* Case 3: Fall behind */
2825 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2826 #if QM_RX_INIT_FALL_BEHIND_PASS
2827 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
2828 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
2829 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2830 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2836 /* An erroneous packet */
2837 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2838 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2839 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2848 VOID
qmProcessBarFrame(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
2851 P_STA_RECORD_T prStaRec
;
2852 P_HIF_RX_HEADER_T prHifRxHdr
;
2853 P_RX_BA_ENTRY_T prReorderQueParm
;
2858 P_QUE_T prReorderQue
;
2859 /* P_SW_RFB_T prReorderedSwRfb; */
2862 ASSERT(prReturnedQue
);
2863 ASSERT(prSwRfb
->prHifRxHdr
);
2865 prHifRxHdr
= prSwRfb
->prHifRxHdr
;
2866 prSwRfb
->ucStaRecIdx
= prHifRxHdr
->ucStaRecIdx
;
2867 prSwRfb
->u2SSN
= HIF_RX_HDR_GET_SN(prHifRxHdr
); /* The new SSN */
2868 prSwRfb
->ucTid
= (UINT_8
) (HIF_RX_HDR_GET_TID(prHifRxHdr
));
2870 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2871 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2873 /* Incorrect STA_REC index */
2874 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
2875 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
2876 prSwRfb
->ucStaRecIdx
));
2881 /* Check whether the STA_REC is activated */
2882 prStaRec
= &(prAdapter
->arStaRec
[prSwRfb
->ucStaRecIdx
]);
2886 if (!(prStaRec
->fgIsValid
)) {
2887 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2888 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
2894 /* Check whether the BA agreement exists */
2895 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
2896 if (!prReorderQueParm
) {
2897 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2898 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
2904 u4SSN
= (UINT_32
) (prSwRfb
->u2SSN
);
2905 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
2906 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
2907 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
2909 if (qmCompareSnIsLessThan(u4WinStart
, u4SSN
)) {
2910 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SSN
;
2911 prReorderQueParm
->u2WinEnd
=
2912 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
2913 1) % MAX_SEQ_NO_COUNT
;
2915 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb
->ucTid
, u4SSN
,
2916 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
2917 qmPopOutDueToFallAhead(prReorderQueParm
, prReturnedQue
);
2920 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SSN
, u4WinStart
,
2928 qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb
,
2929 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
2931 P_SW_RFB_T prExaminedQueuedSwRfb
;
2932 P_QUE_T prReorderQue
;
2934 ASSERT(prReorderQueParm
);
2935 ASSERT(prReturnedQue
);
2937 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
2938 prExaminedQueuedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
2940 /* There are no packets queued in the Reorder Queue */
2941 if (prExaminedQueuedSwRfb
== NULL
) {
2942 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
2943 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
2944 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
2945 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
2946 prReorderQue
->u4NumElem
++;
2949 /* Determine the insert position */
2952 /* Case 1: Terminate. A duplicate packet */
2953 if (((prExaminedQueuedSwRfb
->u2SSN
) == (prSwRfb
->u2SSN
))) {
2954 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
2955 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
2959 /* Case 2: Terminate. The insert point is found */
2960 else if (qmCompareSnIsLessThan((prSwRfb
->u2SSN
),
2961 (prExaminedQueuedSwRfb
->u2SSN
))) {
2965 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
2967 prExaminedQueuedSwRfb
=
2968 (P_SW_RFB_T
) (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prNext
);
2970 } while (prExaminedQueuedSwRfb
);
2972 /* Update the Reorder Queue Parameters according to the found insert position */
2973 if (prExaminedQueuedSwRfb
== NULL
) {
2974 /* The received packet shall be placed at the tail */
2975 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
2976 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
2977 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
2978 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) (prSwRfb
);
2980 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
=
2981 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
;
2982 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= (P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
;
2983 if (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
) == (prReorderQue
->prHead
)) {
2984 /* The received packet will become the head */
2985 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
2987 (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
)->prNext
=
2988 (P_QUE_ENTRY_T
) prSwRfb
;
2990 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
= (P_QUE_ENTRY_T
) prSwRfb
;
2993 prReorderQue
->u4NumElem
++;
3001 qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb
,
3002 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3004 P_QUE_T prReorderQue
;
3006 ASSERT(prReorderQueParm
);
3007 ASSERT(prReturnedQue
);
3009 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3011 /* There are no packets queued in the Reorder Queue */
3012 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3013 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
3014 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3015 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3017 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
3018 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3019 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
3021 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
3022 prReorderQue
->u4NumElem
++;
3027 VOID
qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3029 P_SW_RFB_T prReorderedSwRfb
;
3030 P_QUE_T prReorderQue
;
3031 BOOLEAN fgDequeuHead
, fgMissing
;
3032 OS_SYSTIME rCurrentTime
, *prMissTimeout
;
3034 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3038 prMissTimeout
= &(g_arMissTimeout
[prReorderQueParm
->ucStaRecIdx
][prReorderQueParm
->ucTid
]);
3039 if ((*prMissTimeout
)) {
3041 GET_CURRENT_SYSTIME(&rCurrentTime
);
3044 /* Check whether any packet can be indicated to the higher layer */
3046 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3050 /* Always examine the head packet */
3051 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3052 fgDequeuHead
= FALSE
;
3054 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3055 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3057 fgDequeuHead
= TRUE
;
3058 prReorderQueParm
->u2WinStart
=
3059 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3061 /* SN > WinStart, break to update WinEnd */
3063 if ((fgMissing
== TRUE
) &&
3064 CHECK_FOR_TIMEOUT(rCurrentTime
, (*prMissTimeout
),
3065 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
))) {
3067 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3068 prReorderQueParm
->ucTid
, prReorderedSwRfb
->u2SSN
));
3069 fgDequeuHead
= TRUE
;
3070 prReorderQueParm
->u2WinStart
=
3071 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3079 /* Dequeue the head packet */
3082 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3083 prReorderQue
->prHead
= NULL
;
3084 prReorderQue
->prTail
= NULL
;
3086 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3087 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3089 prReorderQue
->u4NumElem
--;
3090 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3091 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3095 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3098 if (fgMissing
== FALSE
) {
3099 GET_CURRENT_SYSTIME(prMissTimeout
);
3103 /* After WinStart has been determined, update the WinEnd */
3104 prReorderQueParm
->u2WinEnd
=
3105 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3106 1) % MAX_SEQ_NO_COUNT
);
3110 VOID
qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3112 P_SW_RFB_T prReorderedSwRfb
;
3113 P_QUE_T prReorderQue
;
3114 BOOLEAN fgDequeuHead
;
3116 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3118 /* Check whether any packet can be indicated to the higher layer */
3120 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3124 /* Always examine the head packet */
3125 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3126 fgDequeuHead
= FALSE
;
3128 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3129 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3131 fgDequeuHead
= TRUE
;
3132 prReorderQueParm
->u2WinStart
=
3133 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3136 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3137 else if (qmCompareSnIsLessThan((UINT_32
) (prReorderedSwRfb
->u2SSN
),
3138 (UINT_32
) (prReorderQueParm
->u2WinStart
))) {
3140 fgDequeuHead
= TRUE
;
3144 /* SN > WinStart, break to update WinEnd */
3150 /* Dequeue the head packet */
3153 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3154 prReorderQue
->prHead
= NULL
;
3155 prReorderQue
->prTail
= NULL
;
3157 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3158 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3160 prReorderQue
->u4NumElem
--;
3161 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3162 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3166 /* After WinStart has been determined, update the WinEnd */
3167 prReorderQueParm
->u2WinEnd
=
3168 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3169 1) % MAX_SEQ_NO_COUNT
);
3173 BOOLEAN
qmCompareSnIsLessThan(IN UINT_32 u4SnLess
, IN UINT_32 u4SnGreater
)
3175 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
3176 if ((u4SnLess
+ HALF_SEQ_NO_COUNT
) <= u4SnGreater
) { /* Shall be <= */
3180 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
3181 else if ((u4SnGreater
+ HALF_SEQ_NO_COUNT
) < u4SnLess
) {
3185 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
3186 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
3188 return (u4SnLess
< u4SnGreater
);
3193 /*----------------------------------------------------------------------------*/
3195 * \brief Handle Mailbox RX messages
3197 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
3201 /*----------------------------------------------------------------------------*/
3202 VOID
qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg
)
3204 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
3209 /*----------------------------------------------------------------------------*/
3211 * \brief Handle ADD RX BA Event from the FW
3213 * \param[in] prAdapter Adapter pointer
3214 * \param[in] prEvent The event packet from the FW
3218 /*----------------------------------------------------------------------------*/
3219 VOID
qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
3221 P_EVENT_RX_ADDBA_T prEventRxAddBa
;
3222 P_STA_RECORD_T prStaRec
;
3226 DBGLOG(QM
, INFO
, ("QM:Event +RxBa\n"));
3228 prEventRxAddBa
= (P_EVENT_RX_ADDBA_T
) prEvent
;
3229 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxAddBa
->ucStaRecIdx
);
3232 /* Invalid STA_REC index, discard the event packet */
3234 DBGLOG(QM
, INFO
, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
3238 if (!(prStaRec
->fgIsValid
)) {
3239 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3240 DBGLOG(QM
, WARN
, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
3246 u4Tid
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_TID_MASK
)
3247 >> BA_PARAM_SET_TID_MASK_OFFSET
);
3249 u4WinSize
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
3250 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
3252 if (!qmAddRxBaEntry(prAdapter
,
3255 (prEventRxAddBa
->u2BAStartSeqCtrl
>> OFFSET_BAR_SSC_SN
),
3256 (UINT_16
) u4WinSize
)) {
3258 /* FW shall ensure the availabiilty of the free-to-use BA entry */
3259 DBGLOG(QM
, ERROR
, ("QM: (Error) qmAddRxBaEntry() failure\n"));
3265 /*----------------------------------------------------------------------------*/
3267 * \brief Handle DEL RX BA Event from the FW
3269 * \param[in] prAdapter Adapter pointer
3270 * \param[in] prEvent The event packet from the FW
3274 /*----------------------------------------------------------------------------*/
3275 VOID
qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
3277 P_EVENT_RX_DELBA_T prEventRxDelBa
;
3278 P_STA_RECORD_T prStaRec
;
3280 /* DbgPrint("QM:Event -RxBa\n"); */
3282 prEventRxDelBa
= (P_EVENT_RX_DELBA_T
) prEvent
;
3283 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxDelBa
->ucStaRecIdx
);
3286 /* Invalid STA_REC index, discard the event packet */
3291 if (!(prStaRec
->fgIsValid
)) {
3292 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3298 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, prEventRxDelBa
->ucTid
, TRUE
);
3302 P_RX_BA_ENTRY_T
qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter
, UINT_8 ucStaRecIdx
, UINT_8 ucTid
)
3305 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
3307 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
3309 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
3310 if (prQM
->arRxBaTable
[i
].fgIsValid
) {
3311 if ((prQM
->arRxBaTable
[i
].ucStaRecIdx
== ucStaRecIdx
) &&
3312 (prQM
->arRxBaTable
[i
].ucTid
== ucTid
)) {
3313 return &prQM
->arRxBaTable
[i
];
3321 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter
,
3322 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN UINT_16 u2WinStart
, IN UINT_16 u2WinSize
)
3325 P_RX_BA_ENTRY_T prRxBaEntry
= NULL
;
3326 P_STA_RECORD_T prStaRec
;
3327 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
3329 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
3331 if (ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
3332 /* Invalid STA_REC index, discard the event packet */
3334 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
3339 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
3342 /* if(!(prStaRec->fgIsValid)){ */
3343 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
3347 /* 4 <1> Delete before adding */
3348 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3349 if (qmLookupRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
)) {
3350 qmDelRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
, TRUE
); /* prQM->ucRxBaCount-- */
3352 /* 4 <2> Add a new BA entry */
3353 /* No available entry to store the BA agreement info. Retrun FALSE. */
3354 if (prQM
->ucRxBaCount
>= CFG_NUM_OF_RX_BA_AGREEMENTS
) {
3356 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
3359 /* Find the free-to-use BA entry */
3360 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
3361 if (!prQM
->arRxBaTable
[i
].fgIsValid
) {
3362 prRxBaEntry
= &(prQM
->arRxBaTable
[i
]);
3363 prQM
->ucRxBaCount
++;
3364 DBGLOG(QM
, LOUD
, ("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
));
3369 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
3370 u2WinSize
+= CFG_RX_BA_INC_SIZE
;
3372 prRxBaEntry
->ucStaRecIdx
= ucStaRecIdx
;
3373 prRxBaEntry
->ucTid
= ucTid
;
3374 prRxBaEntry
->u2WinStart
= u2WinStart
;
3375 prRxBaEntry
->u2WinSize
= u2WinSize
;
3376 prRxBaEntry
->u2WinEnd
= ((u2WinStart
+ u2WinSize
- 1) % MAX_SEQ_NO_COUNT
);
3377 prRxBaEntry
->fgIsValid
= TRUE
;
3378 prRxBaEntry
->fgIsWaitingForPktWithSsn
= TRUE
;
3380 g_arMissTimeout
[ucStaRecIdx
][ucTid
] = 0;
3383 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
3384 ucStaRecIdx
, ucTid
, prRxBaEntry
->u2WinStart
, prRxBaEntry
->u2WinEnd
,
3385 prRxBaEntry
->u2WinSize
));
3387 /* Update the BA entry reference table for per-packet lookup */
3388 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = prRxBaEntry
;
3390 /* This shall not happen because FW should keep track of the usage of RX BA entries */
3392 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
3401 qmDelRxBaEntry(IN P_ADAPTER_T prAdapter
,
3402 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN BOOLEAN fgFlushToHost
)
3404 P_RX_BA_ENTRY_T prRxBaEntry
;
3405 P_STA_RECORD_T prStaRec
;
3406 P_SW_RFB_T prFlushedPacketList
= NULL
;
3407 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
3409 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
3411 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
3415 if (!(prStaRec
->fgIsValid
)) {
3416 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
3421 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3422 prRxBaEntry
= prStaRec
->aprRxReorderParamRefTbl
[ucTid
];
3426 prFlushedPacketList
= qmFlushStaRxQueue(prAdapter
, ucStaRecIdx
, ucTid
);
3428 if (prFlushedPacketList
) {
3430 if (fgFlushToHost
) {
3431 wlanProcessQueuedSwRfb(prAdapter
, prFlushedPacketList
);
3435 P_SW_RFB_T prNextSwRfb
;
3436 prSwRfb
= prFlushedPacketList
;
3440 (P_SW_RFB_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
)
3442 nicRxReturnRFB(prAdapter
, prSwRfb
);
3443 prSwRfb
= prNextSwRfb
;
3450 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
3451 /* Update RX BA entry state. Note that RX queue flush is not done here */
3452 prRxBaEntry
->fgIsValid
= FALSE
;
3453 prQM
->ucRxBaCount
--;
3457 DbgPrint("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
);
3460 /* Update STA RX BA table */
3461 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = NULL
;
3464 DBGLOG(QM
, INFO
, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx
, ucTid
));
3470 #if CFG_HIF_RX_STARVATION_WARNING
3472 P_RX_CTRL_T prRxCtrl
;
3473 prRxCtrl
= &prAdapter
->rRxCtrl
;
3475 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl
->u4QueuedCnt
,
3476 prRxCtrl
->u4DequeuedCnt
));
3482 /*----------------------------------------------------------------------------*/
3484 * \brief To process WMM related IEs in ASSOC_RSP
3486 * \param[in] prAdapter Adapter pointer
3487 * \param[in] prSwRfb The received frame
3488 * \param[in] pucIE The pointer to the first IE in the frame
3489 * \param[in] u2IELength The total length of IEs in the frame
3493 /*----------------------------------------------------------------------------*/
3495 mqmProcessAssocReq(IN P_ADAPTER_T prAdapter
,
3496 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
3498 P_STA_RECORD_T prStaRec
;
3501 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
3502 P_IE_WMM_INFO_T prIeWmmInfo
;
3504 DEBUGFUNC("mqmProcessAssocReq");
3509 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
3512 if (prStaRec
== NULL
) {
3516 prStaRec
->fgIsQoS
= FALSE
;
3517 prStaRec
->fgIsWmmSupported
= prStaRec
->fgIsUapsdSupported
= FALSE
;
3521 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
3522 if (!prAdapter
->rWifiVar
.fgSupportQoS
) {
3527 /* Determine whether QoS is enabled with the association */
3529 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
3530 switch (IE_ID(pucIE
)) {
3533 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
3534 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
3536 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
3537 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
3543 if (IE_LEN(pucIE
) != 7) {
3544 break; /* WMM Info IE with a wrong length */
3546 prStaRec
->fgIsQoS
= TRUE
;
3547 prStaRec
->fgIsWmmSupported
= TRUE
;
3549 prIeWmmInfo
= (P_IE_WMM_INFO_T
) pucIE
;
3550 ucQosInfo
= prIeWmmInfo
->ucQosInfo
;
3551 ucQosInfoAC
= ucQosInfo
& BITS(0, 3);
3553 prStaRec
->fgIsUapsdSupported
=
3554 ((ucQosInfoAC
) ? TRUE
: FALSE
) &
3555 prAdapter
->rWifiVar
.fgSupportUAPSD
;
3559 if (ucQosInfoAC
& WMM_QOS_INFO_VO_UAPSD
) {
3560 ucBmpAC
|= BIT(ACI_VO
);
3562 if (ucQosInfoAC
& WMM_QOS_INFO_VI_UAPSD
) {
3563 ucBmpAC
|= BIT(ACI_VI
);
3565 if (ucQosInfoAC
& WMM_QOS_INFO_BE_UAPSD
) {
3566 ucBmpAC
|= BIT(ACI_BE
);
3568 if (ucQosInfoAC
& WMM_QOS_INFO_BK_UAPSD
) {
3569 ucBmpAC
|= BIT(ACI_BK
);
3572 prStaRec
->ucBmpTriggerAC
=
3573 prStaRec
->ucBmpDeliveryAC
= ucBmpAC
;
3575 prStaRec
->ucUapsdSp
=
3577 WMM_QOS_INFO_MAX_SP_LEN_MASK
) >> 5;
3583 /* Other WMM QoS IEs. Ignore any */
3587 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3591 case ELEM_ID_HT_CAP
:
3592 /* Some client won't put the WMM IE if client is 802.11n */
3593 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
3594 prStaRec
->fgIsQoS
= TRUE
;
3602 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
3608 /*----------------------------------------------------------------------------*/
3610 * \brief To process WMM related IEs in ASSOC_RSP
3612 * \param[in] prAdapter Adapter pointer
3613 * \param[in] prSwRfb The received frame
3614 * \param[in] pucIE The pointer to the first IE in the frame
3615 * \param[in] u2IELength The total length of IEs in the frame
3619 /*----------------------------------------------------------------------------*/
3621 mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter
,
3622 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
3624 P_STA_RECORD_T prStaRec
;
3627 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
3629 DEBUGFUNC("mqmProcessAssocRsp");
3634 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
3637 if (prStaRec
== NULL
) {
3641 prStaRec
->fgIsQoS
= FALSE
;
3645 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
3646 prStaRec
->fgIsWmmSupported
, prAdapter
->rWifiVar
.fgSupportQoS
));
3648 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
3649 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
3650 if ((!prAdapter
->rWifiVar
.fgSupportQoS
)) {
3654 /* Determine whether QoS is enabled with the association */
3656 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
3657 switch (IE_ID(pucIE
)) {
3659 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
3660 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
3662 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
3663 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
3664 if (IE_LEN(pucIE
) != 24) {
3665 break; /* WMM Info IE with a wrong length */
3667 prStaRec
->fgIsQoS
= TRUE
;
3670 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
3671 if (IE_LEN(pucIE
) != 7) {
3672 break; /* WMM Info IE with a wrong length */
3674 prStaRec
->fgIsQoS
= TRUE
;
3678 /* Other WMM QoS IEs. Ignore any */
3682 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3685 case ELEM_ID_HT_CAP
:
3686 /* Some AP won't put the WMM IE if client is 802.11n */
3687 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
3688 prStaRec
->fgIsQoS
= TRUE
;
3696 /* Parse AC parameters and write to HW CRs */
3697 if ((prStaRec
->fgIsQoS
) && (prStaRec
->eStaType
== STA_TYPE_LEGACY_AP
)) {
3698 mqmParseEdcaParameters(prAdapter
, prSwRfb
, pucIEStart
, u2IELength
, TRUE
);
3701 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
3702 if (prStaRec
->fgIsWmmSupported
) {
3703 nicQmUpdateWmmParms(prAdapter
, prStaRec
->ucNetTypeIndex
);
3709 /*----------------------------------------------------------------------------*/
3711 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
3713 * \param[in] prAdapter Adapter pointer
3714 * \param[in] prSwRfb The received frame
3715 * \param[in] pucIE The pointer to the first IE in the frame
3716 * \param[in] u2IELength The total length of IEs in the frame
3717 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
3721 /*----------------------------------------------------------------------------*/
3723 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter
,
3724 IN P_SW_RFB_T prSwRfb
,
3725 IN PUINT_8 pucIE
, IN UINT_16 u2IELength
, IN BOOLEAN fgForceOverride
)
3727 P_STA_RECORD_T prStaRec
;
3729 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
3730 P_BSS_INFO_T prBssInfo
;
3732 DEBUGFUNC("mqmParseEdcaParameters");
3737 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
3740 if (prStaRec
== NULL
) {
3744 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
3745 prStaRec
->fgIsWmmSupported
, prStaRec
->fgIsQoS
));
3747 if ((!prAdapter
->rWifiVar
.fgSupportQoS
) || (!prStaRec
->fgIsWmmSupported
)
3748 || (!prStaRec
->fgIsQoS
)) {
3752 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prStaRec
->ucNetTypeIndex
]);
3754 /* Goal: Obtain the EDCA parameters */
3755 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
3756 switch (IE_ID(pucIE
)) {
3759 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
3760 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
3762 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
3763 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
3764 if (IE_LEN(pucIE
) != 24) {
3765 break; /* WMM Param IE with a wrong length */
3767 P_AC_QUE_PARMS_T prAcQueParams
;
3768 P_IE_WMM_PARAM_T prIeWmmParam
;
3769 ENUM_WMM_ACI_T eAci
;
3770 PUINT_8 pucWmmParamSetCount
;
3773 pucWmmParamSetCount
=
3774 &(prBssInfo
->ucWmmParamSetCount
);
3776 prIeWmmParam
= (P_IE_WMM_PARAM_T
) pucIE
;
3778 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
3779 if (!fgForceOverride
) {
3780 if (*pucWmmParamSetCount
==
3783 WMM_QOS_INFO_PARAM_SET_CNT
)) {
3784 break; /* Ignore the IE without updating HW CRs */
3788 /* Update Parameter Set Count */
3789 *pucWmmParamSetCount
=
3791 ucQosInfo
& WMM_QOS_INFO_PARAM_SET_CNT
);
3793 /* Update EDCA parameters */
3794 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
3797 &prBssInfo
->arACQueParms
[eAci
];
3798 mqmFillAcQueParam(prIeWmmParam
, eAci
,
3801 prAcQueParams
->fgIsACMSet
=
3803 u2Aifsn
& WMM_ACIAIFSN_ACM
) ? TRUE
:
3805 prAcQueParams
->u2Aifsn
&=
3809 ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
3810 eAci
, prAcQueParams
->fgIsACMSet
,
3811 prAcQueParams
->u2Aifsn
,
3812 prAcQueParams
->u2CWmin
,
3813 prAcQueParams
->u2CWmax
,
3814 prAcQueParams
->u2TxopLimit
));
3820 /* Other WMM QoS IEs. Ignore */
3825 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
3834 /*----------------------------------------------------------------------------*/
3836 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
3838 * \param[in] prAdapter Adapter pointer
3839 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
3840 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
3841 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
3845 /*----------------------------------------------------------------------------*/
3847 mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam
,
3848 IN UINT_32 u4AcOffset
, OUT P_AC_QUE_PARMS_T prAcQueParams
)
3850 prAcQueParams
->u2Aifsn
= *((PUINT_8
) (&(prIeWmmParam
->ucAciAifsn_BE
)) + (u4AcOffset
* 4));
3852 prAcQueParams
->u2CWmax
=
3853 BIT(((*((PUINT_8
) (&(prIeWmmParam
->ucEcw_BE
)) + (u4AcOffset
* 4))) & WMM_ECW_WMAX_MASK
)
3854 >> WMM_ECW_WMAX_OFFSET
) - 1;
3856 prAcQueParams
->u2CWmin
=
3857 BIT((*((PUINT_8
) (&(prIeWmmParam
->ucEcw_BE
)) + (u4AcOffset
* 4))) & WMM_ECW_WMIN_MASK
) -
3860 WLAN_GET_FIELD_16(((PUINT_8
) (&(prIeWmmParam
->aucTxopLimit_BE
)) + (u4AcOffset
* 4)),
3861 &(prAcQueParams
->u2TxopLimit
));
3863 prAcQueParams
->ucGuradTime
= TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME
;
3869 /*----------------------------------------------------------------------------*/
3871 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
3873 * \param[in] prAdapter Adapter pointer
3874 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
3875 * \param[out] prStaRec The obtained info is stored in the STA_REC
3879 /*----------------------------------------------------------------------------*/
3881 mqmProcessScanResult(IN P_ADAPTER_T prAdapter
,
3882 IN P_BSS_DESC_T prScanResult
, OUT P_STA_RECORD_T prStaRec
)
3887 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
3889 DEBUGFUNC("mqmProcessScanResult");
3891 ASSERT(prScanResult
);
3894 /* Reset the flag before parsing */
3895 prStaRec
->fgIsWmmSupported
= prStaRec
->fgIsUapsdSupported
= FALSE
;
3897 if (!prAdapter
->rWifiVar
.fgSupportQoS
) {
3901 u2IELength
= prScanResult
->u2IELength
;
3902 pucIE
= prScanResult
->aucIEBuf
;
3904 /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */
3905 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
3906 switch (IE_ID(pucIE
)) {
3908 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
3909 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
3911 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
3912 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
3913 if (IE_LEN(pucIE
) != 24) {
3914 break; /* WMM Param IE with a wrong length */
3916 prStaRec
->fgIsWmmSupported
= TRUE
;
3917 prStaRec
->fgIsUapsdSupported
=
3918 (((((P_IE_WMM_PARAM_T
) pucIE
)->
3919 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
3924 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
3925 if (IE_LEN(pucIE
) != 7) {
3926 break; /* WMM Info IE with a wrong length */
3928 prStaRec
->fgIsWmmSupported
= TRUE
;
3929 prStaRec
->fgIsUapsdSupported
=
3930 (((((P_IE_WMM_INFO_T
) pucIE
)->
3931 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
3937 /* A WMM QoS IE that doesn't matter. Ignore it. */
3941 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
3946 /* A WMM IE that doesn't matter. Ignore it. */
3950 DBGLOG(QM
, LOUD
, ("MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n",
3951 prStaRec
->fgIsWmmSupported
, prStaRec
->fgIsUapsdSupported
));
3956 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter
,
3957 IN PUINT_8 pucEthDestAddr
, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType
)
3960 P_STA_RECORD_T prTempStaRec
;
3962 prTempStaRec
= NULL
;
3966 /* 4 <1> DA = BMCAST */
3967 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr
)) {
3968 return STA_REC_INDEX_BMCAST
;
3971 /* 4 <2> Check if an AP STA is present */
3972 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
3973 prTempStaRec
= &(prAdapter
->arStaRec
[i
]);
3974 if ((prTempStaRec
->ucNetTypeIndex
== eNetworkType
)
3975 && (prTempStaRec
->fgIsAp
)
3976 && (prTempStaRec
->fgIsValid
)) {
3977 return prTempStaRec
->ucIndex
;
3981 /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */
3982 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
3983 prTempStaRec
= &(prAdapter
->arStaRec
[i
]);
3984 if (prTempStaRec
->fgIsValid
) {
3985 if (EQUAL_MAC_ADDR(prTempStaRec
->aucMacAddr
, pucEthDestAddr
)) {
3986 return prTempStaRec
->ucIndex
;
3992 /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */
3993 return STA_REC_INDEX_NOT_FOUND
;
3997 /*----------------------------------------------------------------------------*/
3999 * @brief Generate the WMM Info IE
4001 * \param[in] prAdapter Adapter pointer
4002 * @param prMsduInfo The TX MMPDU
4006 /*----------------------------------------------------------------------------*/
4007 VOID
mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
4009 P_IE_WMM_INFO_T prIeWmmInfo
;
4010 UINT_32 ucUapsd
[] = {
4011 WMM_QOS_INFO_BE_UAPSD
,
4012 WMM_QOS_INFO_BK_UAPSD
,
4013 WMM_QOS_INFO_VI_UAPSD
,
4014 WMM_QOS_INFO_VO_UAPSD
4016 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4018 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo
;
4019 P_BSS_INFO_T prBssInfo
;
4020 P_STA_RECORD_T prStaRec
;
4022 DEBUGFUNC("mqmGenerateWmmInfoIE");
4026 /* In case QoS is not turned off, exit directly */
4027 if (!prAdapter
->rWifiVar
.fgSupportQoS
) {
4031 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
4034 if (prStaRec
== NULL
) {
4038 if (!prStaRec
->fgIsWmmSupported
) {
4042 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prStaRec
->ucNetTypeIndex
]);
4044 prPmProfSetupInfo
= &prBssInfo
->rPmProfSetupInfo
;
4046 prIeWmmInfo
= (P_IE_WMM_INFO_T
)
4047 ((PUINT_8
) prMsduInfo
->prPacket
+ prMsduInfo
->u2FrameLength
);
4049 prIeWmmInfo
->ucId
= ELEM_ID_WMM
;
4050 prIeWmmInfo
->ucLength
= ELEM_MAX_LEN_WMM_INFO
;
4052 /* WMM-2.2.1 WMM Information Element Field Values */
4053 prIeWmmInfo
->aucOui
[0] = aucWfaOui
[0];
4054 prIeWmmInfo
->aucOui
[1] = aucWfaOui
[1];
4055 prIeWmmInfo
->aucOui
[2] = aucWfaOui
[2];
4056 prIeWmmInfo
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
4057 prIeWmmInfo
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_INFO
;
4059 prIeWmmInfo
->ucVersion
= VERSION_WMM
;
4060 prIeWmmInfo
->ucQosInfo
= 0;
4062 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4063 /* if(prAdapter->rWifiVar.fgSupportUAPSD){ */
4064 if (prAdapter
->rWifiVar
.fgSupportUAPSD
&& prStaRec
->fgIsUapsdSupported
) {
4066 UINT_8 ucQosInfo
= 0;
4070 /* Static U-APSD setting */
4071 for (i
= ACI_BE
; i
<= ACI_VO
; i
++) {
4072 if (prPmProfSetupInfo
->ucBmpDeliveryAC
& prPmProfSetupInfo
->
4073 ucBmpTriggerAC
& BIT(i
)) {
4074 ucQosInfo
|= (UINT_8
) ucUapsd
[i
];
4079 if (prPmProfSetupInfo
->ucBmpDeliveryAC
& prPmProfSetupInfo
->ucBmpTriggerAC
) {
4080 switch (prPmProfSetupInfo
->ucUapsdSp
) {
4081 case WMM_MAX_SP_LENGTH_ALL
:
4082 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_ALL
;
4085 case WMM_MAX_SP_LENGTH_2
:
4086 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
4089 case WMM_MAX_SP_LENGTH_4
:
4090 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_4
;
4093 case WMM_MAX_SP_LENGTH_6
:
4094 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_6
;
4098 DBGLOG(QM
, INFO
, ("MQM: Incorrect SP length\n"));
4099 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
4103 prIeWmmInfo
->ucQosInfo
= ucQosInfo
;
4107 /* Increment the total IE length for the Element ID and Length fields. */
4108 prMsduInfo
->u2FrameLength
+= IE_SIZE(prIeWmmInfo
);
4114 /*----------------------------------------------------------------------------*/
4116 * @brief log2 calculation for CW
4118 * @param[in] val value
4122 /*----------------------------------------------------------------------------*/
4124 UINT_32
cwlog2(UINT_32 val
)
4130 while (val
>= 512) {
4147 /*----------------------------------------------------------------------------*/
4149 * @brief Generate the WMM Param IE
4151 * \param[in] prAdapter Adapter pointer
4152 * @param prMsduInfo The TX MMPDU
4156 /*----------------------------------------------------------------------------*/
4157 VOID
mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
4159 P_IE_WMM_PARAM_T prIeWmmParam
;
4161 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4170 P_BSS_INFO_T prBssInfo
;
4171 P_STA_RECORD_T prStaRec
;
4172 ENUM_WMM_ACI_T eAci
;
4174 DEBUGFUNC("mqmGenerateWmmParamIE");
4175 DBGLOG(QM
, LOUD
, ("\n"));
4179 /* In case QoS is not turned off, exit directly */
4180 if (!prAdapter
->rWifiVar
.fgSupportQoS
) {
4184 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
4187 if (!prStaRec
->fgIsQoS
) {
4192 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prMsduInfo
->ucNetworkType
]);
4194 if (!prBssInfo
->fgIsQBSS
) {
4197 #if 0 /* 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. */
4198 if (prBssInfo
->eCurrentOPMode
!= OP_MODE_ACCESS_POINT
&&
4199 prBssInfo
->eCurrentOPMode
!= OP_MODE_BOW
) {
4204 prIeWmmParam
= (P_IE_WMM_PARAM_T
)
4205 ((PUINT_8
) prMsduInfo
->prPacket
+ prMsduInfo
->u2FrameLength
);
4207 prIeWmmParam
->ucId
= ELEM_ID_WMM
;
4208 prIeWmmParam
->ucLength
= ELEM_MAX_LEN_WMM_PARAM
;
4210 /* WMM-2.2.1 WMM Information Element Field Values */
4211 prIeWmmParam
->aucOui
[0] = aucWfaOui
[0];
4212 prIeWmmParam
->aucOui
[1] = aucWfaOui
[1];
4213 prIeWmmParam
->aucOui
[2] = aucWfaOui
[2];
4214 prIeWmmParam
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
4215 prIeWmmParam
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_PARAM
;
4217 prIeWmmParam
->ucVersion
= VERSION_WMM
;
4218 prIeWmmParam
->ucQosInfo
= (prBssInfo
->ucWmmParamSetCount
& WMM_QOS_INFO_PARAM_SET_CNT
);
4220 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4221 if (prAdapter
->rWifiVar
.fgSupportUAPSD
) {
4223 prIeWmmParam
->ucQosInfo
|= WMM_QOS_INFO_UAPSD
;
4227 /* EDCA parameter */
4229 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
4231 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
4232 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */
4233 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
4234 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
4235 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
4236 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
4238 *(((PUINT_8
) (&prIeWmmParam
->ucAciAifsn_BE
)) + (eAci
<< 2)) = (UINT_8
) (aucACI
[eAci
]
4241 arACQueParmsForBcast
4249 arACQueParmsForBcast
4252 (WMM_ACIAIFSN_AIFSN
)));
4254 *(((PUINT_8
) (&prIeWmmParam
->ucEcw_BE
)) + (eAci
<< 2)) = (UINT_8
) (0
4257 aucCWminLog2ForBcast
4262 aucCWmaxLog2ForBcast
4264 WMM_ECW_WMAX_OFFSET
)
4269 *(((PUINT_8
) (&prIeWmmParam
->ucEcw_BE
)) + (eAci
<< 2)) = (UINT_8
) (0
4273 arACQueParmsForBcast
4281 arACQueParmsForBcast
4285 WMM_ECW_WMAX_OFFSET
)
4291 WLAN_SET_FIELD_16(((PUINT_8
) (prIeWmmParam
->aucTxopLimit_BE
)) + (eAci
<< 2)
4292 , prBssInfo
->arACQueParmsForBcast
[eAci
].u2TxopLimit
);
4296 /* Increment the total IE length for the Element ID and Length fields. */
4297 prMsduInfo
->u2FrameLength
+= IE_SIZE(prIeWmmParam
);
4305 qmGetFrameAction(IN P_ADAPTER_T prAdapter
,
4306 IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType
,
4307 IN UINT_8 ucStaRecIdx
,
4308 IN P_MSDU_INFO_T prMsduInfo
, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType
)
4310 P_BSS_INFO_T prBssInfo
;
4311 P_STA_RECORD_T prStaRec
;
4312 P_WLAN_MAC_HEADER_T prWlanFrame
;
4313 UINT_16 u2TxFrameCtrl
;
4315 DEBUGFUNC("qmGetFrameAction");
4317 #if (NIC_TX_BUFF_COUNT_TC4 > 2)
4318 #define QM_MGMT_QUUEUD_THRESHOLD 2
4320 #define QM_MGMT_QUUEUD_THRESHOLD 1
4323 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD
<= (NIC_TX_BUFF_COUNT_TC4
));
4324 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD
> 0);
4326 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[eNetworkType
]);
4327 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, ucStaRecIdx
);
4329 /* XXX Check BOW P2P AIS time ot set active */
4330 if (!IS_BSS_ACTIVE(prBssInfo
)) {
4331 if (eFrameType
== FRAME_TYPE_MMPDU
) {
4332 prWlanFrame
= (P_WLAN_MAC_HEADER_T
) prMsduInfo
->prPacket
;
4333 u2TxFrameCtrl
= (prWlanFrame
->u2FrameCtrl
) & MASK_FRAME_TYPE
; /* Optimized for ARM */
4334 if ((u2TxFrameCtrl
== MAC_FRAME_DEAUTH
)
4335 && (prMsduInfo
->pfTxDoneHandler
== NULL
)) {
4336 return FRAME_ACTION_TX_PKT
;
4342 ("Drop packets Action (Inactive %u).\n", prBssInfo
->ucNetTypeIndex
));
4343 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_INACTIVE_BSS_DROP
);
4344 return FRAME_ACTION_DROP_PKT
;
4347 /* TODO Handle disconnect issue */
4349 /* P2P probe Request frame */
4351 if (eFrameType
== FRAME_TYPE_MMPDU
) {
4352 ASSERT(prMsduInfo
!= NULL
);
4353 prWlanFrame
= (P_WLAN_MAC_HEADER_T
) prMsduInfo
->prPacket
;
4354 u2TxFrameCtrl
= (prWlanFrame
->u2FrameCtrl
) & MASK_FRAME_TYPE
; /* Optimized for ARM */
4356 if (u2TxFrameCtrl
== MAC_FRAME_BEACON
) {
4357 if (prBssInfo
->fgIsNetAbsent
) {
4358 return FRAME_ACTION_DROP_PKT
;
4360 } else if (u2TxFrameCtrl
== MAC_FRAME_PROBE_RSP
) {
4361 if (prBssInfo
->fgIsNetAbsent
) {
4364 } else if (u2TxFrameCtrl
== MAC_FRAME_DEAUTH
) {
4365 if (prBssInfo
->fgIsNetAbsent
) {
4368 DBGLOG(P2P
, LOUD
, ("Sending DEAUTH Frame\n"));
4369 return FRAME_ACTION_TX_PKT
;
4371 /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */
4372 else if (u2TxFrameCtrl
== MAC_FRAME_ASSOC_REQ
4373 || u2TxFrameCtrl
== MAC_FRAME_AUTH
4374 || u2TxFrameCtrl
== MAC_FRAME_REASSOC_REQ
4375 || u2TxFrameCtrl
== MAC_FRAME_PROBE_REQ
4376 || u2TxFrameCtrl
== MAC_FRAME_ACTION
) {
4379 if (prStaRec
->fgIsInPS
) {
4380 if (nicTxGetResource(prAdapter
, TC4_INDEX
) >=
4381 QM_MGMT_QUUEUD_THRESHOLD
) {
4382 return FRAME_ACTION_TX_PKT
;
4384 return FRAME_ACTION_QUEUE_PKT
;
4388 return FRAME_ACTION_TX_PKT
;
4392 return FRAME_ACTION_TX_PKT
;
4394 if (!prStaRec
->fgIsInUse
) {
4395 return FRAME_ACTION_DROP_PKT
;
4399 } /* FRAME_TYPE_MMPDU */
4400 else if ((eFrameType
== FRAME_TYPE_802_1X
)) {
4403 return FRAME_ACTION_TX_PKT
;
4405 if (!prStaRec
->fgIsInUse
) {
4406 return FRAME_ACTION_DROP_PKT
;
4408 if (prStaRec
->fgIsInPS
) {
4409 if (nicTxGetResource(prAdapter
, TC4_INDEX
) >=
4410 QM_MGMT_QUUEUD_THRESHOLD
) {
4411 return FRAME_ACTION_TX_PKT
;
4413 return FRAME_ACTION_QUEUE_PKT
;
4418 } /* FRAME_TYPE_802_1X */
4419 else if ((!IS_BSS_ACTIVE(prBssInfo
))
4421 || (!prStaRec
->fgIsInUse
)) {
4422 return FRAME_ACTION_DROP_PKT
;
4426 if (prBssInfo
->fgIsNetAbsent
) {
4427 DBGLOG(QM
, LOUD
, ("Queue packets (Absent %u).\n", prBssInfo
->ucNetTypeIndex
));
4428 return FRAME_ACTION_QUEUE_PKT
;
4431 if (prStaRec
&& prStaRec
->fgIsInPS
) {
4432 DBGLOG(QM
, LOUD
, ("Queue packets (PS %u).\n", prStaRec
->fgIsInPS
));
4433 return FRAME_ACTION_QUEUE_PKT
;
4435 switch (eFrameType
) {
4436 case FRAME_TYPE_802_1X
:
4437 if (!prStaRec
->fgIsValid
) {
4438 return FRAME_ACTION_QUEUE_PKT
;
4442 case FRAME_TYPE_MMPDU
:
4450 return FRAME_ACTION_TX_PKT
;
4454 /*----------------------------------------------------------------------------*/
4456 * \brief Handle BSS change operation Event from the FW
4458 * \param[in] prAdapter Adapter pointer
4459 * \param[in] prEvent The event packet from the FW
4463 /*----------------------------------------------------------------------------*/
4464 VOID
qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4466 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus
;
4467 P_BSS_INFO_T prBssInfo
;
4468 BOOLEAN fgIsNetAbsentOld
;
4470 prEventBssStatus
= (P_EVENT_BSS_ABSENCE_PRESENCE_T
) prEvent
;
4471 prBssInfo
= &(prAdapter
->rWifiVar
.arBssInfo
[prEventBssStatus
->ucNetTypeIdx
]);
4472 fgIsNetAbsentOld
= prBssInfo
->fgIsNetAbsent
;
4473 prBssInfo
->fgIsNetAbsent
= prEventBssStatus
->fgIsAbsent
;
4474 prBssInfo
->ucBssFreeQuota
= prEventBssStatus
->ucBssFreeQuota
;
4476 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
4477 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
4479 DBGLOG(QM
, TRACE
, ("NAF=%d,%d,%d\n",
4480 prEventBssStatus
->ucNetTypeIdx
, prBssInfo
->fgIsNetAbsent
,
4481 prBssInfo
->ucBssFreeQuota
));
4483 if (!prBssInfo
->fgIsNetAbsent
) {
4484 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_27
);
4486 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_28
);
4488 /* From Absent to Present */
4489 if ((fgIsNetAbsentOld
) && (!prBssInfo
->fgIsNetAbsent
)) {
4490 kalSetEvent(prAdapter
->prGlueInfo
);
4495 /*----------------------------------------------------------------------------*/
4497 * \brief Handle STA change PS mode Event from the FW
4499 * \param[in] prAdapter Adapter pointer
4500 * \param[in] prEvent The event packet from the FW
4504 /*----------------------------------------------------------------------------*/
4505 VOID
qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4507 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode
;
4508 P_STA_RECORD_T prStaRec
;
4509 BOOLEAN fgIsInPSOld
;
4511 /* DbgPrint("QM:Event -RxBa\n"); */
4513 prEventStaChangePsMode
= (P_EVENT_STA_CHANGE_PS_MODE_T
) prEvent
;
4514 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaChangePsMode
->ucStaRecIdx
);
4519 fgIsInPSOld
= prStaRec
->fgIsInPS
;
4520 prStaRec
->fgIsInPS
= prEventStaChangePsMode
->fgIsInPs
;
4522 qmUpdateFreeQuota(prAdapter
,
4524 prEventStaChangePsMode
->ucUpdateMode
,
4525 prEventStaChangePsMode
->ucFreeQuota
);
4527 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
4528 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
4531 DBGLOG(QM
, TRACE
, ("PS=%d,%d\n",
4532 prEventStaChangePsMode
->ucStaRecIdx
, prStaRec
->fgIsInPS
));
4534 /* From PS to Awake */
4535 if ((fgIsInPSOld
) && (!prStaRec
->fgIsInPS
)) {
4536 kalSetEvent(prAdapter
->prGlueInfo
);
4541 /*----------------------------------------------------------------------------*/
4543 * \brief Update STA free quota Event from FW
4545 * \param[in] prAdapter Adapter pointer
4546 * \param[in] prEvent The event packet from the FW
4550 /*----------------------------------------------------------------------------*/
4551 VOID
qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4553 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota
;
4554 P_STA_RECORD_T prStaRec
;
4557 prEventStaUpdateFreeQuota
= (P_EVENT_STA_UPDATE_FREE_QUOTA_T
) prEvent
;
4558 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaUpdateFreeQuota
->ucStaRecIdx
);
4562 if (prStaRec
->fgIsInPS
) {
4563 qmUpdateFreeQuota(prAdapter
,
4565 prEventStaUpdateFreeQuota
->ucUpdateMode
,
4566 prEventStaUpdateFreeQuota
->ucFreeQuota
);
4568 kalSetEvent(prAdapter
->prGlueInfo
);
4572 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
4573 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
4574 prEventStaUpdateFreeQuota
->ucUpdateMode
,
4575 prEventStaUpdateFreeQuota
->ucFreeQuota
));
4578 DBGLOG(QM
, TRACE
, ("UFQ=%d,%d,%d\n",
4579 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
4580 prEventStaUpdateFreeQuota
->ucUpdateMode
,
4581 prEventStaUpdateFreeQuota
->ucFreeQuota
));
4589 /*----------------------------------------------------------------------------*/
4591 * \brief Update STA free quota
4593 * \param[in] prStaRec the STA
4594 * \param[in] ucUpdateMode the method to update free quota
4595 * \param[in] ucFreeQuota the value for update
4599 /*----------------------------------------------------------------------------*/
4601 qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter
,
4602 IN P_STA_RECORD_T prStaRec
, IN UINT_8 ucUpdateMode
, IN UINT_8 ucFreeQuota
)
4605 UINT_8 ucFreeQuotaForNonDelivery
;
4606 UINT_8 ucFreeQuotaForDelivery
;
4609 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
4610 prStaRec
->ucFreeQuota
, ucUpdateMode
, ucFreeQuota
));
4612 if (!prStaRec
->fgIsInPS
)
4615 switch (ucUpdateMode
) {
4616 case FREE_QUOTA_UPDATE_MODE_INIT
:
4617 case FREE_QUOTA_UPDATE_MODE_OVERWRITE
:
4618 prStaRec
->ucFreeQuota
= ucFreeQuota
;
4620 case FREE_QUOTA_UPDATE_MODE_INCREASE
:
4621 prStaRec
->ucFreeQuota
+= ucFreeQuota
;
4623 case FREE_QUOTA_UPDATE_MODE_DECREASE
:
4624 prStaRec
->ucFreeQuota
-= ucFreeQuota
;
4630 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec
->ucFreeQuota
));
4632 ucFreeQuota
= prStaRec
->ucFreeQuota
;
4634 ucFreeQuotaForNonDelivery
= 0;
4635 ucFreeQuotaForDelivery
= 0;
4637 if (ucFreeQuota
> 0) {
4638 if (prStaRec
->fgIsQoS
&& prStaRec
->fgIsUapsdSupported
4639 /* && prAdapter->rWifiVar.fgSupportQoS
4640 && prAdapter->rWifiVar.fgSupportUAPSD */) {
4641 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
4643 if (prStaRec
->ucFreeQuotaForNonDelivery
> 0
4644 && prStaRec
->ucFreeQuotaForDelivery
> 0) {
4645 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
4646 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
4647 } else if (prStaRec
->ucFreeQuotaForNonDelivery
== 0
4648 && prStaRec
->ucFreeQuotaForDelivery
== 0) {
4649 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
4650 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
4651 } else if (prStaRec
->ucFreeQuotaForNonDelivery
> 0) {
4652 /* NonDelivery is not busy */
4653 if (ucFreeQuota
>= 3) {
4654 ucFreeQuotaForNonDelivery
= 2;
4655 ucFreeQuotaForDelivery
=
4656 ucFreeQuota
- ucFreeQuotaForNonDelivery
;
4658 ucFreeQuotaForDelivery
= ucFreeQuota
;
4659 ucFreeQuotaForNonDelivery
= 0;
4661 } else if (prStaRec
->ucFreeQuotaForDelivery
> 0) {
4662 /* Delivery is not busy */
4663 if (ucFreeQuota
>= 3) {
4664 ucFreeQuotaForDelivery
= 2;
4665 ucFreeQuotaForNonDelivery
=
4666 ucFreeQuota
- ucFreeQuotaForDelivery
;
4668 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
4669 ucFreeQuotaForDelivery
= 0;
4674 /* !prStaRec->fgIsUapsdSupported */
4675 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
4676 ucFreeQuotaForDelivery
= 0;
4679 /* ucFreeQuota > 0 */
4680 prStaRec
->ucFreeQuotaForDelivery
= ucFreeQuotaForDelivery
;
4681 prStaRec
->ucFreeQuotaForNonDelivery
= ucFreeQuotaForNonDelivery
;
4683 DBGLOG(QM
, LOUD
, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
4684 prStaRec
->ucFreeQuotaForDelivery
, prStaRec
->ucFreeQuotaForNonDelivery
));
4688 /*----------------------------------------------------------------------------*/
4690 * \brief Return the reorder queued RX packets
4694 * \return The number of queued RX packets
4696 /*----------------------------------------------------------------------------*/
4697 UINT_32
qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter
)
4700 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4702 /* XXX The summation may impact the performance */
4703 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
4704 u4Total
+= prQM
->arRxBaTable
[i
].rReOrderQue
.u4NumElem
;
4706 if (QUEUE_IS_EMPTY(&(prQM
->arRxBaTable
[i
].rReOrderQue
))) {
4707 ASSERT(prQM
->arRxBaTable
[i
].rReOrderQue
== 0);
4711 ASSERT(u4Total
<= (CFG_NUM_OF_QM_RX_PKT_NUM
* 2));