2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#3 $
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.
18 ** 11 04 2013 terry.wu
19 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
20 ** 1. Fix Tx resource counter calculation issue
21 ** 2. Add more protection for Tx pending counter equals to 0 issue
23 ** 10 29 2013 tsaiyuan.hsu
24 ** [BORA00002222] MT6630 unified MAC RXM
25 ** fix the wlan index when rx control frames.
27 ** 10 16 2013 terry.wu
28 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
29 ** Refine per-STA dequeue algorithm
31 ** 09 25 2013 tsaiyuan.hsu
32 ** [BORA00002222] MT6630 unified MAC RXM
33 ** not check duplication for BMC packets.
35 ** 09 25 2013 terry.wu
36 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
37 ** Add fast TC resource adjustment feature
39 ** 09 24 2013 tsaiyuan.hsu
40 ** [BORA00002222] MT6630 unified MAC RXM
41 ** check if through header translated by HW before enter into reordering buffer.
43 ** 08 30 2013 yuche.tsai
44 ** [BORA00002761] [MT6630][Wi-Fi Direct][Driver] Group Interface formation
45 ** Fix Wi-Fi Direct Tx Probe Request Channel Bug.
47 ** 08 23 2013 terry.wu
48 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
49 ** 1. Reset MSDU_INFO for data packet to avoid unexpected Tx status
50 ** 2. Drop Tx packet to non-associated STA in driver
52 ** 08 19 2013 terry.wu
53 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
54 ** 1. Enable TC resource adjust feature
55 ** 2. Set Non-QoS data frame to TC5
57 ** 08 07 2013 tsaiyuan.hsu
58 ** [BORA00002222] MT6630 unified MAC RXM
61 ** 08 06 2013 tsaiyuan.hsu
62 ** [BORA00002222] MT6630 unified MAC RXM
63 ** change the sequence to retrive SSN by group4.
65 ** 08 06 2013 terry.wu
66 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
67 ** Set BMC packet retry limit to unlimit
69 ** 08 05 2013 terry.wu
70 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
71 ** 1. Change BMC Q resource counter to page
73 ** 07 31 2013 terry.wu
74 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
75 ** 1. Fix NetDev binding issue
78 ** [BORA00002446] [MT6630] [Wi-Fi] [Driver] Update the security function code
79 ** Add Rx TKIP mic check
81 ** 07 30 2013 tsaiyuan.hsu
82 ** [BORA00002222] MT6630 unified MAC RXM
83 ** add defragmentation.
85 ** 07 29 2013 tsaiyuan.hsu
86 ** [BORA00002222] MT6630 unified MAC RXM
87 ** enable rx duplicate check.
89 ** 07 26 2013 terry.wu
90 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
91 ** 1. Reduce extra Tx frame header parsing
92 ** 2. Add TX port control
93 ** 3. Add net interface to BSS binding
95 ** 07 18 2013 terry.wu
96 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
97 ** 1. Update TxDesc PF bit setting rule
98 ** 2. Remove unnecessary QM function
100 ** 07 12 2013 tsaiyuan.hsu
101 ** [BORA00002222] MT6630 unified MAC RXM
102 ** 1. fix rx groups retrival.
103 ** 2. avoid reordering if bmc packets
105 ** 07 10 2013 terry.wu
106 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
107 ** 1. Fix KE at qmEnqueueTxPackets while turning off
108 ** 2. Temp solution for Tx protected data packet
110 ** 07 04 2013 terry.wu
111 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
112 ** Update Tx path for 1x packet
114 ** 07 04 2013 terry.wu
115 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
116 ** Update for 1st Connection.
118 ** 07 03 2013 tsaiyuan.hsu
119 ** [BORA00002222] MT6630 unified MAC RXM
122 ** 07 03 2013 tsaiyuan.hsu
123 ** [BORA00002222] MT6630 unified MAC RXM
124 ** 1. correct header offset
125 ** 2. tentatively disable duplicate check .
127 ** 03 20 2013 tsaiyuan.hsu
128 ** [BORA00002222] MT6630 unified MAC RXM
129 ** add rx duplicate check.
131 ** 03 12 2013 tsaiyuan.hsu
132 ** [BORA00002222] MT6630 unified MAC RXM
133 ** add rx data and mangement processing.
135 ** 03 12 2013 terry.wu
136 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
137 ** Update Tx utility function for management frame
140 ** [BORA00002227] [MT6630 Wi-Fi][Driver] Update for Makefile and HIFSYS modifications
141 ** take use of GET_BSS_INFO_BY_INDEX() and MAX_BSS_INDEX macros
142 ** for correctly indexing of BSS-INFO pointers
144 ** 01 28 2013 cm.chang
145 ** [BORA00002149] [MT6630 Wi-Fi] Initial software development
149 ** [BORA00002253] [MT6630 Wi-Fi][Driver][Firmware] Add NLO and timeout mechanism to SCN module
150 ** modification for ucBssIndex migration
152 ** 01 21 2013 terry.wu
153 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
154 ** Update TX path based on new ucBssIndex modifications.
156 ** 01 15 2013 terry.wu
157 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
158 ** Update Tx done resource release mechanism.
160 ** 12 27 2012 terry.wu
161 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
162 ** Update MQM index mapping mechanism
165 ** 3. ACI to network TC resource
167 ** 12 21 2012 terry.wu
168 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
169 ** Update TxD template feature.
171 ** 12 18 2012 terry.wu
172 ** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
173 ** Page count resource management.
175 ** 09 17 2012 cm.chang
176 ** [BORA00002149] [MT6630 Wi-Fi] Initial software development
177 ** Duplicate source from MT6620 v2.3 driver branch
178 ** (Davinci label: MT6620_WIFI_Driver_V2_3_120913_1942_As_MT6630_Base)
180 * 03 02 2012 terry.wu
182 * Sync CFG80211 modification from branch 2,2.
184 * 02 23 2012 eddie.chen
185 * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule
186 * Change the enqueue policy when ACM = 1.
188 * 11 22 2011 yuche.tsai
190 * Code refine, remove one #if 0 code.
192 * 11 19 2011 eddie.chen
193 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
196 * 11 18 2011 yuche.tsai
198 * CONFIG P2P support RSSI query, default turned off.
200 * 11 18 2011 eddie.chen
201 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
202 * Fix xlog format to hex format
204 * 11 17 2011 tsaiyuan.hsu
205 * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3.
206 * avoid deactivating staRec when changing state from 3 to 3.
208 * 11 11 2011 tsaiyuan.hsu
209 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
210 * add debug msg for xlog.
212 * 11 11 2011 tsaiyuan.hsu
213 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
214 * add debug counters of bb and ar for xlog.
216 * 11 10 2011 eddie.chen
217 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
218 * Use short name for xlog.
220 * 11 10 2011 eddie.chen
221 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
222 * Modify the QM xlog level and remove LOG_FUNC.
224 * 11 10 2011 chinglan.wang
226 * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP.
228 * 11 09 2011 chinglan.wang
230 * [WiFi direct]Can't make P2P connect via PBC.
232 * 11 08 2011 eddie.chen
233 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
236 * 11 07 2011 tsaiyuan.hsu
237 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
238 * add debug counters and periodically dump counters for debugging.
240 * 11 01 2011 chinglan.wang
242 * Modify the Wi-Fi method of the flush TX queue when disconnect the AP.
243 * 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..
246 * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check un-expect
247 * let the Rx BA accept even the sta not valid.
249 * 09 28 2011 tsaiyuan.hsu
250 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
251 * enlarge window size only by 4.
253 * 09 01 2011 tsaiyuan.hsu
254 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
255 * set rx window size as twice buffer size.
257 * 08 23 2011 yuche.tsai
259 * Fix multicast address list issue.
261 * 08 03 2011 tsaiyuan.hsu
262 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
263 * force window size at least 16.
265 * 08 02 2011 yuche.tsai
266 * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue.
267 * Fix GO send deauth frame issue.
269 * 07 26 2011 eddie.chen
270 * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter
271 * API for query the RX reorder queued packets counter.
273 * 07 07 2011 eddie.chen
274 * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS.
275 * Add setEvent when free quota is updated.
277 * 07 05 2011 eddie.chen
278 * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS.
279 * Send 1x when peer STA is in PS.
281 * 05 31 2011 eddie.chen
282 * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931
283 * Fix the QM quota in MT5931.
285 * 05 11 2011 eddie.chen
286 * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
287 * Fix dest type when GO packet copying.
289 * 05 09 2011 yuche.tsai
290 * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved)
291 * Deauthentication frame is not bound to network active status.
293 * 05 09 2011 eddie.chen
294 * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
295 * Check free number before copying broadcast packet.
297 * 04 14 2011 eddie.chen
298 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
299 * Check the SW RFB free. Fix the compile warning..
301 * 04 12 2011 eddie.chen
302 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
303 * Fix the sta index in processing security frame
304 * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4
307 * 04 11 2011 yuche.tsai
308 * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue.
309 * Fix kernel panic issue when MMPDU of P2P is pending in driver.
311 * 04 08 2011 eddie.chen
312 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
315 * 03 28 2011 eddie.chen
316 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
317 * Fix Klockwork warning.
319 * 03 28 2011 eddie.chen
320 * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW
321 * Fix wmm parameters in beacon for BOW.
323 * 03 15 2011 eddie.chen
324 * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter
325 * Add sw debug counter for QM.
327 * 02 23 2011 eddie.chen
328 * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap
329 * Fix parsing WMM INFO and bmp delivery bitmap definition.
331 * 02 17 2011 eddie.chen
332 * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel
333 * 1) Chnage GetFrameAction decision when BSS is absent.
334 * 2) Check channel and resource in processing ProbeRequest
336 * 02 08 2011 eddie.chen
337 * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode
338 * Add event STA agint timeout
340 * 01 27 2011 tsaiyuan.hsu
341 * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support
343 * 1. not support 11r, only use strength of signal to determine roaming.
344 * 2. not enable CFG_SUPPORT_ROAMING until completion of full test.
345 * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw
346 * 4. assume that change of link quality in smooth way.
348 * 01 25 2011 yuche.tsai
349 * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record.
350 * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role.
352 * 01 24 2011 eddie.chen
353 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
356 * 01 24 2011 eddie.chen
357 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
358 * Add destination decision in AP mode.
361 * [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!!!
362 * Allow 802.1x can be send even the net is not active due the drver / fw sync issue.
364 * 01 13 2011 eddie.chen
365 * [WCXRP00000322] Add WMM IE in beacon,
366 Add per station flow control when STA is in PS
367 * Fix typo and compile error.
369 * 01 12 2011 eddie.chen
370 * [WCXRP00000322] Add WMM IE in beacon,
371 Add per station flow control when STA is in PS
372 * Fix WMM parameter condition for STA
374 * 01 12 2011 eddie.chen
375 * [WCXRP00000322] Add WMM IE in beacon,
376 Add per station flow control when STA is in PS
377 * 1) Check Bss if support QoS before adding WMMIE
378 * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control
380 * 01 12 2011 george.huang
381 * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability
382 * Update MQM for WMM IE generation method
384 * 01 11 2011 eddie.chen
385 * [WCXRP00000322] Add WMM IE in beacon,
386 Add per station flow control when STA is in PS
388 * Add per STA flow control when STA is in PS mode
390 * 01 03 2011 george.huang
391 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
392 * update prStaRec->fgIsUapsdSupported flag.
394 * 12 29 2010 eddie.chen
395 * [WCXRP00000322] Add WMM IE in beacon,
396 Add per station flow control when STA is in PS
398 * Add WMM parameter for broadcast.
400 * 12 29 2010 eddie.chen
401 * [WCXRP00000322] Add WMM IE in beacon,
402 Add per station flow control when STA is in PS
404 * 1) PS flow control event
406 * 2) WMM IE in beacon, assoc resp, probe resp
408 * 12 23 2010 george.huang
409 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
410 * 1. update WMM IE parsing, with ASSOC REQ handling
411 * 2. extend U-APSD parameter passing from driver to FW
414 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
415 * use the #14 and modify the add code for check MMPDU.
418 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
419 * only MMPDU not check the netActive flag.
422 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
423 * not check the netActive flag for mgmt .
426 * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only
427 * remove ENUM_NETWORK_TYPE_T definitions
429 * 09 21 2010 kevin.huang
430 * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
431 * Eliminate Linux Compile Warning
433 * 08 30 2010 yarco.yang
435 * Fixed klockwork error message
437 * 08 18 2010 yarco.yang
439 * 1. Fixed HW checksum offload function not work under Linux issue.
440 * 2. Add debug message.
442 * 08 10 2010 yarco.yang
446 * 08 06 2010 yarco.yang
448 * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action
452 * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet
453 * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found
455 * 07 20 2010 yarco.yang
457 * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake
459 * 07 16 2010 yarco.yang
461 * 1. Support BSS Absence/Presence Event
462 * 2. Support STA change PS mode Event
463 * 3. Support BMC forwarding for AP mode.
465 * 07 14 2010 yarco.yang
467 * 1. Remove CFG_MQM_MIGRATION
468 * 2. Add CMD_UPDATE_WMM_PARMS command
470 * 07 13 2010 yarco.yang
473 * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing
475 * 07 09 2010 yarco.yang
477 * [MT6620 and MT5931] SW Migration: Add ADDBA support
481 * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
483 * 07 08 2010 yarco.yang
484 * [WPD00003837][MT6620]Data Path Refine
487 * 07 06 2010 yarco.yang
488 * [WPD00003837][MT6620]Data Path Refine
489 * Use fgInUse instead of fgIsValid for De-queue judgement
491 * 07 06 2010 yarco.yang
492 * [WPD00003837][MT6620]Data Path Refine
493 * For MMPDU, STA_REC will be decided by caller module
495 * 07 06 2010 yarco.yang
496 * [WPD00003837][MT6620]Data Path Refine
497 * Add MGMT Packet type for HIF_TX_HEADER
499 * 06 29 2010 yarco.yang
500 * [WPD00003837][MT6620]Data Path Refine
501 * replace g_rQM with Adpater->rQM
504 * [WPD00003833][MT6620 and MT5931] Driver migration
505 * add API in que_mgt to retrieve sta-rec index for security frames.
507 * 06 23 2010 yarco.yang
508 * [WPD00003837][MT6620]Data Path Refine
509 * Merge g_arStaRec[] into adapter->arStaRec[]
511 * 06 21 2010 yarco.yang
512 * [WPD00003837][MT6620]Data Path Refine
513 * Support CFG_MQM_MIGRATION flag
516 * [WPD00003833][MT6620 and MT5931] Driver migration
517 * 1) migrate assoc.c.
518 * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness
519 * 3) add configuration options for CNM_MEM and RSN modules
520 * 4) add data path for management frames
521 * 5) eliminate rPacketInfo of MSDU_INFO_T
523 * 06 06 2010 kevin.huang
524 * [WPD00003832][MT6620 5931] Create driver base
525 * [MT6620 5931] Create driver base
527 * 03 31 2010 tehuang.liu
528 * [WPD00001943]Create WiFi test driver framework on WinXP
529 * Refined the debug msg
532 * [WPD00001943]Create WiFi test driver framework on WinXP
533 * comment out one assertion which refer to undefined data member.
535 * 03 30 2010 tehuang.liu
536 * [WPD00001943]Create WiFi test driver framework on WinXP
537 * Enabled adaptive TC resource control
539 * 03 24 2010 jeffrey.chang
540 * [WPD00003826]Initial import for Linux port
541 * initial import for Linux port
543 * 03 17 2010 tehuang.liu
544 * [WPD00001943]Create WiFi test driver framework on WinXP
545 * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST)
547 * 03 11 2010 tehuang.liu
548 * [WPD00001943]Create WiFi test driver framework on WinXP
549 * Fixed buffer leak when processing BAR frames
551 * 03 02 2010 tehuang.liu
552 * [WPD00001943]Create WiFi test driver framework on WinXP
553 * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5
555 * 03 01 2010 tehuang.liu
556 * [WPD00001943]Create WiFi test driver framework on WinXP
557 * Fixed STA_REC index determination bug (fgIsValid shall be checked)
559 * 02 25 2010 tehuang.liu
560 * [WPD00001943]Create WiFi test driver framework on WinXP
561 * Refined function qmDetermineStaRecIndex() for BMCAST packets
563 * 02 25 2010 tehuang.liu
564 * [WPD00001943]Create WiFi test driver framework on WinXP
565 * Enabled multi-STA TX path with fairness
567 * 02 24 2010 tehuang.liu
568 * [WPD00001943]Create WiFi test driver framework on WinXP
569 * Enabled dynamically activating and deactivating STA_RECs
571 * 02 24 2010 tehuang.liu
572 * [WPD00001943]Create WiFi test driver framework on WinXP
573 * Added code for dynamic activating and deactivating STA_RECs.
575 * 01 13 2010 tehuang.liu
576 * [WPD00001943]Create WiFi test driver framework on WinXP
577 * Enabled the 802.1x path
579 * 01 13 2010 tehuang.liu
580 * [WPD00001943]Create WiFi test driver framework on WinXP
581 * Enabled the Burst_End Indication mechanism
582 ** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468
583 ** Fixed casting for qmAddRxBaEntry()
584 ** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752
585 ** remove SD1_SD3.. flag
586 ** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468
587 ** Added RX buffer reordering functions
588 ** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468
589 ** Modified Flush Queue function to let queues be reinitialized
590 ** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468
591 ** Added flushing per-Type queues code
592 ** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468
593 ** Added Debug msgs and fixed incorrect assert
594 ** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468
595 ** Bug fixing (qmDequeueTxPackets local variable initialization)
596 ** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752
597 ** correct and surpress PREfast warning
598 ** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468
599 ** Used SD1_SD3_DATAPATH_INTEGRATION
600 ** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468
605 /*******************************************************************************
606 * C O M P I L E R F L A G S
607 ********************************************************************************
610 /*******************************************************************************
611 * E X T E R N A L R E F E R E N C E S
612 ********************************************************************************
617 extern UINT_8 g_arTdlsLink
[MAXNUM_TDLS_PEER
];
619 /*******************************************************************************
621 ********************************************************************************
624 /*******************************************************************************
626 ********************************************************************************
629 /*******************************************************************************
630 * P U B L I C D A T A
631 ********************************************************************************
633 OS_SYSTIME g_arMissTimeout
[CFG_STA_REC_NUM
][CFG_RX_MAX_BA_TID_NUM
];
635 const UINT_8 aucTid2ACI
[TX_DESC_TID_NUM
] = {
636 WMM_AC_BE_INDEX
, /* TID0 */
637 WMM_AC_BK_INDEX
, /* TID1 */
638 WMM_AC_BK_INDEX
, /* TID2 */
639 WMM_AC_BE_INDEX
, /* TID3 */
640 WMM_AC_VI_INDEX
, /* TID4 */
641 WMM_AC_VI_INDEX
, /* TID5 */
642 WMM_AC_VO_INDEX
, /* TID6 */
643 WMM_AC_VO_INDEX
/* TID7 */
646 const UINT_8 aucACI2TxQIdx
[WMM_AC_INDEX_NUM
] = {
647 TX_QUEUE_INDEX_AC1
, /* WMM_AC_BE_INDEX */
648 TX_QUEUE_INDEX_AC0
, /* WMM_AC_BK_INDEX */
649 TX_QUEUE_INDEX_AC2
, /* WMM_AC_VI_INDEX */
650 TX_QUEUE_INDEX_AC3
/* WMM_AC_VO_INDEX */
653 const UINT_8 arNetwork2TcResource
[HW_BSSID_NUM
+ 1][NET_TC_NUM
] = {
655 /* AC_BE, AC_BK, AC_VI, AC_VO, MGMT, non-StaRec/non-QoS/BMC */
656 {TC1_INDEX
, TC0_INDEX
, TC2_INDEX
, TC3_INDEX
, TC4_INDEX
, TC5_INDEX
}, /* AIS */
657 {TC1_INDEX
, TC0_INDEX
, TC2_INDEX
, TC3_INDEX
, TC4_INDEX
, TC5_INDEX
}, /* P2P/BoW */
658 {TC1_INDEX
, TC0_INDEX
, TC2_INDEX
, TC3_INDEX
, TC4_INDEX
, TC5_INDEX
}, /* P2P/BoW */
659 {TC1_INDEX
, TC0_INDEX
, TC2_INDEX
, TC3_INDEX
, TC4_INDEX
, TC5_INDEX
}, /* P2P/BoW */
660 {TC1_INDEX
, TC0_INDEX
, TC2_INDEX
, TC3_INDEX
, TC4_INDEX
, TC5_INDEX
}, /* P2P_DEV */
663 /* {TC7_INDEX, TC6_INDEX, TC8_INDEX, TC9_INDEX, TC4_INDEX, TC10_INDEX}, */
666 const UINT_8 aucWmmAC2TcResourceSet1
[WMM_AC_INDEX_NUM
] = {
673 #if NIC_TX_ENABLE_SECOND_HW_QUEUE
674 const UINT_8 aucWmmAC2TcResourceSet2
[WMM_AC_INDEX_NUM
] = {
681 /*******************************************************************************
682 * P R I V A T E D A T A
683 ********************************************************************************
687 /*******************************************************************************
689 ********************************************************************************
692 #define qmHandleRxPackets_AOSP_0 \
693 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) { \
694 prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; \
695 } else if (UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr, pucEthDestAddr)) { \
696 prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD; \
697 /* TODO : need to check the dst mac is valid */ \
698 /* If src mac is invalid, the packet will be freed in fw */ \
700 #if CFG_RX_REORDERING_ENABLED
701 #define qmHandleRxPackets_AOSP_1 \
702 /* ToDo[6630]: duplicate removal */ \
703 if (!fgIsBMC && nicRxIsDuplicateFrame(prCurrSwRfb) == TRUE) { \
704 DBGLOG(QM, TRACE, ("Duplicated packet is detected\n")); \
705 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; \
707 /* ToDo[6630]: defragmentation */ \
708 if (prCurrSwRfb->fgFragFrame) { \
709 prCurrSwRfb = incRxDefragMPDU(prAdapter, prCurrSwRfb, prReturnedQue); \
711 prRxStatus = prCurrSwRfb->prRxStatus; \
712 DBGLOG(QM, TRACE, ("defragmentation RxStatus=%x\n", prRxStatus)); \
717 if (HAL_RX_STATUS_GET_SEC_MODE(prRxStatus) == CIPHER_SUITE_TKIP_WO_MIC) { \
718 if (prCurrSwRfb->prStaRec) { \
720 P_BSS_INFO_T prBssInfo = NULL; \
721 PUINT_8 pucMicKey = NULL; \
722 ucBssIndex = prCurrSwRfb->prStaRec->ucBssIndex; \
723 ASSERT(ucBssIndex < BSS_INFO_NUM); \
724 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); \
726 if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { \
727 pucMicKey = &(prAdapter->rWifiVar.rAisSpecificBssInfo.aucRxMicKey[0]); \
731 /* pucMicKey = &prCurrSwRfb->prStaRec->aucRxMicKey[0]; */ \
733 /* SW TKIP MIC verify */ \
734 /* TODO:[6630] Need to Check Header Translation Case */ \
735 if (pucMicKey == NULL) { \
736 DBGLOG(RX, ERROR, ("Mark NULL the Packet for TKIP Key Error\n")); \
739 else if (tkipMicDecapsulate(prCurrSwRfb, pucMicKey) == FALSE) { \
744 DBGLOG(RX, ERROR, ("Mark NULL the Packet for TKIP Mic Error\n")); \
745 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; \
748 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb); \
753 /*******************************************************************************
754 * F U N C T I O N D E C L A R A T I O N S
755 ********************************************************************************
758 /*******************************************************************************
760 ********************************************************************************
763 /*----------------------------------------------------------------------------*/
765 * \brief Init Queue Managment for TX
771 /*----------------------------------------------------------------------------*/
772 VOID
qmInit(IN P_ADAPTER_T prAdapter
)
775 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
776 UINT_32 u4TotalMinReservedTcResource
= 0;
777 UINT_32 u4TotalTcResource
= 0;
778 UINT_32 u4TotalGurantedTcResource
= 0;
781 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
783 /* DbgPrint("QM: Enter qmInit()\n"); */
785 /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */
786 for (u4Idx
= 0; u4Idx
< NUM_OF_PER_TYPE_TX_QUEUES
; u4Idx
++) {
787 QUEUE_INITIALIZE(&(prQM
->arTxQueue
[u4Idx
]));
790 /* 4 <3> Initialize the RX BA table and RX queues */
791 /* Initialize the RX Reordering Parameters and Queues */
792 for (u4Idx
= 0; u4Idx
< CFG_NUM_OF_RX_BA_AGREEMENTS
; u4Idx
++) {
793 prQM
->arRxBaTable
[u4Idx
].fgIsValid
= FALSE
;
794 QUEUE_INITIALIZE(&(prQM
->arRxBaTable
[u4Idx
].rReOrderQue
));
795 prQM
->arRxBaTable
[u4Idx
].u2WinStart
= 0xFFFF;
796 prQM
->arRxBaTable
[u4Idx
].u2WinEnd
= 0xFFFF;
798 prQM
->arRxBaTable
[u4Idx
].fgIsWaitingForPktWithSsn
= FALSE
;
799 prQM
->arRxBaTable
[u4Idx
].fgHasBubble
= FALSE
;
801 cnmTimerInitTimer(prAdapter
,
802 &(prQM
->arRxBaTable
[u4Idx
].rReorderBubbleTimer
),
803 (PFN_MGMT_TIMEOUT_FUNC
) qmHandleReorderBubbleTimeout
,
804 (ULONG
) (&prQM
->arRxBaTable
[u4Idx
]));
807 prQM
->ucRxBaCount
= 0;
809 kalMemSet(&g_arMissTimeout
, 0, sizeof(g_arMissTimeout
));
811 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
812 /* 4 <4> Initialize TC resource control variables */
813 for (u4Idx
= 0; u4Idx
< TC_NUM
; u4Idx
++) {
814 prQM
->au4AverageQueLen
[u4Idx
] = 0;
817 ASSERT(prQM
->u4TimeToAdjustTcResource
&& prQM
->u4TimeToUpdateQueLen
);
819 for(u4Idx
= 0; u4Idx
< TC_NUM
; u4Idx
++) {
820 prQM
->au4CurrentTcResource
[u4Idx
] = prAdapter
->rTxCtrl
.rTc
.au2MaxNumOfBuffer
[u4Idx
];
822 if(u4Idx
!= TC4_INDEX
) {
823 u4TotalTcResource
+= prQM
->au4CurrentTcResource
[u4Idx
];
824 u4TotalGurantedTcResource
+= prQM
->au4GuaranteedTcResource
[u4Idx
];
825 u4TotalMinReservedTcResource
+= prQM
->au4MinReservedTcResource
[u4Idx
];
830 if(u4TotalMinReservedTcResource
> u4TotalTcResource
) {
831 kalMemZero(prQM
->au4MinReservedTcResource
, sizeof(prQM
->au4MinReservedTcResource
));
834 if(u4TotalGurantedTcResource
> u4TotalTcResource
) {
835 kalMemZero(prQM
->au4GuaranteedTcResource
, sizeof(prQM
->au4GuaranteedTcResource
));
838 u4TotalGurantedTcResource
= 0;
840 /* Initialize Residual TC resource */
841 for(u4Idx
= 0; u4Idx
< TC_NUM
; u4Idx
++) {
842 if(prQM
->au4GuaranteedTcResource
[u4Idx
] < prQM
->au4MinReservedTcResource
[u4Idx
]) {
843 prQM
->au4GuaranteedTcResource
[u4Idx
] = prQM
->au4MinReservedTcResource
[u4Idx
];
846 if(u4Idx
!= TC4_INDEX
) {
847 u4TotalGurantedTcResource
+= prQM
->au4GuaranteedTcResource
[u4Idx
];
851 prQM
->u4ResidualTcResource
= u4TotalTcResource
- u4TotalGurantedTcResource
;
853 prQM
->fgTcResourcePostAnnealing
= FALSE
;
855 #if QM_FAST_TC_RESOURCE_CTRL
856 prQM
->fgTcResourceFastReaction
= FALSE
;
862 prQM
->u4PktCount
= 0;
864 #if QM_TEST_FAIR_FORWARDING
866 prQM
->u4CurrentStaRecIndexToEnqueue
= 0;
868 UINT_8 aucMacAddr
[MAC_ADDR_LEN
];
869 P_STA_RECORD_T prStaRec
;
871 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
872 aucMacAddr
[0] = 0x11;
873 aucMacAddr
[1] = 0x22;
874 aucMacAddr
[2] = 0xAA;
875 aucMacAddr
[3] = 0xBB;
876 aucMacAddr
[4] = 0xCC;
877 aucMacAddr
[5] = 0xDD;
879 prStaRec
= &prAdapter
->arStaRec
[1];
882 prStaRec
->fgIsValid
= TRUE
;
883 prStaRec
->fgIsQoS
= TRUE
;
884 prStaRec
->fgIsInPS
= FALSE
;
885 prStaRec
->ucNetTypeIndex
= NETWORK_TYPE_AIS_INDEX
;
886 COPY_MAC_ADDR((prStaRec
)->aucMacAddr
, aucMacAddr
);
894 #if QM_FORWARDING_FAIRNESS
895 for (u4Idx
= 0; u4Idx
< NUM_OF_PER_STA_TX_QUEUES
; u4Idx
++) {
896 prQM
->au4ResourceUsedCount
[u4Idx
] = 0;
897 prQM
->au4HeadStaRecIndex
[u4Idx
] = 0;
900 prQM
->u4GlobalResourceUsedCount
= 0;
903 prQM
->u4TxAllowedStaCount
= 0;
908 VOID
qmTestCases(IN P_ADAPTER_T prAdapter
)
910 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
912 DbgPrint("QM: ** TEST MODE **\n");
914 if (QM_TEST_STA_REC_DETERMINATION
) {
915 if (prAdapter
->arStaRec
[0].fgIsValid
) {
916 prAdapter
->arStaRec
[0].fgIsValid
= FALSE
;
917 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
919 prAdapter
->arStaRec
[0].fgIsValid
= TRUE
;
920 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
924 if (QM_TEST_STA_REC_DEACTIVATION
) {
925 /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */
927 if (prAdapter
->arStaRec
[0].fgIsValid
) {
929 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
930 qmDeactivateStaRec(prAdapter
, &prAdapter
->arStaRec
[0]);
933 UINT_8 aucMacAddr
[MAC_ADDR_LEN
];
935 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
936 aucMacAddr
[0] = 0x11;
937 aucMacAddr
[1] = 0x22;
938 aucMacAddr
[2] = 0xAA;
939 aucMacAddr
[3] = 0xBB;
940 aucMacAddr
[4] = 0xCC;
941 aucMacAddr
[5] = 0xDD;
943 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
944 qmActivateStaRec(prAdapter
, /* Adapter pointer */
945 0, /* STA_REC index from FW */
947 NETWORK_TYPE_AIS_INDEX
, /* Network type */
949 aucMacAddr
/* MAC address */
954 if (QM_TEST_FAIR_FORWARDING
) {
955 if (prAdapter
->arStaRec
[1].fgIsValid
) {
956 prQM
->u4CurrentStaRecIndexToEnqueue
++;
957 prQM
->u4CurrentStaRecIndexToEnqueue
%= 2;
958 DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n",
959 prQM
->u4CurrentStaRecIndexToEnqueue
);
966 /*----------------------------------------------------------------------------*/
968 * \brief Update a STA_REC
970 * \param[in] prAdapter Pointer to the Adapter instance
971 * \param[in] prStaRec The pointer of the STA_REC
975 /*----------------------------------------------------------------------------*/
976 VOID
qmUpdateStaRec(IN P_ADAPTER_T prAdapter
, IN P_STA_RECORD_T prStaRec
)
978 P_BSS_INFO_T prBssInfo
;
979 BOOLEAN fgIsTxAllowed
= FALSE
;
985 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
987 /* 4 <1> Ensure STA is valid */
988 if (prStaRec
->fgIsValid
) {
989 /* 4 <2.1> STA/BSS is protected */
990 if (secIsProtectedBss(prAdapter
, prBssInfo
)) {
991 if (prStaRec
->fgIsTxKeyReady
) {
992 fgIsTxAllowed
= TRUE
;
995 /* 4 <2.2> OPEN security */
997 fgIsTxAllowed
= TRUE
;
1000 /* 4 <x> Update StaRec */
1001 if (prStaRec
->fgIsTxAllowed
!= fgIsTxAllowed
) {
1002 if (fgIsTxAllowed
) {
1003 prAdapter
->rQM
.u4TxAllowedStaCount
++;
1005 prAdapter
->rQM
.u4TxAllowedStaCount
--;
1009 prStaRec
->fgIsTxAllowed
= fgIsTxAllowed
;
1014 /*----------------------------------------------------------------------------*/
1016 * \brief Activate a STA_REC
1018 * \param[in] prAdapter Pointer to the Adapter instance
1019 * \param[in] prStaRec The pointer of the STA_REC
1023 /*----------------------------------------------------------------------------*/
1024 VOID
qmActivateStaRec(IN P_ADAPTER_T prAdapter
, IN P_STA_RECORD_T prStaRec
)
1026 /* 4 <1> Deactivate first */
1031 if (prStaRec
->fgIsValid
) { /* The STA_REC has been activated */
1033 ("QM: (WARNING) Activating a STA_REC which has been activated\n"));
1034 DBGLOG(QM
, WARN
, ("QM: (WARNING) Deactivating a STA_REC before re-activating\n"));
1035 qmDeactivateStaRec(prAdapter
, prStaRec
); /* To flush TX/RX queues and del RX BA agreements */
1037 /* 4 <2> Activate the STA_REC */
1038 /* Reset buffer count */
1039 prStaRec
->ucFreeQuota
= 0;
1040 prStaRec
->ucFreeQuotaForDelivery
= 0;
1041 prStaRec
->ucFreeQuotaForNonDelivery
= 0;
1043 /* Init the STA_REC */
1044 prStaRec
->fgIsValid
= TRUE
;
1045 prStaRec
->fgIsInPS
= FALSE
;
1047 /* Default setting of TX/RX AMPDU */
1048 prStaRec
->fgTxAmpduEn
= IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucAmpduTx
);
1049 prStaRec
->fgRxAmpduEn
= IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucAmpduRx
);
1051 nicTxGenerateDescTemplate(prAdapter
, prStaRec
);
1053 qmUpdateStaRec(prAdapter
, prStaRec
);
1055 /* Done in qmInit() or qmDeactivateStaRec() */
1057 /* At the beginning, no RX BA agreements have been established */
1058 for (i
= 0; i
< CFG_RX_MAX_BA_TID_NUM
; i
++) {
1059 (prStaRec
->aprRxReorderParamRefTbl
)[i
] = NULL
;
1063 DBGLOG(QM
, INFO
, ("QM: +STA[%ld]\n", (UINT_32
) prStaRec
->ucIndex
));
1066 /*----------------------------------------------------------------------------*/
1068 * \brief Deactivate a STA_REC
1070 * \param[in] prAdapter Pointer to the Adapter instance
1071 * \param[in] u4StaRecIdx The index of the STA_REC
1075 /*----------------------------------------------------------------------------*/
1076 VOID
qmDeactivateStaRec(IN P_ADAPTER_T prAdapter
, IN P_STA_RECORD_T prStaRec
)
1079 P_MSDU_INFO_T prFlushedTxPacketList
= NULL
;
1084 /* 4 <1> Flush TX queues */
1085 prFlushedTxPacketList
= qmFlushStaTxQueues(prAdapter
, prStaRec
->ucIndex
);
1087 if (prFlushedTxPacketList
) {
1088 wlanProcessQueuedMsduInfo(prAdapter
, prFlushedTxPacketList
);
1090 /* 4 <2> Flush RX queues and delete RX BA agreements */
1091 for (i
= 0; i
< CFG_RX_MAX_BA_TID_NUM
; i
++) {
1092 /* Delete the RX BA entry with TID = i */
1093 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, (UINT_8
) i
, FALSE
);
1096 /* 4 <3> Deactivate the STA_REC */
1097 prStaRec
->fgIsValid
= FALSE
;
1098 prStaRec
->fgIsInPS
= FALSE
;
1099 prStaRec
->fgIsTxKeyReady
= FALSE
;
1101 /* Reset buffer count */
1102 prStaRec
->ucFreeQuota
= 0;
1103 prStaRec
->ucFreeQuotaForDelivery
= 0;
1104 prStaRec
->ucFreeQuotaForNonDelivery
= 0;
1106 nicTxFreeDescTemplate(prAdapter
, prStaRec
);
1108 qmUpdateStaRec(prAdapter
, prStaRec
);
1110 DBGLOG(QM
, INFO
, ("QM: -STA[%u]\n", prStaRec
->ucIndex
));
1114 /*----------------------------------------------------------------------------*/
1116 * \brief Deactivate a STA_REC
1118 * \param[in] prAdapter Pointer to the Adapter instance
1119 * \param[in] ucBssIndex The index of the BSS
1123 /*----------------------------------------------------------------------------*/
1124 VOID
qmFreeAllByBssIdx(IN P_ADAPTER_T prAdapter
, IN UINT_8 ucBssIndex
)
1129 QUE_T rNeedToFreeQue
;
1131 P_QUE_T prNeedToFreeQue
;
1133 P_MSDU_INFO_T prMsduInfo
;
1136 prQM
= &prAdapter
->rQM
;
1137 prQue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
1139 QUEUE_INITIALIZE(&rNeedToFreeQue
);
1140 QUEUE_INITIALIZE(&rTempQue
);
1142 prNeedToFreeQue
= &rNeedToFreeQue
;
1143 prTempQue
= &rTempQue
;
1145 QUEUE_MOVE_ALL(prTempQue
, prQue
);
1147 QUEUE_REMOVE_HEAD(prTempQue
, prMsduInfo
, P_MSDU_INFO_T
);
1148 while (prMsduInfo
) {
1150 if (prMsduInfo
->ucBssIndex
== ucBssIndex
) {
1151 QUEUE_INSERT_TAIL(prNeedToFreeQue
, (P_QUE_ENTRY_T
) prMsduInfo
);
1153 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prMsduInfo
);
1156 QUEUE_REMOVE_HEAD(prTempQue
, prMsduInfo
, P_MSDU_INFO_T
);
1158 if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue
)) {
1159 wlanProcessQueuedMsduInfo(prAdapter
,
1160 (P_MSDU_INFO_T
) QUEUE_GET_HEAD(prNeedToFreeQue
));
1165 /*----------------------------------------------------------------------------*/
1167 * \brief Flush all TX queues
1171 * \return The flushed packets (in a list of MSDU_INFOs)
1173 /*----------------------------------------------------------------------------*/
1174 P_MSDU_INFO_T
qmFlushTxQueues(IN P_ADAPTER_T prAdapter
)
1176 UINT_8 ucStaArrayIdx
;
1177 UINT_8 ucQueArrayIdx
;
1179 P_MSDU_INFO_T prMsduInfoListHead
;
1180 P_MSDU_INFO_T prMsduInfoListTail
;
1182 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1184 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushTxQueues()\n"));
1186 prMsduInfoListHead
= NULL
;
1187 prMsduInfoListTail
= NULL
;
1189 /* Concatenate all MSDU_INFOs in per-STA queues */
1190 for (ucStaArrayIdx
= 0; ucStaArrayIdx
< CFG_NUM_OF_STA_RECORD
; ucStaArrayIdx
++) {
1192 /* Always check each STA_REC when flushing packets no matter it is inactive or active */
1194 if (!prAdapter
->arStaRec
[ucStaArrayIdx
].fgIsValid
) {
1195 continue; /* Continue to check the next STA_REC */
1199 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_STA_TX_QUEUES
; ucQueArrayIdx
++) {
1201 (&(prAdapter
->arStaRec
[ucStaArrayIdx
].arTxQueue
[ucQueArrayIdx
]))) {
1202 continue; /* Continue to check the next TX queue of the same STA */
1205 if (!prMsduInfoListHead
) {
1207 /* The first MSDU_INFO is found */
1208 prMsduInfoListHead
= (P_MSDU_INFO_T
)
1209 QUEUE_GET_HEAD(&prAdapter
->arStaRec
[ucStaArrayIdx
].
1210 arTxQueue
[ucQueArrayIdx
]);
1211 prMsduInfoListTail
= (P_MSDU_INFO_T
)
1212 QUEUE_GET_TAIL(&prAdapter
->arStaRec
[ucStaArrayIdx
].
1213 arTxQueue
[ucQueArrayIdx
]);
1215 /* Concatenate the MSDU_INFO list with the existing list */
1216 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1217 QUEUE_GET_HEAD(&prAdapter
->
1218 arStaRec
[ucStaArrayIdx
].
1219 arTxQueue
[ucQueArrayIdx
]));
1221 prMsduInfoListTail
= (P_MSDU_INFO_T
)
1222 QUEUE_GET_TAIL(&prAdapter
->arStaRec
[ucStaArrayIdx
].
1223 arTxQueue
[ucQueArrayIdx
]);
1226 QUEUE_INITIALIZE(&prAdapter
->arStaRec
[ucStaArrayIdx
].
1227 arTxQueue
[ucQueArrayIdx
]);
1231 /* Flush per-Type queues */
1232 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_TYPE_TX_QUEUES
; ucQueArrayIdx
++) {
1234 if (QUEUE_IS_EMPTY(&(prQM
->arTxQueue
[ucQueArrayIdx
]))) {
1235 continue; /* Continue to check the next TX queue of the same STA */
1238 if (!prMsduInfoListHead
) {
1240 /* The first MSDU_INFO is found */
1241 prMsduInfoListHead
= (P_MSDU_INFO_T
)
1242 QUEUE_GET_HEAD(&prQM
->arTxQueue
[ucQueArrayIdx
]);
1243 prMsduInfoListTail
= (P_MSDU_INFO_T
)
1244 QUEUE_GET_TAIL(&prQM
->arTxQueue
[ucQueArrayIdx
]);
1246 /* Concatenate the MSDU_INFO list with the existing list */
1247 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1248 QUEUE_GET_HEAD(&prQM
->arTxQueue
[ucQueArrayIdx
]));
1250 prMsduInfoListTail
= (P_MSDU_INFO_T
)
1251 QUEUE_GET_TAIL(&prQM
->arTxQueue
[ucQueArrayIdx
]);
1254 QUEUE_INITIALIZE(&prQM
->arTxQueue
[ucQueArrayIdx
]);
1258 if (prMsduInfoListTail
) {
1259 /* Terminate the MSDU_INFO list with a NULL pointer */
1260 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
, NULL
);
1263 return prMsduInfoListHead
;
1267 /*----------------------------------------------------------------------------*/
1269 * \brief Flush TX packets for a particular STA
1271 * \param[in] u4StaRecIdx STA_REC index
1273 * \return The flushed packets (in a list of MSDU_INFOs)
1275 /*----------------------------------------------------------------------------*/
1276 P_MSDU_INFO_T
qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StaRecIdx
)
1278 UINT_8 ucQueArrayIdx
;
1279 P_MSDU_INFO_T prMsduInfoListHead
;
1280 P_MSDU_INFO_T prMsduInfoListTail
;
1281 P_STA_RECORD_T prStaRec
;
1283 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx
));
1285 ASSERT(u4StaRecIdx
< CFG_NUM_OF_STA_RECORD
);
1287 prMsduInfoListHead
= NULL
;
1288 prMsduInfoListTail
= NULL
;
1290 prStaRec
= &prAdapter
->arStaRec
[u4StaRecIdx
];
1293 /* No matter whether this is an activated STA_REC, do flush */
1295 if (!prStaRec
->fgIsValid
) {
1300 /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */
1301 for (ucQueArrayIdx
= 0; ucQueArrayIdx
< NUM_OF_PER_STA_TX_QUEUES
; ucQueArrayIdx
++) {
1302 if (QUEUE_IS_EMPTY(&(prStaRec
->arTxQueue
[ucQueArrayIdx
]))) {
1306 if (!prMsduInfoListHead
) {
1307 /* The first MSDU_INFO is found */
1308 prMsduInfoListHead
= (P_MSDU_INFO_T
)
1309 QUEUE_GET_HEAD(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1310 prMsduInfoListTail
= (P_MSDU_INFO_T
)
1311 QUEUE_GET_TAIL(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1313 /* Concatenate the MSDU_INFO list with the existing list */
1314 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1315 QUEUE_GET_HEAD(&prStaRec
->
1316 arTxQueue
[ucQueArrayIdx
]));
1318 prMsduInfoListTail
=
1319 (P_MSDU_INFO_T
) QUEUE_GET_TAIL(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1322 QUEUE_INITIALIZE(&prStaRec
->arTxQueue
[ucQueArrayIdx
]);
1327 if (prMsduInfoListTail
) {
1328 /* Terminate the MSDU_INFO list with a NULL pointer */
1329 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail
,
1330 nicGetPendingStaMMPDU(prAdapter
, (UINT_8
) u4StaRecIdx
));
1332 prMsduInfoListHead
= nicGetPendingStaMMPDU(prAdapter
, (UINT_8
) u4StaRecIdx
);
1336 return prMsduInfoListHead
;
1340 /*----------------------------------------------------------------------------*/
1342 * \brief Flush RX packets
1346 * \return The flushed packets (in a list of SW_RFBs)
1348 /*----------------------------------------------------------------------------*/
1349 P_SW_RFB_T
qmFlushRxQueues(IN P_ADAPTER_T prAdapter
)
1352 P_SW_RFB_T prSwRfbListHead
;
1353 P_SW_RFB_T prSwRfbListTail
;
1354 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1356 prSwRfbListHead
= prSwRfbListTail
= NULL
;
1358 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushRxQueues()\n"));
1360 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
1361 if (QUEUE_IS_NOT_EMPTY(&(prQM
->arRxBaTable
[i
].rReOrderQue
))) {
1362 if (!prSwRfbListHead
) {
1364 /* The first MSDU_INFO is found */
1365 prSwRfbListHead
= (P_SW_RFB_T
)
1366 QUEUE_GET_HEAD(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1367 prSwRfbListTail
= (P_SW_RFB_T
)
1368 QUEUE_GET_TAIL(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1370 /* Concatenate the MSDU_INFO list with the existing list */
1371 QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail
,
1373 (prQM
->arRxBaTable
[i
].
1376 prSwRfbListTail
= (P_SW_RFB_T
)
1377 QUEUE_GET_TAIL(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1380 QUEUE_INITIALIZE(&(prQM
->arRxBaTable
[i
].rReOrderQue
));
1387 if (prSwRfbListTail
) {
1388 /* Terminate the MSDU_INFO list with a NULL pointer */
1389 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail
, NULL
);
1391 return prSwRfbListHead
;
1396 /*----------------------------------------------------------------------------*/
1398 * \brief Flush RX packets with respect to a particular STA
1400 * \param[in] u4StaRecIdx STA_REC index
1401 * \param[in] u4Tid TID
1403 * \return The flushed packets (in a list of SW_RFBs)
1405 /*----------------------------------------------------------------------------*/
1406 P_SW_RFB_T
qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StaRecIdx
, IN UINT_32 u4Tid
)
1409 P_SW_RFB_T prSwRfbListHead
;
1410 P_SW_RFB_T prSwRfbListTail
;
1411 P_RX_BA_ENTRY_T prReorderQueParm
;
1412 P_STA_RECORD_T prStaRec
;
1414 DBGLOG(QM
, TRACE
, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx
));
1416 prSwRfbListHead
= prSwRfbListTail
= NULL
;
1418 prStaRec
= &prAdapter
->arStaRec
[u4StaRecIdx
];
1421 /* No matter whether this is an activated STA_REC, do flush */
1423 if (!prStaRec
->fgIsValid
) {
1428 /* Obtain the RX BA Entry pointer */
1429 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[u4Tid
]);
1431 /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */
1432 if (prReorderQueParm
) {
1434 if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm
->rReOrderQue
))) {
1436 prSwRfbListHead
= (P_SW_RFB_T
)
1437 QUEUE_GET_HEAD(&(prReorderQueParm
->rReOrderQue
));
1438 prSwRfbListTail
= (P_SW_RFB_T
)
1439 QUEUE_GET_TAIL(&(prReorderQueParm
->rReOrderQue
));
1442 QUEUE_INITIALIZE(&(prReorderQueParm
->rReOrderQue
));
1447 if (prSwRfbListTail
) {
1448 /* Terminate the MSDU_INFO list with a NULL pointer */
1449 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail
, NULL
);
1451 return prSwRfbListHead
;
1456 P_QUE_T
qmDetermineStaTxQueue(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
,
1459 P_QUE_T prTxQue
= NULL
;
1460 P_STA_RECORD_T prStaRec
;
1461 ENUM_WMM_ACI_T eAci
= WMM_AC_BE_INDEX
;
1462 BOOLEAN fgCheckACMAgain
;
1464 P_BSS_INFO_T prBssInfo
;
1465 UINT_8 aucNextUP
[WMM_AC_INDEX_NUM
] =
1471 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prMsduInfo
->ucBssIndex
);
1472 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prMsduInfo
->ucStaRecIndex
);
1474 if (prMsduInfo
->ucUserPriority
< 8) {
1475 QM_DBG_CNT_INC(&prAdapter
->rQM
, prMsduInfo
->ucUserPriority
+ 15);
1476 /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */
1477 /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */
1480 eAci
= WMM_AC_BE_INDEX
;
1482 fgCheckACMAgain
= FALSE
;
1483 if (prStaRec
->fgIsQoS
) {
1484 if (prMsduInfo
->ucUserPriority
< TX_DESC_TID_NUM
) {
1485 eAci
= aucTid2ACI
[prMsduInfo
->ucUserPriority
];
1486 prTxQue
= &prStaRec
->arTxQueue
[aucACI2TxQIdx
[eAci
]];
1487 ucTC
= arNetwork2TcResource
[prMsduInfo
->ucBssIndex
][eAci
];
1489 prTxQue
= &prStaRec
->arTxQueue
[TX_QUEUE_INDEX_AC1
];
1491 eAci
= WMM_AC_BE_INDEX
;
1492 DBGLOG(QM
, WARN
, ("Packet TID is not in [0~7]\n"));
1495 if ((prBssInfo
->arACQueParms
[eAci
].ucIsACMSet
) && (eAci
!= WMM_AC_BK_INDEX
)) {
1496 prMsduInfo
->ucUserPriority
= aucNextUP
[eAci
];
1497 fgCheckACMAgain
= TRUE
;
1500 prTxQue
= &prStaRec
->arTxQueue
[TX_QUEUE_INDEX_NON_QOS
];
1501 ucTC
= arNetwork2TcResource
[prMsduInfo
->ucBssIndex
][NET_TC_NON_STAREC_NON_QOS_INDEX
];
1504 if (prAdapter
->rWifiVar
.ucTcRestrict
< TC_NUM
) {
1505 ucTC
= prAdapter
->rWifiVar
.ucTcRestrict
;
1506 prTxQue
= &prStaRec
->arTxQueue
[ucTC
];
1509 } while (fgCheckACMAgain
);
1517 qmSetTxPacketDescTemplate(IN P_ADAPTER_T prAdapter
,
1518 IN P_MSDU_INFO_T prMsduInfo
)
1520 P_STA_RECORD_T prStaRec
=
1521 QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prMsduInfo
->ucStaRecIndex
);
1523 /* Check the Tx descriptor template is valid */
1524 if (prStaRec
&& prStaRec
->aprTxDescTemplate
[prMsduInfo
->ucUserPriority
]) {
1525 prMsduInfo
->fgIsTXDTemplateValid
= TRUE
;
1529 ("Cannot get TXD template for STA[%u] QoS[%u] MSDU UP[%u]\n",
1530 prStaRec
->ucIndex
, prStaRec
->fgIsQoS
,
1531 prMsduInfo
->ucUserPriority
));
1533 prMsduInfo
->fgIsTXDTemplateValid
= FALSE
;
1538 /*----------------------------------------------------------------------------*/
1540 * \brief Enqueue TX packets
1542 * \param[in] prMsduInfoListHead Pointer to the list of TX packets
1544 * \return The freed packets, which are not enqueued
1546 /*----------------------------------------------------------------------------*/
1547 P_MSDU_INFO_T
qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfoListHead
)
1549 P_MSDU_INFO_T prMsduInfoReleaseList
;
1550 P_MSDU_INFO_T prCurrentMsduInfo
;
1551 P_MSDU_INFO_T prNextMsduInfo
;
1554 QUE_T rNotEnqueuedQue
;
1557 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1558 P_BSS_INFO_T prBssInfo
;
1559 BOOLEAN fgDropPacket
;
1561 DBGLOG(QM
, LOUD
, ("Enter qmEnqueueTxPackets\n"));
1563 ASSERT(prMsduInfoListHead
);
1565 prMsduInfoReleaseList
= NULL
;
1566 prCurrentMsduInfo
= NULL
;
1567 QUEUE_INITIALIZE(&rNotEnqueuedQue
);
1568 prNextMsduInfo
= prMsduInfoListHead
;
1571 prCurrentMsduInfo
= prNextMsduInfo
;
1572 prNextMsduInfo
= QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo
);
1575 /* 4 <0> Sanity check of BSS_INFO */
1576 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prCurrentMsduInfo
->ucBssIndex
);
1580 fgDropPacket
= TRUE
;
1581 } else if (IS_BSS_ACTIVE(prBssInfo
)) {
1583 fgDropPacket
= FALSE
;
1586 fgDropPacket
= TRUE
;
1589 if (!fgDropPacket
) {
1590 /* 4 <1> Lookup the STA_REC index */
1591 /* The ucStaRecIndex will be set in this function */
1592 qmDetermineStaRecIndex(prAdapter
, prCurrentMsduInfo
);
1595 ("Enqueue MSDU by StaRec[%u]!\n", prCurrentMsduInfo
->ucStaRecIndex
));
1597 switch (prCurrentMsduInfo
->ucStaRecIndex
) {
1598 case STA_REC_INDEX_BMCAST
:
1599 prTxQue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
1600 ucTC
= arNetwork2TcResource
[prCurrentMsduInfo
->ucBssIndex
]
1601 [NET_TC_NON_STAREC_NON_QOS_INDEX
];
1603 /* Always set BMC packet retry limit to unlimited */
1604 if (!(prCurrentMsduInfo
->u4Option
& MSDU_OPT_MANUAL_RETRY_LIMIT
)) {
1605 nicTxSetPktRetryLimit(prCurrentMsduInfo
, TX_DESC_TX_COUNT_NO_LIMIT
);
1608 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_23
);
1611 case STA_REC_INDEX_NOT_FOUND
:
1612 /* Drop packet if no STA_REC is found */
1613 DBGLOG(QM
, TRACE
, ("Drop the Packet for no STA_REC\n"));
1615 prTxQue
= &rNotEnqueuedQue
;
1617 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_INACTIVE_STA_DROP
);
1618 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_24
);
1622 prTxQue
= qmDetermineStaTxQueue(prAdapter
, prCurrentMsduInfo
, &ucTC
);
1624 } /* switch (prCurrentMsduInfo->ucStaRecIndex) */
1626 if ((prCurrentMsduInfo
->eSrc
== TX_PACKET_FORWARDING
)) {
1627 DBGLOG(QM
, TRACE
, ("Forward Pkt to STA[%u] BSS[%u]\n",
1628 prCurrentMsduInfo
->ucStaRecIndex
,
1629 prCurrentMsduInfo
->ucBssIndex
));
1631 if (prTxQue
->u4NumElem
>= prQM
->u4MaxForwardBufferCount
) {
1633 ("Drop the Packet for full Tx queue (forwarding) Bss %u\n",
1634 prCurrentMsduInfo
->ucBssIndex
));
1635 prTxQue
= &rNotEnqueuedQue
;
1636 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_FORWARD_OVERFLOW_DROP
);
1642 ("Drop the Packet for inactive Bss %u\n",
1643 prCurrentMsduInfo
->ucBssIndex
));
1644 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_31
);
1645 prTxQue
= &rNotEnqueuedQue
;
1646 TX_INC_CNT(&prAdapter
->rTxCtrl
, TX_INACTIVE_BSS_DROP
);
1649 /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */
1650 /* Note that the BSS Index and STA_REC index are determined in
1651 * qmDetermineStaRecIndex(prCurrentMsduInfo).
1653 prCurrentMsduInfo
->ucTC
= ucTC
;
1655 /* Check the Tx descriptor template is valid */
1656 qmSetTxPacketDescTemplate(prAdapter
, prCurrentMsduInfo
);
1658 /* 4 <4> Enqueue the packet */
1659 QUEUE_INSERT_TAIL(prTxQue
, (P_QUE_ENTRY_T
) prCurrentMsduInfo
);
1661 #if QM_FAST_TC_RESOURCE_CTRL && QM_ADAPTIVE_TC_RESOURCE_CTRL
1662 if (prTxQue
!= &rNotEnqueuedQue
) {
1663 /* Check and trigger fast TC resource adjustment for queued packets */
1664 qmCheckForFastTcResourceCtrl(prAdapter
, ucTC
);
1669 if (++prQM
->u4PktCount
== QM_TEST_TRIGGER_TX_COUNT
) {
1670 prQM
->u4PktCount
= 0;
1671 qmTestCases(prAdapter
);
1675 DBGLOG(QM
, LOUD
, ("Current queue length = %u\n", prTxQue
->u4NumElem
));
1676 } while (prNextMsduInfo
);
1678 if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue
)) {
1679 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(&rNotEnqueuedQue
), NULL
);
1680 prMsduInfoReleaseList
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(&rNotEnqueuedQue
);
1682 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
1683 /* 4 <x> Update TC resource control related variables */
1684 /* Keep track of the queue length */
1685 qmDoAdaptiveTcResourceCtrl(prAdapter
);
1688 return prMsduInfoReleaseList
;
1691 /*----------------------------------------------------------------------------*/
1693 * \brief Determine the STA_REC index for a packet
1695 * \param[in] prMsduInfo Pointer to the packet
1699 /*----------------------------------------------------------------------------*/
1700 VOID
qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
1704 P_STA_RECORD_T prTempStaRec
;
1705 P_BSS_INFO_T prBssInfo
;
1707 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prMsduInfo
->ucBssIndex
);
1708 prTempStaRec
= NULL
;
1712 DBGLOG(QM
, LOUD
, ("Msdu BSS Idx[%u] OpMode[%u] StaRecOfApExist[%u]\n",
1713 prMsduInfo
->ucBssIndex
,
1714 prBssInfo
->eCurrentOPMode
, prBssInfo
->prStaRecOfAP
? TRUE
: FALSE
));
1716 switch (prBssInfo
->eCurrentOPMode
) {
1718 case OP_MODE_ACCESS_POINT
:
1719 /* 4 <1> DA = BMCAST */
1720 if (IS_BMCAST_MAC_ADDR(prMsduInfo
->aucEthDestAddr
)) {
1721 prMsduInfo
->ucStaRecIndex
= STA_REC_INDEX_BMCAST
;
1722 DBGLOG(QM
, LOUD
, ("TX with DA = BMCAST\n"));
1727 /* Infra Client/GC */
1728 case OP_MODE_INFRASTRUCTURE
:
1730 if (prBssInfo
->prStaRecOfAP
) {
1731 #if CFG_SUPPORT_TDLS
1734 cnmGetTdlsPeerByAddress(prAdapter
, prBssInfo
->ucBssIndex
,
1735 prMsduInfo
->aucEthDestAddr
);
1736 if (IS_DLS_STA(prTempStaRec
) && prTempStaRec
->ucStaState
== STA_STATE_3
) {
1737 if (g_arTdlsLink
[prTempStaRec
->ucTdlsIndex
]) {
1738 prMsduInfo
->ucStaRecIndex
= prTempStaRec
->ucIndex
;
1743 /* 4 <2> Check if an AP STA is present */
1744 prTempStaRec
= prBssInfo
->prStaRecOfAP
;
1747 ("StaOfAp Idx[%u] WIDX[%u] Valid[%u] TxAllowed[%u] InUse[%u] Type[%u]\n",
1748 prTempStaRec
->ucIndex
, prTempStaRec
->ucWlanIndex
,
1749 prTempStaRec
->fgIsValid
, prTempStaRec
->fgIsTxAllowed
,
1750 prTempStaRec
->fgIsInUse
, prTempStaRec
->eStaType
));
1752 if (prTempStaRec
->fgIsInUse
) {
1753 prMsduInfo
->ucStaRecIndex
= prTempStaRec
->ucIndex
;
1754 DBGLOG(QM
, LOUD
, ("TX with AP_STA[%u]\n", prTempStaRec
->ucIndex
));
1760 case OP_MODE_P2P_DEVICE
:
1768 /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */
1769 for (i
= 0; i
< CFG_NUM_OF_STA_RECORD
; i
++) {
1770 prTempStaRec
= &(prAdapter
->arStaRec
[i
]);
1771 if (prTempStaRec
->fgIsInUse
) {
1772 if (EQUAL_MAC_ADDR(prTempStaRec
->aucMacAddr
, prMsduInfo
->aucEthDestAddr
)) {
1773 prMsduInfo
->ucStaRecIndex
= prTempStaRec
->ucIndex
;
1774 DBGLOG(QM
, LOUD
, ("TX with STA[%u]\n", prTempStaRec
->ucIndex
));
1780 /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */
1781 prMsduInfo
->ucStaRecIndex
= STA_REC_INDEX_NOT_FOUND
;
1782 DBGLOG(QM
, LOUD
, ("QM: TX with STA_REC_INDEX_NOT_FOUND\n"));
1784 #if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING)
1785 prMsduInfo
->ucStaRecIndex
= (UINT_8
) prQM
->u4CurrentStaRecIndexToEnqueue
;
1789 P_STA_RECORD_T
qmDetermineStaToBeDequeued(IN P_ADAPTER_T prAdapter
, IN UINT_32 u4StartStaRecIndex
)
1795 P_QUE_T
qmDequeueStaTxPackets(IN P_ADAPTER_T prAdapter
)
1801 /*----------------------------------------------------------------------------*/
1803 * \brief Dequeue TX packets from a STA_REC for a particular TC
1805 * \param[out] prQue The queue to put the dequeued packets
1806 * \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX)
1807 * \param[in] ucMaxNum The maximum amount of dequeued packets
1811 /*----------------------------------------------------------------------------*/
1813 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter
,
1816 IN UINT_32 u4CurrentQuota
, IN UINT_32 u4TotalQuota
)
1818 UINT_32 ucLoop
; /* Loop for */
1820 UINT_32 u4CurStaIndex
= 0;
1821 UINT_32 u4CurStaUsedResource
= 0;
1823 P_STA_RECORD_T prStaRec
; /* The current focused STA */
1824 P_BSS_INFO_T prBssInfo
; /* The Bss for current focused STA */
1825 P_QUE_T prCurrQueue
; /* The current TX queue to dequeue */
1826 P_MSDU_INFO_T prDequeuedPkt
; /* The dequeued packet */
1828 UINT_32 u4CurStaForwardFrameCount
; /* To remember the total forwarded packets for a STA */
1829 UINT_32 u4MaxForwardFrameCountLimit
; /* The maximum number of packets a STA can forward */
1830 UINT_32 u4AvaliableResource
; /* The TX resource amount */
1831 UINT_32 u4MaxResourceLimit
;
1833 BOOLEAN fgEndThisRound
;
1834 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
1836 PUINT_8 pucPsStaFreeQuota
;
1839 if (!u4CurrentQuota
) {
1840 DBGLOG(TX
, LOUD
, ("(Fairness) Skip TC = %u u4CurrentQuota = %u\n",
1841 ucTC
, u4CurrentQuota
));
1842 return u4CurrentQuota
;
1844 /* 4 <1> Assign init value */
1845 u4AvaliableResource
= u4CurrentQuota
;
1846 u4MaxResourceLimit
= u4TotalQuota
;
1848 #if QM_FORWARDING_FAIRNESS
1849 u4CurStaIndex
= prQM
->au4HeadStaRecIndex
[ucTC
];
1850 u4CurStaUsedResource
= prQM
->au4ResourceUsedCount
[ucTC
];
1853 fgEndThisRound
= FALSE
;
1855 u4CurStaForwardFrameCount
= 0;
1857 DBGLOG(QM
, LOUD
, ("(Fairness) TC[%u] Init Head STA[%u] Resource[%u]\n",
1858 ucTC
, u4CurStaIndex
, u4AvaliableResource
));
1860 /* 4 <2> Traverse STA array from Head STA */
1861 /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */
1862 while (ucLoop
< CFG_NUM_OF_STA_RECORD
) {
1863 prStaRec
= &prAdapter
->arStaRec
[u4CurStaIndex
];
1865 /* 4 <2.1> Find a Tx allowed STA */
1866 /* Only Data frame (1x was not included) will be queued in */
1867 if (prStaRec
->fgIsTxAllowed
) {
1868 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
1870 prCurrQueue
= &prStaRec
->arTxQueue
[ucTC
];
1871 prDequeuedPkt
= NULL
;
1872 pucPsStaFreeQuota
= NULL
;
1873 /* Set default forward count limit to unlimited */
1874 u4MaxForwardFrameCountLimit
= QM_STA_FORWARD_COUNT_UNLIMITED
;
1876 /* 4 <2.2> Update forward frame/page count limit for this STA */
1877 /* AP mode: STA in PS buffer handling */
1878 if (prStaRec
->fgIsInPS
) {
1879 if (prStaRec
->fgIsQoS
&&
1880 prStaRec
->fgIsUapsdSupported
&&
1881 (prStaRec
->ucBmpTriggerAC
& BIT(ucTC
))) {
1882 u4MaxForwardFrameCountLimit
=
1883 prStaRec
->ucFreeQuotaForDelivery
;
1884 pucPsStaFreeQuota
= &prStaRec
->ucFreeQuotaForDelivery
;
1886 /* ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); */
1887 u4MaxForwardFrameCountLimit
=
1888 prStaRec
->ucFreeQuotaForNonDelivery
;
1889 pucPsStaFreeQuota
= &prStaRec
->ucFreeQuotaForNonDelivery
;
1895 /* Absent BSS handling */
1896 if (prBssInfo
->fgIsNetAbsent
) {
1897 if (u4MaxForwardFrameCountLimit
> prBssInfo
->ucBssFreeQuota
) {
1898 u4MaxForwardFrameCountLimit
= prBssInfo
->ucBssFreeQuota
;
1901 /* 4 <2.3> Dequeue packet */
1902 /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1903 while (!QUEUE_IS_EMPTY(prCurrQueue
)) {
1904 prDequeuedPkt
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(prCurrQueue
);
1906 if ((u4CurStaForwardFrameCount
>= u4MaxForwardFrameCountLimit
) ||
1907 (u4CurStaUsedResource
>= u4MaxResourceLimit
)) {
1911 } else if (prDequeuedPkt
->ucPageCount
> u4AvaliableResource
) {
1912 /* Avaliable Resource is not enough */
1913 if (!(prAdapter
->rWifiVar
.ucAlwaysResetUsedRes
& BIT(0))) {
1914 fgEndThisRound
= TRUE
;
1918 /* Avaliable to be Tx */
1920 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
,
1923 if (!QUEUE_IS_EMPTY(prCurrQueue
)) {
1924 /* XXX: check all queues for STA */
1925 prDequeuedPkt
->ucPsForwardingType
=
1926 PS_FORWARDING_MORE_DATA_ENABLED
;
1929 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
1931 u4AvaliableResource
-= prDequeuedPkt
->ucPageCount
;
1932 u4CurStaUsedResource
+= prDequeuedPkt
->ucPageCount
;
1933 u4CurStaForwardFrameCount
++;
1938 /* AP mode: Update STA in PS Free quota */
1939 if (prStaRec
->fgIsInPS
&& pucPsStaFreeQuota
) {
1940 if ((*pucPsStaFreeQuota
) >= u4CurStaForwardFrameCount
) {
1941 (*pucPsStaFreeQuota
) -= u4CurStaForwardFrameCount
;
1943 (*pucPsStaFreeQuota
) = 0;
1947 if (prBssInfo
->fgIsNetAbsent
) {
1948 if (prBssInfo
->ucBssFreeQuota
>= u4CurStaForwardFrameCount
) {
1949 prBssInfo
->ucBssFreeQuota
-= u4CurStaForwardFrameCount
;
1951 prBssInfo
->ucBssFreeQuota
= 0;
1956 if (fgEndThisRound
) {
1957 /* End this round */
1961 /* Prepare for next STA */
1964 u4CurStaIndex
%= CFG_NUM_OF_STA_RECORD
;
1965 u4CurStaUsedResource
= 0;
1966 u4CurStaForwardFrameCount
= 0;
1970 /* 4 <3> Store Head Sta information to QM */
1971 /* No need to count used resource if thers is only one STA */
1972 if ((prQM
->u4TxAllowedStaCount
== 1) || (prAdapter
->rWifiVar
.ucAlwaysResetUsedRes
& BIT(1))) {
1973 u4CurStaUsedResource
= 0;
1975 #if QM_FORWARDING_FAIRNESS
1976 prQM
->au4HeadStaRecIndex
[ucTC
] = u4CurStaIndex
;
1977 prQM
->au4ResourceUsedCount
[ucTC
] = u4CurStaUsedResource
;
1980 DBGLOG(QM
, LOUD
, ("(Fairness) TC[%u] Scheduled Head STA[%u] Left Resource[%u]\n",
1981 ucTC
, u4CurStaIndex
, u4AvaliableResource
));
1983 return u4AvaliableResource
;
1986 /*----------------------------------------------------------------------------*/
1988 * \brief Dequeue TX packets from a per-Type-based Queue for a particular TC
1990 * \param[out] prQue The queue to put the dequeued packets
1991 * \param[in] ucTC The TC index (Shall always be TC5_INDEX)
1992 * \param[in] ucMaxNum The maximum amount of availiable resource
1996 /*----------------------------------------------------------------------------*/
1998 qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter
,
2001 IN UINT_32 u4CurrentQuota
, IN UINT_32 u4TotalQuota
)
2003 UINT_32 u4AvaliableResource
, u4LeftResource
;
2004 UINT_32 u4MaxResourceLimit
;
2005 UINT_32 u4TotalUsedResource
= 0;
2007 PFN_DEQUEUE_FUNCTION pfnDeQFunc
[2];
2008 BOOLEAN fgChangeDeQFunc
= TRUE
;
2009 BOOLEAN fgGlobalQueFirst
= TRUE
;
2011 DBGLOG(QM
, LOUD
, ("Enter %s (TC = %d, quota = %u)\n", __func__
, ucTC
, u4CurrentQuota
));
2013 /* TC5: Broadcast/Multicast data packets */
2014 if ((u4CurrentQuota
== 0) || (ucTC
!= TC5_INDEX
)) {
2018 prQM
= &prAdapter
->rQM
;
2020 u4AvaliableResource
= u4CurrentQuota
;
2021 u4MaxResourceLimit
= u4TotalQuota
;
2022 #if QM_FORWARDING_FAIRNESS
2023 u4TotalUsedResource
= prQM
->u4GlobalResourceUsedCount
;
2024 fgGlobalQueFirst
= prQM
->fgGlobalQFirst
;
2027 /* Dequeue function selection */
2028 if (fgGlobalQueFirst
) {
2029 pfnDeQFunc
[0] = qmDequeueTxPacketsFromGlobalQueue
;
2030 pfnDeQFunc
[1] = qmDequeueTxPacketsFromPerStaQueues
;
2032 pfnDeQFunc
[0] = qmDequeueTxPacketsFromPerStaQueues
;
2033 pfnDeQFunc
[1] = qmDequeueTxPacketsFromGlobalQueue
;
2036 /* 1st dequeue function */
2037 u4LeftResource
= pfnDeQFunc
[0] (prAdapter
,
2040 u4AvaliableResource
,
2041 (u4MaxResourceLimit
- u4TotalUsedResource
));
2043 /* dequeue function comsumes no resource, change */
2044 if ((u4LeftResource
>= u4AvaliableResource
) &&
2045 (u4AvaliableResource
>= NIC_TX_MAX_PAGE_PER_FRAME
)) {
2047 fgChangeDeQFunc
= TRUE
;
2049 u4TotalUsedResource
+= (u4AvaliableResource
- u4LeftResource
);
2050 /* Used resource exceeds limit, change */
2051 if (u4TotalUsedResource
>= u4MaxResourceLimit
) {
2052 fgChangeDeQFunc
= TRUE
;
2056 if (fgChangeDeQFunc
) {
2057 fgGlobalQueFirst
= !fgGlobalQueFirst
;
2058 u4TotalUsedResource
= 0;
2061 /* 2nd dequeue function */
2062 u4LeftResource
= pfnDeQFunc
[1] (prAdapter
, prQue
, ucTC
, u4LeftResource
, u4MaxResourceLimit
);
2064 #if QM_FORWARDING_FAIRNESS
2065 prQM
->fgGlobalQFirst
= fgGlobalQueFirst
;
2066 prQM
->u4GlobalResourceUsedCount
= u4TotalUsedResource
;
2069 } /* qmDequeueTxPacketsFromPerTypeQueues */
2071 /*----------------------------------------------------------------------------*/
2073 * \brief Dequeue TX packets from a QM global Queue for a particular TC
2075 * \param[out] prQue The queue to put the dequeued packets
2076 * \param[in] ucTC The TC index (Shall always be TC5_INDEX)
2077 * \param[in] ucMaxNum The maximum amount of availiable resource
2081 /*----------------------------------------------------------------------------*/
2083 qmDequeueTxPacketsFromGlobalQueue(IN P_ADAPTER_T prAdapter
,
2086 IN UINT_32 u4CurrentQuota
, IN UINT_32 u4TotalQuota
)
2088 P_BSS_INFO_T prBssInfo
;
2089 P_QUE_T prCurrQueue
;
2090 UINT_32 u4AvaliableResource
;
2091 P_MSDU_INFO_T prDequeuedPkt
;
2092 P_MSDU_INFO_T prBurstEndPkt
;
2097 DBGLOG(QM
, LOUD
, ("Enter %s (TC = %d, quota = %u)\n", __func__
, ucTC
, u4CurrentQuota
));
2099 /* TC5: Broadcast/Multicast data packets */
2100 if (u4CurrentQuota
== 0) {
2101 return u4CurrentQuota
;
2104 prQM
= &prAdapter
->rQM
;
2106 /* 4 <1> Determine the queue */
2107 prCurrQueue
= &prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
];
2108 u4AvaliableResource
= u4CurrentQuota
;
2109 prDequeuedPkt
= NULL
;
2110 prBurstEndPkt
= NULL
;
2112 QUEUE_INITIALIZE(&rMergeQue
);
2113 prMergeQue
= &rMergeQue
;
2115 /* 4 <2> Dequeue packets */
2116 while (!QUEUE_IS_EMPTY(prCurrQueue
)) {
2117 prDequeuedPkt
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(prCurrQueue
);
2118 if (prDequeuedPkt
->ucPageCount
> u4AvaliableResource
) {
2121 QUEUE_REMOVE_HEAD(prCurrQueue
, prDequeuedPkt
, P_MSDU_INFO_T
);
2122 ASSERT(prDequeuedPkt
->ucTC
== ucTC
);
2123 ASSERT(prDequeuedPkt
->ucBssIndex
<= MAX_BSS_INDEX
);
2125 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prDequeuedPkt
->ucBssIndex
);
2127 if (IS_BSS_ACTIVE(prBssInfo
)) {
2128 if (!prBssInfo
->fgIsNetAbsent
) {
2129 QUEUE_INSERT_TAIL(prQue
, (P_QUE_ENTRY_T
) prDequeuedPkt
);
2130 prBurstEndPkt
= prDequeuedPkt
;
2131 u4AvaliableResource
-= prDequeuedPkt
->ucPageCount
;
2132 QM_DBG_CNT_INC(prQM
, QM_DBG_CNT_26
);
2134 QUEUE_INSERT_TAIL(prMergeQue
,
2135 (P_QUE_ENTRY_T
) prDequeuedPkt
);
2138 QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt
, NULL
);
2139 wlanProcessQueuedMsduInfo(prAdapter
, prDequeuedPkt
);
2144 if (QUEUE_IS_NOT_EMPTY(prMergeQue
)) {
2145 QUEUE_CONCATENATE_QUEUES(prMergeQue
, prCurrQueue
);
2146 QUEUE_MOVE_ALL(prCurrQueue
, prMergeQue
);
2147 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(prCurrQueue
), NULL
);
2150 return u4AvaliableResource
;
2153 /*----------------------------------------------------------------------------*/
2155 * \brief Dequeue TX packets to send to HIF TX
2157 * \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2159 * \return The list of dequeued TX packets
2161 /*----------------------------------------------------------------------------*/
2162 P_MSDU_INFO_T
qmDequeueTxPackets(IN P_ADAPTER_T prAdapter
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2165 P_MSDU_INFO_T prReturnedPacketListHead
;
2167 UINT_32 u4MaxQuotaLimit
;
2169 DBGLOG(QM
, LOUD
, ("Enter qmDequeueTxPackets\n"));
2171 QUEUE_INITIALIZE(&rReturnedQue
);
2173 prReturnedPacketListHead
= NULL
;
2175 /* TC0 to TC3: AC0~AC3 (commands packets are not handled by QM) */
2176 for (i
= TC3_INDEX
; i
>= TC0_INDEX
; i
--) {
2177 DBGLOG(QM
, LOUD
, ("Dequeue packets from Per-STA queue[%u]\n", i
));
2179 /* If only one STA is Tx allowed, no need to restrict Max quota */
2180 if (prAdapter
->rWifiVar
.u4MaxTxDeQLimit
) {
2181 u4MaxQuotaLimit
= prAdapter
->rWifiVar
.u4MaxTxDeQLimit
;
2182 } else if (prAdapter
->rQM
.u4TxAllowedStaCount
== 1) {
2183 u4MaxQuotaLimit
= QM_STA_FORWARD_COUNT_UNLIMITED
;
2185 u4MaxQuotaLimit
= (UINT_32
) prTcqStatus
->au2MaxNumOfPage
[i
];
2188 qmDequeueTxPacketsFromPerStaQueues(prAdapter
,
2191 (UINT_32
) prTcqStatus
->au2FreePageCount
[i
],
2194 /* The aggregate number of dequeued packets */
2195 DBGLOG(QM
, LOUD
, ("DQA)[%u](%lu)\n", i
, rReturnedQue
.u4NumElem
));
2198 /* TC5 (BMCAST or non-QoS packets) */
2199 qmDequeueTxPacketsFromPerTypeQueues(prAdapter
,
2202 prTcqStatus
->au2FreePageCount
[TC5_INDEX
],
2203 prTcqStatus
->au2MaxNumOfPage
[TC5_INDEX
]);
2206 ("Current total number of dequeued packets = %u\n", rReturnedQue
.u4NumElem
));
2208 if (QUEUE_IS_NOT_EMPTY(&rReturnedQue
)) {
2209 prReturnedPacketListHead
= (P_MSDU_INFO_T
) QUEUE_GET_HEAD(&rReturnedQue
);
2210 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T
) QUEUE_GET_TAIL(&rReturnedQue
), NULL
);
2213 return prReturnedPacketListHead
;
2216 #if CFG_SUPPORT_MULTITHREAD
2217 /*----------------------------------------------------------------------------*/
2219 * \brief Dequeue TX packets to send to HIF TX
2221 * \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2223 * \return The list of dequeued TX packets
2225 /*----------------------------------------------------------------------------*/
2226 P_MSDU_INFO_T
qmDequeueTxPacketsMthread(IN P_ADAPTER_T prAdapter
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2230 P_MSDU_INFO_T prReturnedPacketListHead
;
2231 /* QUE_T rReturnedQue; */
2232 /* UINT_32 u4MaxQuotaLimit; */
2233 P_MSDU_INFO_T prMsduInfo
, prNextMsduInfo
;
2235 KAL_SPIN_LOCK_DECLARATION();
2237 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TX_RESOURCE
);
2239 prReturnedPacketListHead
= qmDequeueTxPackets(prAdapter
, prTcqStatus
);
2241 /* require the resource first to prevent from unsync */
2242 prMsduInfo
= prReturnedPacketListHead
;
2243 while (prMsduInfo
) {
2244 prNextMsduInfo
= (P_MSDU_INFO_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
) prMsduInfo
);
2245 prTcqStatus
->au2FreePageCount
[prMsduInfo
->ucTC
] -=
2246 nicTxGetPageCount(prMsduInfo
->u2FrameLength
, FALSE
);
2247 prTcqStatus
->au2FreeBufferCount
[prMsduInfo
->ucTC
] =
2248 (prTcqStatus
->au2FreePageCount
[prMsduInfo
->ucTC
] / NIC_TX_MAX_PAGE_PER_FRAME
);
2249 prMsduInfo
= prNextMsduInfo
;
2252 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TX_RESOURCE
);
2254 return prReturnedPacketListHead
;
2257 /*----------------------------------------------------------------------------*/
2259 * \brief Adjust the TC quotas according to traffic demands
2261 * \param[out] prTcqAdjust The resulting adjustment
2262 * \param[in] prTcqStatus Info about the current TC quotas and counters
2266 /*----------------------------------------------------------------------------*/
2268 qmAdjustTcQuotasMthread(IN P_ADAPTER_T prAdapter
,
2269 OUT P_TX_TCQ_ADJUST_T prTcqAdjust
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2271 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2273 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2275 KAL_SPIN_LOCK_DECLARATION();
2277 /* Must initialize */
2278 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2279 prTcqAdjust
->acVariation
[i
] = 0;
2282 /* 4 <1> If TC resource is not just adjusted, exit directly */
2283 if (!prQM
->fgTcResourcePostAnnealing
) {
2286 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2288 INT_32 i4TotalExtraQuota
= 0;
2289 INT_32 ai4ExtraQuota
[QM_ACTIVE_TC_NUM
];
2290 BOOLEAN fgResourceRedistributed
= TRUE
;
2292 /* Must initialize */
2293 for (i
= 0; i
< TC_NUM
; i
++) {
2294 prTcqAdjust
->acVariation
[i
] = 0;
2297 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TX_RESOURCE
);
2298 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TC_RESOURCE
);
2300 /* Obtain the free-to-distribute resource */
2301 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2303 (INT_32
) prTcqStatus
->au2MaxNumOfBuffer
[i
] -
2304 (INT_32
) prQM
->au4CurrentTcResource
[i
];
2306 if (ai4ExtraQuota
[i
] > 0) { /* The resource shall be reallocated to other TCs */
2307 if (ai4ExtraQuota
[i
] > prTcqStatus
->au2FreeBufferCount
[i
]) {
2308 ai4ExtraQuota
[i
] = prTcqStatus
->au2FreeBufferCount
[i
];
2309 fgResourceRedistributed
= FALSE
;
2312 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2313 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2317 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TC_RESOURCE
);
2319 /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */
2320 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2321 if (ai4ExtraQuota
[i
] < 0) {
2322 if ((-ai4ExtraQuota
[i
]) > i4TotalExtraQuota
) {
2323 ai4ExtraQuota
[i
] = (-i4TotalExtraQuota
);
2324 fgResourceRedistributed
= FALSE
;
2327 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2328 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2332 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2333 prQM
->fgTcResourcePostAnnealing
= (!fgResourceRedistributed
);
2335 for (i
= 0; i
< TC_NUM
; i
++) {
2336 prTcqStatus
->au2FreePageCount
[i
] +=
2337 (prTcqAdjust
->acVariation
[i
] * NIC_TX_MAX_PAGE_PER_FRAME
);
2338 prTcqStatus
->au2MaxNumOfPage
[i
] +=
2339 (prTcqAdjust
->acVariation
[i
] * NIC_TX_MAX_PAGE_PER_FRAME
);
2341 prTcqStatus
->au2FreeBufferCount
[i
] += prTcqAdjust
->acVariation
[i
];
2342 prTcqStatus
->au2MaxNumOfBuffer
[i
] += prTcqAdjust
->acVariation
[i
];
2344 ASSERT(prTcqStatus
->au2FreeBufferCount
[i
] >= 0);
2345 ASSERT(prTcqStatus
->au2MaxNumOfBuffer
[i
] >= 0);
2348 #if QM_FAST_TC_RESOURCE_CTRL
2349 prQM
->fgTcResourceFastReaction
= FALSE
;
2351 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TX_RESOURCE
);
2362 /*----------------------------------------------------------------------------*/
2364 * \brief Adjust the TC quotas according to traffic demands
2366 * \param[out] prTcqAdjust The resulting adjustment
2367 * \param[in] prTcqStatus Info about the current TC quotas and counters
2371 /*----------------------------------------------------------------------------*/
2373 qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter
,
2374 OUT P_TX_TCQ_ADJUST_T prTcqAdjust
, IN P_TX_TCQ_STATUS_T prTcqStatus
)
2376 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2378 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2380 /* Must initialize */
2381 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2382 prTcqAdjust
->acVariation
[i
] = 0;
2385 /* 4 <1> If TC resource is not just adjusted, exit directly */
2386 if (!prQM
->fgTcResourcePostAnnealing
) {
2389 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2391 INT_32 i4TotalExtraQuota
= 0;
2392 INT_32 ai4ExtraQuota
[QM_ACTIVE_TC_NUM
];
2393 BOOLEAN fgResourceRedistributed
= TRUE
;
2395 /* Obtain the free-to-distribute resource */
2396 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2398 (INT_32
) prTcqStatus
->au2MaxNumOfBuffer
[i
] -
2399 (INT_32
) prQM
->au4CurrentTcResource
[i
];
2401 if (ai4ExtraQuota
[i
] > 0) { /* The resource shall be reallocated to other TCs */
2402 if (ai4ExtraQuota
[i
] > prTcqStatus
->au2FreeBufferCount
[i
]) {
2403 ai4ExtraQuota
[i
] = prTcqStatus
->au2FreeBufferCount
[i
];
2404 fgResourceRedistributed
= FALSE
;
2407 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2408 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2412 /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */
2413 for (i
= 0; i
< QM_ACTIVE_TC_NUM
; i
++) {
2414 if (ai4ExtraQuota
[i
] < 0) {
2415 if ((-ai4ExtraQuota
[i
]) > i4TotalExtraQuota
) {
2416 ai4ExtraQuota
[i
] = (-i4TotalExtraQuota
);
2417 fgResourceRedistributed
= FALSE
;
2420 i4TotalExtraQuota
+= ai4ExtraQuota
[i
];
2421 prTcqAdjust
->acVariation
[i
] = (INT_8
) (-ai4ExtraQuota
[i
]);
2425 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2426 prQM
->fgTcResourcePostAnnealing
= (!fgResourceRedistributed
);
2428 #if QM_FAST_TC_RESOURCE_CTRL
2429 prQM
->fgTcResourceFastReaction
= FALSE
;
2432 #if QM_PRINT_TC_RESOURCE_CTRL
2433 DBGLOG(QM
, LOUD
, ("QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n",
2434 prTcqStatus
->au2FreeBufferCount
[0],
2435 prTcqStatus
->au2FreeBufferCount
[1],
2436 prTcqStatus
->au2FreeBufferCount
[2],
2437 prTcqStatus
->au2FreeBufferCount
[3],
2438 prTcqStatus
->au2FreeBufferCount
[4],
2439 prTcqStatus
->au2FreeBufferCount
[5]));
2449 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2450 /*----------------------------------------------------------------------------*/
2452 * \brief Update the average TX queue length for the TC resource control mechanism
2458 /*----------------------------------------------------------------------------*/
2459 VOID
qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter
)
2461 INT_32 u4CurrQueLen
, u4Tc
, u4StaRecIdx
;
2462 P_STA_RECORD_T prStaRec
;
2463 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2464 P_BSS_INFO_T prBssInfo
;
2466 /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */
2467 for (u4Tc
= 0; u4Tc
< QM_ACTIVE_TC_NUM
; u4Tc
++) {
2470 /* Calculate per-STA queue length */
2471 for (u4StaRecIdx
= 0; u4StaRecIdx
< CFG_NUM_OF_STA_RECORD
; u4StaRecIdx
++) {
2472 prStaRec
= cnmGetStaRecByIndex(prAdapter
, u4StaRecIdx
);
2474 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
2476 /* If the STA is activated, get the queue length */
2477 if ((prStaRec
->fgIsValid
) && (!prBssInfo
->fgIsNetAbsent
)) {
2478 u4CurrQueLen
+= (prStaRec
->arTxQueue
[u4Tc
].u4NumElem
);
2483 if (u4Tc
== TC5_INDEX
) {
2484 /* Update the queue length for TC5 (BMCAST) */
2485 u4CurrQueLen
+= prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
].u4NumElem
;
2488 if (prQM
->au4AverageQueLen
[u4Tc
] == 0){
2489 prQM
->au4AverageQueLen
[u4Tc
] = (u4CurrQueLen
<< prQM
->u4QueLenMovingAverage
);
2492 prQM
->au4AverageQueLen
[u4Tc
] -= (prQM
->au4AverageQueLen
[u4Tc
] >> prQM
->u4QueLenMovingAverage
);
2493 prQM
->au4AverageQueLen
[u4Tc
] += (u4CurrQueLen
);
2497 /* Update the queue length for TC5 (BMCAST) */
2498 u4CurrQueLen
= prQM
->arTxQueue
[TX_QUEUE_INDEX_BMCAST
].u4NumElem
;
2500 if (prQM
->au4AverageQueLen
[TC5_INDEX
] == 0) {
2501 prQM
->au4AverageQueLen
[TC5_INDEX
] = (u4CurrQueLen
<< QM_QUE_LEN_MOVING_AVE_FACTOR
);
2503 prQM
->au4AverageQueLen
[TC5_INDEX
] -=
2504 (prQM
->au4AverageQueLen
[TC5_INDEX
] >> QM_QUE_LEN_MOVING_AVE_FACTOR
);
2505 prQM
->au4AverageQueLen
[TC5_INDEX
] += (u4CurrQueLen
);
2512 qmAllocateResidualTcResource(
2513 IN P_ADAPTER_T prAdapter
,
2514 IN PINT_32 ai4TcResDemand
,
2515 IN PUINT_32 pu4ResidualResource
,
2516 IN PUINT_32 pu4ShareCount
2519 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2520 UINT_32 u4Share
= 0 ;
2523 UINT_32 au4AdjTc
[] = {TC3_INDEX
, TC2_INDEX
, TC5_INDEX
, TC1_INDEX
, TC0_INDEX
};
2524 UINT_32 u4AdjTcSize
= (sizeof(au4AdjTc
) / sizeof(UINT_32
));
2525 UINT_32 u4ResidualResource
= *pu4ResidualResource
;
2526 UINT_32 u4ShareCount
= *pu4ShareCount
;
2528 /* If there is no resource left, exit directly */
2529 if (u4ResidualResource
== 0){
2533 /* This shall not happen */
2534 if (u4ShareCount
== 0){
2535 prQM
->au4CurrentTcResource
[TC1_INDEX
] += u4ResidualResource
;
2536 DBGLOG(QM
, ERROR
, ("QM: (Error) u4ShareCount = 0\n"));
2540 /* Share the residual resource evenly */
2541 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2543 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2544 /* Skip TC4 (not adjustable) */
2545 if (u4TcIdx
== TC4_INDEX
) {
2549 if (ai4TcResDemand
[u4TcIdx
] > 0){
2550 if (ai4TcResDemand
[u4TcIdx
] > u4Share
){
2551 prQM
->au4CurrentTcResource
[u4TcIdx
] += u4Share
;
2552 u4ResidualResource
-= u4Share
;
2553 ai4TcResDemand
[u4TcIdx
] -= u4Share
;
2556 prQM
->au4CurrentTcResource
[u4TcIdx
] += ai4TcResDemand
[u4TcIdx
];
2557 u4ResidualResource
-= ai4TcResDemand
[u4TcIdx
];
2558 ai4TcResDemand
[u4TcIdx
] = 0;
2564 /* By priority, allocate the left resource that is not divisible by u4Share */
2566 while(u4ResidualResource
) {
2567 u4TcIdx
= au4AdjTc
[ucIdx
];
2569 if (ai4TcResDemand
[u4TcIdx
]){
2570 prQM
->au4CurrentTcResource
[u4TcIdx
]++;
2571 u4ResidualResource
--;
2572 ai4TcResDemand
[u4TcIdx
]--;
2574 if(ai4TcResDemand
[u4TcIdx
] == 0) {
2579 if(u4ShareCount
<= 0) {
2584 ucIdx
%= u4AdjTcSize
;
2587 /* Allocate the left resource */
2588 prQM
->au4CurrentTcResource
[TC3_INDEX
] += u4ResidualResource
;
2590 *pu4ResidualResource
= u4ResidualResource
;
2591 *pu4ShareCount
= u4ShareCount
;
2596 /*----------------------------------------------------------------------------*/
2598 * \brief Assign TX resource for each TC according to TX queue length and current assignment
2604 /*----------------------------------------------------------------------------*/
2605 VOID
qmReassignTcResource(IN P_ADAPTER_T prAdapter
)
2607 INT_32 i4TotalResourceDemand
= 0;
2608 UINT_32 u4ResidualResource
= 0;
2610 INT_32 ai4TcResDemand
[QM_ACTIVE_TC_NUM
];
2611 UINT_32 u4ShareCount
= 0;
2612 UINT_32 u4Share
= 0;
2613 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2615 /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to
2616 * start the TC-quota adjusting procedure, which will be invoked upon every TX Done
2619 /* 4 <1> Determine the demands */
2620 /* Determine the amount of extra resource to fulfill all of the demands */
2621 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++) {
2622 /* Skip TC4, which is not adjustable */
2623 if (u4TcIdx
== TC4_INDEX
) {
2627 /* Define: extra_demand = que_length + min_reserved_quota - current_quota */
2628 ai4TcResDemand
[u4TcIdx
] = (QM_GET_TX_QUEUE_LEN(prAdapter
, u4TcIdx
) +
2629 prQM
->au4MinReservedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2631 /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */
2632 if (QM_GET_TX_QUEUE_LEN(prAdapter
, u4TcIdx
)) {
2633 ai4TcResDemand
[u4TcIdx
] += prQM
->u4ExtraReservedTcResource
;
2636 i4TotalResourceDemand
+= ai4TcResDemand
[u4TcIdx
];
2639 //4 <2> Case 1: Demand <= Total Resource
2640 if(i4TotalResourceDemand
<= 0) {
2642 /* 4 <2.1> Calculate the residual resource evenly */
2643 u4ShareCount
= (QM_ACTIVE_TC_NUM
- 1); /* excluding TC4 */
2644 u4ResidualResource
= (UINT_32
) (-i4TotalResourceDemand
);
2645 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2647 /* 4 <2.2> Satisfy every TC and share the residual resource evenly */
2648 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++) {
2649 /* Skip TC4 (not adjustable) */
2650 if (u4TcIdx
== TC4_INDEX
) {
2654 prQM
->au4CurrentTcResource
[u4TcIdx
] += (ai4TcResDemand
[u4TcIdx
] + u4Share
);
2656 /* Every TC is fully satisfied */
2657 ai4TcResDemand
[u4TcIdx
] = 0;
2659 /* The left resource will be allocated to TC3 */
2660 u4ResidualResource
-= u4Share
;
2663 /* 4 <2.3> Allocate the left resource to TC3 (VO) */
2664 prQM
->au4CurrentTcResource
[TC3_INDEX
] += (u4ResidualResource
);
2667 /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */
2670 u4ResidualResource
= prQM
->u4ResidualTcResource
;
2672 /* 4 <3.1> Allocated resouce amount = minimum of (guaranteed, total demand) */
2673 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++) {
2674 /* Skip TC4 (not adjustable) */
2675 if (u4TcIdx
== TC4_INDEX
) {
2679 /* The demand can be fulfilled with the guaranteed resource amount */
2680 if ((prQM
->au4CurrentTcResource
[u4TcIdx
] + ai4TcResDemand
[u4TcIdx
]) <=
2681 prQM
->au4GuaranteedTcResource
[u4TcIdx
]){
2683 prQM
->au4CurrentTcResource
[u4TcIdx
] += ai4TcResDemand
[u4TcIdx
];
2684 u4ResidualResource
+=
2685 (prQM
->au4GuaranteedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2686 ai4TcResDemand
[u4TcIdx
] = 0;
2689 /* The demand can not be fulfilled with the guaranteed resource amount */
2691 ai4TcResDemand
[u4TcIdx
] -=
2692 (prQM
->au4GuaranteedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2694 prQM
->au4CurrentTcResource
[u4TcIdx
] = prQM
->au4GuaranteedTcResource
[u4TcIdx
];
2699 //4 <3.2> Allocate the residual resource
2700 qmAllocateResidualTcResource(prAdapter
, ai4TcResDemand
, &u4ResidualResource
, &u4ShareCount
);
2703 prQM
->fgTcResourcePostAnnealing
= TRUE
;
2705 #if QM_PRINT_TC_RESOURCE_CTRL
2707 DBGLOG(QM
, INFO
, ("QM: TC Rsc adjust to [%03u:%03u:%03u:%03u:%03u:%03u]\n",
2708 prQM
->au4CurrentTcResource
[0], prQM
->au4CurrentTcResource
[1],
2709 prQM
->au4CurrentTcResource
[2], prQM
->au4CurrentTcResource
[3],
2710 prQM
->au4CurrentTcResource
[4], prQM
->au4CurrentTcResource
[5]));
2716 qmReassignTcResource(
2717 IN P_ADAPTER_T prAdapter
2720 INT_32 i4TotalResourceDemand
= 0;
2721 UINT_32 u4ResidualResource
= 0;
2723 INT_32 ai4PerTcResourceDemand
[QM_ACTIVE_TC_NUM
];
2724 UINT_32 u4ShareCount
= 0;
2725 UINT_32 u4Share
= 0 ;
2726 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2728 /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to
2729 * start the TC-quota adjusting procedure, which will be invoked upon every TX Done
2732 //4 <1> Determine the demands
2733 /* Determine the amount of extra resource to fulfill all of the demands */
2734 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2735 /* Skip TC4, which is not adjustable */
2736 if (u4TcIdx
== TC4_INDEX
) {
2740 /* Define: extra_demand = que_length + min_reserved_quota - current_quota */
2741 ai4PerTcResourceDemand
[u4TcIdx
] = (QM_GET_TX_QUEUE_LEN(prAdapter
, u4TcIdx
) +
2742 prQM
->au4MinReservedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2744 /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */
2745 if (QM_GET_TX_QUEUE_LEN(prAdapter
, u4TcIdx
)){
2746 ai4PerTcResourceDemand
[u4TcIdx
] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY
;
2749 i4TotalResourceDemand
+= ai4PerTcResourceDemand
[u4TcIdx
];
2752 //4 <2> Case 1: Demand <= Total Resource
2753 if(i4TotalResourceDemand
<= 0) {
2755 //4 <2.1> Satisfy every TC
2756 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2757 /* Skip TC4 (not adjustable) */
2758 if (u4TcIdx
== TC4_INDEX
) {
2762 prQM
->au4CurrentTcResource
[u4TcIdx
] += ai4PerTcResourceDemand
[u4TcIdx
];
2765 //4 <2.2> Share the residual resource evenly
2766 u4ShareCount
= (QM_ACTIVE_TC_NUM
- 1); /* excluding TC4 */
2767 u4ResidualResource
= (UINT_32
)(-i4TotalResourceDemand
);
2768 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2770 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2771 /* Skip TC4 (not adjustable) */
2772 if (u4TcIdx
== TC4_INDEX
) {
2776 prQM
->au4CurrentTcResource
[u4TcIdx
] += u4Share
;
2778 /* Every TC is fully satisfied */
2779 ai4PerTcResourceDemand
[u4TcIdx
] = 0;
2781 /* The left resource will be allocated to TC3 */
2782 u4ResidualResource
-= u4Share
;
2786 //4 <2.1> Calculate the residual resource evenly
2787 u4ShareCount
= (QM_ACTIVE_TC_NUM
- 1); /* excluding TC4 */
2788 u4ResidualResource
= (UINT_32
)(-i4TotalResourceDemand
);
2789 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2791 //4 <2.2> Satisfy every TC and share the residual resource evenly
2792 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2793 /* Skip TC4 (not adjustable) */
2794 if (u4TcIdx
== TC4_INDEX
) {
2798 prQM
->au4CurrentTcResource
[u4TcIdx
] += (ai4PerTcResourceDemand
[u4TcIdx
] + u4Share
);
2800 /* Every TC is fully satisfied */
2801 ai4PerTcResourceDemand
[u4TcIdx
] = 0;
2803 /* The left resource will be allocated to TC3 */
2804 u4ResidualResource
-= u4Share
;
2808 //4 <2.3> Allocate the left resource to TC3 (VO)
2809 prQM
->au4CurrentTcResource
[TC3_INDEX
] += (u4ResidualResource
);
2813 //4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC
2815 u4ResidualResource
= prQM
->u4ResidualTcResource
;
2817 //4 <3.1> Allocated resouce amount = minimum of (guaranteed, total demand)
2818 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2819 /* Skip TC4 (not adjustable) */
2820 if (u4TcIdx
== TC4_INDEX
) {
2824 /* The demand can be fulfilled with the guaranteed resource amount */
2825 if((prQM
->au4CurrentTcResource
[u4TcIdx
] + ai4PerTcResourceDemand
[u4TcIdx
]) < prQM
->au4GuaranteedTcResource
[u4TcIdx
]){
2826 prQM
->au4CurrentTcResource
[u4TcIdx
] += ai4PerTcResourceDemand
[u4TcIdx
];
2827 u4ResidualResource
+= (prQM
->au4GuaranteedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2828 ai4PerTcResourceDemand
[u4TcIdx
] = 0;
2831 /* The demand can not be fulfilled with the guaranteed resource amount */
2833 ai4PerTcResourceDemand
[u4TcIdx
] -= (prQM
->au4GuaranteedTcResource
[u4TcIdx
] - prQM
->au4CurrentTcResource
[u4TcIdx
]);
2834 prQM
->au4CurrentTcResource
[u4TcIdx
] = prQM
->au4GuaranteedTcResource
[u4TcIdx
];
2839 //4 <3.2> Allocate the residual resource
2841 /* If there is no resource left, exit directly */
2842 if (u4ResidualResource
== 0){
2846 /* This shall not happen */
2847 if (u4ShareCount
== 0){
2848 prQM
->au4CurrentTcResource
[TC1_INDEX
] += u4ResidualResource
;
2849 DBGLOG(QM
, ERROR
, ("QM: (Error) u4ShareCount = 0\n"));
2853 /* Share the residual resource evenly */
2854 u4Share
= (u4ResidualResource
/ u4ShareCount
);
2856 for (u4TcIdx
= 0; u4TcIdx
< QM_ACTIVE_TC_NUM
; u4TcIdx
++){
2857 /* Skip TC4 (not adjustable) */
2858 if (u4TcIdx
== TC4_INDEX
) {
2862 if (ai4PerTcResourceDemand
[u4TcIdx
]){
2863 if (ai4PerTcResourceDemand
[u4TcIdx
] - u4Share
){
2864 prQM
->au4CurrentTcResource
[u4TcIdx
] += u4Share
;
2865 u4ResidualResource
-= u4Share
;
2866 ai4PerTcResourceDemand
[u4TcIdx
] -= u4Share
;
2869 prQM
->au4CurrentTcResource
[u4TcIdx
] += ai4PerTcResourceDemand
[u4TcIdx
];
2870 u4ResidualResource
-= ai4PerTcResourceDemand
[u4TcIdx
];
2871 ai4PerTcResourceDemand
[u4TcIdx
] = 0;
2877 /* By priority, allocate the left resource that is not divisible by u4Share */
2878 if (u4ResidualResource
== 0){
2882 if (ai4PerTcResourceDemand
[TC3_INDEX
]){ /* VO */
2883 prQM
->au4CurrentTcResource
[TC3_INDEX
]++;
2884 if (--u4ResidualResource
== 0) {
2889 if (ai4PerTcResourceDemand
[TC2_INDEX
]){ /* VI */
2890 prQM
->au4CurrentTcResource
[TC2_INDEX
]++;
2891 if (--u4ResidualResource
== 0) {
2896 if (ai4PerTcResourceDemand
[TC5_INDEX
]){ /* BMCAST */
2897 prQM
->au4CurrentTcResource
[TC5_INDEX
]++;
2898 if (--u4ResidualResource
== 0) {
2903 if (ai4PerTcResourceDemand
[TC1_INDEX
]){ /* BE */
2904 prQM
->au4CurrentTcResource
[TC1_INDEX
]++;
2905 if (--u4ResidualResource
== 0) {
2910 if (ai4PerTcResourceDemand
[TC0_INDEX
]){ /* BK */
2911 prQM
->au4CurrentTcResource
[TC0_INDEX
]++;
2912 if (--u4ResidualResource
== 0) {
2917 /* Allocate the left resource */
2918 prQM
->au4CurrentTcResource
[TC3_INDEX
] += u4ResidualResource
;
2923 prQM
->fgTcResourcePostAnnealing
= TRUE
;
2925 #if QM_PRINT_TC_RESOURCE_CTRL
2927 DBGLOG(QM
, INFO
, ("QM: TC Rsc adjust to [%03u:%03u:%03u:%03u:%03u:%03u]\n",
2928 prQM
->au4CurrentTcResource
[0],
2929 prQM
->au4CurrentTcResource
[1],
2930 prQM
->au4CurrentTcResource
[2],
2931 prQM
->au4CurrentTcResource
[3],
2932 prQM
->au4CurrentTcResource
[4],
2933 prQM
->au4CurrentTcResource
[5]));
2939 /*----------------------------------------------------------------------------*/
2941 * \brief Adjust TX resource for each TC according to TX queue length and current assignment
2947 /*----------------------------------------------------------------------------*/
2948 VOID
qmDoAdaptiveTcResourceCtrl(IN P_ADAPTER_T prAdapter
)
2950 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
2952 /* 4 <0> Check to update queue length or not */
2953 if (--prQM
->u4TimeToUpdateQueLen
) {
2956 /* 4 <1> Update TC queue length */
2957 prQM
->u4TimeToUpdateQueLen
= QM_INIT_TIME_TO_UPDATE_QUE_LEN
;
2958 qmUpdateAverageTxQueLen(prAdapter
);
2960 /* 4 <2> Adjust TC resource assignment */
2961 /* Check whether it is time to adjust the TC resource assignment */
2962 if (--prQM
->u4TimeToAdjustTcResource
== 0) {
2963 /* The last assignment has not been completely applied */
2964 if (prQM
->fgTcResourcePostAnnealing
) {
2965 /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */
2966 prQM
->u4TimeToAdjustTcResource
= 1;
2969 /* The last assignment has been applied */
2971 prQM
->u4TimeToAdjustTcResource
= QM_INIT_TIME_TO_ADJUST_TC_RSC
;
2972 qmReassignTcResource(prAdapter
);
2973 #if QM_FAST_TC_RESOURCE_CTRL
2974 if (prQM
->fgTcResourceFastReaction
) {
2975 prQM
->fgTcResourceFastReaction
= FALSE
;
2976 nicTxAdjustTcq(prAdapter
);
2983 #if QM_PRINT_TC_RESOURCE_CTRL
2987 for (u4Tc
= 0; u4Tc
< QM_ACTIVE_TC_NUM
; u4Tc
++) {
2988 if (QM_GET_TX_QUEUE_LEN(prAdapter
, u4Tc
) >= 100) {
2989 DBGLOG(QM
, LOUD
, ("QM: QueLen [%ld %ld %ld %ld %ld %ld]\n",
2990 QM_GET_TX_QUEUE_LEN(prAdapter
, 0),
2991 QM_GET_TX_QUEUE_LEN(prAdapter
, 1),
2992 QM_GET_TX_QUEUE_LEN(prAdapter
, 2),
2993 QM_GET_TX_QUEUE_LEN(prAdapter
, 3),
2994 QM_GET_TX_QUEUE_LEN(prAdapter
, 4),
2995 QM_GET_TX_QUEUE_LEN(prAdapter
, 5)
3005 #if QM_FAST_TC_RESOURCE_CTRL
3006 VOID
qmCheckForFastTcResourceCtrl(IN P_ADAPTER_T prAdapter
, IN UINT_8 ucTc
)
3008 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
3010 /* Trigger TC resource adjustment if there is a requirement coming for a empty TC */
3011 if (!prQM
->au4CurrentTcResource
[ucTc
]) {
3012 prQM
->u4TimeToUpdateQueLen
= 1;
3013 prQM
->u4TimeToAdjustTcResource
= 1;
3014 prQM
->fgTcResourceFastReaction
= TRUE
;
3016 DBGLOG(QM
, LOUD
, ("Trigger TC Resource adjustment for TC[%u]\n", ucTc
));
3024 /*----------------------------------------------------------------------------*/
3025 /* RX-Related Queue Management */
3026 /*----------------------------------------------------------------------------*/
3027 /*----------------------------------------------------------------------------*/
3029 * \brief Init Queue Managment for RX
3035 /*----------------------------------------------------------------------------*/
3036 VOID
qmInitRxQueues(IN P_ADAPTER_T prAdapter
)
3038 /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */
3043 /*----------------------------------------------------------------------------*/
3045 * \brief Handle RX packets (buffer reordering)
3047 * \param[in] prSwRfbListHead The list of RX packets
3049 * \return The list of packets which are not buffered for reordering
3051 /*----------------------------------------------------------------------------*/
3052 P_SW_RFB_T
qmHandleRxPackets(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfbListHead
)
3055 #if CFG_RX_REORDERING_ENABLED
3057 P_SW_RFB_T prCurrSwRfb
;
3058 P_SW_RFB_T prNextSwRfb
;
3059 P_HW_MAC_RX_DESC_T prRxStatus
;
3061 P_QUE_T prReturnedQue
;
3062 PUINT_8 pucEthDestAddr
;
3063 BOOLEAN fgIsBMC
, fgIsHTran
;
3066 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3068 DEBUGFUNC("qmHandleRxPackets");
3070 ASSERT(prSwRfbListHead
);
3072 prReturnedQue
= &rReturnedQue
;
3074 QUEUE_INITIALIZE(prReturnedQue
);
3075 prNextSwRfb
= prSwRfbListHead
;
3078 prCurrSwRfb
= prNextSwRfb
;
3079 prNextSwRfb
= QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb
);
3081 /* prHifRxHdr = prCurrSwRfb->prHifRxHdr; // TODO: (Tehuang) Use macro to obtain the pointer */
3082 prRxStatus
= prCurrSwRfb
->prRxStatus
;
3084 /* TODO: (Tehuang) Check if relaying */
3085 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_HOST
;
3087 /* Decide the Destination */
3088 #if CFG_RX_PKTS_DUMP
3089 if (prAdapter
->rRxCtrl
.u4RxPktsDumpTypeMask
& BIT(HIF_RX_PKT_TYPE_DATA
)) {
3091 ("QM RX DATA: net _u sta idx %u wlan idx %u ssn _u tid %u ptype %u 11 %u\n",
3092 /* HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), */
3093 prCurrSwRfb
->ucStaRecIdx
, prRxStatus
->ucWlanIdx
,
3094 /* HIF_RX_HDR_GET_SN(prHifRxHdr), *//* The new SN of the frame */
3095 HAL_RX_STATUS_GET_TID(prRxStatus
),
3096 prCurrSwRfb
->ucPacketType
, prCurrSwRfb
->fgReorderBuffer
));
3098 DBGLOG_MEM8(SW4
, TRACE
, (PUINT_8
) prCurrSwRfb
->pvHeader
,
3099 prCurrSwRfb
->u2PacketLen
);
3103 fgIsBMC
= HAL_RX_STATUS_IS_BC(prRxStatus
) | HAL_RX_STATUS_IS_MC(prRxStatus
);
3105 if (HAL_RX_STATUS_GET_HEADER_TRAN(prRxStatus
) == TRUE
) { /* (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){ */
3108 P_BSS_INFO_T prBssInfo
;
3109 UINT_8 aucTaAddr
[MAC_ADDR_LEN
];
3112 pucEthDestAddr
= prCurrSwRfb
->pvHeader
;
3114 if (prCurrSwRfb
->prStaRec
== NULL
) {
3115 /* Workaround WTBL Issue */
3116 if (prCurrSwRfb
->prRxStatusGroup4
== NULL
) {
3117 DBGLOG_MEM8(SW4
, TRACE
, (PUINT_8
) prCurrSwRfb
->prRxStatus
,
3118 prCurrSwRfb
->prRxStatus
->u2RxByteCount
);
3121 HAL_RX_STATUS_GET_TA(prCurrSwRfb
->prRxStatusGroup4
, aucTaAddr
);
3122 prCurrSwRfb
->ucStaRecIdx
=
3123 secLookupStaRecIndexFromTA(prAdapter
, aucTaAddr
);
3124 if (prCurrSwRfb
->ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
) {
3125 prCurrSwRfb
->prStaRec
=
3126 cnmGetStaRecByIndex(prAdapter
,
3127 prCurrSwRfb
->ucStaRecIdx
);
3129 ("Re-search the staRec = %d, mac = " MACSTR
3130 ", byteCnt= %d\n", prCurrSwRfb
->ucStaRecIdx
,
3131 MAC2STR(aucTaAddr
), prRxStatus
->u2RxByteCount
));
3134 if (prCurrSwRfb
->prStaRec
== NULL
) {
3136 ("Mark NULL the Packet for StaRec == NULL, wlanIdx %d, but via Header Translation\n",
3137 prRxStatus
->ucWlanIdx
));
3138 /* DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prRxStatus, prRxStatus->u2RxByteCount); */
3139 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3140 QUEUE_INSERT_TAIL(prReturnedQue
,
3141 (P_QUE_ENTRY_T
) prCurrSwRfb
);
3145 prCurrSwRfb
->ucWlanIdx
= prCurrSwRfb
->prStaRec
->ucWlanIndex
;
3146 GLUE_SET_PKT_BSS_IDX(prCurrSwRfb
->pvPacket
,
3147 secGetBssIdxByWlanIdx(prAdapter
,
3148 prCurrSwRfb
->ucWlanIdx
));
3150 /* ASSERT(prAdapter->rWifiVar.arWtbl[prCurrSwRfb->ucWlanIdx].ucUsed); */
3151 if (prAdapter
->rRxCtrl
.rFreeSwRfbList
.u4NumElem
3152 > (CFG_RX_MAX_PKT_NUM
- CFG_NUM_OF_QM_RX_PKT_NUM
)) {
3154 ucBssIndex
= prCurrSwRfb
->prStaRec
->ucBssIndex
;
3155 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, ucBssIndex
);
3156 /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */
3160 /* if ((OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) { */
3161 /* fgIsBMC = HAL_RX_STATUS_IS_BC(prRxStatus) | HAL_RX_STATUS_IS_MC(prRxStatus); */
3164 if (IS_BSS_ACTIVE(prBssInfo
)) {
3165 if (OP_MODE_ACCESS_POINT
== prBssInfo
->eCurrentOPMode
) {
3166 qmHandleRxPackets_AOSP_0
;
3167 } /* OP_MODE_ACCESS_POINT */
3168 #if CFG_SUPPORT_PASSPOINT
3169 else if (hs20IsFrameFilterEnabled(prAdapter
, prBssInfo
) &&
3170 hs20IsUnsecuredFrame(prAdapter
, prBssInfo
,
3173 ("Mark NULL the Packet for Dropped Packet %u\n",
3175 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3176 QUEUE_INSERT_TAIL(prReturnedQue
,
3177 (P_QUE_ENTRY_T
) prCurrSwRfb
);
3180 #endif /* CFG_SUPPORT_PASSPOINT */
3183 ("Mark NULL the Packet for inactive Bss %u\n",
3185 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3186 QUEUE_INSERT_TAIL(prReturnedQue
,
3187 (P_QUE_ENTRY_T
) prCurrSwRfb
);
3192 /* Dont not occupy other SW RFB */
3193 DBGLOG(QM
, TRACE
, ("Mark NULL the Packet for less Free Sw Rfb\n"));
3194 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3195 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3200 #if CFG_SUPPORT_WAPI
3201 /* Todo:: Move the data class error check here */
3202 if (prCurrSwRfb
->u2PacketLen
> ETHER_HEADER_LEN
) {
3203 PUINT_8 pc
= (PUINT_8
) prCurrSwRfb
->pvHeader
;
3204 UINT_16 u2Etype
= 0;
3205 u2Etype
= (pc
[ETHER_TYPE_LEN_OFFSET
] << 8) | (pc
[ETHER_TYPE_LEN_OFFSET
+ 1]);
3206 /* for wapi integrity test. WPI_1x packet should be always in non-encrypted mode.
3207 if we received any WPI(0x88b4) packet that is encrypted, drop here. */
3208 if (u2Etype
== ETH_WPI_1X
&&
3209 HAL_RX_STATUS_GET_SEC_MODE(prRxStatus
) != 0) {
3210 DBGLOG(QM
, INFO
, ("drop wpi packet with sec mode\n"));
3211 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3212 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3217 if (prCurrSwRfb
->fgReorderBuffer
&& !fgIsBMC
&& fgIsHTran
) {
3218 /* If this packet should dropped or indicated to the host immediately,
3219 * it should be enqueued into the rReturnedQue with specific flags. If
3220 * this packet should be buffered for reordering, it should be enqueued
3221 * into the reordering queue in the STA_REC rather than into the
3224 qmProcessPktWithReordering(prAdapter
, prCurrSwRfb
, prReturnedQue
);
3226 } else if (prCurrSwRfb
->fgDataFrame
) {
3227 /* Check Class Error */
3229 if (secCheckClassError
3230 (prAdapter
, prCurrSwRfb
, prCurrSwRfb
->prStaRec
) == TRUE
) {
3231 P_RX_BA_ENTRY_T prReorderQueParm
= NULL
;
3233 /* Invalid BA aggrement */
3235 UINT_16 u2FrameCtrl
= 0;
3237 u2FrameCtrl
= HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prCurrSwRfb
->prRxStatusGroup4
);
3238 // Check FC type, if DATA, then no-reordering
3239 if((u2FrameCtrl
& MASK_FRAME_TYPE
) == MAC_FRAME_DATA
){
3240 DBGLOG(QM
, TRACE
, ("FC [0x%04X], no-reordering...\n", u2FrameCtrl
));
3243 prReorderQueParm
= ((prCurrSwRfb
->prStaRec
->aprRxReorderParamRefTbl
)[prCurrSwRfb
->ucTid
]);
3247 if (prReorderQueParm
&& prReorderQueParm
->fgIsValid
3249 qmProcessPktWithReordering(prAdapter
, prCurrSwRfb
,
3252 qmHandleRxPackets_AOSP_1
;
3255 DBGLOG(QM
, TRACE
, ("Mark NULL the Packet for class error\n"));
3256 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3257 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3261 P_WLAN_MAC_HEADER_T prWlanMacHeader
;
3263 ASSERT(prCurrSwRfb
->pvHeader
);
3265 prWlanMacHeader
= (P_WLAN_MAC_HEADER_T
) prCurrSwRfb
->pvHeader
;
3266 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3268 switch (prWlanMacHeader
->u2FrameCtrl
& MASK_FRAME_TYPE
) {
3270 case MAC_FRAME_BLOCK_ACK_REQ
:
3271 qmProcessBarFrame(prAdapter
, prCurrSwRfb
, prReturnedQue
);
3275 ("Mark NULL the Packet for non-interesting type\n"));
3276 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3281 } while (prNextSwRfb
);
3284 /* The returned list of SW_RFBs must end with a NULL pointer */
3285 if (QUEUE_IS_NOT_EMPTY(prReturnedQue
)) {
3286 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T
) QUEUE_GET_TAIL(prReturnedQue
), NULL
);
3289 return (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
);
3293 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3294 return prSwRfbListHead
;
3300 /*----------------------------------------------------------------------------*/
3302 * \brief Reorder the received packet
3304 * \param[in] prSwRfb The RX packet to process
3305 * \param[out] prReturnedQue The queue for indicating packets
3309 /*----------------------------------------------------------------------------*/
3311 qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter
,
3312 IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
3316 P_STA_RECORD_T prStaRec
;
3317 P_HW_MAC_RX_DESC_T prRxStatus
;
3318 P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4
= NULL
;
3319 P_RX_BA_ENTRY_T prReorderQueParm
;
3324 P_QUE_T prReorderQue
;
3325 /* P_SW_RFB_T prReorderedSwRfb; */
3327 DEBUGFUNC("qmProcessPktWithReordering");
3330 ASSERT(prReturnedQue
);
3331 ASSERT(prSwRfb
->prRxStatus
);
3333 /* Incorrect STA_REC index */
3334 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
3335 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3336 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3337 DBGLOG(QM
, WARN
, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
3338 prSwRfb
->ucStaRecIdx
));
3339 authSendDeauthFrame(prAdapter
,
3342 prSwRfb
, REASON_CODE_CLASS_3_ERR
, (PFN_TX_DONE_HANDLER
) NULL
);
3347 /* Check whether the STA_REC is activated */
3348 prStaRec
= prSwRfb
->prStaRec
;
3351 prRxStatus
= prSwRfb
->prRxStatus
;
3352 prSwRfb
->ucTid
= (UINT_8
) (HAL_RX_STATUS_GET_TID(prRxStatus
));
3353 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3356 if (!(prStaRec
->fgIsValid
)) {
3357 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3358 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3359 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3360 DBGLOG(QM
, WARN
, ("Reordering for an invalid STA_REC\n"));
3366 /* Check whether the BA agreement exists */
3367 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
3368 if (!prReorderQueParm
|| !(prReorderQueParm
->fgIsValid
)) {
3369 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3370 prSwRfb
->eDst
= RX_PKT_DESTINATION_HOST
;
3371 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3372 DBGLOG(QM
, TRACE
, ("Reordering for a NULL ReorderQueParm\n"));
3376 prRxStatusGroup4
= prSwRfb
->prRxStatusGroup4
;
3377 if (prRxStatusGroup4
== NULL
) {
3378 DBGLOG(QM
, ERROR
, ("prRxStatusGroup4 is NULL !!!\n"));
3380 ("prSwRfb->pvHeader is 0x%p !!!\n", (PUINT_32
) prSwRfb
->pvHeader
));
3381 DBGLOG(QM
, ERROR
, ("prSwRfb->u2PacketLen is %d !!!\n", prSwRfb
->u2PacketLen
));
3382 DBGLOG(QM
, ERROR
, ("========= START TO DUMP prSwRfb =========\n"));
3383 DBGLOG_MEM8(QM
, ERROR
, prSwRfb
->pvHeader
, prSwRfb
->u2PacketLen
);
3384 DBGLOG(QM
, ERROR
, ("========= END OF DUMP prSwRfb =========\n"));
3385 ASSERT(prRxStatusGroup4
);
3390 HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4
) >> RX_STATUS_SEQ_NUM_OFFSET
;
3392 /* Start to reorder packets */
3393 u4SeqNo
= (UINT_32
) (prSwRfb
->u2SSN
);
3394 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3395 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
3396 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
3399 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3401 /* Case 1: Fall within */
3402 if /* 0 - start - sn - end - 4095 */
3403 (((u4WinStart
<= u4SeqNo
) && (u4SeqNo
<= u4WinEnd
))
3404 /* 0 - end - start - sn - 4095 */
3405 || ((u4WinEnd
< u4WinStart
) && (u4WinStart
<= u4SeqNo
))
3406 /* 0 - sn - end - start - 4095 */
3407 || ((u4SeqNo
<= u4WinEnd
) && (u4WinEnd
< u4WinStart
))) {
3409 qmInsertFallWithinReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
3411 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3412 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3413 /* Let the first received packet pass the reorder check */
3415 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SeqNo
, u4WinStart
,
3418 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SeqNo
;
3419 prReorderQueParm
->u2WinEnd
=
3420 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3421 1) % MAX_SEQ_NO_COUNT
;
3422 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
3427 qmPopOutDueToFallWithin(prAdapter
, prReorderQueParm
, prReturnedQue
);
3429 /* Case 2: Fall ahead */
3431 /* 0 - start - end - sn - (start+2048) - 4095 */
3432 (((u4WinStart
< u4WinEnd
)
3433 && (u4WinEnd
< u4SeqNo
)
3434 && (u4SeqNo
< (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
3435 /* 0 - sn - (start+2048) - start - end - 4095 */
3436 || ((u4SeqNo
< u4WinStart
)
3437 && (u4WinStart
< u4WinEnd
)
3438 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
3439 /* 0 - end - sn - (start+2048) - start - 4095 */
3440 || ((u4WinEnd
< u4SeqNo
)
3441 && (u4SeqNo
< u4WinStart
)
3442 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))) {
3445 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3446 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3447 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
3451 qmInsertFallAheadReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
3453 /* Advance the window after inserting a new tail */
3454 prReorderQueParm
->u2WinEnd
= (UINT_16
) u4SeqNo
;
3455 prReorderQueParm
->u2WinStart
=
3456 (((prReorderQueParm
->u2WinEnd
) - (prReorderQueParm
->u2WinSize
) +
3457 MAX_SEQ_NO_COUNT
+ 1)
3458 % MAX_SEQ_NO_COUNT
);
3460 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3463 /* Case 3: Fall behind */
3466 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3467 #if QM_RX_INIT_FALL_BEHIND_PASS
3468 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3469 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3470 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3471 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3477 /* An erroneous packet */
3478 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3479 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3480 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3489 VOID
qmProcessBarFrame(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
3492 P_STA_RECORD_T prStaRec
;
3493 P_HW_MAC_RX_DESC_T prRxStatus
;
3494 P_RX_BA_ENTRY_T prReorderQueParm
;
3495 P_CTRL_BAR_FRAME_T prBarCtrlFrame
;
3500 P_QUE_T prReorderQue
;
3501 /* P_SW_RFB_T prReorderedSwRfb; */
3504 ASSERT(prReturnedQue
);
3505 ASSERT(prSwRfb
->prRxStatus
);
3506 ASSERT(prSwRfb
->pvHeader
);
3508 prRxStatus
= prSwRfb
->prRxStatus
;
3510 prBarCtrlFrame
= (P_CTRL_BAR_FRAME_T
) prSwRfb
->pvHeader
;
3513 (*((PUINT_16
) ((PUINT_8
) prBarCtrlFrame
+ CTRL_BAR_BAR_CONTROL_OFFSET
))) >>
3514 BAR_CONTROL_TID_INFO_OFFSET
;
3516 (*((PUINT_16
) ((PUINT_8
) prBarCtrlFrame
+ CTRL_BAR_BAR_INFORMATION_OFFSET
))) >>
3519 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3520 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3522 /* Incorrect STA_REC index */
3523 prSwRfb
->ucStaRecIdx
= secLookupStaRecIndexFromTA(prAdapter
, prBarCtrlFrame
->aucSrcAddr
);
3524 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
3525 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
3526 prSwRfb
->ucStaRecIdx
));
3531 /* Check whether the STA_REC is activated */
3532 prSwRfb
->prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
3533 prStaRec
= prSwRfb
->prStaRec
;
3534 if (prStaRec
== NULL
) {
3535 /* ASSERT(prStaRec); */
3539 if (!(prStaRec
->fgIsValid
)) {
3540 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3541 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
3547 /* Check whether the BA agreement exists */
3548 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
3549 if (!prReorderQueParm
) {
3550 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3551 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
3557 u4SSN
= (UINT_32
) (prSwRfb
->u2SSN
);
3558 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3559 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
3560 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
3562 if (qmCompareSnIsLessThan(u4WinStart
, u4SSN
)) {
3563 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SSN
;
3564 prReorderQueParm
->u2WinEnd
=
3565 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3566 1) % MAX_SEQ_NO_COUNT
;
3568 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb
->ucTid
, u4SSN
,
3569 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3570 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3573 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SSN
, u4WinStart
,
3581 qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb
,
3582 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3584 P_SW_RFB_T prExaminedQueuedSwRfb
;
3585 P_QUE_T prReorderQue
;
3587 ASSERT(prReorderQueParm
);
3588 ASSERT(prReturnedQue
);
3590 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3591 prExaminedQueuedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3593 /* There are no packets queued in the Reorder Queue */
3594 if (prExaminedQueuedSwRfb
== NULL
) {
3595 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
3596 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3597 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3598 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
3599 prReorderQue
->u4NumElem
++;
3602 /* Determine the insert position */
3605 /* Case 1: Terminate. A duplicate packet */
3606 if (((prExaminedQueuedSwRfb
->u2SSN
) == (prSwRfb
->u2SSN
))) {
3607 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3608 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3612 /* Case 2: Terminate. The insert point is found */
3613 else if (qmCompareSnIsLessThan((prSwRfb
->u2SSN
),
3614 (prExaminedQueuedSwRfb
->u2SSN
))) {
3618 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3620 prExaminedQueuedSwRfb
=
3621 (P_SW_RFB_T
) (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prNext
);
3623 } while (prExaminedQueuedSwRfb
);
3625 /* Update the Reorder Queue Parameters according to the found insert position */
3626 if (prExaminedQueuedSwRfb
== NULL
) {
3627 /* The received packet shall be placed at the tail */
3628 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
3629 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3630 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
3631 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) (prSwRfb
);
3633 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
=
3634 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
;
3635 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= (P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
;
3636 if (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
) == (prReorderQue
->prHead
)) {
3637 /* The received packet will become the head */
3638 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3640 (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
)->prNext
=
3641 (P_QUE_ENTRY_T
) prSwRfb
;
3643 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
= (P_QUE_ENTRY_T
) prSwRfb
;
3646 prReorderQue
->u4NumElem
++;
3654 qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb
,
3655 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3657 P_QUE_T prReorderQue
;
3659 ASSERT(prReorderQueParm
);
3660 ASSERT(prReturnedQue
);
3662 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3664 /* There are no packets queued in the Reorder Queue */
3665 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3666 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
3667 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3668 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3670 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
3671 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3672 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
3674 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
3675 prReorderQue
->u4NumElem
++;
3681 qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter
,
3682 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3684 P_SW_RFB_T prReorderedSwRfb
;
3685 P_QUE_T prReorderQue
;
3686 BOOLEAN fgDequeuHead
, fgMissing
;
3687 OS_SYSTIME rCurrentTime
, rMissTimeout
;
3689 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3693 rMissTimeout
= g_arMissTimeout
[prReorderQueParm
->ucStaRecIdx
][prReorderQueParm
->ucTid
];
3696 GET_CURRENT_SYSTIME(&rCurrentTime
);
3699 /* Check whether any packet can be indicated to the higher layer */
3701 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3705 /* Always examine the head packet */
3706 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3707 fgDequeuHead
= FALSE
;
3709 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3710 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3712 fgDequeuHead
= TRUE
;
3713 prReorderQueParm
->u2WinStart
=
3714 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3716 /* SN > WinStart, break to update WinEnd */
3718 /* Start bubble timer */
3719 if (!prReorderQueParm
->fgHasBubble
) {
3720 cnmTimerStartTimer(prAdapter
,
3721 &(prReorderQueParm
->rReorderBubbleTimer
),
3722 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3723 prReorderQueParm
->fgHasBubble
= TRUE
;
3724 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
3727 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3728 prReorderQueParm
->ucStaRecIdx
, prReorderedSwRfb
->ucTid
,
3729 prReorderQueParm
->u2FirstBubbleSn
,
3730 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3733 if ((fgMissing
== TRUE
) &&
3734 CHECK_FOR_TIMEOUT(rCurrentTime
, rMissTimeout
,
3735 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
))) {
3737 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3738 prReorderQueParm
->ucTid
, prReorderedSwRfb
->u2SSN
));
3739 fgDequeuHead
= TRUE
;
3740 prReorderQueParm
->u2WinStart
=
3741 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3749 /* Dequeue the head packet */
3752 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3753 prReorderQue
->prHead
= NULL
;
3754 prReorderQue
->prTail
= NULL
;
3756 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3757 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3759 prReorderQue
->u4NumElem
--;
3760 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3761 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3765 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3768 if (fgMissing
== FALSE
) {
3769 GET_CURRENT_SYSTIME(&rMissTimeout
);
3773 /* After WinStart has been determined, update the WinEnd */
3774 prReorderQueParm
->u2WinEnd
=
3775 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3776 1) % MAX_SEQ_NO_COUNT
);
3781 qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter
,
3782 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3784 P_SW_RFB_T prReorderedSwRfb
;
3785 P_QUE_T prReorderQue
;
3786 BOOLEAN fgDequeuHead
;
3788 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3790 /* Check whether any packet can be indicated to the higher layer */
3792 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3796 /* Always examine the head packet */
3797 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3798 fgDequeuHead
= FALSE
;
3800 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3801 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3803 fgDequeuHead
= TRUE
;
3804 prReorderQueParm
->u2WinStart
=
3805 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3808 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3809 else if (qmCompareSnIsLessThan((UINT_32
) (prReorderedSwRfb
->u2SSN
),
3810 (UINT_32
) (prReorderQueParm
->u2WinStart
))) {
3812 fgDequeuHead
= TRUE
;
3816 /* SN > WinStart, break to update WinEnd */
3818 /* Start bubble timer */
3819 if (!prReorderQueParm
->fgHasBubble
) {
3820 cnmTimerStartTimer(prAdapter
,
3821 &(prReorderQueParm
->rReorderBubbleTimer
),
3822 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3823 prReorderQueParm
->fgHasBubble
= TRUE
;
3824 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
3827 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3828 prReorderQueParm
->ucStaRecIdx
, prReorderedSwRfb
->ucTid
,
3829 prReorderQueParm
->u2FirstBubbleSn
,
3830 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3836 /* Dequeue the head packet */
3839 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3840 prReorderQue
->prHead
= NULL
;
3841 prReorderQue
->prTail
= NULL
;
3843 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3844 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3846 prReorderQue
->u4NumElem
--;
3847 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3848 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3852 /* After WinStart has been determined, update the WinEnd */
3853 prReorderQueParm
->u2WinEnd
=
3854 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3855 1) % MAX_SEQ_NO_COUNT
);
3859 VOID
qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter
, IN ULONG ulParamPtr
)
3861 P_RX_BA_ENTRY_T prReorderQueParm
= (P_RX_BA_ENTRY_T
) ulParamPtr
;
3862 P_SW_RFB_T prSwRfb
= (P_SW_RFB_T
) NULL
;
3863 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent
;
3865 KAL_SPIN_LOCK_DECLARATION();
3867 if (!prReorderQueParm
->fgIsValid
) {
3868 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3869 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3873 if (!prReorderQueParm
->fgHasBubble
) {
3875 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3876 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3880 DBGLOG(QM
, TRACE
, ("QM:(Bub Timeout) STA[%u] TID[%u] BubSN[%u]\n",
3881 prReorderQueParm
->ucStaRecIdx
,
3882 prReorderQueParm
->ucTid
, prReorderQueParm
->u2FirstBubbleSn
));
3884 /* Generate a self-inited event to Rx path */
3885 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_FREE_QUE
);
3886 QUEUE_REMOVE_HEAD(&prAdapter
->rRxCtrl
.rFreeSwRfbList
, prSwRfb
, P_SW_RFB_T
);
3887 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_FREE_QUE
);
3890 prCheckReorderEvent
= (P_EVENT_CHECK_REORDER_BUBBLE_T
) prSwRfb
->pucRecvBuff
;
3892 prSwRfb
->ucPacketType
= RX_PKT_TYPE_SW_DEFINED
;
3894 prSwRfb
->prRxStatus
->u2PktTYpe
= RXM_RXD_PKT_TYPE_SW_EVENT
;
3896 prCheckReorderEvent
->ucEID
= EVENT_ID_CHECK_REORDER_BUBBLE
;
3897 prCheckReorderEvent
->ucSeqNum
= 0;
3899 prCheckReorderEvent
->ucStaRecIdx
= prReorderQueParm
->ucStaRecIdx
;
3900 prCheckReorderEvent
->ucTid
= prReorderQueParm
->ucTid
;
3901 prCheckReorderEvent
->u2Length
= sizeof(EVENT_CHECK_REORDER_BUBBLE_T
);
3903 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_QUE
);
3904 QUEUE_INSERT_TAIL(&prAdapter
->rRxCtrl
.rReceivedRfbList
, &prSwRfb
->rQueEntry
);
3905 RX_INC_CNT(&prAdapter
->rRxCtrl
, RX_MPDU_TOTAL_COUNT
);
3906 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_QUE
);
3908 DBGLOG(QM
, LOUD
, ("QM:(Bub Check Event Sent) STA[%u] TID[%u]\n",
3909 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3911 nicRxProcessRFBs(prAdapter
);
3913 DBGLOG(QM
, LOUD
, ("QM:(Bub Check Event Handled) STA[%u] TID[%u]\n",
3914 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3917 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bub check event alloc failed\n",
3918 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3920 cnmTimerStartTimer(prAdapter
, &(prReorderQueParm
->rReorderBubbleTimer
),
3921 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3923 DBGLOG(QM
, TRACE
, ("QM:(Bub Timer Restart) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3924 prReorderQueParm
->ucStaRecIdx
,
3925 prReorderQueParm
->ucTid
,
3926 prReorderQueParm
->u2FirstBubbleSn
,
3927 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3933 VOID
qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
3935 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent
=
3936 (P_EVENT_CHECK_REORDER_BUBBLE_T
) prEvent
;
3937 P_RX_BA_ENTRY_T prReorderQueParm
;
3938 P_QUE_T prReorderQue
;
3940 P_QUE_T prReturnedQue
= &rReturnedQue
;
3941 P_SW_RFB_T prReorderedSwRfb
, prSwRfb
;
3943 QUEUE_INITIALIZE(prReturnedQue
);
3945 /* Get target Rx BA entry */
3946 prReorderQueParm
= qmLookupRxBaEntry(prAdapter
,
3947 prCheckReorderEvent
->ucStaRecIdx
,
3948 prCheckReorderEvent
->ucTid
);
3951 if (!prReorderQueParm
) {
3952 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3953 prCheckReorderEvent
->ucStaRecIdx
, prCheckReorderEvent
->ucTid
));
3957 if (!prReorderQueParm
->fgIsValid
) {
3958 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3959 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3963 if (!prReorderQueParm
->fgHasBubble
) {
3965 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3966 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3970 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3972 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3973 prReorderQueParm
->fgHasBubble
= FALSE
;
3976 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3977 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3982 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Event Got) STA[%u] TID[%u]\n",
3983 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3985 /* Expected bubble timeout => pop out packets before win_end */
3986 if (prReorderQueParm
->u2FirstBubbleSn
== prReorderQueParm
->u2WinStart
) {
3988 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_TAIL(prReorderQue
);
3990 prReorderQueParm
->u2WinStart
= prReorderedSwRfb
->u2SSN
+ 1;
3991 prReorderQueParm
->u2WinEnd
=
3992 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3993 1) % MAX_SEQ_NO_COUNT
;
3995 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3997 DBGLOG(QM
, TRACE
, ("QM:(Bub Flush) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3998 prReorderQueParm
->ucStaRecIdx
,
3999 prReorderQueParm
->ucTid
,
4000 prReorderQueParm
->u2FirstBubbleSn
,
4001 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
4003 if (QUEUE_IS_NOT_EMPTY(prReturnedQue
)) {
4004 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T
) QUEUE_GET_TAIL(prReturnedQue
), NULL
);
4006 prSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
);
4009 ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out SN[%u]\n",
4010 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
,
4014 (P_SW_RFB_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
) prSwRfb
);
4017 wlanProcessQueuedSwRfb(prAdapter
,
4018 (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
));
4020 DBGLOG(QM
, TRACE
, ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out 0 packet\n",
4021 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
4024 prReorderQueParm
->fgHasBubble
= FALSE
;
4026 /* First bubble has been filled but others exist */
4028 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
4029 cnmTimerStartTimer(prAdapter
, &(prReorderQueParm
->rReorderBubbleTimer
),
4030 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
4032 DBGLOG(QM
, TRACE
, ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
4033 prReorderQueParm
->ucStaRecIdx
,
4034 prReorderQueParm
->ucTid
,
4035 prReorderQueParm
->u2FirstBubbleSn
,
4036 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
4043 BOOLEAN
qmCompareSnIsLessThan(IN UINT_32 u4SnLess
, IN UINT_32 u4SnGreater
)
4045 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
4046 if ((u4SnLess
+ HALF_SEQ_NO_COUNT
) <= u4SnGreater
) { /* Shall be <= */
4050 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
4051 else if ((u4SnGreater
+ HALF_SEQ_NO_COUNT
) < u4SnLess
) {
4055 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
4056 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
4058 return u4SnLess
< u4SnGreater
;
4063 /*----------------------------------------------------------------------------*/
4065 * \brief Handle Mailbox RX messages
4067 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
4071 /*----------------------------------------------------------------------------*/
4072 VOID
qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg
)
4074 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
4079 /*----------------------------------------------------------------------------*/
4081 * \brief Handle ADD RX BA Event from the FW
4083 * \param[in] prAdapter Adapter pointer
4084 * \param[in] prEvent The event packet from the FW
4088 /*----------------------------------------------------------------------------*/
4089 VOID
qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4091 P_EVENT_RX_ADDBA_T prEventRxAddBa
;
4092 P_STA_RECORD_T prStaRec
;
4096 DBGLOG(QM
, INFO
, ("QM:Event +RxBa\n"));
4098 prEventRxAddBa
= (P_EVENT_RX_ADDBA_T
) prEvent
;
4099 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxAddBa
->ucStaRecIdx
);
4102 /* Invalid STA_REC index, discard the event packet */
4104 DBGLOG(QM
, INFO
, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
4108 if (!(prStaRec
->fgIsValid
)) {
4109 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4110 DBGLOG(QM
, WARN
, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
4116 u4Tid
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_TID_MASK
)
4117 >> BA_PARAM_SET_TID_MASK_OFFSET
);
4119 u4WinSize
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
4120 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
4122 if (!qmAddRxBaEntry(prAdapter
,
4125 (prEventRxAddBa
->u2BAStartSeqCtrl
>> OFFSET_BAR_SSC_SN
),
4126 (UINT_16
) u4WinSize
)) {
4128 /* FW shall ensure the availabiilty of the free-to-use BA entry */
4129 DBGLOG(QM
, ERROR
, ("QM: (Error) qmAddRxBaEntry() failure\n"));
4135 /*----------------------------------------------------------------------------*/
4137 * \brief Handle DEL RX BA Event from the FW
4139 * \param[in] prAdapter Adapter pointer
4140 * \param[in] prEvent The event packet from the FW
4144 /*----------------------------------------------------------------------------*/
4145 VOID
qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4147 P_EVENT_RX_DELBA_T prEventRxDelBa
;
4148 P_STA_RECORD_T prStaRec
;
4150 /* DbgPrint("QM:Event -RxBa\n"); */
4152 prEventRxDelBa
= (P_EVENT_RX_DELBA_T
) prEvent
;
4153 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxDelBa
->ucStaRecIdx
);
4156 /* Invalid STA_REC index, discard the event packet */
4161 if (!(prStaRec
->fgIsValid
)) {
4162 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4168 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, prEventRxDelBa
->ucTid
, TRUE
);
4172 P_RX_BA_ENTRY_T
qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter
, UINT_8 ucStaRecIdx
, UINT_8 ucTid
)
4175 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4177 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
4179 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
4180 if (prQM
->arRxBaTable
[i
].fgIsValid
) {
4181 if ((prQM
->arRxBaTable
[i
].ucStaRecIdx
== ucStaRecIdx
) &&
4182 (prQM
->arRxBaTable
[i
].ucTid
== ucTid
)) {
4183 return &prQM
->arRxBaTable
[i
];
4191 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter
,
4192 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN UINT_16 u2WinStart
, IN UINT_16 u2WinSize
)
4195 P_RX_BA_ENTRY_T prRxBaEntry
= NULL
;
4196 P_STA_RECORD_T prStaRec
;
4197 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4199 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
4201 if (ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
4202 /* Invalid STA_REC index, discard the event packet */
4204 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
4209 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
4212 /* if(!(prStaRec->fgIsValid)){ */
4213 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
4217 /* 4 <1> Delete before adding */
4218 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4219 if (qmLookupRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
)) {
4220 qmDelRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
, TRUE
); /* prQM->ucRxBaCount-- */
4222 /* 4 <2> Add a new BA entry */
4223 /* No available entry to store the BA agreement info. Retrun FALSE. */
4224 if (prQM
->ucRxBaCount
>= CFG_NUM_OF_RX_BA_AGREEMENTS
) {
4226 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
4229 /* Find the free-to-use BA entry */
4230 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
4231 if (!prQM
->arRxBaTable
[i
].fgIsValid
) {
4232 prRxBaEntry
= &(prQM
->arRxBaTable
[i
]);
4233 prQM
->ucRxBaCount
++;
4234 DBGLOG(QM
, LOUD
, ("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
));
4239 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
4240 u2WinSize
+= CFG_RX_BA_INC_SIZE
;
4242 prRxBaEntry
->ucStaRecIdx
= ucStaRecIdx
;
4243 prRxBaEntry
->ucTid
= ucTid
;
4244 prRxBaEntry
->u2WinStart
= u2WinStart
;
4245 prRxBaEntry
->u2WinSize
= u2WinSize
;
4246 prRxBaEntry
->u2WinEnd
= ((u2WinStart
+ u2WinSize
- 1) % MAX_SEQ_NO_COUNT
);
4247 prRxBaEntry
->fgIsValid
= TRUE
;
4248 prRxBaEntry
->fgIsWaitingForPktWithSsn
= TRUE
;
4249 prRxBaEntry
->fgHasBubble
= FALSE
;
4251 g_arMissTimeout
[ucStaRecIdx
][ucTid
] = 0;
4254 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
4255 ucStaRecIdx
, ucTid
, prRxBaEntry
->u2WinStart
, prRxBaEntry
->u2WinEnd
,
4256 prRxBaEntry
->u2WinSize
));
4258 /* Update the BA entry reference table for per-packet lookup */
4259 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = prRxBaEntry
;
4261 /* This shall not happen because FW should keep track of the usage of RX BA entries */
4263 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
4272 qmDelRxBaEntry(IN P_ADAPTER_T prAdapter
,
4273 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN BOOLEAN fgFlushToHost
)
4275 P_RX_BA_ENTRY_T prRxBaEntry
;
4276 P_STA_RECORD_T prStaRec
;
4277 P_SW_RFB_T prFlushedPacketList
= NULL
;
4278 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4280 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
4282 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
4286 if (!(prStaRec
->fgIsValid
)) {
4287 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
4292 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4293 prRxBaEntry
= prStaRec
->aprRxReorderParamRefTbl
[ucTid
];
4297 prFlushedPacketList
= qmFlushStaRxQueue(prAdapter
, ucStaRecIdx
, ucTid
);
4299 if (prFlushedPacketList
) {
4301 if (fgFlushToHost
) {
4302 wlanProcessQueuedSwRfb(prAdapter
, prFlushedPacketList
);
4306 P_SW_RFB_T prNextSwRfb
;
4307 prSwRfb
= prFlushedPacketList
;
4311 (P_SW_RFB_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
)
4313 nicRxReturnRFB(prAdapter
, prSwRfb
);
4314 prSwRfb
= prNextSwRfb
;
4322 if (prRxBaEntry
->fgHasBubble
) {
4323 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], DELBA\n",
4324 prRxBaEntry
->ucStaRecIdx
, prRxBaEntry
->ucTid
));
4326 cnmTimerStopTimer(prAdapter
, &prRxBaEntry
->rReorderBubbleTimer
);
4327 prRxBaEntry
->fgHasBubble
= FALSE
;
4329 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
4330 /* Update RX BA entry state. Note that RX queue flush is not done here */
4331 prRxBaEntry
->fgIsValid
= FALSE
;
4332 prQM
->ucRxBaCount
--;
4336 DbgPrint("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
);
4339 /* Update STA RX BA table */
4340 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = NULL
;
4343 DBGLOG(QM
, INFO
, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx
, ucTid
));
4349 #if CFG_HIF_RX_STARVATION_WARNING
4351 P_RX_CTRL_T prRxCtrl
;
4352 prRxCtrl
= &prAdapter
->rRxCtrl
;
4354 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl
->u4QueuedCnt
,
4355 prRxCtrl
->u4DequeuedCnt
));
4361 mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter
,
4362 IN PUINT_8 pucIE
, IN P_STA_RECORD_T prStaRec
)
4364 P_IE_WMM_INFO_T prIeWmmInfo
;
4368 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4370 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4371 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4373 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4374 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4375 if (IE_LEN(pucIE
) != 7) {
4376 break; /* WMM Info IE with a wrong length */
4379 prStaRec
->fgIsQoS
= TRUE
;
4380 prStaRec
->fgIsWmmSupported
= TRUE
;
4382 prIeWmmInfo
= (P_IE_WMM_INFO_T
) pucIE
;
4383 ucQosInfo
= prIeWmmInfo
->ucQosInfo
;
4384 ucQosInfoAC
= ucQosInfo
& BITS(0, 3);
4386 if(IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
))
4387 prStaRec
->fgIsUapsdSupported
= (ucQosInfoAC
) ? TRUE
: FALSE
;
4389 prStaRec
->fgIsUapsdSupported
= FALSE
;
4393 if (ucQosInfoAC
& WMM_QOS_INFO_VO_UAPSD
) {
4394 ucBmpAC
|= BIT(ACI_VO
);
4396 if (ucQosInfoAC
& WMM_QOS_INFO_VI_UAPSD
) {
4397 ucBmpAC
|= BIT(ACI_VI
);
4399 if (ucQosInfoAC
& WMM_QOS_INFO_BE_UAPSD
) {
4400 ucBmpAC
|= BIT(ACI_BE
);
4402 if (ucQosInfoAC
& WMM_QOS_INFO_BK_UAPSD
) {
4403 ucBmpAC
|= BIT(ACI_BK
);
4405 prStaRec
->ucBmpTriggerAC
= prStaRec
->ucBmpDeliveryAC
= ucBmpAC
;
4406 prStaRec
->ucUapsdSp
= (ucQosInfo
& WMM_QOS_INFO_MAX_SP_LEN_MASK
) >> 5;
4410 /* Other WMM QoS IEs. Ignore any */
4416 /*----------------------------------------------------------------------------*/
4418 * \brief To process WMM related IEs in ASSOC_RSP
4420 * \param[in] prAdapter Adapter pointer
4421 * \param[in] prSwRfb The received frame
4422 * \param[in] pucIE The pointer to the first IE in the frame
4423 * \param[in] u2IELength The total length of IEs in the frame
4427 /*----------------------------------------------------------------------------*/
4429 mqmProcessAssocReq(IN P_ADAPTER_T prAdapter
,
4430 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4432 P_STA_RECORD_T prStaRec
;
4437 DEBUGFUNC("mqmProcessAssocReq");
4442 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4445 if (prStaRec
== NULL
) {
4449 prStaRec
->fgIsQoS
= FALSE
;
4450 prStaRec
->fgIsWmmSupported
= prStaRec
->fgIsUapsdSupported
= FALSE
;
4454 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4455 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4460 /* Determine whether QoS is enabled with the association */
4462 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4463 switch (IE_ID(pucIE
)) {
4464 case ELEM_ID_VENDOR
:
4465 mqmParseAssocReqWmmIe(prAdapter
, pucIE
, prStaRec
);
4467 prStaRec
->u4Flags
= 0;
4468 #if CFG_SUPPORT_MTK_SYNERGY
4469 if (rlmParseCheckMTKOuiIE(prAdapter
, pucIE
, &u4Flags
)) {
4470 prStaRec
->u4Flags
= u4Flags
;
4476 case ELEM_ID_HT_CAP
:
4477 /* Some client won't put the WMM IE if client is 802.11n */
4478 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
4479 prStaRec
->fgIsQoS
= TRUE
;
4487 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
4493 mqmParseAssocRspWmmIe(IN PUINT_8 pucIE
, IN P_STA_RECORD_T prStaRec
)
4495 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4497 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4498 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4500 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4501 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4502 if (IE_LEN(pucIE
) != 24) {
4503 break; /* WMM Info IE with a wrong length */
4505 prStaRec
->fgIsQoS
= TRUE
;
4508 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4509 if (IE_LEN(pucIE
) != 7) {
4510 break; /* WMM Info IE with a wrong length */
4512 prStaRec
->fgIsQoS
= TRUE
;
4516 /* Other WMM QoS IEs. Ignore any */
4522 /*----------------------------------------------------------------------------*/
4524 * \brief To process WMM related IEs in ASSOC_RSP
4526 * \param[in] prAdapter Adapter pointer
4527 * \param[in] prSwRfb The received frame
4528 * \param[in] pucIE The pointer to the first IE in the frame
4529 * \param[in] u2IELength The total length of IEs in the frame
4533 /*----------------------------------------------------------------------------*/
4535 mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter
,
4536 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4538 P_STA_RECORD_T prStaRec
;
4543 DEBUGFUNC("mqmProcessAssocRsp");
4548 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4551 if (prStaRec
== NULL
) {
4555 prStaRec
->fgIsQoS
= FALSE
;
4559 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
4560 prStaRec
->fgIsWmmSupported
, prAdapter
->rWifiVar
.ucQoS
));
4562 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4563 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
4564 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4568 /* Determine whether QoS is enabled with the association */
4570 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4571 switch (IE_ID(pucIE
)) {
4572 case ELEM_ID_VENDOR
:
4573 /* Process WMM related IE */
4574 mqmParseAssocRspWmmIe(pucIE
, prStaRec
);
4576 prStaRec
->u4Flags
= 0;
4577 #if CFG_SUPPORT_MTK_SYNERGY
4578 if (rlmParseCheckMTKOuiIE(prAdapter
, pucIE
, &u4Flags
)) {
4579 prStaRec
->u4Flags
= u4Flags
;
4585 case ELEM_ID_HT_CAP
:
4586 /* Some AP won't put the WMM IE if client is 802.11n */
4587 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
4588 prStaRec
->fgIsQoS
= TRUE
;
4596 /* Parse AC parameters and write to HW CRs */
4597 if ((prStaRec
->fgIsQoS
) && (prStaRec
->eStaType
== STA_TYPE_LEGACY_AP
)) {
4598 mqmParseEdcaParameters(prAdapter
, prSwRfb
, pucIEStart
, u2IELength
, TRUE
);
4601 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
4602 if (prStaRec
->fgIsWmmSupported
) {
4603 nicQmUpdateWmmParms(prAdapter
, prStaRec
->ucBssIndex
);
4608 /*----------------------------------------------------------------------------*/
4616 /*----------------------------------------------------------------------------*/
4618 mqmProcessBcn(IN P_ADAPTER_T prAdapter
,
4619 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4621 P_BSS_INFO_T prBssInfo
;
4622 BOOLEAN fgNewParameter
;
4629 DBGLOG(QM
, TRACE
, ("Enter %s\n", __func__
));
4631 fgNewParameter
= FALSE
;
4633 for (i
= 0; i
< BSS_INFO_NUM
; i
++) {
4634 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, i
);
4636 if (IS_BSS_ACTIVE(prBssInfo
)) {
4637 if (prBssInfo
->eCurrentOPMode
== OP_MODE_INFRASTRUCTURE
&&
4638 prBssInfo
->eConnectionState
== PARAM_MEDIA_STATE_CONNECTED
) {
4639 /* P2P client or AIS infra STA */
4640 if (EQUAL_MAC_ADDR(prBssInfo
->aucBSSID
,
4641 ((P_WLAN_MAC_MGMT_HEADER_T
)
4642 (prSwRfb
->pvHeader
))->aucBSSID
)) {
4644 fgNewParameter
= mqmParseEdcaParameters(prAdapter
,
4650 /* Appy new parameters if necessary */
4651 if (fgNewParameter
) {
4652 /* DBGLOG(QM, INFO, ("Update EDCA parameter for BSS[%u]\n", prBssInfo->ucBssIndex)); */
4653 nicQmUpdateWmmParms(prAdapter
, prBssInfo
->ucBssIndex
);
4654 fgNewParameter
= FALSE
;
4656 } /* end of IS_BSS_ACTIVE() */
4661 mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo
, IN PUINT_8 pucIE
,
4662 IN BOOLEAN fgForceOverride
)
4664 P_AC_QUE_PARMS_T prAcQueParams
;
4665 P_IE_WMM_PARAM_T prIeWmmParam
;
4666 ENUM_WMM_ACI_T eAci
;
4667 BOOLEAN fgNewParameter
= FALSE
;
4670 if (IE_LEN(pucIE
) != 24) {
4671 break; /* WMM Param IE with a wrong length */
4674 prIeWmmParam
= (P_IE_WMM_PARAM_T
) pucIE
;
4676 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
4677 if(!fgForceOverride
) {
4678 if(mqmCompareEdcaParameters(prIeWmmParam
, prBssInfo
)) {
4679 fgNewParameter
= FALSE
;
4684 fgNewParameter
= TRUE
;
4685 /* Update Parameter Set Count */
4686 prBssInfo
->ucWmmParamSetCount
= (prIeWmmParam
->ucQosInfo
& WMM_QOS_INFO_PARAM_SET_CNT
);
4687 /* Update EDCA parameters */
4688 for(eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
4689 prAcQueParams
= &prBssInfo
->arACQueParms
[eAci
];
4690 mqmFillAcQueParam(prIeWmmParam
, eAci
, prAcQueParams
);
4691 DBGLOG(QM
, INFO
, ("BSS[%u]: eAci[%d] ACM[%d] Aifsn[%d] CWmin/max[%d/%d]"
4692 "TxopLimit[%d] NewParameter[%d]\n",
4693 prBssInfo
->ucBssIndex
, eAci
, prAcQueParams
->ucIsACMSet
, prAcQueParams
->u2Aifsn
,
4694 prAcQueParams
->u2CWmin
, prAcQueParams
->u2CWmax
, prAcQueParams
->u2TxopLimit
, fgNewParameter
));
4698 return fgNewParameter
;
4701 /*----------------------------------------------------------------------------*/
4703 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
4705 * \param[in] prAdapter Adapter pointer
4706 * \param[in] prSwRfb The received frame
4707 * \param[in] pucIE The pointer to the first IE in the frame
4708 * \param[in] u2IELength The total length of IEs in the frame
4709 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
4713 /*----------------------------------------------------------------------------*/
4715 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter
,
4716 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
,
4717 IN BOOLEAN fgForceOverride
)
4719 P_STA_RECORD_T prStaRec
;
4721 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4722 P_BSS_INFO_T prBssInfo
;
4723 BOOLEAN fgNewParameter
= FALSE
;
4725 DEBUGFUNC("mqmParseEdcaParameters");
4735 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4736 /* ASSERT(prStaRec); */
4738 if (prStaRec
== NULL
) {
4742 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
4743 prStaRec
->fgIsWmmSupported
, prStaRec
->fgIsQoS
));
4745 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
) || (!prStaRec
->fgIsWmmSupported
)
4746 || (!prStaRec
->fgIsQoS
)) {
4750 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
4752 /* Goal: Obtain the EDCA parameters */
4753 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4754 switch (IE_ID(pucIE
)) {
4756 if (!((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4757 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3)))) {
4761 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4762 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4763 fgNewParameter
= mqmUpdateEdcaParameters(prBssInfo
, pucIE
, fgForceOverride
);
4767 /* Other WMM QoS IEs. Ignore */
4771 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4778 return fgNewParameter
;
4781 BOOLEAN
mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam
, IN P_BSS_INFO_T prBssInfo
)
4783 P_AC_QUE_PARMS_T prAcQueParams
;
4784 P_WMM_AC_PARAM_T prWmmAcParams
;
4785 ENUM_WMM_ACI_T eAci
;
4789 /* Check Set Count */
4790 if (prBssInfo
->ucWmmParamSetCount
!= (prIeWmmParam
->ucQosInfo
& WMM_QOS_INFO_PARAM_SET_CNT
)) {
4794 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
4795 prAcQueParams
= &prBssInfo
->arACQueParms
[eAci
];
4796 prWmmAcParams
= &prIeWmmParam
->arAcParam
[eAci
];
4799 if (prAcQueParams
->ucIsACMSet
!=
4800 ((prWmmAcParams
->ucAciAifsn
& WMM_ACIAIFSN_ACM
) ? TRUE
: FALSE
)) {
4805 if (prAcQueParams
->u2Aifsn
!= (prWmmAcParams
->ucAciAifsn
& WMM_ACIAIFSN_AIFSN
)) {
4810 if (prAcQueParams
->u2CWmax
!=
4811 (BIT((prWmmAcParams
->ucEcw
& WMM_ECW_WMAX_MASK
) >> WMM_ECW_WMAX_OFFSET
) - 1)) {
4816 if (prAcQueParams
->u2CWmin
!= (BIT(prWmmAcParams
->ucEcw
& WMM_ECW_WMIN_MASK
) - 1)) {
4820 if (prAcQueParams
->u2TxopLimit
!= prWmmAcParams
->u2TxopLimit
) {
4829 /*----------------------------------------------------------------------------*/
4831 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
4833 * \param[in] prAdapter Adapter pointer
4834 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
4835 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
4836 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
4840 /*----------------------------------------------------------------------------*/
4842 mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam
,
4843 IN UINT_32 u4AcOffset
, OUT P_AC_QUE_PARMS_T prAcQueParams
)
4845 P_WMM_AC_PARAM_T prAcParam
= &prIeWmmParam
->arAcParam
[u4AcOffset
];
4847 prAcQueParams
->ucIsACMSet
= (prAcParam
->ucAciAifsn
& WMM_ACIAIFSN_ACM
) ? TRUE
: FALSE
;
4849 prAcQueParams
->u2Aifsn
= (prAcParam
->ucAciAifsn
& WMM_ACIAIFSN_AIFSN
);
4851 prAcQueParams
->u2CWmax
=
4852 BIT((prAcParam
->ucEcw
& WMM_ECW_WMAX_MASK
) >> WMM_ECW_WMAX_OFFSET
) - 1;
4854 prAcQueParams
->u2CWmin
= BIT(prAcParam
->ucEcw
& WMM_ECW_WMIN_MASK
) - 1;
4856 WLAN_GET_FIELD_16(&prAcParam
->u2TxopLimit
, &prAcQueParams
->u2TxopLimit
);
4858 prAcQueParams
->ucGuradTime
= TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME
;
4863 /*----------------------------------------------------------------------------*/
4865 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
4867 * \param[in] prAdapter Adapter pointer
4868 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
4869 * \param[out] prStaRec The obtained info is stored in the STA_REC
4873 /*----------------------------------------------------------------------------*/
4875 mqmProcessScanResult(IN P_ADAPTER_T prAdapter
,
4876 IN P_BSS_DESC_T prScanResult
, OUT P_STA_RECORD_T prStaRec
)
4881 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4884 DEBUGFUNC("mqmProcessScanResult");
4886 ASSERT(prScanResult
);
4889 /* Reset the flag before parsing */
4890 prStaRec
->fgIsWmmSupported
= FALSE
;
4891 prStaRec
->fgIsUapsdSupported
= FALSE
;
4892 prStaRec
->fgIsQoS
= FALSE
;
4896 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4900 u2IELength
= prScanResult
->u2IELength
;
4901 pucIE
= prScanResult
->aucIEBuf
;
4903 /* <1> Determine whether the peer supports WMM/QoS and UAPSDU */
4904 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4905 switch (IE_ID(pucIE
)) {
4907 case ELEM_ID_EXTENDED_CAP
:
4908 #if CFG_SUPPORT_TDLS
4909 TdlsBssExtCapParse(prStaRec
, pucIE
);
4910 #endif /* CFG_SUPPORT_TDLS */
4914 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4915 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4917 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4918 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4919 if (IE_LEN(pucIE
) != 24) {
4920 break; /* WMM Param IE with a wrong length */
4922 prStaRec
->fgIsWmmSupported
= TRUE
;
4923 prStaRec
->fgIsUapsdSupported
=
4924 (((((P_IE_WMM_PARAM_T
) pucIE
)->
4925 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
4930 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4931 if (IE_LEN(pucIE
) != 7) {
4932 break; /* WMM Info IE with a wrong length */
4934 prStaRec
->fgIsWmmSupported
= TRUE
;
4935 prStaRec
->fgIsUapsdSupported
=
4936 (((((P_IE_WMM_INFO_T
) pucIE
)->
4937 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
4943 /* A WMM QoS IE that doesn't matter. Ignore it. */
4947 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4952 /* A WMM IE that doesn't matter. Ignore it. */
4957 /* <1> Determine QoS */
4958 if (prStaRec
->ucDesiredPhyTypeSet
& (PHY_TYPE_SET_802_11N
| PHY_TYPE_SET_802_11AC
)) {
4962 if (fgIsHtVht
|| prStaRec
->fgIsWmmSupported
) {
4963 prStaRec
->fgIsQoS
= TRUE
;
4968 /*----------------------------------------------------------------------------*/
4970 * @brief Generate the WMM Info IE by Param
4972 * \param[in] prAdapter Adapter pointer
4973 * @param prMsduInfo The TX MMPDU
4977 /*----------------------------------------------------------------------------*/
4979 mqmFillWmmInfoIE(P_UINT_8 pucOutBuf
,
4980 BOOLEAN fgSupportUAPSD
,
4981 UINT_8 ucBmpDeliveryAC
, UINT_8 ucBmpTriggerAC
, UINT_8 ucUapsdSp
)
4983 P_IE_WMM_INFO_T prIeWmmInfo
;
4984 UINT_32 ucUapsd
[] = {
4985 WMM_QOS_INFO_BE_UAPSD
,
4986 WMM_QOS_INFO_BK_UAPSD
,
4987 WMM_QOS_INFO_VI_UAPSD
,
4988 WMM_QOS_INFO_VO_UAPSD
4990 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4994 prIeWmmInfo
= (P_IE_WMM_INFO_T
) pucOutBuf
;
4996 prIeWmmInfo
->ucId
= ELEM_ID_WMM
;
4997 prIeWmmInfo
->ucLength
= ELEM_MAX_LEN_WMM_INFO
;
4999 /* WMM-2.2.1 WMM Information Element Field Values */
5000 prIeWmmInfo
->aucOui
[0] = aucWfaOui
[0];
5001 prIeWmmInfo
->aucOui
[1] = aucWfaOui
[1];
5002 prIeWmmInfo
->aucOui
[2] = aucWfaOui
[2];
5003 prIeWmmInfo
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
5004 prIeWmmInfo
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_INFO
;
5006 prIeWmmInfo
->ucVersion
= VERSION_WMM
;
5007 prIeWmmInfo
->ucQosInfo
= 0;
5009 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5010 if (fgSupportUAPSD
) {
5011 UINT_8 ucQosInfo
= 0;
5014 /* Static U-APSD setting */
5015 for (i
= ACI_BE
; i
<= ACI_VO
; i
++) {
5016 if (ucBmpDeliveryAC
& ucBmpTriggerAC
& BIT(i
)) {
5017 ucQosInfo
|= (UINT_8
) ucUapsd
[i
];
5021 if (ucBmpDeliveryAC
& ucBmpTriggerAC
) {
5022 switch (ucUapsdSp
) {
5023 case WMM_MAX_SP_LENGTH_ALL
:
5024 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_ALL
;
5027 case WMM_MAX_SP_LENGTH_2
:
5028 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
5031 case WMM_MAX_SP_LENGTH_4
:
5032 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_4
;
5035 case WMM_MAX_SP_LENGTH_6
:
5036 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_6
;
5040 DBGLOG(QM
, INFO
, ("MQM: Incorrect SP length\n"));
5041 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
5045 prIeWmmInfo
->ucQosInfo
= ucQosInfo
;
5049 /* Increment the total IE length for the Element ID and Length fields. */
5050 return IE_SIZE(prIeWmmInfo
);
5054 /*----------------------------------------------------------------------------*/
5056 * @brief Generate the WMM Info IE
5058 * \param[in] prAdapter Adapter pointer
5059 * @param prMsduInfo The TX MMPDU
5063 /*----------------------------------------------------------------------------*/
5065 mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter
,
5066 P_BSS_INFO_T prBssInfo
, P_STA_RECORD_T prStaRec
, P_UINT_8 pucOutBuf
)
5068 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo
;
5069 BOOLEAN fgSupportUapsd
;
5073 /* In case QoS is not turned off, exit directly */
5074 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5078 if (prStaRec
== NULL
) {
5082 if (!prStaRec
->fgIsWmmSupported
) {
5086 prPmProfSetupInfo
= &prBssInfo
->rPmProfSetupInfo
;
5088 fgSupportUapsd
= (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)
5089 && prStaRec
->fgIsUapsdSupported
);
5091 return mqmFillWmmInfoIE(pucOutBuf
,
5093 prPmProfSetupInfo
->ucBmpDeliveryAC
,
5094 prPmProfSetupInfo
->ucBmpTriggerAC
, prPmProfSetupInfo
->ucUapsdSp
);
5097 /*----------------------------------------------------------------------------*/
5099 * @brief Generate the WMM Info IE
5101 * \param[in] prAdapter Adapter pointer
5102 * @param prMsduInfo The TX MMPDU
5106 /*----------------------------------------------------------------------------*/
5107 VOID
mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
5109 P_BSS_INFO_T prBssInfo
;
5110 P_STA_RECORD_T prStaRec
;
5113 DEBUGFUNC("mqmGenerateWmmInfoIE");
5117 /* In case QoS is not turned off, exit directly */
5118 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5122 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5125 if (prStaRec
== NULL
) {
5129 if (!prStaRec
->fgIsWmmSupported
) {
5133 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
5135 u4Length
= mqmGenerateWmmInfoIEByStaRec(prAdapter
,
5138 ((PUINT_8
) prMsduInfo
->prPacket
+
5139 prMsduInfo
->u2FrameLength
));
5141 prMsduInfo
->u2FrameLength
+= u4Length
;
5144 /*----------------------------------------------------------------------------*/
5146 * @brief Generate the WMM Param IE
5148 * \param[in] prAdapter Adapter pointer
5149 * @param prMsduInfo The TX MMPDU
5153 /*----------------------------------------------------------------------------*/
5154 VOID
mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
5156 P_IE_WMM_PARAM_T prIeWmmParam
;
5158 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
5167 P_BSS_INFO_T prBssInfo
;
5168 P_STA_RECORD_T prStaRec
;
5169 ENUM_WMM_ACI_T eAci
;
5170 P_WMM_AC_PARAM_T prAcParam
;
5172 DEBUGFUNC("mqmGenerateWmmParamIE");
5173 DBGLOG(QM
, LOUD
, ("\n"));
5177 /* In case QoS is not turned off, exit directly */
5178 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5182 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5185 if (!prStaRec
->fgIsQoS
) {
5190 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prMsduInfo
->ucBssIndex
);
5192 if (!prBssInfo
->fgIsQBSS
) {
5196 prIeWmmParam
= (P_IE_WMM_PARAM_T
)
5197 ((PUINT_8
) prMsduInfo
->prPacket
+ prMsduInfo
->u2FrameLength
);
5199 prIeWmmParam
->ucId
= ELEM_ID_WMM
;
5200 prIeWmmParam
->ucLength
= ELEM_MAX_LEN_WMM_PARAM
;
5202 /* WMM-2.2.1 WMM Information Element Field Values */
5203 prIeWmmParam
->aucOui
[0] = aucWfaOui
[0];
5204 prIeWmmParam
->aucOui
[1] = aucWfaOui
[1];
5205 prIeWmmParam
->aucOui
[2] = aucWfaOui
[2];
5206 prIeWmmParam
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
5207 prIeWmmParam
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_PARAM
;
5209 prIeWmmParam
->ucVersion
= VERSION_WMM
;
5210 prIeWmmParam
->ucQosInfo
= (prBssInfo
->ucWmmParamSetCount
& WMM_QOS_INFO_PARAM_SET_CNT
);
5212 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5213 if (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)) {
5214 prIeWmmParam
->ucQosInfo
|= WMM_QOS_INFO_UAPSD
;
5217 /* EDCA parameter */
5219 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
5220 prAcParam
= &prIeWmmParam
->arAcParam
[eAci
];
5222 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5223 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5224 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5225 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5226 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5227 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5230 prAcParam
->ucAciAifsn
= aucACI
[eAci
];
5232 if (prBssInfo
->arACQueParmsForBcast
[eAci
].ucIsACMSet
) {
5233 prAcParam
->ucAciAifsn
|= WMM_ACIAIFSN_ACM
;
5236 prAcParam
->ucAciAifsn
|=
5237 (prBssInfo
->arACQueParmsForBcast
[eAci
].u2Aifsn
& WMM_ACIAIFSN_AIFSN
);
5240 prAcParam
->ucEcw
= (prBssInfo
->aucCWminLog2ForBcast
[eAci
] & WMM_ECW_WMIN_MASK
);
5244 aucCWmaxLog2ForBcast
[eAci
] << WMM_ECW_WMAX_OFFSET
) & WMM_ECW_WMAX_MASK
);
5247 WLAN_SET_FIELD_16(&prAcParam
->u2TxopLimit
,
5248 prBssInfo
->arACQueParmsForBcast
[eAci
].u2TxopLimit
);
5252 /* Increment the total IE length for the Element ID and Length fields. */
5253 prMsduInfo
->u2FrameLength
+= IE_SIZE(prIeWmmParam
);
5258 #if CFG_SUPPORT_TDLS
5259 /*----------------------------------------------------------------------------*/
5261 * @brief Generate the WMM Param IE
5263 * \param[in] prAdapter Adapter pointer
5264 * @param prMsduInfo The TX MMPDU
5268 /*----------------------------------------------------------------------------*/
5269 UINT_32
mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter
, P_BSS_INFO_T prBssInfo
, PUINT_8 pOutBuf
)
5271 P_IE_WMM_PARAM_T prIeWmmParam
;
5273 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
5282 ENUM_WMM_ACI_T eAci
;
5283 P_WMM_AC_PARAM_T prAcParam
;
5285 DEBUGFUNC("mqmGenerateWmmParamIE");
5286 DBGLOG(QM
, LOUD
, ("\n"));
5291 /* In case QoS is not turned off, exit directly */
5292 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5293 return WLAN_STATUS_SUCCESS
;
5297 if (!prBssInfo
->fgIsQBSS
) {
5298 return WLAN_STATUS_SUCCESS
;
5303 prIeWmmParam
= (P_IE_WMM_PARAM_T
) pOutBuf
;
5306 prIeWmmParam
->ucId
= ELEM_ID_WMM
;
5307 prIeWmmParam
->ucLength
= ELEM_MAX_LEN_WMM_PARAM
;
5309 /* WMM-2.2.1 WMM Information Element Field Values */
5310 prIeWmmParam
->aucOui
[0] = aucWfaOui
[0];
5311 prIeWmmParam
->aucOui
[1] = aucWfaOui
[1];
5312 prIeWmmParam
->aucOui
[2] = aucWfaOui
[2];
5313 prIeWmmParam
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
5314 prIeWmmParam
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_PARAM
;
5316 prIeWmmParam
->ucVersion
= VERSION_WMM
;
5317 prIeWmmParam
->ucQosInfo
= (prBssInfo
->ucWmmParamSetCount
& WMM_QOS_INFO_PARAM_SET_CNT
);
5319 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5320 if (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)) {
5321 prIeWmmParam
->ucQosInfo
|= WMM_QOS_INFO_UAPSD
;
5324 /* EDCA parameter */
5326 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
5327 prAcParam
= &prIeWmmParam
->arAcParam
[eAci
];
5329 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5330 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5331 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5332 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5333 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5334 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5337 prAcParam
->ucAciAifsn
= aucACI
[eAci
];
5339 if (prBssInfo
->arACQueParmsForBcast
[eAci
].ucIsACMSet
) {
5340 prAcParam
->ucAciAifsn
|= WMM_ACIAIFSN_ACM
;
5343 prAcParam
->ucAciAifsn
|=
5344 (prBssInfo
->arACQueParmsForBcast
[eAci
].u2Aifsn
& WMM_ACIAIFSN_AIFSN
);
5347 prAcParam
->ucEcw
= (prBssInfo
->aucCWminLog2ForBcast
[eAci
] & WMM_ECW_WMIN_MASK
);
5351 aucCWmaxLog2ForBcast
[eAci
] << WMM_ECW_WMAX_OFFSET
) & WMM_ECW_WMAX_MASK
);
5354 WLAN_SET_FIELD_16(&prAcParam
->u2TxopLimit
,
5355 prBssInfo
->arACQueParmsForBcast
[eAci
].u2TxopLimit
);
5359 /* Increment the total IE length for the Element ID and Length fields. */
5360 return IE_SIZE(prIeWmmParam
);
5369 qmGetFrameAction(IN P_ADAPTER_T prAdapter
,
5370 IN UINT_8 ucBssIndex
,
5371 IN UINT_8 ucStaRecIdx
,
5372 IN P_MSDU_INFO_T prMsduInfo
, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType
)
5374 ENUM_FRAME_ACTION_T eFrameAction
= FRAME_ACTION_TX_PKT
;
5375 P_BSS_INFO_T prBssInfo
;
5376 P_STA_RECORD_T prStaRec
;
5377 /* P_WLAN_MAC_HEADER_T prWlanFrame; */
5378 /* UINT_16 u2TxFrameCtrl; */
5380 DEBUGFUNC("qmGetFrameAction");
5382 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, ucBssIndex
);
5383 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, ucStaRecIdx
);
5386 /* 4 <1> Tx, if FORCE_TX is set */
5388 if (prMsduInfo
->ucControlFlag
& MSDU_CONTROL_FLAG_FORCE_TX
) {
5389 eFrameAction
= FRAME_ACTION_TX_PKT
;
5393 /* 4 <2> Drop, if BSS is inactive */
5394 if (!IS_BSS_ACTIVE(prBssInfo
)) {
5396 ("Drop packets (BSS[%u] is INACTIVE)\n", prBssInfo
->ucBssIndex
));
5397 eFrameAction
= FRAME_ACTION_DROP_PKT
;
5400 /* 4 <3> Check based on StaRec */
5402 /* 4 <3.1> Drop, if StaRec is not in use */
5403 if (!prStaRec
->fgIsInUse
) {
5405 ("Drop packets (Sta[%u] not in USE)\n", prStaRec
->ucIndex
));
5406 eFrameAction
= FRAME_ACTION_DROP_PKT
;
5409 /* 4 <3.2> Sta in PS */
5410 if (prStaRec
->fgIsInPS
) {
5411 /* 4 <3.2.1> Tx, if resource is enough */
5412 if (nicTxGetResource
5414 nicTxGetFrameResourceType(eFrameType
,
5416 QM_MGMT_QUEUED_THRESHOLD
) {
5417 eFrameAction
= FRAME_ACTION_TX_PKT
;
5420 /* 4 <3.2.2> Queue, if resource is not enough */
5423 ("Queue packets (Sta[%u] in PS)\n",
5424 prStaRec
->ucIndex
));
5425 eFrameAction
= FRAME_ACTION_QUEUE_PKT
;
5430 /* 4 <4> Queue, if BSS is absent */
5431 if (prBssInfo
->fgIsNetAbsent
) {
5433 ("Queue packets (BSS[%u] Absent)\n", prBssInfo
->ucBssIndex
));
5434 eFrameAction
= FRAME_ACTION_QUEUE_PKT
;
5440 return eFrameAction
;
5444 /*----------------------------------------------------------------------------*/
5446 * \brief Handle BSS change operation Event from the FW
5448 * \param[in] prAdapter Adapter pointer
5449 * \param[in] prEvent The event packet from the FW
5453 /*----------------------------------------------------------------------------*/
5454 VOID
qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5456 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus
;
5457 P_BSS_INFO_T prBssInfo
;
5458 BOOLEAN fgIsNetAbsentOld
;
5460 prEventBssStatus
= (P_EVENT_BSS_ABSENCE_PRESENCE_T
) prEvent
;
5461 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prEventBssStatus
->ucBssIndex
);
5462 fgIsNetAbsentOld
= prBssInfo
->fgIsNetAbsent
;
5463 prBssInfo
->fgIsNetAbsent
= prEventBssStatus
->ucIsAbsent
;
5464 prBssInfo
->ucBssFreeQuota
= prEventBssStatus
->ucBssFreeQuota
;
5466 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
5467 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
5469 DBGLOG(QM
, INFO
, ("NAF=%d,%d,%d\n",
5470 prEventBssStatus
->ucBssIndex
, prBssInfo
->fgIsNetAbsent
,
5471 prBssInfo
->ucBssFreeQuota
));
5473 if (!prBssInfo
->fgIsNetAbsent
) {
5474 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_27
);
5476 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_28
);
5478 /* From Absent to Present */
5479 if ((fgIsNetAbsentOld
) && (!prBssInfo
->fgIsNetAbsent
)) {
5480 kalSetEvent(prAdapter
->prGlueInfo
);
5485 /*----------------------------------------------------------------------------*/
5487 * \brief Handle STA change PS mode Event from the FW
5489 * \param[in] prAdapter Adapter pointer
5490 * \param[in] prEvent The event packet from the FW
5494 /*----------------------------------------------------------------------------*/
5495 VOID
qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5497 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode
;
5498 P_STA_RECORD_T prStaRec
;
5499 BOOLEAN fgIsInPSOld
;
5501 /* DbgPrint("QM:Event -RxBa\n"); */
5503 prEventStaChangePsMode
= (P_EVENT_STA_CHANGE_PS_MODE_T
) prEvent
;
5504 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaChangePsMode
->ucStaRecIdx
);
5505 /* ASSERT(prStaRec); */
5509 fgIsInPSOld
= prStaRec
->fgIsInPS
;
5510 prStaRec
->fgIsInPS
= prEventStaChangePsMode
->ucIsInPs
;
5512 qmUpdateFreeQuota(prAdapter
,
5514 prEventStaChangePsMode
->ucUpdateMode
,
5515 prEventStaChangePsMode
->ucFreeQuota
);
5517 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
5518 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
5521 DBGLOG(QM
, INFO
, ("PS=%d,%d\n",
5522 prEventStaChangePsMode
->ucStaRecIdx
, prStaRec
->fgIsInPS
));
5524 /* From PS to Awake */
5525 if ((fgIsInPSOld
) && (!prStaRec
->fgIsInPS
)) {
5526 kalSetEvent(prAdapter
->prGlueInfo
);
5531 /*----------------------------------------------------------------------------*/
5533 * \brief Update STA free quota Event from FW
5535 * \param[in] prAdapter Adapter pointer
5536 * \param[in] prEvent The event packet from the FW
5540 /*----------------------------------------------------------------------------*/
5541 VOID
qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5543 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota
;
5544 P_STA_RECORD_T prStaRec
;
5547 prEventStaUpdateFreeQuota
= (P_EVENT_STA_UPDATE_FREE_QUOTA_T
) prEvent
;
5548 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaUpdateFreeQuota
->ucStaRecIdx
);
5550 * Station Record possible been freed.
5552 /* ASSERT(prStaRec); */
5555 if (prStaRec
->fgIsInPS
) {
5556 qmUpdateFreeQuota(prAdapter
,
5558 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5559 prEventStaUpdateFreeQuota
->ucFreeQuota
);
5561 kalSetEvent(prAdapter
->prGlueInfo
);
5565 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
5566 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
5567 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5568 prEventStaUpdateFreeQuota
->ucFreeQuota
));
5571 DBGLOG(QM
, TRACE
, ("UFQ=%d,%d,%d\n",
5572 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
5573 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5574 prEventStaUpdateFreeQuota
->ucFreeQuota
));
5582 /*----------------------------------------------------------------------------*/
5584 * \brief Update STA free quota
5586 * \param[in] prStaRec the STA
5587 * \param[in] ucUpdateMode the method to update free quota
5588 * \param[in] ucFreeQuota the value for update
5592 /*----------------------------------------------------------------------------*/
5594 qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter
,
5595 IN P_STA_RECORD_T prStaRec
, IN UINT_8 ucUpdateMode
, IN UINT_8 ucFreeQuota
)
5598 UINT_8 ucFreeQuotaForNonDelivery
;
5599 UINT_8 ucFreeQuotaForDelivery
;
5602 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
5603 prStaRec
->ucFreeQuota
, ucUpdateMode
, ucFreeQuota
));
5605 if (!prStaRec
->fgIsInPS
)
5608 switch (ucUpdateMode
) {
5609 case FREE_QUOTA_UPDATE_MODE_INIT
:
5610 case FREE_QUOTA_UPDATE_MODE_OVERWRITE
:
5611 prStaRec
->ucFreeQuota
= ucFreeQuota
;
5613 case FREE_QUOTA_UPDATE_MODE_INCREASE
:
5614 prStaRec
->ucFreeQuota
+= ucFreeQuota
;
5616 case FREE_QUOTA_UPDATE_MODE_DECREASE
:
5617 prStaRec
->ucFreeQuota
-= ucFreeQuota
;
5623 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec
->ucFreeQuota
));
5625 ucFreeQuota
= prStaRec
->ucFreeQuota
;
5627 ucFreeQuotaForNonDelivery
= 0;
5628 ucFreeQuotaForDelivery
= 0;
5630 if (ucFreeQuota
> 0) {
5631 if (prStaRec
->fgIsQoS
&& prStaRec
->fgIsUapsdSupported
5632 /* && prAdapter->rWifiVar.fgSupportQoS
5633 && prAdapter->rWifiVar.fgSupportUAPSD */) {
5634 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
5636 if (prStaRec
->ucFreeQuotaForNonDelivery
> 0
5637 && prStaRec
->ucFreeQuotaForDelivery
> 0) {
5638 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
5639 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5640 } else if (prStaRec
->ucFreeQuotaForNonDelivery
== 0
5641 && prStaRec
->ucFreeQuotaForDelivery
== 0) {
5642 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
5643 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5644 } else if (prStaRec
->ucFreeQuotaForNonDelivery
> 0) {
5645 /* NonDelivery is not busy */
5646 if (ucFreeQuota
>= 3) {
5647 ucFreeQuotaForNonDelivery
= 2;
5648 ucFreeQuotaForDelivery
=
5649 ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5651 ucFreeQuotaForDelivery
= ucFreeQuota
;
5652 ucFreeQuotaForNonDelivery
= 0;
5654 } else if (prStaRec
->ucFreeQuotaForDelivery
> 0) {
5655 /* Delivery is not busy */
5656 if (ucFreeQuota
>= 3) {
5657 ucFreeQuotaForDelivery
= 2;
5658 ucFreeQuotaForNonDelivery
=
5659 ucFreeQuota
- ucFreeQuotaForDelivery
;
5661 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
5662 ucFreeQuotaForDelivery
= 0;
5667 /* !prStaRec->fgIsUapsdSupported */
5668 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
5669 ucFreeQuotaForDelivery
= 0;
5672 /* ucFreeQuota > 0 */
5673 prStaRec
->ucFreeQuotaForDelivery
= ucFreeQuotaForDelivery
;
5674 prStaRec
->ucFreeQuotaForNonDelivery
= ucFreeQuotaForNonDelivery
;
5676 DBGLOG(QM
, LOUD
, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
5677 prStaRec
->ucFreeQuotaForDelivery
, prStaRec
->ucFreeQuotaForNonDelivery
));
5681 /*----------------------------------------------------------------------------*/
5683 * \brief Return the reorder queued RX packets
5687 * \return The number of queued RX packets
5689 /*----------------------------------------------------------------------------*/
5690 UINT_32
qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter
)
5693 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
5695 /* XXX The summation may impact the performance */
5696 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
5697 u4Total
+= prQM
->arRxBaTable
[i
].rReOrderQue
.u4NumElem
;
5699 if (QUEUE_IS_EMPTY(&(prQM
->arRxBaTable
[i
].rReOrderQue
))) {
5700 ASSERT(prQM
->arRxBaTable
[i
].rReOrderQue
== 0);
5704 ASSERT(u4Total
<= (CFG_NUM_OF_QM_RX_PKT_NUM
* 2));
5708 /*----------------------------------------------------------------------------*/
5710 * \brief Dump current queue status
5716 /*----------------------------------------------------------------------------*/
5717 VOID
qmDumpQueueStatus(IN P_ADAPTER_T prAdapter
)
5719 P_TX_CTRL_T prTxCtrl
;
5721 P_GLUE_INFO_T prGlueInfo
;
5723 UINT_32 u4TotalBufferCount
, u4TotalPageCount
, u4CurBufferCount
, u4CurPageCount
;
5725 DEBUGFUNC(("%s", __func__
));
5727 prTxCtrl
= &prAdapter
->rTxCtrl
;
5728 prQM
= &prAdapter
->rQM
;
5729 prGlueInfo
= prAdapter
->prGlueInfo
;
5730 u4TotalBufferCount
= 0;
5731 u4TotalPageCount
= 0;
5732 u4CurBufferCount
= 0;
5735 DBGLOG(SW4
, INFO
, ("\n------<Dump QUEUE Status>------\n"));
5737 for(i
= TC0_INDEX
; i
< TC_NUM
; i
++) {
5738 DBGLOG(SW4
, INFO
, ("TC%u ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5740 prTxCtrl
->rTc
.au2MaxNumOfBuffer
[i
],
5741 prTxCtrl
->rTc
.au2MaxNumOfPage
[i
],
5742 prTxCtrl
->rTc
.au2FreeBufferCount
[i
],
5743 prTxCtrl
->rTc
.au2FreePageCount
[i
]));
5745 u4TotalBufferCount
+= prTxCtrl
->rTc
.au2MaxNumOfBuffer
[i
];
5746 u4TotalPageCount
+= prTxCtrl
->rTc
.au2MaxNumOfPage
[i
];
5747 u4CurBufferCount
+= prTxCtrl
->rTc
.au2FreeBufferCount
[i
];
5748 u4CurPageCount
+= prTxCtrl
->rTc
.au2FreePageCount
[i
];
5751 DBGLOG(SW4
, INFO
, ("ToT ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5752 u4TotalBufferCount
, u4TotalPageCount
, u4CurBufferCount
, u4CurPageCount
));
5754 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5756 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
5757 for(i
= TC0_INDEX
; i
< TC_NUM
; i
++) {
5759 DBGLOG(SW4
, INFO
,("TC%u AvgQLen[%04u] minRsv[%02u] CurTcRes[%02u] GrtdTcRes[%02u]\n",
5761 QM_GET_TX_QUEUE_LEN(prAdapter
, i
),
5762 prQM
->au4MinReservedTcResource
[i
],
5763 prQM
->au4CurrentTcResource
[i
],
5764 prQM
->au4GuaranteedTcResource
[i
]));
5767 DBGLOG(SW4
, INFO
,("Resource Residual[%u] ExtraRsv[%u]\n",
5768 prQM
->u4ResidualTcResource
,
5769 prQM
->u4ExtraReservedTcResource
));
5770 DBGLOG(SW4
, INFO
,("QueLenMovingAvg[%u] Time2AdjResource[%u] Time2UpdateQLen[%u]\n",
5771 prQM
->u4QueLenMovingAverage
,
5772 prQM
->u4TimeToAdjustTcResource
,
5773 prQM
->u4TimeToUpdateQueLen
));
5776 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5778 #if QM_FORWARDING_FAIRNESS
5779 for (i
= 0; i
< NUM_OF_PER_STA_TX_QUEUES
; i
++) {
5781 ("TC%u HeadSta[%u] ResourceUsedCount[%u]\n", i
, prQM
->au4HeadStaRecIndex
[i
],
5782 prQM
->au4ResourceUsedCount
[i
]));
5786 DBGLOG(SW4
, INFO
, ("BMC or unknown TxQueue Len[%u]\n", prQM
->arTxQueue
[0].u4NumElem
));
5788 ("Pending QLen Normal[%u] Sec[%u]\n", prGlueInfo
->i4TxPendingFrameNum
,
5789 prGlueInfo
->i4TxPendingSecurityFrameNum
));
5792 for (i
= 0; i
< HW_BSSID_NUM
; i
++) {
5793 DBGLOG(SW4
, INFO
, ("Pending BSS[%u] QLen[%u:%u:%u:%u]\n",
5795 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][0],
5796 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][1],
5797 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][2],
5798 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][3]));
5801 DBGLOG(SW4
, INFO
, ("Pending FWD CNT[%d]\n", prTxCtrl
->i4PendingFwdFrameCount
));
5802 DBGLOG(SW4
, INFO
, ("Pending MGMT CNT[%d]\n", prTxCtrl
->i4TxMgmtPendingNum
));
5804 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5806 DBGLOG(SW4
, INFO
, ("Total RFB[%u]\n", CFG_RX_MAX_PKT_NUM
));
5807 DBGLOG(SW4
, INFO
, ("rFreeSwRfbList[%u]\n", prAdapter
->rRxCtrl
.rFreeSwRfbList
.u4NumElem
));
5809 ("rReceivedRfbList[%u]\n", prAdapter
->rRxCtrl
.rReceivedRfbList
.u4NumElem
));
5811 ("rIndicatedRfbList[%u]\n", prAdapter
->rRxCtrl
.rIndicatedRfbList
.u4NumElem
));
5812 DBGLOG(SW4
, INFO
, ("ucNumIndPacket[%u]\n", prAdapter
->rRxCtrl
.ucNumIndPacket
));
5813 DBGLOG(SW4
, INFO
, ("ucNumRetainedPacket[%u]\n", prAdapter
->rRxCtrl
.ucNumRetainedPacket
));
5815 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5816 DBGLOG(SW4
, INFO
, ("CMD: FreeCmd[%u/%u] PendingCmd[%u] Cmd2Tx[%u]\n",
5817 prAdapter
->rFreeCmdList
.u4NumElem
,
5818 CFG_TX_MAX_CMD_PKT_NUM
,
5819 prAdapter
->rPendingCmdQueue
.u4NumElem
, prGlueInfo
->rCmdQueue
.u4NumElem
));
5820 DBGLOG(SW4
, INFO
, ("MGMT: FreeMgmt[%u/%u] PendingMgmt[%u]\n",
5821 prAdapter
->rTxCtrl
.rFreeMsduInfoList
.u4NumElem
,
5822 CFG_TX_MAX_PKT_NUM
, prAdapter
->rTxCtrl
.rTxMgmtTxingQueue
.u4NumElem
));
5825 DBGLOG(SW4
, INFO
, ("---------------------------------\n\n"));
5832 #if CFG_M0VE_BA_TO_DRIVER
5833 /*----------------------------------------------------------------------------*/
5835 * @brief Send DELBA Action frame
5837 * @param fgIsInitiator DELBA_ROLE_INITIATOR or DELBA_ROLE_RECIPIENT
5838 * @param prStaRec Pointer to the STA_REC of the receiving peer
5839 * @param u4Tid TID of the BA entry
5840 * @param u4ReasonCode The reason code carried in the Action frame
5844 /*----------------------------------------------------------------------------*/
5846 mqmSendDelBaFrame(IN P_ADAPTER_T prAdapter
,
5847 IN BOOLEAN fgIsInitiator
,
5848 IN P_STA_RECORD_T prStaRec
, IN UINT_32 u4Tid
, IN UINT_32 u4ReasonCode
)
5851 P_MSDU_INFO_T prTxMsduInfo
;
5852 P_ACTION_DELBA_FRAME_T prDelBaFrame
;
5853 P_BSS_INFO_T prBssInfo
;
5855 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmSendDelBaFrame()\n"));
5859 /* 3 <1> Block the message in case of invalid STA */
5860 if (!prStaRec
->fgIsInUse
) {
5861 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
5864 /* Check HT-capabale STA */
5865 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
5867 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
5868 prStaRec
->ucDesiredPhyTypeSet
));
5871 /* 4 <2> Construct the DELBA frame */
5872 prTxMsduInfo
= (P_MSDU_INFO_T
) cnmMgtPktAlloc(prAdapter
, ACTION_DELBA_FRAME_LEN
);
5874 if (!prTxMsduInfo
) {
5876 ("[Puff][%s]: (Warning) DELBA for TID=%ld was not sent (MSDU_INFO alloc failure)\n",
5881 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
5883 /* Fill the Action frame */
5885 (P_ACTION_DELBA_FRAME_T
) ((UINT_32
) (prTxMsduInfo
->prPacket
) + MAC_TX_RESERVED_FIELD
);
5886 prDelBaFrame
->u2FrameCtrl
= MAC_FRAME_ACTION
;
5887 #if CFG_SUPPORT_802_11W
5888 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
5889 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) DELBA is 80211w enabled\n", __func__
));
5890 prDelBaFrame
->u2FrameCtrl
|= MASK_FC_PROTECTED_FRAME
;
5894 prDelBaFrame
->u2DurationID
= 0;
5895 prDelBaFrame
->ucCategory
= CATEGORY_BLOCK_ACK_ACTION
;
5896 prDelBaFrame
->ucAction
= ACTION_DELBA
;
5898 prDelBaFrame
->u2DelBaParameterSet
= 0;
5899 prDelBaFrame
->u2DelBaParameterSet
|= ((fgIsInitiator
? ACTION_DELBA_INITIATOR_MASK
: 0));
5900 prDelBaFrame
->u2DelBaParameterSet
|=
5901 ((u4Tid
<< ACTION_DELBA_TID_OFFSET
) & ACTION_DELBA_TID_MASK
);
5902 prDelBaFrame
->u2ReasonCode
= u4ReasonCode
;
5904 COPY_MAC_ADDR(prDelBaFrame
->aucDestAddr
, prStaRec
->aucMacAddr
);
5905 COPY_MAC_ADDR(prDelBaFrame
->aucSrcAddr
, prBssInfo
->aucOwnMacAddr
);
5906 COPY_MAC_ADDR(prDelBaFrame
->aucBSSID
, prBssInfo
->aucBSSID
);
5908 /* 4 <3> Configure the MSDU_INFO and forward it to TXM */
5909 TX_SET_MMPDU(prAdapter
,
5911 prStaRec
->ucBssIndex
,
5912 (prStaRec
!= NULL
) ? (prStaRec
->ucIndex
) : (STA_REC_INDEX_NOT_FOUND
),
5913 WLAN_MAC_HEADER_LEN
, ACTION_DELBA_FRAME_LEN
, NULL
, MSDU_RATE_MODE_AUTO
);
5915 #if CFG_SUPPORT_802_11W
5916 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
5917 DBGLOG(RSN
, INFO
, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
5918 nicTxConfigPktOption(prTxMsduInfo
, MSDU_OPT_PROTECTED_FRAME
, TRUE
);
5922 /* TID and fgIsInitiator are needed when processing TX Done of the DELBA frame */
5923 prTxMsduInfo
->ucTID
= (UINT_8
) u4Tid
;
5924 prTxMsduInfo
->ucControlFlag
= (fgIsInitiator
? 1 : 0);
5926 nicTxEnqueueMsdu(prAdapter
, prTxMsduInfo
);
5929 ("[Puff][%s]: Send DELBA for TID=%ld Initiator=%d\n", __func__
, u4Tid
,
5934 /*----------------------------------------------------------------------------*/
5936 * @brief Callback function for the TX Done event for an ADDBA_RSP
5938 * @param prMsduInfo The TX packet
5939 * @param rWlanStatus WLAN_STATUS_SUCCESS if TX is successful
5941 * @return WLAN_STATUS_BUFFER_RETAINED is returned if the buffer shall not be freed by TXM
5943 /*----------------------------------------------------------------------------*/
5945 mqmCallbackAddBaRspSent(IN P_ADAPTER_T prAdapter
,
5946 IN P_MSDU_INFO_T prMsduInfo
, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus
)
5948 P_RX_BA_ENTRY_T prRxBaEntry
;
5949 P_STA_RECORD_T prStaRec
;
5954 /* ASSERT(prMsduInfo); */
5955 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5958 prQM
= &prAdapter
->rQM
;
5960 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmCallbackAddBaRspSent()\n"));
5962 /* 4 <0> Check STA_REC status */
5963 /* Check STA_REC is inuse */
5964 if (!prStaRec
->fgIsInUse
) {
5965 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
5966 return WLAN_STATUS_SUCCESS
;
5968 /* Check HT-capabale STA */
5969 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
5971 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
5972 prStaRec
->ucDesiredPhyTypeSet
));
5973 return WLAN_STATUS_SUCCESS
; /* To free the received ADDBA_REQ directly */
5975 /* 4 <1> Find the corresponding BA entry */
5976 u4Tid
= prMsduInfo
->ucTID
; /* TID is stored in MSDU_INFO when composing the ADDBA_RSP frame */
5977 prRxBaEntry
= &prQM
->arRxBaTable
[u4Tid
];
5979 /* Note: Due to some reason, for example, receiving a DELBA, the BA entry may not be in state NEGO */
5980 /* 4 <2> INVALID state */
5983 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)(invalid BA)\n",
5984 __func__
, prStaRec
->ucIndex
, u4Tid
));
5986 /* 4 <3> NEGO, ACTIVE, or DELETING state */
5988 switch (rTxDoneStatus
) {
5989 /* 4 <Case 1> TX Success */
5990 case TX_RESULT_SUCCESS
:
5993 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)\n",
5994 __func__
, prStaRec
->ucIndex
, u4Tid
));
5997 /* 4 <Case 1.1> NEGO or ACTIVE state */
5998 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_DELETING
) {
5999 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
6000 BA_ENTRY_STATUS_ACTIVE
);
6002 /* 4 <Case 1.2> DELETING state */
6004 /* Deleting is on-going, so do nothing and wait for TX done of the DELBA frame */
6008 /* 4 <Case 2> TX Failure */
6012 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld Entry_Status=%d)(TX failed)\n",
6013 __func__
, prStaRec
->ucIndex
, u4Tid
, prRxBaEntry
->ucStatus
));
6015 /* 4 <Case 2.1> NEGO or ACTIVE state */
6016 /* Notify the host to delete the agreement */
6017 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_DELETING
) {
6018 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
6019 BA_ENTRY_STATUS_DELETING
);
6021 /* Send DELBA to the peer to ensure the BA state is synchronized */
6022 mqmSendDelBaFrame(prAdapter
, DELBA_ROLE_RECIPIENT
, prStaRec
, u4Tid
,
6023 STATUS_CODE_UNSPECIFIED_FAILURE
);
6025 /* 4 <Case 2.2> DELETING state */
6027 /* Deleting is on-going, so do nothing and wait for the TX done of the DELBA frame */
6036 return WLAN_STATUS_SUCCESS
; /* TXM shall release the packet */
6041 /*----------------------------------------------------------------------------*/
6043 * @brief Check if there is any idle RX BA
6045 * @param u4Param (not used)
6049 /*----------------------------------------------------------------------------*/
6050 VOID
mqmTimeoutCheckIdleRxBa(IN P_ADAPTER_T prAdapter
, IN ULONG ulParamPtr
)
6053 P_RX_BA_ENTRY_T prRxBa
;
6054 UINT_32 u4IdleCountThreshold
= 0;
6055 P_STA_RECORD_T prStaRec
;
6058 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmTimeoutIdleRxBaDetection()\n"));
6060 prQM
= &prAdapter
->rQM
;
6062 /* 4 <1> Restart the timer */
6063 cnmTimerStopTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6064 cnmTimerStartTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
,
6065 MQM_IDLE_RX_BA_CHECK_INTERVAL
);
6067 /* 4 <2> Increment the idle count for each idle BA */
6068 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
6070 prRxBa
= &prQM
->arRxBaTable
[i
];
6072 if (prRxBa
->ucStatus
== BA_ENTRY_STATUS_ACTIVE
) {
6074 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prRxBa
->ucStaRecIdx
);
6076 if (!prStaRec
->fgIsInUse
) {
6078 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
6081 /* Check HT-capabale STA */
6082 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
6084 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n",
6085 __func__
, prStaRec
->ucDesiredPhyTypeSet
));
6088 /* 4 <2.1> Idle detected, increment idle count and see if a DELBA should be sent */
6089 if (prRxBa
->u2SnapShotSN
== prStaRec
->au2CachedSeqCtrl
[prRxBa
->ucTid
]) {
6091 prRxBa
->ucIdleCount
++;
6093 ASSERT(prRxBa
->ucTid
< 8);
6094 switch (aucTid2ACI
[prRxBa
->ucTid
]) {
6096 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_BK
;
6099 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_BE
;
6102 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_VI
;
6105 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_VO
;
6109 if (prRxBa
->ucIdleCount
>= u4IdleCountThreshold
) {
6110 mqmRxModifyBaEntryStatus(prAdapter
, prRxBa
,
6111 BA_ENTRY_STATUS_INVALID
);
6112 mqmSendDelBaFrame(prAdapter
, DELBA_ROLE_RECIPIENT
, prStaRec
,
6113 (UINT_32
) prRxBa
->ucTid
,
6114 REASON_CODE_PEER_TIME_OUT
);
6115 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, prRxBa
->ucTid
,
6119 /* 4 <2.2> Activity detected */
6121 prRxBa
->u2SnapShotSN
= prStaRec
->au2CachedSeqCtrl
[prRxBa
->ucTid
];
6122 prRxBa
->ucIdleCount
= 0;
6123 continue; /* check the next BA entry */
6131 /*----------------------------------------------------------------------------*/
6133 * @brief Do RX BA entry state transition
6135 * @param prRxBaEntry The BA entry pointer
6136 * @param eStatus The state to transition to
6140 /*----------------------------------------------------------------------------*/
6142 mqmRxModifyBaEntryStatus(IN P_ADAPTER_T prAdapter
,
6143 IN P_RX_BA_ENTRY_T prRxBaEntry
, IN ENUM_BA_ENTRY_STATUS_T eStatus
)
6145 P_STA_RECORD_T prStaRec
;
6148 BOOLEAN fgResetScoreBoard
= FALSE
;
6150 ASSERT(prRxBaEntry
);
6152 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prRxBaEntry
->ucStaRecIdx
);
6154 prQM
= &prAdapter
->rQM
;
6156 if (prRxBaEntry
->ucStatus
== (UINT_8
) eStatus
) {
6158 ("[Puff][%s]: eStatus are identical...\n", __func__
, prRxBaEntry
->ucStatus
));
6161 /* 4 <1> State transition from state X */
6162 switch (prRxBaEntry
->ucStatus
) {
6164 /* 4 <1.1> From (X = INVALID) to (ACTIVE or NEGO or DELETING) */
6165 case BA_ENTRY_STATUS_INVALID
:
6167 /* Associate the BA entry with the STA_REC when leaving INVALID state */
6168 kalMemCopy(&prQM
->arRxBaTable
[prRxBaEntry
->ucTid
], prRxBaEntry
,
6169 sizeof(RX_BA_ENTRY_T
));
6171 /* Increment the RX BA counter */
6172 prQM
->ucRxBaCount
++;
6173 ASSERT(prQM
->ucRxBaCount
<= CFG_NUM_OF_RX_BA_AGREEMENTS
);
6175 /* Since AMPDU may be received during INVALID state */
6176 fgResetScoreBoard
= TRUE
;
6178 /* Reset Idle Count since this BA entry is being activated now.
6179 * Note: If there is no ACTIVE entry, the idle detection timer will not be started.
6181 prRxBaEntry
->ucIdleCount
= 0;
6184 /* 4 <1.2> Other cases */
6189 /* 4 <2> State trasition to state Y */
6192 /* 4 <2.1> From (NEGO, ACTIVE, DELETING) to (Y=INVALID) */
6193 case BA_ENTRY_STATUS_INVALID
:
6195 /* Disassociate the BA entry with the STA_REC */
6196 kalMemZero(&prQM
->arRxBaTable
[prRxBaEntry
->ucTid
], sizeof(RX_BA_ENTRY_T
));
6198 /* Decrement the RX BA counter */
6199 prQM
->ucRxBaCount
--;
6200 ASSERT(prQM
->ucRxBaCount
< CFG_NUM_OF_RX_BA_AGREEMENTS
);
6203 fgResetScoreBoard
= TRUE
;
6205 /* If there is not any BA agreement, stop doing idle detection */
6206 if (prQM
->ucRxBaCount
== 0) {
6208 (prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
)) {
6209 cnmTimerStopTimer(prAdapter
,
6210 &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6211 MQM_CLEAR_FLAG(prAdapter
->u4FlagBitmap
,
6212 MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
);
6218 /* 4 <2.2> From (any) to (Y=ACTIVE) */
6219 case BA_ENTRY_STATUS_ACTIVE
:
6221 /* If there is at least one BA going into ACTIVE, start idle detection */
6222 if (!MQM_CHECK_FLAG(prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
)) {
6223 cnmTimerInitTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
, (PFN_MGMT_TIMEOUT_FUNC
) mqmTimeoutCheckIdleRxBa
, (ULONG
) NULL
); /* No parameter */
6225 cnmTimerStopTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6227 #if MQM_IDLE_RX_BA_DETECTION
6228 cnmTimerStartTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
,
6229 MQM_IDLE_RX_BA_CHECK_INTERVAL
);
6230 MQM_SET_FLAG(prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
);
6236 case BA_ENTRY_STATUS_NEGO
:
6241 if (fgResetScoreBoard
) {
6242 P_CMD_RESET_BA_SCOREBOARD_T prCmdBody
;
6244 prCmdBody
= (P_CMD_RESET_BA_SCOREBOARD_T
)
6245 cnmMemAlloc(prAdapter
, RAM_TYPE_BUF
, sizeof(CMD_RESET_BA_SCOREBOARD_T
));
6248 prCmdBody
->ucflag
= MAC_ADDR_TID_MATCH
;
6249 prCmdBody
->ucTID
= prRxBaEntry
->ucTid
;
6250 kalMemCopy(prCmdBody
->aucMacAddr
, prStaRec
->aucMacAddr
, PARAM_MAC_ADDR_LEN
);
6252 wlanoidResetBAScoreboard(prAdapter
, prCmdBody
, sizeof(CMD_RESET_BA_SCOREBOARD_T
));
6256 DBGLOG(QM
, WARN
, ("[Puff]QM: (RX_BA) [STA=%d TID=%d] status from %d to %d\n",
6257 prRxBaEntry
->ucStaRecIdx
, prRxBaEntry
->ucTid
,
6258 prRxBaEntry
->ucStatus
, eStatus
));
6260 prRxBaEntry
->ucStatus
= (UINT_8
) eStatus
;
6265 /*----------------------------------------------------------------------------*/
6273 /*----------------------------------------------------------------------------*/
6274 VOID
mqmHandleAddBaReq(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
)
6276 P_STA_RECORD_T prStaRec
;
6277 P_BSS_INFO_T prBssInfo
;
6278 P_ACTION_ADDBA_REQ_FRAME_T prAddBaReq
;
6279 ACTION_ADDBA_REQ_BODY_T rAddBaReqBody
;
6280 P_ACTION_ADDBA_RSP_FRAME_T prAddBaRsp
;
6281 ACTION_ADDBA_RSP_BODY_T rAddBaRspBody
;
6282 P_RX_BA_ENTRY_T prRxBaEntry
;
6283 P_MSDU_INFO_T prTxMsduInfo
;
6286 BOOLEAN fgIsReqAccepted
= TRUE
; /* Reject or accept the ADDBA_REQ */
6287 BOOLEAN fgIsNewEntryAdded
= FALSE
; /* Indicator: Whether a new RX BA entry will be added */
6290 UINT_32 u4StaRecIdx
;
6296 UINT_32 u4BuffSizeBT
;
6301 prStaRec
= prSwRfb
->prStaRec
;
6302 prQM
= &prAdapter
->rQM
;
6307 /* 4 <0> Check if this is an active HT-capable STA */
6308 /* Check STA_REC is inuse */
6309 if (!prStaRec
->fgIsInUse
) {
6311 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
6314 /* Check HT-capabale STA */
6315 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
6317 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
6318 prStaRec
->ucDesiredPhyTypeSet
));
6319 break; /* To free the received ADDBA_REQ directly */
6321 /* 4 <1> Check user configurations and HW capabilities */
6322 /* Check configurations (QoS support, AMPDU RX support) */
6323 if ((!prAdapter
->rWifiVar
.fgSupportQoS
) ||
6324 (!prAdapter
->rWifiVar
.fgSupportAmpduRx
) || (!prStaRec
->fgRxAmpduEn
)) {
6326 ("[Puff][%s]: (Warning) BA ACK Policy not supported fgSupportQoS(%d), fgSupportAmpduRx(%d), fgRxAmpduEn(%d)\n",
6327 __func__
, prAdapter
->rWifiVar
.fgSupportQoS
,
6328 prAdapter
->rWifiVar
.fgSupportAmpduRx
, prStaRec
->fgRxAmpduEn
));
6329 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6331 /* Check capability */
6332 prAddBaReq
= ((P_ACTION_ADDBA_REQ_FRAME_T
) (prSwRfb
->pvHeader
));
6333 kalMemCopy((PUINT_8
) (&rAddBaReqBody
),
6334 (PUINT_8
) (&(prAddBaReq
->aucBAParameterSet
[0])), 6);
6335 if ((((rAddBaReqBody
.
6336 u2BAParameterSet
) & BA_PARAM_SET_ACK_POLICY_MASK
) >>
6337 BA_PARAM_SET_ACK_POLICY_MASK_OFFSET
)
6338 != BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA
) { /* Only Immediate_BA is supported */
6340 ("[Puff][%s]: (Warning) BA ACK Policy not supported (0x%08X)\n",
6341 __func__
, rAddBaReqBody
.u2BAParameterSet
));
6342 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6345 /* 4 <2> Determine the RX BA entry (existing or to be added) */
6346 /* Note: BA entry index = (TID, STA_REC index) */
6349 u2BAParameterSet
) & BA_PARAM_SET_TID_MASK
) >> BA_PARAM_SET_TID_MASK_OFFSET
);
6350 u4StaRecIdx
= prStaRec
->ucIndex
;
6352 ("[Puff][%s]: BA entry index = [TID(%d), STA_REC index(%d)]\n", __func__
,
6353 u4Tid
, u4StaRecIdx
));
6355 u2WinStart
= ((rAddBaReqBody
.u2BAStartSeqCtrl
) >> OFFSET_BAR_SSC_SN
);
6356 u2WinSize
= (((rAddBaReqBody
.u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
6357 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
6359 ("[Puff][%s]: BA entry info = [WinStart(%d), WinSize(%d)]\n", __func__
,
6360 u2WinStart
, u2WinSize
));
6363 if (fgIsReqAccepted
) {
6365 prRxBaEntry
= &prQM
->arRxBaTable
[u4Tid
];
6369 /* 4 <Case 2.1> INVALID state && BA entry available --> Add a new entry and accept */
6370 if (prQM
->ucRxBaCount
< CFG_NUM_OF_RX_BA_AGREEMENTS
) {
6372 fgIsNewEntryAdded
= qmAddRxBaEntry(prAdapter
,
6373 (UINT_8
) u4StaRecIdx
,
6375 u2WinStart
, u2WinSize
);
6377 if (!fgIsNewEntryAdded
) {
6379 ("[Puff][%s]: (Error) Free RX BA entry alloc failure\n"));
6380 fgIsReqAccepted
= FALSE
;
6383 ("[Puff][%s]: Create a new BA Entry\n"));
6386 /* 4 <Case 2.2> INVALID state && BA entry unavailable --> Reject the ADDBA_REQ */
6389 ("[Puff][%s]: (Warning) Free RX BA entry unavailable(req: %d)\n",
6390 __func__
, prQM
->ucRxBaCount
));
6391 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6395 /* 4 <Case 2.3> NEGO or DELETING state --> Ignore the ADDBA_REQ */
6396 /* For NEGO: do nothing. Wait for TX Done of ADDBA_RSP */
6397 /* For DELETING: do nothing. Wait for TX Done of DELBA */
6398 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_ACTIVE
) {
6400 ("[Puff][%s]: (Warning) ADDBA_REQ for TID=%ld is received during status:%d (Ignore)\n",
6401 __func__
, u4Tid
, prRxBaEntry
->ucStatus
));
6402 break; /* Ignore the ADDBA_REQ since the current state is NEGO */
6404 /* 4 <Case 2.4> ACTIVE state --> Accept */
6405 /* Send an ADDBA_RSP to accept the request again */
6409 /* 4 <3> Construct the ADDBA_RSP frame */
6411 (P_MSDU_INFO_T
) cnmMgtPktAlloc(prAdapter
, ACTION_ADDBA_RSP_FRAME_LEN
);
6412 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
6414 if (!prTxMsduInfo
) {
6416 /* The peer may send an ADDBA_REQ message later.
6417 * Do nothing to the BA entry. No DELBA will be sent (because cnmMgtPktAlloc() may fail again).
6418 * No BA deletion event will be sent to the host (because cnmMgtPktAlloc() may fail again).
6421 ("[Puff][%s]: (Warning) ADDBA_RSP alloc failure\n", __func__
));
6423 if (fgIsNewEntryAdded
) { /* If a new entry has been created due to this ADDBA_REQ, delete it */
6424 ASSERT(prRxBaEntry
);
6425 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
6426 BA_ENTRY_STATUS_INVALID
);
6429 break; /* Exit directly to free the ADDBA_REQ */
6432 /* Fill the ADDBA_RSP message */
6434 (P_ACTION_ADDBA_RSP_FRAME_T
) ((UINT_32
) (prTxMsduInfo
->prPacket
) +
6435 MAC_TX_RESERVED_FIELD
);
6436 prAddBaRsp
->u2FrameCtrl
= MAC_FRAME_ACTION
;
6438 #if CFG_SUPPORT_802_11W
6439 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
6441 ("[Puff][%s]: (Warning) ADDBA_RSP is 80211w enabled\n", __func__
));
6442 prAddBaReq
->u2FrameCtrl
|= MASK_FC_PROTECTED_FRAME
;
6445 prAddBaRsp
->u2DurationID
= 0;
6446 prAddBaRsp
->ucCategory
= CATEGORY_BLOCK_ACK_ACTION
;
6447 prAddBaRsp
->ucAction
= ACTION_ADDBA_RSP
;
6448 prAddBaRsp
->ucDialogToken
= prAddBaReq
->ucDialogToken
;
6451 ("[Puff][%s]: (Warning) ADDBA_RSP DurationID(%d) Category(%d) Action(%d) DialogToken(%d)\n",
6452 __func__
, prAddBaRsp
->u2DurationID
, prAddBaRsp
->ucCategory
,
6453 prAddBaRsp
->ucAction
, prAddBaRsp
->ucDialogToken
));
6455 if (fgIsReqAccepted
) {
6456 rAddBaRspBody
.u2StatusCode
= STATUS_CODE_SUCCESSFUL
;
6458 rAddBaRspBody
.u2StatusCode
= STATUS_CODE_REQ_DECLINED
;
6461 /* WinSize = min(WinSize in ADDBA_REQ, CFG_RX_BA_MAX_WINSIZE) */
6462 u4BuffSize
= (((rAddBaReqBody
.u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
6463 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
6465 /*If ADDBA req WinSize<=0 => use default WinSize(16) */
6466 if ((u4BuffSize
> CFG_RX_BA_MAX_WINSIZE
) || (u4BuffSize
<= 0)) {
6467 u4BuffSize
= CFG_RX_BA_MAX_WINSIZE
;
6470 /* TODO: Call BT coexistence function to limit the winsize */
6471 u4BuffSizeBT
= bcmRequestBaWinSize();
6472 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) bcmRequestBaWinSize(%d)\n",
6473 __func__
, u4BuffSizeBT
));
6475 if (u4BuffSize
> u4BuffSizeBT
) {
6476 u4BuffSize
= u4BuffSizeBT
;
6478 #endif /* CFG_SUPPORT_BCM */
6480 rAddBaRspBody
.u2BAParameterSet
= (BA_POLICY_IMMEDIATE
|
6481 (u4Tid
<< BA_PARAM_SET_TID_MASK_OFFSET
) |
6483 BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
));
6485 /* TODO: Determine the BA timeout value according to the default preference */
6486 rAddBaRspBody
.u2BATimeoutValue
= rAddBaReqBody
.u2BATimeoutValue
;
6489 ("[Puff][%s]: (Warning) ADDBA_RSP u4BuffSize(%d) StatusCode(%d) BAParameterSet(0x%08X) BATimeoutValue(%d)\n",
6490 __func__
, u4BuffSize
, rAddBaRspBody
.u2StatusCode
,
6491 rAddBaRspBody
.u2BAParameterSet
, rAddBaRspBody
.u2BATimeoutValue
));
6493 kalMemCopy((PUINT_8
) (&(prAddBaRsp
->aucStatusCode
[0])), (PUINT_8
) (&rAddBaRspBody
),
6496 COPY_MAC_ADDR(prAddBaRsp
->aucDestAddr
, prStaRec
->aucMacAddr
);
6497 COPY_MAC_ADDR(prAddBaRsp
->aucSrcAddr
, prBssInfo
->aucOwnMacAddr
);
6498 /* COPY_MAC_ADDR(prAddBaRsp->aucBSSID,g_aprBssInfo[prStaRec->ucNetTypeIndex]->aucBSSID); */
6499 COPY_MAC_ADDR(prAddBaRsp
->aucBSSID
, prAddBaReq
->aucBSSID
);
6502 /* 4 <4> Forward the ADDBA_RSP to TXM */
6503 TX_SET_MMPDU(prAdapter
,
6505 prStaRec
->ucBssIndex
,
6506 (prStaRec
!= NULL
) ? (prStaRec
->ucIndex
) : (STA_REC_INDEX_NOT_FOUND
),
6507 WLAN_MAC_HEADER_LEN
,
6508 ACTION_ADDBA_RSP_FRAME_LEN
,
6509 mqmCallbackAddBaRspSent
, MSDU_RATE_MODE_AUTO
);
6511 #if CFG_SUPPORT_802_11W
6512 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
6513 DBGLOG(RSN
, INFO
, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
6514 nicTxConfigPktOption(prTxMsduInfo
, MSDU_OPT_PROTECTED_FRAME
, TRUE
);
6518 /* Note: prTxMsduInfo->ucTID is not used for transmitting the ADDBA_RSP.
6519 * However, when processing TX Done of this ADDBA_RSP, the TID value is needed, so
6520 * store the TID value in advance to prevent parsing the ADDBA_RSP frame
6522 prTxMsduInfo
->ucTID
= (UINT_8
) u4Tid
;
6524 nicTxEnqueueMsdu(prAdapter
, prTxMsduInfo
);
6527 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld)\n", __func__
,
6528 prStaRec
->ucIndex
, u4Tid
));
6532 /* 4 <5> Notify the host to start buffer reordering */
6533 if (fgIsNewEntryAdded
) { /* Only when a new BA entry is indeed added will the host be notified */
6534 ASSERT(fgIsReqAccepted
);
6536 prSwRfbEventToHost
= (P_SW_RFB_T
) cnmMgtPktAlloc(EVENT_RX_ADDBA_PACKET_LEN
);
6538 if (!prSwRfbEventToHost
) {
6540 /* Note: DELBA will not be sent since cnmMgtPktAlloc() may fail again. However, it does not
6541 * matter because upon receipt of AMPDUs without a RX BA agreement, MQM will send DELBA frames
6544 DBGLOG(MQM
, WARN
, ("MQM: (Warning) EVENT packet alloc failed\n"));
6546 /* Ensure that host and FW are synchronized */
6547 mqmRxModifyBaEntryStatus(prRxBaEntry
, BA_ENTRY_STATUS_INVALID
);
6549 break; /* Free the received ADDBA_REQ */
6552 prEventRxAddBa
= (P_EVENT_RX_ADDBA_T
) prSwRfbEventToHost
->pucBuffer
;
6553 prEventRxAddBa
->ucStaRecIdx
= (UINT_8
) u4StaRecIdx
;
6554 prEventRxAddBa
->u2Length
= EVENT_RX_ADDBA_PACKET_LEN
;
6555 prEventRxAddBa
->ucEID
= EVENT_ID_RX_ADDBA
;
6556 prEventRxAddBa
->ucSeqNum
= 0; /* Unsolicited event packet */
6557 prEventRxAddBa
->u2BAParameterSet
= rAddBaRspBody
.u2BAParameterSet
;
6558 prEventRxAddBa
->u2BAStartSeqCtrl
= rAddBaReqBody
.u2BAStartSeqCtrl
;
6559 prEventRxAddBa
->u2BATimeoutValue
= rAddBaReqBody
.u2BATimeoutValue
;
6560 prEventRxAddBa
->ucDialogToken
= prAddBaReq
->ucDialogToken
;
6563 ("MQM: (RX_BA) Event ADDBA ---> driver (STA=%ld TID=%ld WinStart=%d)\n",
6565 (prEventRxAddBa
->u2BAStartSeqCtrl
>> 4)));
6567 /* Configure the SW_RFB for the Event packet */
6568 RXM_SET_EVENT_PACKET(
6569 /* P_SW_RFB_T */ (P_SW_RFB_T
)
6571 /* HIF RX Packet pointer */
6572 (PUINT_8
) prEventRxAddBa
,
6573 /* HIF RX port number */ HIF_RX0_INDEX
6576 rxmSendEventToHost(prSwRfbEventToHost
);
6587 /*----------------------------------------------------------------------------*/
6595 /*----------------------------------------------------------------------------*/
6596 VOID
mqmHandleAddBaRsp(IN P_SW_RFB_T prSwRfb
)
6601 /*----------------------------------------------------------------------------*/
6609 /*----------------------------------------------------------------------------*/
6610 VOID
mqmHandleDelBa(IN P_SW_RFB_T prSwRfb
)
6615 /*----------------------------------------------------------------------------*/
6623 /*----------------------------------------------------------------------------*/
6624 VOID
mqmHandleBaActionFrame(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
)
6626 P_WLAN_ACTION_FRAME prRxFrame
;
6631 prRxFrame
= (P_WLAN_ACTION_FRAME
) prSwRfb
->pvHeader
;
6632 DBGLOG(RLM
, WARN
, ("[Puff][%s] Action(%d)\n", __func__
, prRxFrame
->ucAction
));
6634 switch (prRxFrame
->ucAction
) {
6636 case ACTION_ADDBA_REQ
:
6637 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) ADDBA_REQ <--- peer\n", __func__
));
6638 mqmHandleAddBaReq(prAdapter
, prSwRfb
);
6641 case ACTION_ADDBA_RSP
:
6642 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) ADDBA_RSP <--- peer\n", __func__
));
6643 mqmHandleAddBaRsp(prSwRfb
);
6647 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) DELBA <--- peer\n", __func__
));
6648 mqmHandleDelBa(prSwRfb
);
6652 DBGLOG(RLM
, WARN
, ("[Puff][%s] Unknown BA Action Frame\n", __func__
));