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 /* Todo:: Move the data class error check here */
3202 if (prCurrSwRfb
->fgReorderBuffer
&& !fgIsBMC
&& fgIsHTran
) {
3203 /* If this packet should dropped or indicated to the host immediately,
3204 * it should be enqueued into the rReturnedQue with specific flags. If
3205 * this packet should be buffered for reordering, it should be enqueued
3206 * into the reordering queue in the STA_REC rather than into the
3209 qmProcessPktWithReordering(prAdapter
, prCurrSwRfb
, prReturnedQue
);
3211 } else if (prCurrSwRfb
->fgDataFrame
) {
3212 /* Check Class Error */
3214 if (secCheckClassError
3215 (prAdapter
, prCurrSwRfb
, prCurrSwRfb
->prStaRec
) == TRUE
) {
3216 P_RX_BA_ENTRY_T prReorderQueParm
= NULL
;
3218 /* Invalid BA aggrement */
3220 UINT_16 u2FrameCtrl
= 0;
3222 u2FrameCtrl
= HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prCurrSwRfb
->prRxStatusGroup4
);
3223 // Check FC type, if DATA, then no-reordering
3224 if((u2FrameCtrl
& MASK_FRAME_TYPE
) == MAC_FRAME_DATA
){
3225 DBGLOG(QM
, TRACE
, ("FC [0x%04X], no-reordering...\n", u2FrameCtrl
));
3228 prReorderQueParm
= ((prCurrSwRfb
->prStaRec
->aprRxReorderParamRefTbl
)[prCurrSwRfb
->ucTid
]);
3232 if (prReorderQueParm
&& prReorderQueParm
->fgIsValid
3234 qmProcessPktWithReordering(prAdapter
, prCurrSwRfb
,
3237 qmHandleRxPackets_AOSP_1
;
3240 DBGLOG(QM
, TRACE
, ("Mark NULL the Packet for class error\n"));
3241 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3242 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3246 P_WLAN_MAC_HEADER_T prWlanMacHeader
;
3248 ASSERT(prCurrSwRfb
->pvHeader
);
3250 prWlanMacHeader
= (P_WLAN_MAC_HEADER_T
) prCurrSwRfb
->pvHeader
;
3251 prCurrSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3253 switch (prWlanMacHeader
->u2FrameCtrl
& MASK_FRAME_TYPE
) {
3255 case MAC_FRAME_BLOCK_ACK_REQ
:
3256 qmProcessBarFrame(prAdapter
, prCurrSwRfb
, prReturnedQue
);
3260 ("Mark NULL the Packet for non-interesting type\n"));
3261 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prCurrSwRfb
);
3266 } while (prNextSwRfb
);
3269 /* The returned list of SW_RFBs must end with a NULL pointer */
3270 if (QUEUE_IS_NOT_EMPTY(prReturnedQue
)) {
3271 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T
) QUEUE_GET_TAIL(prReturnedQue
), NULL
);
3274 return (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
);
3278 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3279 return prSwRfbListHead
;
3285 /*----------------------------------------------------------------------------*/
3287 * \brief Reorder the received packet
3289 * \param[in] prSwRfb The RX packet to process
3290 * \param[out] prReturnedQue The queue for indicating packets
3294 /*----------------------------------------------------------------------------*/
3296 qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter
,
3297 IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
3301 P_STA_RECORD_T prStaRec
;
3302 P_HW_MAC_RX_DESC_T prRxStatus
;
3303 P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4
= NULL
;
3304 P_RX_BA_ENTRY_T prReorderQueParm
;
3309 P_QUE_T prReorderQue
;
3310 /* P_SW_RFB_T prReorderedSwRfb; */
3312 DEBUGFUNC("qmProcessPktWithReordering");
3315 ASSERT(prReturnedQue
);
3316 ASSERT(prSwRfb
->prRxStatus
);
3318 /* Incorrect STA_REC index */
3319 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
3320 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3321 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3322 DBGLOG(QM
, WARN
, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
3323 prSwRfb
->ucStaRecIdx
));
3324 authSendDeauthFrame(prAdapter
,
3327 prSwRfb
, REASON_CODE_CLASS_3_ERR
, (PFN_TX_DONE_HANDLER
) NULL
);
3332 /* Check whether the STA_REC is activated */
3333 prStaRec
= prSwRfb
->prStaRec
;
3336 prRxStatus
= prSwRfb
->prRxStatus
;
3337 prSwRfb
->ucTid
= (UINT_8
) (HAL_RX_STATUS_GET_TID(prRxStatus
));
3338 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3341 if (!(prStaRec
->fgIsValid
)) {
3342 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3343 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3344 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3345 DBGLOG(QM
, WARN
, ("Reordering for an invalid STA_REC\n"));
3351 /* Check whether the BA agreement exists */
3352 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
3353 if (!prReorderQueParm
|| !(prReorderQueParm
->fgIsValid
)) {
3354 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3355 prSwRfb
->eDst
= RX_PKT_DESTINATION_HOST
;
3356 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3357 DBGLOG(QM
, TRACE
, ("Reordering for a NULL ReorderQueParm\n"));
3361 prRxStatusGroup4
= prSwRfb
->prRxStatusGroup4
;
3362 if (prRxStatusGroup4
== NULL
) {
3363 DBGLOG(QM
, ERROR
, ("prRxStatusGroup4 is NULL !!!\n"));
3365 ("prSwRfb->pvHeader is 0x%p !!!\n", (PUINT_32
) prSwRfb
->pvHeader
));
3366 DBGLOG(QM
, ERROR
, ("prSwRfb->u2PacketLen is %d !!!\n", prSwRfb
->u2PacketLen
));
3367 DBGLOG(QM
, ERROR
, ("========= START TO DUMP prSwRfb =========\n"));
3368 DBGLOG_MEM8(QM
, ERROR
, prSwRfb
->pvHeader
, prSwRfb
->u2PacketLen
);
3369 DBGLOG(QM
, ERROR
, ("========= END OF DUMP prSwRfb =========\n"));
3370 ASSERT(prRxStatusGroup4
);
3375 HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4
) >> RX_STATUS_SEQ_NUM_OFFSET
;
3377 /* Start to reorder packets */
3378 u4SeqNo
= (UINT_32
) (prSwRfb
->u2SSN
);
3379 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3380 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
3381 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
3384 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3386 /* Case 1: Fall within */
3387 if /* 0 - start - sn - end - 4095 */
3388 (((u4WinStart
<= u4SeqNo
) && (u4SeqNo
<= u4WinEnd
))
3389 /* 0 - end - start - sn - 4095 */
3390 || ((u4WinEnd
< u4WinStart
) && (u4WinStart
<= u4SeqNo
))
3391 /* 0 - sn - end - start - 4095 */
3392 || ((u4SeqNo
<= u4WinEnd
) && (u4WinEnd
< u4WinStart
))) {
3394 qmInsertFallWithinReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
3396 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3397 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3398 /* Let the first received packet pass the reorder check */
3400 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SeqNo
, u4WinStart
,
3403 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SeqNo
;
3404 prReorderQueParm
->u2WinEnd
=
3405 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3406 1) % MAX_SEQ_NO_COUNT
;
3407 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
3412 qmPopOutDueToFallWithin(prAdapter
, prReorderQueParm
, prReturnedQue
);
3414 /* Case 2: Fall ahead */
3416 /* 0 - start - end - sn - (start+2048) - 4095 */
3417 (((u4WinStart
< u4WinEnd
)
3418 && (u4WinEnd
< u4SeqNo
)
3419 && (u4SeqNo
< (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
3420 /* 0 - sn - (start+2048) - start - end - 4095 */
3421 || ((u4SeqNo
< u4WinStart
)
3422 && (u4WinStart
< u4WinEnd
)
3423 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))
3424 /* 0 - end - sn - (start+2048) - start - 4095 */
3425 || ((u4WinEnd
< u4SeqNo
)
3426 && (u4SeqNo
< u4WinStart
)
3427 && ((u4SeqNo
+ MAX_SEQ_NO_COUNT
) < (u4WinStart
+ HALF_SEQ_NO_COUNT
)))) {
3430 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3431 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3432 prReorderQueParm
->fgIsWaitingForPktWithSsn
= FALSE
;
3436 qmInsertFallAheadReorderPkt(prSwRfb
, prReorderQueParm
, prReturnedQue
);
3438 /* Advance the window after inserting a new tail */
3439 prReorderQueParm
->u2WinEnd
= (UINT_16
) u4SeqNo
;
3440 prReorderQueParm
->u2WinStart
=
3441 (((prReorderQueParm
->u2WinEnd
) - (prReorderQueParm
->u2WinSize
) +
3442 MAX_SEQ_NO_COUNT
+ 1)
3443 % MAX_SEQ_NO_COUNT
);
3445 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3448 /* Case 3: Fall behind */
3451 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3452 #if QM_RX_INIT_FALL_BEHIND_PASS
3453 if (prReorderQueParm
->fgIsWaitingForPktWithSsn
) {
3454 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3455 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3456 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3462 /* An erroneous packet */
3463 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3464 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3465 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3474 VOID
qmProcessBarFrame(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
, OUT P_QUE_T prReturnedQue
)
3477 P_STA_RECORD_T prStaRec
;
3478 P_HW_MAC_RX_DESC_T prRxStatus
;
3479 P_RX_BA_ENTRY_T prReorderQueParm
;
3480 P_CTRL_BAR_FRAME_T prBarCtrlFrame
;
3485 P_QUE_T prReorderQue
;
3486 /* P_SW_RFB_T prReorderedSwRfb; */
3489 ASSERT(prReturnedQue
);
3490 ASSERT(prSwRfb
->prRxStatus
);
3491 ASSERT(prSwRfb
->pvHeader
);
3493 prRxStatus
= prSwRfb
->prRxStatus
;
3495 prBarCtrlFrame
= (P_CTRL_BAR_FRAME_T
) prSwRfb
->pvHeader
;
3498 (*((PUINT_16
) ((PUINT_8
) prBarCtrlFrame
+ CTRL_BAR_BAR_CONTROL_OFFSET
))) >>
3499 BAR_CONTROL_TID_INFO_OFFSET
;
3501 (*((PUINT_16
) ((PUINT_8
) prBarCtrlFrame
+ CTRL_BAR_BAR_INFORMATION_OFFSET
))) >>
3504 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3505 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3507 /* Incorrect STA_REC index */
3508 prSwRfb
->ucStaRecIdx
= secLookupStaRecIndexFromTA(prAdapter
, prBarCtrlFrame
->aucSrcAddr
);
3509 if (prSwRfb
->ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
3510 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
3511 prSwRfb
->ucStaRecIdx
));
3516 /* Check whether the STA_REC is activated */
3517 prSwRfb
->prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
3518 prStaRec
= prSwRfb
->prStaRec
;
3519 if (prStaRec
== NULL
) {
3520 /* ASSERT(prStaRec); */
3524 if (!(prStaRec
->fgIsValid
)) {
3525 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3526 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
3532 /* Check whether the BA agreement exists */
3533 prReorderQueParm
= ((prStaRec
->aprRxReorderParamRefTbl
)[prSwRfb
->ucTid
]);
3534 if (!prReorderQueParm
) {
3535 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3536 DBGLOG(QM
, WARN
, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
3542 u4SSN
= (UINT_32
) (prSwRfb
->u2SSN
);
3543 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3544 u4WinStart
= (UINT_32
) (prReorderQueParm
->u2WinStart
);
3545 u4WinEnd
= (UINT_32
) (prReorderQueParm
->u2WinEnd
);
3547 if (qmCompareSnIsLessThan(u4WinStart
, u4SSN
)) {
3548 prReorderQueParm
->u2WinStart
= (UINT_16
) u4SSN
;
3549 prReorderQueParm
->u2WinEnd
=
3550 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3551 1) % MAX_SEQ_NO_COUNT
;
3553 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb
->ucTid
, u4SSN
,
3554 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3555 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3558 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb
->ucTid
, u4SSN
, u4WinStart
,
3566 qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb
,
3567 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3569 P_SW_RFB_T prExaminedQueuedSwRfb
;
3570 P_QUE_T prReorderQue
;
3572 ASSERT(prReorderQueParm
);
3573 ASSERT(prReturnedQue
);
3575 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3576 prExaminedQueuedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3578 /* There are no packets queued in the Reorder Queue */
3579 if (prExaminedQueuedSwRfb
== NULL
) {
3580 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
3581 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3582 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3583 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
3584 prReorderQue
->u4NumElem
++;
3587 /* Determine the insert position */
3590 /* Case 1: Terminate. A duplicate packet */
3591 if (((prExaminedQueuedSwRfb
->u2SSN
) == (prSwRfb
->u2SSN
))) {
3592 prSwRfb
->eDst
= RX_PKT_DESTINATION_NULL
;
3593 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prSwRfb
);
3597 /* Case 2: Terminate. The insert point is found */
3598 else if (qmCompareSnIsLessThan((prSwRfb
->u2SSN
),
3599 (prExaminedQueuedSwRfb
->u2SSN
))) {
3603 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3605 prExaminedQueuedSwRfb
=
3606 (P_SW_RFB_T
) (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prNext
);
3608 } while (prExaminedQueuedSwRfb
);
3610 /* Update the Reorder Queue Parameters according to the found insert position */
3611 if (prExaminedQueuedSwRfb
== NULL
) {
3612 /* The received packet shall be placed at the tail */
3613 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
3614 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3615 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
3616 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) (prSwRfb
);
3618 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
=
3619 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
;
3620 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= (P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
;
3621 if (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
) == (prReorderQue
->prHead
)) {
3622 /* The received packet will become the head */
3623 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3625 (((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
)->prNext
=
3626 (P_QUE_ENTRY_T
) prSwRfb
;
3628 ((P_QUE_ENTRY_T
) prExaminedQueuedSwRfb
)->prPrev
= (P_QUE_ENTRY_T
) prSwRfb
;
3631 prReorderQue
->u4NumElem
++;
3639 qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb
,
3640 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3642 P_QUE_T prReorderQue
;
3644 ASSERT(prReorderQueParm
);
3645 ASSERT(prReturnedQue
);
3647 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3649 /* There are no packets queued in the Reorder Queue */
3650 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3651 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= NULL
;
3652 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3653 prReorderQue
->prHead
= (P_QUE_ENTRY_T
) prSwRfb
;
3655 ((P_QUE_ENTRY_T
) prSwRfb
)->prPrev
= prReorderQue
->prTail
;
3656 ((P_QUE_ENTRY_T
) prSwRfb
)->prNext
= NULL
;
3657 (prReorderQue
->prTail
)->prNext
= (P_QUE_ENTRY_T
) (prSwRfb
);
3659 prReorderQue
->prTail
= (P_QUE_ENTRY_T
) prSwRfb
;
3660 prReorderQue
->u4NumElem
++;
3666 qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter
,
3667 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3669 P_SW_RFB_T prReorderedSwRfb
;
3670 P_QUE_T prReorderQue
;
3671 BOOLEAN fgDequeuHead
, fgMissing
;
3672 OS_SYSTIME rCurrentTime
, rMissTimeout
;
3674 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3678 rMissTimeout
= g_arMissTimeout
[prReorderQueParm
->ucStaRecIdx
][prReorderQueParm
->ucTid
];
3681 GET_CURRENT_SYSTIME(&rCurrentTime
);
3684 /* Check whether any packet can be indicated to the higher layer */
3686 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3690 /* Always examine the head packet */
3691 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3692 fgDequeuHead
= FALSE
;
3694 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3695 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3697 fgDequeuHead
= TRUE
;
3698 prReorderQueParm
->u2WinStart
=
3699 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3701 /* SN > WinStart, break to update WinEnd */
3703 /* Start bubble timer */
3704 if (!prReorderQueParm
->fgHasBubble
) {
3705 cnmTimerStartTimer(prAdapter
,
3706 &(prReorderQueParm
->rReorderBubbleTimer
),
3707 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3708 prReorderQueParm
->fgHasBubble
= TRUE
;
3709 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
3712 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3713 prReorderQueParm
->ucStaRecIdx
, prReorderedSwRfb
->ucTid
,
3714 prReorderQueParm
->u2FirstBubbleSn
,
3715 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3718 if ((fgMissing
== TRUE
) &&
3719 CHECK_FOR_TIMEOUT(rCurrentTime
, rMissTimeout
,
3720 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
))) {
3722 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3723 prReorderQueParm
->ucTid
, prReorderedSwRfb
->u2SSN
));
3724 fgDequeuHead
= TRUE
;
3725 prReorderQueParm
->u2WinStart
=
3726 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3734 /* Dequeue the head packet */
3737 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3738 prReorderQue
->prHead
= NULL
;
3739 prReorderQue
->prTail
= NULL
;
3741 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3742 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3744 prReorderQue
->u4NumElem
--;
3745 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3746 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3750 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3753 if (fgMissing
== FALSE
) {
3754 GET_CURRENT_SYSTIME(&rMissTimeout
);
3758 /* After WinStart has been determined, update the WinEnd */
3759 prReorderQueParm
->u2WinEnd
=
3760 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3761 1) % MAX_SEQ_NO_COUNT
);
3766 qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter
,
3767 IN P_RX_BA_ENTRY_T prReorderQueParm
, OUT P_QUE_T prReturnedQue
)
3769 P_SW_RFB_T prReorderedSwRfb
;
3770 P_QUE_T prReorderQue
;
3771 BOOLEAN fgDequeuHead
;
3773 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3775 /* Check whether any packet can be indicated to the higher layer */
3777 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3781 /* Always examine the head packet */
3782 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReorderQue
);
3783 fgDequeuHead
= FALSE
;
3785 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3786 if ((prReorderedSwRfb
->u2SSN
) == (prReorderQueParm
->u2WinStart
)) {
3788 fgDequeuHead
= TRUE
;
3789 prReorderQueParm
->u2WinStart
=
3790 (((prReorderedSwRfb
->u2SSN
) + 1) % MAX_SEQ_NO_COUNT
);
3793 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3794 else if (qmCompareSnIsLessThan((UINT_32
) (prReorderedSwRfb
->u2SSN
),
3795 (UINT_32
) (prReorderQueParm
->u2WinStart
))) {
3797 fgDequeuHead
= TRUE
;
3801 /* SN > WinStart, break to update WinEnd */
3803 /* Start bubble timer */
3804 if (!prReorderQueParm
->fgHasBubble
) {
3805 cnmTimerStartTimer(prAdapter
,
3806 &(prReorderQueParm
->rReorderBubbleTimer
),
3807 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3808 prReorderQueParm
->fgHasBubble
= TRUE
;
3809 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
3812 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3813 prReorderQueParm
->ucStaRecIdx
, prReorderedSwRfb
->ucTid
,
3814 prReorderQueParm
->u2FirstBubbleSn
,
3815 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3821 /* Dequeue the head packet */
3824 if (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
== NULL
) {
3825 prReorderQue
->prHead
= NULL
;
3826 prReorderQue
->prTail
= NULL
;
3828 prReorderQue
->prHead
= ((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
;
3829 (((P_QUE_ENTRY_T
) prReorderedSwRfb
)->prNext
)->prPrev
= NULL
;
3831 prReorderQue
->u4NumElem
--;
3832 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3833 QUEUE_INSERT_TAIL(prReturnedQue
, (P_QUE_ENTRY_T
) prReorderedSwRfb
);
3837 /* After WinStart has been determined, update the WinEnd */
3838 prReorderQueParm
->u2WinEnd
=
3839 (((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3840 1) % MAX_SEQ_NO_COUNT
);
3844 VOID
qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter
, IN ULONG ulParamPtr
)
3846 P_RX_BA_ENTRY_T prReorderQueParm
= (P_RX_BA_ENTRY_T
) ulParamPtr
;
3847 P_SW_RFB_T prSwRfb
= (P_SW_RFB_T
) NULL
;
3848 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent
;
3850 KAL_SPIN_LOCK_DECLARATION();
3852 if (!prReorderQueParm
->fgIsValid
) {
3853 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3854 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3858 if (!prReorderQueParm
->fgHasBubble
) {
3860 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3861 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3865 DBGLOG(QM
, TRACE
, ("QM:(Bub Timeout) STA[%u] TID[%u] BubSN[%u]\n",
3866 prReorderQueParm
->ucStaRecIdx
,
3867 prReorderQueParm
->ucTid
, prReorderQueParm
->u2FirstBubbleSn
));
3869 /* Generate a self-inited event to Rx path */
3870 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_FREE_QUE
);
3871 QUEUE_REMOVE_HEAD(&prAdapter
->rRxCtrl
.rFreeSwRfbList
, prSwRfb
, P_SW_RFB_T
);
3872 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_FREE_QUE
);
3875 prCheckReorderEvent
= (P_EVENT_CHECK_REORDER_BUBBLE_T
) prSwRfb
->pucRecvBuff
;
3877 prSwRfb
->ucPacketType
= RX_PKT_TYPE_SW_DEFINED
;
3879 prSwRfb
->prRxStatus
->u2PktTYpe
= RXM_RXD_PKT_TYPE_SW_EVENT
;
3881 prCheckReorderEvent
->ucEID
= EVENT_ID_CHECK_REORDER_BUBBLE
;
3882 prCheckReorderEvent
->ucSeqNum
= 0;
3884 prCheckReorderEvent
->ucStaRecIdx
= prReorderQueParm
->ucStaRecIdx
;
3885 prCheckReorderEvent
->ucTid
= prReorderQueParm
->ucTid
;
3886 prCheckReorderEvent
->u2Length
= sizeof(EVENT_CHECK_REORDER_BUBBLE_T
);
3888 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_QUE
);
3889 QUEUE_INSERT_TAIL(&prAdapter
->rRxCtrl
.rReceivedRfbList
, &prSwRfb
->rQueEntry
);
3890 RX_INC_CNT(&prAdapter
->rRxCtrl
, RX_MPDU_TOTAL_COUNT
);
3891 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_RX_QUE
);
3893 DBGLOG(QM
, LOUD
, ("QM:(Bub Check Event Sent) STA[%u] TID[%u]\n",
3894 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3896 nicRxProcessRFBs(prAdapter
);
3898 DBGLOG(QM
, LOUD
, ("QM:(Bub Check Event Handled) STA[%u] TID[%u]\n",
3899 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3902 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bub check event alloc failed\n",
3903 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3905 cnmTimerStartTimer(prAdapter
, &(prReorderQueParm
->rReorderBubbleTimer
),
3906 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
3908 DBGLOG(QM
, TRACE
, ("QM:(Bub Timer Restart) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3909 prReorderQueParm
->ucStaRecIdx
,
3910 prReorderQueParm
->ucTid
,
3911 prReorderQueParm
->u2FirstBubbleSn
,
3912 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3918 VOID
qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
3920 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent
=
3921 (P_EVENT_CHECK_REORDER_BUBBLE_T
) prEvent
;
3922 P_RX_BA_ENTRY_T prReorderQueParm
;
3923 P_QUE_T prReorderQue
;
3925 P_QUE_T prReturnedQue
= &rReturnedQue
;
3926 P_SW_RFB_T prReorderedSwRfb
, prSwRfb
;
3928 QUEUE_INITIALIZE(prReturnedQue
);
3930 /* Get target Rx BA entry */
3931 prReorderQueParm
= qmLookupRxBaEntry(prAdapter
,
3932 prCheckReorderEvent
->ucStaRecIdx
,
3933 prCheckReorderEvent
->ucTid
);
3936 if (!prReorderQueParm
) {
3937 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3938 prCheckReorderEvent
->ucStaRecIdx
, prCheckReorderEvent
->ucTid
));
3942 if (!prReorderQueParm
->fgIsValid
) {
3943 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3944 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3948 if (!prReorderQueParm
->fgHasBubble
) {
3950 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3951 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3955 prReorderQue
= &(prReorderQueParm
->rReOrderQue
);
3957 if (QUEUE_IS_EMPTY(prReorderQue
)) {
3958 prReorderQueParm
->fgHasBubble
= FALSE
;
3961 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3962 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3967 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Event Got) STA[%u] TID[%u]\n",
3968 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
3970 /* Expected bubble timeout => pop out packets before win_end */
3971 if (prReorderQueParm
->u2FirstBubbleSn
== prReorderQueParm
->u2WinStart
) {
3973 prReorderedSwRfb
= (P_SW_RFB_T
) QUEUE_GET_TAIL(prReorderQue
);
3975 prReorderQueParm
->u2WinStart
= prReorderedSwRfb
->u2SSN
+ 1;
3976 prReorderQueParm
->u2WinEnd
=
3977 ((prReorderQueParm
->u2WinStart
) + (prReorderQueParm
->u2WinSize
) -
3978 1) % MAX_SEQ_NO_COUNT
;
3980 qmPopOutDueToFallAhead(prAdapter
, prReorderQueParm
, prReturnedQue
);
3982 DBGLOG(QM
, TRACE
, ("QM:(Bub Flush) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3983 prReorderQueParm
->ucStaRecIdx
,
3984 prReorderQueParm
->ucTid
,
3985 prReorderQueParm
->u2FirstBubbleSn
,
3986 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
3988 if (QUEUE_IS_NOT_EMPTY(prReturnedQue
)) {
3989 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T
) QUEUE_GET_TAIL(prReturnedQue
), NULL
);
3991 prSwRfb
= (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
);
3994 ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out SN[%u]\n",
3995 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
,
3999 (P_SW_RFB_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
) prSwRfb
);
4002 wlanProcessQueuedSwRfb(prAdapter
,
4003 (P_SW_RFB_T
) QUEUE_GET_HEAD(prReturnedQue
));
4005 DBGLOG(QM
, TRACE
, ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out 0 packet\n",
4006 prReorderQueParm
->ucStaRecIdx
, prReorderQueParm
->ucTid
));
4009 prReorderQueParm
->fgHasBubble
= FALSE
;
4011 /* First bubble has been filled but others exist */
4013 prReorderQueParm
->u2FirstBubbleSn
= prReorderQueParm
->u2WinStart
;
4014 cnmTimerStartTimer(prAdapter
, &(prReorderQueParm
->rReorderBubbleTimer
),
4015 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS
);
4017 DBGLOG(QM
, TRACE
, ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
4018 prReorderQueParm
->ucStaRecIdx
,
4019 prReorderQueParm
->ucTid
,
4020 prReorderQueParm
->u2FirstBubbleSn
,
4021 prReorderQueParm
->u2WinStart
, prReorderQueParm
->u2WinEnd
));
4028 BOOLEAN
qmCompareSnIsLessThan(IN UINT_32 u4SnLess
, IN UINT_32 u4SnGreater
)
4030 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
4031 if ((u4SnLess
+ HALF_SEQ_NO_COUNT
) <= u4SnGreater
) { /* Shall be <= */
4035 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
4036 else if ((u4SnGreater
+ HALF_SEQ_NO_COUNT
) < u4SnLess
) {
4040 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
4041 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
4043 return u4SnLess
< u4SnGreater
;
4048 /*----------------------------------------------------------------------------*/
4050 * \brief Handle Mailbox RX messages
4052 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
4056 /*----------------------------------------------------------------------------*/
4057 VOID
qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg
)
4059 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
4064 /*----------------------------------------------------------------------------*/
4066 * \brief Handle ADD RX BA Event from the FW
4068 * \param[in] prAdapter Adapter pointer
4069 * \param[in] prEvent The event packet from the FW
4073 /*----------------------------------------------------------------------------*/
4074 VOID
qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4076 P_EVENT_RX_ADDBA_T prEventRxAddBa
;
4077 P_STA_RECORD_T prStaRec
;
4081 DBGLOG(QM
, INFO
, ("QM:Event +RxBa\n"));
4083 prEventRxAddBa
= (P_EVENT_RX_ADDBA_T
) prEvent
;
4084 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxAddBa
->ucStaRecIdx
);
4087 /* Invalid STA_REC index, discard the event packet */
4089 DBGLOG(QM
, INFO
, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
4093 if (!(prStaRec
->fgIsValid
)) {
4094 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4095 DBGLOG(QM
, WARN
, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
4101 u4Tid
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_TID_MASK
)
4102 >> BA_PARAM_SET_TID_MASK_OFFSET
);
4104 u4WinSize
= (((prEventRxAddBa
->u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
4105 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
4107 if (!qmAddRxBaEntry(prAdapter
,
4110 (prEventRxAddBa
->u2BAStartSeqCtrl
>> OFFSET_BAR_SSC_SN
),
4111 (UINT_16
) u4WinSize
)) {
4113 /* FW shall ensure the availabiilty of the free-to-use BA entry */
4114 DBGLOG(QM
, ERROR
, ("QM: (Error) qmAddRxBaEntry() failure\n"));
4120 /*----------------------------------------------------------------------------*/
4122 * \brief Handle DEL RX BA Event from the FW
4124 * \param[in] prAdapter Adapter pointer
4125 * \param[in] prEvent The event packet from the FW
4129 /*----------------------------------------------------------------------------*/
4130 VOID
qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
4132 P_EVENT_RX_DELBA_T prEventRxDelBa
;
4133 P_STA_RECORD_T prStaRec
;
4135 /* DbgPrint("QM:Event -RxBa\n"); */
4137 prEventRxDelBa
= (P_EVENT_RX_DELBA_T
) prEvent
;
4138 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventRxDelBa
->ucStaRecIdx
);
4141 /* Invalid STA_REC index, discard the event packet */
4146 if (!(prStaRec
->fgIsValid
)) {
4147 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4153 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, prEventRxDelBa
->ucTid
, TRUE
);
4157 P_RX_BA_ENTRY_T
qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter
, UINT_8 ucStaRecIdx
, UINT_8 ucTid
)
4160 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4162 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
4164 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
4165 if (prQM
->arRxBaTable
[i
].fgIsValid
) {
4166 if ((prQM
->arRxBaTable
[i
].ucStaRecIdx
== ucStaRecIdx
) &&
4167 (prQM
->arRxBaTable
[i
].ucTid
== ucTid
)) {
4168 return &prQM
->arRxBaTable
[i
];
4176 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter
,
4177 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN UINT_16 u2WinStart
, IN UINT_16 u2WinSize
)
4180 P_RX_BA_ENTRY_T prRxBaEntry
= NULL
;
4181 P_STA_RECORD_T prStaRec
;
4182 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4184 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
4186 if (ucStaRecIdx
>= CFG_NUM_OF_STA_RECORD
) {
4187 /* Invalid STA_REC index, discard the event packet */
4189 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
4194 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
4197 /* if(!(prStaRec->fgIsValid)){ */
4198 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
4202 /* 4 <1> Delete before adding */
4203 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4204 if (qmLookupRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
)) {
4205 qmDelRxBaEntry(prAdapter
, ucStaRecIdx
, ucTid
, TRUE
); /* prQM->ucRxBaCount-- */
4207 /* 4 <2> Add a new BA entry */
4208 /* No available entry to store the BA agreement info. Retrun FALSE. */
4209 if (prQM
->ucRxBaCount
>= CFG_NUM_OF_RX_BA_AGREEMENTS
) {
4211 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
4214 /* Find the free-to-use BA entry */
4215 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
4216 if (!prQM
->arRxBaTable
[i
].fgIsValid
) {
4217 prRxBaEntry
= &(prQM
->arRxBaTable
[i
]);
4218 prQM
->ucRxBaCount
++;
4219 DBGLOG(QM
, LOUD
, ("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
));
4224 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
4225 u2WinSize
+= CFG_RX_BA_INC_SIZE
;
4227 prRxBaEntry
->ucStaRecIdx
= ucStaRecIdx
;
4228 prRxBaEntry
->ucTid
= ucTid
;
4229 prRxBaEntry
->u2WinStart
= u2WinStart
;
4230 prRxBaEntry
->u2WinSize
= u2WinSize
;
4231 prRxBaEntry
->u2WinEnd
= ((u2WinStart
+ u2WinSize
- 1) % MAX_SEQ_NO_COUNT
);
4232 prRxBaEntry
->fgIsValid
= TRUE
;
4233 prRxBaEntry
->fgIsWaitingForPktWithSsn
= TRUE
;
4234 prRxBaEntry
->fgHasBubble
= FALSE
;
4236 g_arMissTimeout
[ucStaRecIdx
][ucTid
] = 0;
4239 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
4240 ucStaRecIdx
, ucTid
, prRxBaEntry
->u2WinStart
, prRxBaEntry
->u2WinEnd
,
4241 prRxBaEntry
->u2WinSize
));
4243 /* Update the BA entry reference table for per-packet lookup */
4244 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = prRxBaEntry
;
4246 /* This shall not happen because FW should keep track of the usage of RX BA entries */
4248 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM
->ucRxBaCount
));
4257 qmDelRxBaEntry(IN P_ADAPTER_T prAdapter
,
4258 IN UINT_8 ucStaRecIdx
, IN UINT_8 ucTid
, IN BOOLEAN fgFlushToHost
)
4260 P_RX_BA_ENTRY_T prRxBaEntry
;
4261 P_STA_RECORD_T prStaRec
;
4262 P_SW_RFB_T prFlushedPacketList
= NULL
;
4263 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
4265 ASSERT(ucStaRecIdx
< CFG_NUM_OF_STA_RECORD
);
4267 prStaRec
= &prAdapter
->arStaRec
[ucStaRecIdx
];
4271 if (!(prStaRec
->fgIsValid
)) {
4272 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
4277 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4278 prRxBaEntry
= prStaRec
->aprRxReorderParamRefTbl
[ucTid
];
4282 prFlushedPacketList
= qmFlushStaRxQueue(prAdapter
, ucStaRecIdx
, ucTid
);
4284 if (prFlushedPacketList
) {
4286 if (fgFlushToHost
) {
4287 wlanProcessQueuedSwRfb(prAdapter
, prFlushedPacketList
);
4291 P_SW_RFB_T prNextSwRfb
;
4292 prSwRfb
= prFlushedPacketList
;
4296 (P_SW_RFB_T
) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T
)
4298 nicRxReturnRFB(prAdapter
, prSwRfb
);
4299 prSwRfb
= prNextSwRfb
;
4307 if (prRxBaEntry
->fgHasBubble
) {
4308 DBGLOG(QM
, TRACE
, ("QM:(Bub Check Cancel) STA[%u] TID[%u], DELBA\n",
4309 prRxBaEntry
->ucStaRecIdx
, prRxBaEntry
->ucTid
));
4311 cnmTimerStopTimer(prAdapter
, &prRxBaEntry
->rReorderBubbleTimer
);
4312 prRxBaEntry
->fgHasBubble
= FALSE
;
4314 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
4315 /* Update RX BA entry state. Note that RX queue flush is not done here */
4316 prRxBaEntry
->fgIsValid
= FALSE
;
4317 prQM
->ucRxBaCount
--;
4321 DbgPrint("QM: ucRxBaCount=%d\n", prQM
->ucRxBaCount
);
4324 /* Update STA RX BA table */
4325 prStaRec
->aprRxReorderParamRefTbl
[ucTid
] = NULL
;
4328 DBGLOG(QM
, INFO
, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx
, ucTid
));
4334 #if CFG_HIF_RX_STARVATION_WARNING
4336 P_RX_CTRL_T prRxCtrl
;
4337 prRxCtrl
= &prAdapter
->rRxCtrl
;
4339 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl
->u4QueuedCnt
,
4340 prRxCtrl
->u4DequeuedCnt
));
4346 mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter
,
4347 IN PUINT_8 pucIE
, IN P_STA_RECORD_T prStaRec
)
4349 P_IE_WMM_INFO_T prIeWmmInfo
;
4353 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4355 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4356 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4358 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4359 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4360 if (IE_LEN(pucIE
) != 7) {
4361 break; /* WMM Info IE with a wrong length */
4364 prStaRec
->fgIsQoS
= TRUE
;
4365 prStaRec
->fgIsWmmSupported
= TRUE
;
4367 prIeWmmInfo
= (P_IE_WMM_INFO_T
) pucIE
;
4368 ucQosInfo
= prIeWmmInfo
->ucQosInfo
;
4369 ucQosInfoAC
= ucQosInfo
& BITS(0, 3);
4371 if(IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
))
4372 prStaRec
->fgIsUapsdSupported
= (ucQosInfoAC
) ? TRUE
: FALSE
;
4374 prStaRec
->fgIsUapsdSupported
= FALSE
;
4378 if (ucQosInfoAC
& WMM_QOS_INFO_VO_UAPSD
) {
4379 ucBmpAC
|= BIT(ACI_VO
);
4381 if (ucQosInfoAC
& WMM_QOS_INFO_VI_UAPSD
) {
4382 ucBmpAC
|= BIT(ACI_VI
);
4384 if (ucQosInfoAC
& WMM_QOS_INFO_BE_UAPSD
) {
4385 ucBmpAC
|= BIT(ACI_BE
);
4387 if (ucQosInfoAC
& WMM_QOS_INFO_BK_UAPSD
) {
4388 ucBmpAC
|= BIT(ACI_BK
);
4390 prStaRec
->ucBmpTriggerAC
= prStaRec
->ucBmpDeliveryAC
= ucBmpAC
;
4391 prStaRec
->ucUapsdSp
= (ucQosInfo
& WMM_QOS_INFO_MAX_SP_LEN_MASK
) >> 5;
4395 /* Other WMM QoS IEs. Ignore any */
4401 /*----------------------------------------------------------------------------*/
4403 * \brief To process WMM related IEs in ASSOC_RSP
4405 * \param[in] prAdapter Adapter pointer
4406 * \param[in] prSwRfb The received frame
4407 * \param[in] pucIE The pointer to the first IE in the frame
4408 * \param[in] u2IELength The total length of IEs in the frame
4412 /*----------------------------------------------------------------------------*/
4414 mqmProcessAssocReq(IN P_ADAPTER_T prAdapter
,
4415 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4417 P_STA_RECORD_T prStaRec
;
4422 DEBUGFUNC("mqmProcessAssocReq");
4427 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4430 if (prStaRec
== NULL
) {
4434 prStaRec
->fgIsQoS
= FALSE
;
4435 prStaRec
->fgIsWmmSupported
= prStaRec
->fgIsUapsdSupported
= FALSE
;
4439 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4440 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4445 /* Determine whether QoS is enabled with the association */
4447 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4448 switch (IE_ID(pucIE
)) {
4449 case ELEM_ID_VENDOR
:
4450 mqmParseAssocReqWmmIe(prAdapter
, pucIE
, prStaRec
);
4452 prStaRec
->u4Flags
= 0;
4453 #if CFG_SUPPORT_MTK_SYNERGY
4454 if (rlmParseCheckMTKOuiIE(prAdapter
, pucIE
, &u4Flags
)) {
4455 prStaRec
->u4Flags
= u4Flags
;
4461 case ELEM_ID_HT_CAP
:
4462 /* Some client won't put the WMM IE if client is 802.11n */
4463 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
4464 prStaRec
->fgIsQoS
= TRUE
;
4472 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
4478 mqmParseAssocRspWmmIe(IN PUINT_8 pucIE
, IN P_STA_RECORD_T prStaRec
)
4480 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4482 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4483 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4485 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4486 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4487 if (IE_LEN(pucIE
) != 24) {
4488 break; /* WMM Info IE with a wrong length */
4490 prStaRec
->fgIsQoS
= TRUE
;
4493 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4494 if (IE_LEN(pucIE
) != 7) {
4495 break; /* WMM Info IE with a wrong length */
4497 prStaRec
->fgIsQoS
= TRUE
;
4501 /* Other WMM QoS IEs. Ignore any */
4507 /*----------------------------------------------------------------------------*/
4509 * \brief To process WMM related IEs in ASSOC_RSP
4511 * \param[in] prAdapter Adapter pointer
4512 * \param[in] prSwRfb The received frame
4513 * \param[in] pucIE The pointer to the first IE in the frame
4514 * \param[in] u2IELength The total length of IEs in the frame
4518 /*----------------------------------------------------------------------------*/
4520 mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter
,
4521 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4523 P_STA_RECORD_T prStaRec
;
4528 DEBUGFUNC("mqmProcessAssocRsp");
4533 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4536 if (prStaRec
== NULL
) {
4540 prStaRec
->fgIsQoS
= FALSE
;
4544 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
4545 prStaRec
->fgIsWmmSupported
, prAdapter
->rWifiVar
.ucQoS
));
4547 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4548 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
4549 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4553 /* Determine whether QoS is enabled with the association */
4555 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4556 switch (IE_ID(pucIE
)) {
4557 case ELEM_ID_VENDOR
:
4558 /* Process WMM related IE */
4559 mqmParseAssocRspWmmIe(pucIE
, prStaRec
);
4561 prStaRec
->u4Flags
= 0;
4562 #if CFG_SUPPORT_MTK_SYNERGY
4563 if (rlmParseCheckMTKOuiIE(prAdapter
, pucIE
, &u4Flags
)) {
4564 prStaRec
->u4Flags
= u4Flags
;
4570 case ELEM_ID_HT_CAP
:
4571 /* Some AP won't put the WMM IE if client is 802.11n */
4572 if (IE_LEN(pucIE
) == (sizeof(IE_HT_CAP_T
) - 2)) {
4573 prStaRec
->fgIsQoS
= TRUE
;
4581 /* Parse AC parameters and write to HW CRs */
4582 if ((prStaRec
->fgIsQoS
) && (prStaRec
->eStaType
== STA_TYPE_LEGACY_AP
)) {
4583 mqmParseEdcaParameters(prAdapter
, prSwRfb
, pucIEStart
, u2IELength
, TRUE
);
4586 DBGLOG(QM
, TRACE
, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec
->fgIsQoS
));
4587 if (prStaRec
->fgIsWmmSupported
) {
4588 nicQmUpdateWmmParms(prAdapter
, prStaRec
->ucBssIndex
);
4593 /*----------------------------------------------------------------------------*/
4601 /*----------------------------------------------------------------------------*/
4603 mqmProcessBcn(IN P_ADAPTER_T prAdapter
,
4604 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
)
4606 P_BSS_INFO_T prBssInfo
;
4607 BOOLEAN fgNewParameter
;
4614 DBGLOG(QM
, TRACE
, ("Enter %s\n", __func__
));
4616 fgNewParameter
= FALSE
;
4618 for (i
= 0; i
< BSS_INFO_NUM
; i
++) {
4619 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, i
);
4621 if (IS_BSS_ACTIVE(prBssInfo
)) {
4622 if (prBssInfo
->eCurrentOPMode
== OP_MODE_INFRASTRUCTURE
&&
4623 prBssInfo
->eConnectionState
== PARAM_MEDIA_STATE_CONNECTED
) {
4624 /* P2P client or AIS infra STA */
4625 if (EQUAL_MAC_ADDR(prBssInfo
->aucBSSID
,
4626 ((P_WLAN_MAC_MGMT_HEADER_T
)
4627 (prSwRfb
->pvHeader
))->aucBSSID
)) {
4629 fgNewParameter
= mqmParseEdcaParameters(prAdapter
,
4635 /* Appy new parameters if necessary */
4636 if (fgNewParameter
) {
4637 /* DBGLOG(QM, INFO, ("Update EDCA parameter for BSS[%u]\n", prBssInfo->ucBssIndex)); */
4638 nicQmUpdateWmmParms(prAdapter
, prBssInfo
->ucBssIndex
);
4639 fgNewParameter
= FALSE
;
4641 } /* end of IS_BSS_ACTIVE() */
4646 mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo
, IN PUINT_8 pucIE
,
4647 IN BOOLEAN fgForceOverride
)
4649 P_AC_QUE_PARMS_T prAcQueParams
;
4650 P_IE_WMM_PARAM_T prIeWmmParam
;
4651 ENUM_WMM_ACI_T eAci
;
4652 BOOLEAN fgNewParameter
= FALSE
;
4655 if (IE_LEN(pucIE
) != 24) {
4656 break; /* WMM Param IE with a wrong length */
4659 prIeWmmParam
= (P_IE_WMM_PARAM_T
) pucIE
;
4661 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
4662 if(!fgForceOverride
) {
4663 if(mqmCompareEdcaParameters(prIeWmmParam
, prBssInfo
)) {
4664 fgNewParameter
= FALSE
;
4669 fgNewParameter
= TRUE
;
4670 /* Update Parameter Set Count */
4671 prBssInfo
->ucWmmParamSetCount
= (prIeWmmParam
->ucQosInfo
& WMM_QOS_INFO_PARAM_SET_CNT
);
4672 /* Update EDCA parameters */
4673 for(eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
4674 prAcQueParams
= &prBssInfo
->arACQueParms
[eAci
];
4675 mqmFillAcQueParam(prIeWmmParam
, eAci
, prAcQueParams
);
4676 DBGLOG(QM
, INFO
, ("BSS[%u]: eAci[%d] ACM[%d] Aifsn[%d] CWmin/max[%d/%d]"
4677 "TxopLimit[%d] NewParameter[%d]\n",
4678 prBssInfo
->ucBssIndex
, eAci
, prAcQueParams
->ucIsACMSet
, prAcQueParams
->u2Aifsn
,
4679 prAcQueParams
->u2CWmin
, prAcQueParams
->u2CWmax
, prAcQueParams
->u2TxopLimit
, fgNewParameter
));
4683 return fgNewParameter
;
4686 /*----------------------------------------------------------------------------*/
4688 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
4690 * \param[in] prAdapter Adapter pointer
4691 * \param[in] prSwRfb The received frame
4692 * \param[in] pucIE The pointer to the first IE in the frame
4693 * \param[in] u2IELength The total length of IEs in the frame
4694 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
4698 /*----------------------------------------------------------------------------*/
4700 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter
,
4701 IN P_SW_RFB_T prSwRfb
, IN PUINT_8 pucIE
, IN UINT_16 u2IELength
,
4702 IN BOOLEAN fgForceOverride
)
4704 P_STA_RECORD_T prStaRec
;
4706 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4707 P_BSS_INFO_T prBssInfo
;
4708 BOOLEAN fgNewParameter
= FALSE
;
4710 DEBUGFUNC("mqmParseEdcaParameters");
4720 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prSwRfb
->ucStaRecIdx
);
4721 /* ASSERT(prStaRec); */
4723 if (prStaRec
== NULL
) {
4727 DBGLOG(QM
, TRACE
, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
4728 prStaRec
->fgIsWmmSupported
, prStaRec
->fgIsQoS
));
4730 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
) || (!prStaRec
->fgIsWmmSupported
)
4731 || (!prStaRec
->fgIsQoS
)) {
4735 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
4737 /* Goal: Obtain the EDCA parameters */
4738 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4739 switch (IE_ID(pucIE
)) {
4741 if (!((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4742 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3)))) {
4746 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4747 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4748 fgNewParameter
= mqmUpdateEdcaParameters(prBssInfo
, pucIE
, fgForceOverride
);
4752 /* Other WMM QoS IEs. Ignore */
4756 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4763 return fgNewParameter
;
4766 BOOLEAN
mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam
, IN P_BSS_INFO_T prBssInfo
)
4768 P_AC_QUE_PARMS_T prAcQueParams
;
4769 P_WMM_AC_PARAM_T prWmmAcParams
;
4770 ENUM_WMM_ACI_T eAci
;
4774 /* Check Set Count */
4775 if (prBssInfo
->ucWmmParamSetCount
!= (prIeWmmParam
->ucQosInfo
& WMM_QOS_INFO_PARAM_SET_CNT
)) {
4779 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
4780 prAcQueParams
= &prBssInfo
->arACQueParms
[eAci
];
4781 prWmmAcParams
= &prIeWmmParam
->arAcParam
[eAci
];
4784 if (prAcQueParams
->ucIsACMSet
!=
4785 ((prWmmAcParams
->ucAciAifsn
& WMM_ACIAIFSN_ACM
) ? TRUE
: FALSE
)) {
4790 if (prAcQueParams
->u2Aifsn
!= (prWmmAcParams
->ucAciAifsn
& WMM_ACIAIFSN_AIFSN
)) {
4795 if (prAcQueParams
->u2CWmax
!=
4796 (BIT((prWmmAcParams
->ucEcw
& WMM_ECW_WMAX_MASK
) >> WMM_ECW_WMAX_OFFSET
) - 1)) {
4801 if (prAcQueParams
->u2CWmin
!= (BIT(prWmmAcParams
->ucEcw
& WMM_ECW_WMIN_MASK
) - 1)) {
4805 if (prAcQueParams
->u2TxopLimit
!= prWmmAcParams
->u2TxopLimit
) {
4814 /*----------------------------------------------------------------------------*/
4816 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
4818 * \param[in] prAdapter Adapter pointer
4819 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
4820 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
4821 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
4825 /*----------------------------------------------------------------------------*/
4827 mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam
,
4828 IN UINT_32 u4AcOffset
, OUT P_AC_QUE_PARMS_T prAcQueParams
)
4830 P_WMM_AC_PARAM_T prAcParam
= &prIeWmmParam
->arAcParam
[u4AcOffset
];
4832 prAcQueParams
->ucIsACMSet
= (prAcParam
->ucAciAifsn
& WMM_ACIAIFSN_ACM
) ? TRUE
: FALSE
;
4834 prAcQueParams
->u2Aifsn
= (prAcParam
->ucAciAifsn
& WMM_ACIAIFSN_AIFSN
);
4836 prAcQueParams
->u2CWmax
=
4837 BIT((prAcParam
->ucEcw
& WMM_ECW_WMAX_MASK
) >> WMM_ECW_WMAX_OFFSET
) - 1;
4839 prAcQueParams
->u2CWmin
= BIT(prAcParam
->ucEcw
& WMM_ECW_WMIN_MASK
) - 1;
4841 WLAN_GET_FIELD_16(&prAcParam
->u2TxopLimit
, &prAcQueParams
->u2TxopLimit
);
4843 prAcQueParams
->ucGuradTime
= TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME
;
4848 /*----------------------------------------------------------------------------*/
4850 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
4852 * \param[in] prAdapter Adapter pointer
4853 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
4854 * \param[out] prStaRec The obtained info is stored in the STA_REC
4858 /*----------------------------------------------------------------------------*/
4860 mqmProcessScanResult(IN P_ADAPTER_T prAdapter
,
4861 IN P_BSS_DESC_T prScanResult
, OUT P_STA_RECORD_T prStaRec
)
4866 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4869 DEBUGFUNC("mqmProcessScanResult");
4871 ASSERT(prScanResult
);
4874 /* Reset the flag before parsing */
4875 prStaRec
->fgIsWmmSupported
= FALSE
;
4876 prStaRec
->fgIsUapsdSupported
= FALSE
;
4877 prStaRec
->fgIsQoS
= FALSE
;
4881 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
4885 u2IELength
= prScanResult
->u2IELength
;
4886 pucIE
= prScanResult
->aucIEBuf
;
4888 /* <1> Determine whether the peer supports WMM/QoS and UAPSDU */
4889 IE_FOR_EACH(pucIE
, u2IELength
, u2Offset
) {
4890 switch (IE_ID(pucIE
)) {
4892 case ELEM_ID_EXTENDED_CAP
:
4893 #if CFG_SUPPORT_TDLS
4894 TdlsBssExtCapParse(prStaRec
, pucIE
);
4895 #endif /* CFG_SUPPORT_TDLS */
4899 if ((WMM_IE_OUI_TYPE(pucIE
) == VENDOR_OUI_TYPE_WMM
) &&
4900 (!kalMemCmp(WMM_IE_OUI(pucIE
), aucWfaOui
, 3))) {
4902 switch (WMM_IE_OUI_SUBTYPE(pucIE
)) {
4903 case VENDOR_OUI_SUBTYPE_WMM_PARAM
:
4904 if (IE_LEN(pucIE
) != 24) {
4905 break; /* WMM Param IE with a wrong length */
4907 prStaRec
->fgIsWmmSupported
= TRUE
;
4908 prStaRec
->fgIsUapsdSupported
=
4909 (((((P_IE_WMM_PARAM_T
) pucIE
)->
4910 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
4915 case VENDOR_OUI_SUBTYPE_WMM_INFO
:
4916 if (IE_LEN(pucIE
) != 7) {
4917 break; /* WMM Info IE with a wrong length */
4919 prStaRec
->fgIsWmmSupported
= TRUE
;
4920 prStaRec
->fgIsUapsdSupported
=
4921 (((((P_IE_WMM_INFO_T
) pucIE
)->
4922 ucQosInfo
) & WMM_QOS_INFO_UAPSD
) ? TRUE
:
4928 /* A WMM QoS IE that doesn't matter. Ignore it. */
4932 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4937 /* A WMM IE that doesn't matter. Ignore it. */
4942 /* <1> Determine QoS */
4943 if (prStaRec
->ucDesiredPhyTypeSet
& (PHY_TYPE_SET_802_11N
| PHY_TYPE_SET_802_11AC
)) {
4947 if (fgIsHtVht
|| prStaRec
->fgIsWmmSupported
) {
4948 prStaRec
->fgIsQoS
= TRUE
;
4953 /*----------------------------------------------------------------------------*/
4955 * @brief Generate the WMM Info IE by Param
4957 * \param[in] prAdapter Adapter pointer
4958 * @param prMsduInfo The TX MMPDU
4962 /*----------------------------------------------------------------------------*/
4964 mqmFillWmmInfoIE(P_UINT_8 pucOutBuf
,
4965 BOOLEAN fgSupportUAPSD
,
4966 UINT_8 ucBmpDeliveryAC
, UINT_8 ucBmpTriggerAC
, UINT_8 ucUapsdSp
)
4968 P_IE_WMM_INFO_T prIeWmmInfo
;
4969 UINT_32 ucUapsd
[] = {
4970 WMM_QOS_INFO_BE_UAPSD
,
4971 WMM_QOS_INFO_BK_UAPSD
,
4972 WMM_QOS_INFO_VI_UAPSD
,
4973 WMM_QOS_INFO_VO_UAPSD
4975 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
4979 prIeWmmInfo
= (P_IE_WMM_INFO_T
) pucOutBuf
;
4981 prIeWmmInfo
->ucId
= ELEM_ID_WMM
;
4982 prIeWmmInfo
->ucLength
= ELEM_MAX_LEN_WMM_INFO
;
4984 /* WMM-2.2.1 WMM Information Element Field Values */
4985 prIeWmmInfo
->aucOui
[0] = aucWfaOui
[0];
4986 prIeWmmInfo
->aucOui
[1] = aucWfaOui
[1];
4987 prIeWmmInfo
->aucOui
[2] = aucWfaOui
[2];
4988 prIeWmmInfo
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
4989 prIeWmmInfo
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_INFO
;
4991 prIeWmmInfo
->ucVersion
= VERSION_WMM
;
4992 prIeWmmInfo
->ucQosInfo
= 0;
4994 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4995 if (fgSupportUAPSD
) {
4996 UINT_8 ucQosInfo
= 0;
4999 /* Static U-APSD setting */
5000 for (i
= ACI_BE
; i
<= ACI_VO
; i
++) {
5001 if (ucBmpDeliveryAC
& ucBmpTriggerAC
& BIT(i
)) {
5002 ucQosInfo
|= (UINT_8
) ucUapsd
[i
];
5006 if (ucBmpDeliveryAC
& ucBmpTriggerAC
) {
5007 switch (ucUapsdSp
) {
5008 case WMM_MAX_SP_LENGTH_ALL
:
5009 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_ALL
;
5012 case WMM_MAX_SP_LENGTH_2
:
5013 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
5016 case WMM_MAX_SP_LENGTH_4
:
5017 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_4
;
5020 case WMM_MAX_SP_LENGTH_6
:
5021 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_6
;
5025 DBGLOG(QM
, INFO
, ("MQM: Incorrect SP length\n"));
5026 ucQosInfo
|= WMM_QOS_INFO_MAX_SP_2
;
5030 prIeWmmInfo
->ucQosInfo
= ucQosInfo
;
5034 /* Increment the total IE length for the Element ID and Length fields. */
5035 return IE_SIZE(prIeWmmInfo
);
5039 /*----------------------------------------------------------------------------*/
5041 * @brief Generate the WMM Info IE
5043 * \param[in] prAdapter Adapter pointer
5044 * @param prMsduInfo The TX MMPDU
5048 /*----------------------------------------------------------------------------*/
5050 mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter
,
5051 P_BSS_INFO_T prBssInfo
, P_STA_RECORD_T prStaRec
, P_UINT_8 pucOutBuf
)
5053 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo
;
5054 BOOLEAN fgSupportUapsd
;
5058 /* In case QoS is not turned off, exit directly */
5059 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5063 if (prStaRec
== NULL
) {
5067 if (!prStaRec
->fgIsWmmSupported
) {
5071 prPmProfSetupInfo
= &prBssInfo
->rPmProfSetupInfo
;
5073 fgSupportUapsd
= (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)
5074 && prStaRec
->fgIsUapsdSupported
);
5076 return mqmFillWmmInfoIE(pucOutBuf
,
5078 prPmProfSetupInfo
->ucBmpDeliveryAC
,
5079 prPmProfSetupInfo
->ucBmpTriggerAC
, prPmProfSetupInfo
->ucUapsdSp
);
5082 /*----------------------------------------------------------------------------*/
5084 * @brief Generate the WMM Info IE
5086 * \param[in] prAdapter Adapter pointer
5087 * @param prMsduInfo The TX MMPDU
5091 /*----------------------------------------------------------------------------*/
5092 VOID
mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
5094 P_BSS_INFO_T prBssInfo
;
5095 P_STA_RECORD_T prStaRec
;
5098 DEBUGFUNC("mqmGenerateWmmInfoIE");
5102 /* In case QoS is not turned off, exit directly */
5103 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5107 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5110 if (prStaRec
== NULL
) {
5114 if (!prStaRec
->fgIsWmmSupported
) {
5118 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
5120 u4Length
= mqmGenerateWmmInfoIEByStaRec(prAdapter
,
5123 ((PUINT_8
) prMsduInfo
->prPacket
+
5124 prMsduInfo
->u2FrameLength
));
5126 prMsduInfo
->u2FrameLength
+= u4Length
;
5129 /*----------------------------------------------------------------------------*/
5131 * @brief Generate the WMM Param IE
5133 * \param[in] prAdapter Adapter pointer
5134 * @param prMsduInfo The TX MMPDU
5138 /*----------------------------------------------------------------------------*/
5139 VOID
mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter
, IN P_MSDU_INFO_T prMsduInfo
)
5141 P_IE_WMM_PARAM_T prIeWmmParam
;
5143 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
5152 P_BSS_INFO_T prBssInfo
;
5153 P_STA_RECORD_T prStaRec
;
5154 ENUM_WMM_ACI_T eAci
;
5155 P_WMM_AC_PARAM_T prAcParam
;
5157 DEBUGFUNC("mqmGenerateWmmParamIE");
5158 DBGLOG(QM
, LOUD
, ("\n"));
5162 /* In case QoS is not turned off, exit directly */
5163 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5167 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5170 if (!prStaRec
->fgIsQoS
) {
5175 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prMsduInfo
->ucBssIndex
);
5177 if (!prBssInfo
->fgIsQBSS
) {
5181 prIeWmmParam
= (P_IE_WMM_PARAM_T
)
5182 ((PUINT_8
) prMsduInfo
->prPacket
+ prMsduInfo
->u2FrameLength
);
5184 prIeWmmParam
->ucId
= ELEM_ID_WMM
;
5185 prIeWmmParam
->ucLength
= ELEM_MAX_LEN_WMM_PARAM
;
5187 /* WMM-2.2.1 WMM Information Element Field Values */
5188 prIeWmmParam
->aucOui
[0] = aucWfaOui
[0];
5189 prIeWmmParam
->aucOui
[1] = aucWfaOui
[1];
5190 prIeWmmParam
->aucOui
[2] = aucWfaOui
[2];
5191 prIeWmmParam
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
5192 prIeWmmParam
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_PARAM
;
5194 prIeWmmParam
->ucVersion
= VERSION_WMM
;
5195 prIeWmmParam
->ucQosInfo
= (prBssInfo
->ucWmmParamSetCount
& WMM_QOS_INFO_PARAM_SET_CNT
);
5197 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5198 if (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)) {
5199 prIeWmmParam
->ucQosInfo
|= WMM_QOS_INFO_UAPSD
;
5202 /* EDCA parameter */
5204 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
5205 prAcParam
= &prIeWmmParam
->arAcParam
[eAci
];
5207 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5208 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5209 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5210 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5211 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5212 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5215 prAcParam
->ucAciAifsn
= aucACI
[eAci
];
5217 if (prBssInfo
->arACQueParmsForBcast
[eAci
].ucIsACMSet
) {
5218 prAcParam
->ucAciAifsn
|= WMM_ACIAIFSN_ACM
;
5221 prAcParam
->ucAciAifsn
|=
5222 (prBssInfo
->arACQueParmsForBcast
[eAci
].u2Aifsn
& WMM_ACIAIFSN_AIFSN
);
5225 prAcParam
->ucEcw
= (prBssInfo
->aucCWminLog2ForBcast
[eAci
] & WMM_ECW_WMIN_MASK
);
5229 aucCWmaxLog2ForBcast
[eAci
] << WMM_ECW_WMAX_OFFSET
) & WMM_ECW_WMAX_MASK
);
5232 WLAN_SET_FIELD_16(&prAcParam
->u2TxopLimit
,
5233 prBssInfo
->arACQueParmsForBcast
[eAci
].u2TxopLimit
);
5237 /* Increment the total IE length for the Element ID and Length fields. */
5238 prMsduInfo
->u2FrameLength
+= IE_SIZE(prIeWmmParam
);
5243 #if CFG_SUPPORT_TDLS
5244 /*----------------------------------------------------------------------------*/
5246 * @brief Generate the WMM Param IE
5248 * \param[in] prAdapter Adapter pointer
5249 * @param prMsduInfo The TX MMPDU
5253 /*----------------------------------------------------------------------------*/
5254 UINT_32
mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter
, P_BSS_INFO_T prBssInfo
, PUINT_8 pOutBuf
)
5256 P_IE_WMM_PARAM_T prIeWmmParam
;
5258 UINT_8 aucWfaOui
[] = VENDOR_OUI_WFA
;
5267 ENUM_WMM_ACI_T eAci
;
5268 P_WMM_AC_PARAM_T prAcParam
;
5270 DEBUGFUNC("mqmGenerateWmmParamIE");
5271 DBGLOG(QM
, LOUD
, ("\n"));
5276 /* In case QoS is not turned off, exit directly */
5277 if (IS_FEATURE_DISABLED(prAdapter
->rWifiVar
.ucQoS
)) {
5278 return WLAN_STATUS_SUCCESS
;
5282 if (!prBssInfo
->fgIsQBSS
) {
5283 return WLAN_STATUS_SUCCESS
;
5288 prIeWmmParam
= (P_IE_WMM_PARAM_T
) pOutBuf
;
5291 prIeWmmParam
->ucId
= ELEM_ID_WMM
;
5292 prIeWmmParam
->ucLength
= ELEM_MAX_LEN_WMM_PARAM
;
5294 /* WMM-2.2.1 WMM Information Element Field Values */
5295 prIeWmmParam
->aucOui
[0] = aucWfaOui
[0];
5296 prIeWmmParam
->aucOui
[1] = aucWfaOui
[1];
5297 prIeWmmParam
->aucOui
[2] = aucWfaOui
[2];
5298 prIeWmmParam
->ucOuiType
= VENDOR_OUI_TYPE_WMM
;
5299 prIeWmmParam
->ucOuiSubtype
= VENDOR_OUI_SUBTYPE_WMM_PARAM
;
5301 prIeWmmParam
->ucVersion
= VERSION_WMM
;
5302 prIeWmmParam
->ucQosInfo
= (prBssInfo
->ucWmmParamSetCount
& WMM_QOS_INFO_PARAM_SET_CNT
);
5304 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5305 if (IS_FEATURE_ENABLED(prAdapter
->rWifiVar
.ucUapsd
)) {
5306 prIeWmmParam
->ucQosInfo
|= WMM_QOS_INFO_UAPSD
;
5309 /* EDCA parameter */
5311 for (eAci
= 0; eAci
< WMM_AC_INDEX_NUM
; eAci
++) {
5312 prAcParam
= &prIeWmmParam
->arAcParam
[eAci
];
5314 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5315 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5316 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5317 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5318 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5319 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5322 prAcParam
->ucAciAifsn
= aucACI
[eAci
];
5324 if (prBssInfo
->arACQueParmsForBcast
[eAci
].ucIsACMSet
) {
5325 prAcParam
->ucAciAifsn
|= WMM_ACIAIFSN_ACM
;
5328 prAcParam
->ucAciAifsn
|=
5329 (prBssInfo
->arACQueParmsForBcast
[eAci
].u2Aifsn
& WMM_ACIAIFSN_AIFSN
);
5332 prAcParam
->ucEcw
= (prBssInfo
->aucCWminLog2ForBcast
[eAci
] & WMM_ECW_WMIN_MASK
);
5336 aucCWmaxLog2ForBcast
[eAci
] << WMM_ECW_WMAX_OFFSET
) & WMM_ECW_WMAX_MASK
);
5339 WLAN_SET_FIELD_16(&prAcParam
->u2TxopLimit
,
5340 prBssInfo
->arACQueParmsForBcast
[eAci
].u2TxopLimit
);
5344 /* Increment the total IE length for the Element ID and Length fields. */
5345 return IE_SIZE(prIeWmmParam
);
5354 qmGetFrameAction(IN P_ADAPTER_T prAdapter
,
5355 IN UINT_8 ucBssIndex
,
5356 IN UINT_8 ucStaRecIdx
,
5357 IN P_MSDU_INFO_T prMsduInfo
, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType
)
5359 ENUM_FRAME_ACTION_T eFrameAction
= FRAME_ACTION_TX_PKT
;
5360 P_BSS_INFO_T prBssInfo
;
5361 P_STA_RECORD_T prStaRec
;
5362 /* P_WLAN_MAC_HEADER_T prWlanFrame; */
5363 /* UINT_16 u2TxFrameCtrl; */
5365 DEBUGFUNC("qmGetFrameAction");
5367 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, ucBssIndex
);
5368 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, ucStaRecIdx
);
5371 /* 4 <1> Tx, if FORCE_TX is set */
5373 if (prMsduInfo
->ucControlFlag
& MSDU_CONTROL_FLAG_FORCE_TX
) {
5374 eFrameAction
= FRAME_ACTION_TX_PKT
;
5378 /* 4 <2> Drop, if BSS is inactive */
5379 if (!IS_BSS_ACTIVE(prBssInfo
)) {
5381 ("Drop packets (BSS[%u] is INACTIVE)\n", prBssInfo
->ucBssIndex
));
5382 eFrameAction
= FRAME_ACTION_DROP_PKT
;
5385 /* 4 <3> Check based on StaRec */
5387 /* 4 <3.1> Drop, if StaRec is not in use */
5388 if (!prStaRec
->fgIsInUse
) {
5390 ("Drop packets (Sta[%u] not in USE)\n", prStaRec
->ucIndex
));
5391 eFrameAction
= FRAME_ACTION_DROP_PKT
;
5394 /* 4 <3.2> Sta in PS */
5395 if (prStaRec
->fgIsInPS
) {
5396 /* 4 <3.2.1> Tx, if resource is enough */
5397 if (nicTxGetResource
5399 nicTxGetFrameResourceType(eFrameType
,
5401 QM_MGMT_QUEUED_THRESHOLD
) {
5402 eFrameAction
= FRAME_ACTION_TX_PKT
;
5405 /* 4 <3.2.2> Queue, if resource is not enough */
5408 ("Queue packets (Sta[%u] in PS)\n",
5409 prStaRec
->ucIndex
));
5410 eFrameAction
= FRAME_ACTION_QUEUE_PKT
;
5415 /* 4 <4> Queue, if BSS is absent */
5416 if (prBssInfo
->fgIsNetAbsent
) {
5418 ("Queue packets (BSS[%u] Absent)\n", prBssInfo
->ucBssIndex
));
5419 eFrameAction
= FRAME_ACTION_QUEUE_PKT
;
5425 return eFrameAction
;
5429 /*----------------------------------------------------------------------------*/
5431 * \brief Handle BSS change operation Event from the FW
5433 * \param[in] prAdapter Adapter pointer
5434 * \param[in] prEvent The event packet from the FW
5438 /*----------------------------------------------------------------------------*/
5439 VOID
qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5441 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus
;
5442 P_BSS_INFO_T prBssInfo
;
5443 BOOLEAN fgIsNetAbsentOld
;
5445 prEventBssStatus
= (P_EVENT_BSS_ABSENCE_PRESENCE_T
) prEvent
;
5446 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prEventBssStatus
->ucBssIndex
);
5447 fgIsNetAbsentOld
= prBssInfo
->fgIsNetAbsent
;
5448 prBssInfo
->fgIsNetAbsent
= prEventBssStatus
->ucIsAbsent
;
5449 prBssInfo
->ucBssFreeQuota
= prEventBssStatus
->ucBssFreeQuota
;
5451 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
5452 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
5454 DBGLOG(QM
, INFO
, ("NAF=%d,%d,%d\n",
5455 prEventBssStatus
->ucBssIndex
, prBssInfo
->fgIsNetAbsent
,
5456 prBssInfo
->ucBssFreeQuota
));
5458 if (!prBssInfo
->fgIsNetAbsent
) {
5459 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_27
);
5461 QM_DBG_CNT_INC(&(prAdapter
->rQM
), QM_DBG_CNT_28
);
5463 /* From Absent to Present */
5464 if ((fgIsNetAbsentOld
) && (!prBssInfo
->fgIsNetAbsent
)) {
5465 kalSetEvent(prAdapter
->prGlueInfo
);
5470 /*----------------------------------------------------------------------------*/
5472 * \brief Handle STA change PS mode Event from the FW
5474 * \param[in] prAdapter Adapter pointer
5475 * \param[in] prEvent The event packet from the FW
5479 /*----------------------------------------------------------------------------*/
5480 VOID
qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5482 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode
;
5483 P_STA_RECORD_T prStaRec
;
5484 BOOLEAN fgIsInPSOld
;
5486 /* DbgPrint("QM:Event -RxBa\n"); */
5488 prEventStaChangePsMode
= (P_EVENT_STA_CHANGE_PS_MODE_T
) prEvent
;
5489 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaChangePsMode
->ucStaRecIdx
);
5490 /* ASSERT(prStaRec); */
5494 fgIsInPSOld
= prStaRec
->fgIsInPS
;
5495 prStaRec
->fgIsInPS
= prEventStaChangePsMode
->ucIsInPs
;
5497 qmUpdateFreeQuota(prAdapter
,
5499 prEventStaChangePsMode
->ucUpdateMode
,
5500 prEventStaChangePsMode
->ucFreeQuota
);
5502 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
5503 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
5506 DBGLOG(QM
, INFO
, ("PS=%d,%d\n",
5507 prEventStaChangePsMode
->ucStaRecIdx
, prStaRec
->fgIsInPS
));
5509 /* From PS to Awake */
5510 if ((fgIsInPSOld
) && (!prStaRec
->fgIsInPS
)) {
5511 kalSetEvent(prAdapter
->prGlueInfo
);
5516 /*----------------------------------------------------------------------------*/
5518 * \brief Update STA free quota Event from FW
5520 * \param[in] prAdapter Adapter pointer
5521 * \param[in] prEvent The event packet from the FW
5525 /*----------------------------------------------------------------------------*/
5526 VOID
qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter
, IN P_WIFI_EVENT_T prEvent
)
5528 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota
;
5529 P_STA_RECORD_T prStaRec
;
5532 prEventStaUpdateFreeQuota
= (P_EVENT_STA_UPDATE_FREE_QUOTA_T
) prEvent
;
5533 prStaRec
= QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter
, prEventStaUpdateFreeQuota
->ucStaRecIdx
);
5535 * Station Record possible been freed.
5537 /* ASSERT(prStaRec); */
5540 if (prStaRec
->fgIsInPS
) {
5541 qmUpdateFreeQuota(prAdapter
,
5543 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5544 prEventStaUpdateFreeQuota
->ucFreeQuota
);
5546 kalSetEvent(prAdapter
->prGlueInfo
);
5550 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
5551 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
5552 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5553 prEventStaUpdateFreeQuota
->ucFreeQuota
));
5556 DBGLOG(QM
, TRACE
, ("UFQ=%d,%d,%d\n",
5557 prEventStaUpdateFreeQuota
->ucStaRecIdx
,
5558 prEventStaUpdateFreeQuota
->ucUpdateMode
,
5559 prEventStaUpdateFreeQuota
->ucFreeQuota
));
5567 /*----------------------------------------------------------------------------*/
5569 * \brief Update STA free quota
5571 * \param[in] prStaRec the STA
5572 * \param[in] ucUpdateMode the method to update free quota
5573 * \param[in] ucFreeQuota the value for update
5577 /*----------------------------------------------------------------------------*/
5579 qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter
,
5580 IN P_STA_RECORD_T prStaRec
, IN UINT_8 ucUpdateMode
, IN UINT_8 ucFreeQuota
)
5583 UINT_8 ucFreeQuotaForNonDelivery
;
5584 UINT_8 ucFreeQuotaForDelivery
;
5587 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
5588 prStaRec
->ucFreeQuota
, ucUpdateMode
, ucFreeQuota
));
5590 if (!prStaRec
->fgIsInPS
)
5593 switch (ucUpdateMode
) {
5594 case FREE_QUOTA_UPDATE_MODE_INIT
:
5595 case FREE_QUOTA_UPDATE_MODE_OVERWRITE
:
5596 prStaRec
->ucFreeQuota
= ucFreeQuota
;
5598 case FREE_QUOTA_UPDATE_MODE_INCREASE
:
5599 prStaRec
->ucFreeQuota
+= ucFreeQuota
;
5601 case FREE_QUOTA_UPDATE_MODE_DECREASE
:
5602 prStaRec
->ucFreeQuota
-= ucFreeQuota
;
5608 DBGLOG(QM
, LOUD
, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec
->ucFreeQuota
));
5610 ucFreeQuota
= prStaRec
->ucFreeQuota
;
5612 ucFreeQuotaForNonDelivery
= 0;
5613 ucFreeQuotaForDelivery
= 0;
5615 if (ucFreeQuota
> 0) {
5616 if (prStaRec
->fgIsQoS
&& prStaRec
->fgIsUapsdSupported
5617 /* && prAdapter->rWifiVar.fgSupportQoS
5618 && prAdapter->rWifiVar.fgSupportUAPSD */) {
5619 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
5621 if (prStaRec
->ucFreeQuotaForNonDelivery
> 0
5622 && prStaRec
->ucFreeQuotaForDelivery
> 0) {
5623 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
5624 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5625 } else if (prStaRec
->ucFreeQuotaForNonDelivery
== 0
5626 && prStaRec
->ucFreeQuotaForDelivery
== 0) {
5627 ucFreeQuotaForNonDelivery
= ucFreeQuota
>> 1;
5628 ucFreeQuotaForDelivery
= ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5629 } else if (prStaRec
->ucFreeQuotaForNonDelivery
> 0) {
5630 /* NonDelivery is not busy */
5631 if (ucFreeQuota
>= 3) {
5632 ucFreeQuotaForNonDelivery
= 2;
5633 ucFreeQuotaForDelivery
=
5634 ucFreeQuota
- ucFreeQuotaForNonDelivery
;
5636 ucFreeQuotaForDelivery
= ucFreeQuota
;
5637 ucFreeQuotaForNonDelivery
= 0;
5639 } else if (prStaRec
->ucFreeQuotaForDelivery
> 0) {
5640 /* Delivery is not busy */
5641 if (ucFreeQuota
>= 3) {
5642 ucFreeQuotaForDelivery
= 2;
5643 ucFreeQuotaForNonDelivery
=
5644 ucFreeQuota
- ucFreeQuotaForDelivery
;
5646 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
5647 ucFreeQuotaForDelivery
= 0;
5652 /* !prStaRec->fgIsUapsdSupported */
5653 ucFreeQuotaForNonDelivery
= ucFreeQuota
;
5654 ucFreeQuotaForDelivery
= 0;
5657 /* ucFreeQuota > 0 */
5658 prStaRec
->ucFreeQuotaForDelivery
= ucFreeQuotaForDelivery
;
5659 prStaRec
->ucFreeQuotaForNonDelivery
= ucFreeQuotaForNonDelivery
;
5661 DBGLOG(QM
, LOUD
, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
5662 prStaRec
->ucFreeQuotaForDelivery
, prStaRec
->ucFreeQuotaForNonDelivery
));
5666 /*----------------------------------------------------------------------------*/
5668 * \brief Return the reorder queued RX packets
5672 * \return The number of queued RX packets
5674 /*----------------------------------------------------------------------------*/
5675 UINT_32
qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter
)
5678 P_QUE_MGT_T prQM
= &prAdapter
->rQM
;
5680 /* XXX The summation may impact the performance */
5681 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
5682 u4Total
+= prQM
->arRxBaTable
[i
].rReOrderQue
.u4NumElem
;
5684 if (QUEUE_IS_EMPTY(&(prQM
->arRxBaTable
[i
].rReOrderQue
))) {
5685 ASSERT(prQM
->arRxBaTable
[i
].rReOrderQue
== 0);
5689 ASSERT(u4Total
<= (CFG_NUM_OF_QM_RX_PKT_NUM
* 2));
5693 /*----------------------------------------------------------------------------*/
5695 * \brief Dump current queue status
5701 /*----------------------------------------------------------------------------*/
5702 VOID
qmDumpQueueStatus(IN P_ADAPTER_T prAdapter
)
5704 P_TX_CTRL_T prTxCtrl
;
5706 P_GLUE_INFO_T prGlueInfo
;
5708 UINT_32 u4TotalBufferCount
, u4TotalPageCount
, u4CurBufferCount
, u4CurPageCount
;
5710 DEBUGFUNC(("%s", __func__
));
5712 prTxCtrl
= &prAdapter
->rTxCtrl
;
5713 prQM
= &prAdapter
->rQM
;
5714 prGlueInfo
= prAdapter
->prGlueInfo
;
5715 u4TotalBufferCount
= 0;
5716 u4TotalPageCount
= 0;
5717 u4CurBufferCount
= 0;
5720 DBGLOG(SW4
, INFO
, ("\n------<Dump QUEUE Status>------\n"));
5722 for(i
= TC0_INDEX
; i
< TC_NUM
; i
++) {
5723 DBGLOG(SW4
, INFO
, ("TC%u ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5725 prTxCtrl
->rTc
.au2MaxNumOfBuffer
[i
],
5726 prTxCtrl
->rTc
.au2MaxNumOfPage
[i
],
5727 prTxCtrl
->rTc
.au2FreeBufferCount
[i
],
5728 prTxCtrl
->rTc
.au2FreePageCount
[i
]));
5730 u4TotalBufferCount
+= prTxCtrl
->rTc
.au2MaxNumOfBuffer
[i
];
5731 u4TotalPageCount
+= prTxCtrl
->rTc
.au2MaxNumOfPage
[i
];
5732 u4CurBufferCount
+= prTxCtrl
->rTc
.au2FreeBufferCount
[i
];
5733 u4CurPageCount
+= prTxCtrl
->rTc
.au2FreePageCount
[i
];
5736 DBGLOG(SW4
, INFO
, ("ToT ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5737 u4TotalBufferCount
, u4TotalPageCount
, u4CurBufferCount
, u4CurPageCount
));
5739 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5741 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
5742 for(i
= TC0_INDEX
; i
< TC_NUM
; i
++) {
5744 DBGLOG(SW4
, INFO
,("TC%u AvgQLen[%04u] minRsv[%02u] CurTcRes[%02u] GrtdTcRes[%02u]\n",
5746 QM_GET_TX_QUEUE_LEN(prAdapter
, i
),
5747 prQM
->au4MinReservedTcResource
[i
],
5748 prQM
->au4CurrentTcResource
[i
],
5749 prQM
->au4GuaranteedTcResource
[i
]));
5752 DBGLOG(SW4
, INFO
,("Resource Residual[%u] ExtraRsv[%u]\n",
5753 prQM
->u4ResidualTcResource
,
5754 prQM
->u4ExtraReservedTcResource
));
5755 DBGLOG(SW4
, INFO
,("QueLenMovingAvg[%u] Time2AdjResource[%u] Time2UpdateQLen[%u]\n",
5756 prQM
->u4QueLenMovingAverage
,
5757 prQM
->u4TimeToAdjustTcResource
,
5758 prQM
->u4TimeToUpdateQueLen
));
5761 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5763 #if QM_FORWARDING_FAIRNESS
5764 for (i
= 0; i
< NUM_OF_PER_STA_TX_QUEUES
; i
++) {
5766 ("TC%u HeadSta[%u] ResourceUsedCount[%u]\n", i
, prQM
->au4HeadStaRecIndex
[i
],
5767 prQM
->au4ResourceUsedCount
[i
]));
5771 DBGLOG(SW4
, INFO
, ("BMC or unknown TxQueue Len[%u]\n", prQM
->arTxQueue
[0].u4NumElem
));
5773 ("Pending QLen Normal[%u] Sec[%u]\n", prGlueInfo
->i4TxPendingFrameNum
,
5774 prGlueInfo
->i4TxPendingSecurityFrameNum
));
5777 for (i
= 0; i
< HW_BSSID_NUM
; i
++) {
5778 DBGLOG(SW4
, INFO
, ("Pending BSS[%u] QLen[%u:%u:%u:%u]\n",
5780 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][0],
5781 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][1],
5782 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][2],
5783 prGlueInfo
->ai4TxPendingFrameNumPerQueue
[i
][3]));
5786 DBGLOG(SW4
, INFO
, ("Pending FWD CNT[%d]\n", prTxCtrl
->i4PendingFwdFrameCount
));
5787 DBGLOG(SW4
, INFO
, ("Pending MGMT CNT[%d]\n", prTxCtrl
->i4TxMgmtPendingNum
));
5789 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5791 DBGLOG(SW4
, INFO
, ("Total RFB[%u]\n", CFG_RX_MAX_PKT_NUM
));
5792 DBGLOG(SW4
, INFO
, ("rFreeSwRfbList[%u]\n", prAdapter
->rRxCtrl
.rFreeSwRfbList
.u4NumElem
));
5794 ("rReceivedRfbList[%u]\n", prAdapter
->rRxCtrl
.rReceivedRfbList
.u4NumElem
));
5796 ("rIndicatedRfbList[%u]\n", prAdapter
->rRxCtrl
.rIndicatedRfbList
.u4NumElem
));
5797 DBGLOG(SW4
, INFO
, ("ucNumIndPacket[%u]\n", prAdapter
->rRxCtrl
.ucNumIndPacket
));
5798 DBGLOG(SW4
, INFO
, ("ucNumRetainedPacket[%u]\n", prAdapter
->rRxCtrl
.ucNumRetainedPacket
));
5800 DBGLOG(SW4
, INFO
, ("---------------------------------\n"));
5801 DBGLOG(SW4
, INFO
, ("CMD: FreeCmd[%u/%u] PendingCmd[%u] Cmd2Tx[%u]\n",
5802 prAdapter
->rFreeCmdList
.u4NumElem
,
5803 CFG_TX_MAX_CMD_PKT_NUM
,
5804 prAdapter
->rPendingCmdQueue
.u4NumElem
, prGlueInfo
->rCmdQueue
.u4NumElem
));
5805 DBGLOG(SW4
, INFO
, ("MGMT: FreeMgmt[%u/%u] PendingMgmt[%u]\n",
5806 prAdapter
->rTxCtrl
.rFreeMsduInfoList
.u4NumElem
,
5807 CFG_TX_MAX_PKT_NUM
, prAdapter
->rTxCtrl
.rTxMgmtTxingQueue
.u4NumElem
));
5810 DBGLOG(SW4
, INFO
, ("---------------------------------\n\n"));
5817 #if CFG_M0VE_BA_TO_DRIVER
5818 /*----------------------------------------------------------------------------*/
5820 * @brief Send DELBA Action frame
5822 * @param fgIsInitiator DELBA_ROLE_INITIATOR or DELBA_ROLE_RECIPIENT
5823 * @param prStaRec Pointer to the STA_REC of the receiving peer
5824 * @param u4Tid TID of the BA entry
5825 * @param u4ReasonCode The reason code carried in the Action frame
5829 /*----------------------------------------------------------------------------*/
5831 mqmSendDelBaFrame(IN P_ADAPTER_T prAdapter
,
5832 IN BOOLEAN fgIsInitiator
,
5833 IN P_STA_RECORD_T prStaRec
, IN UINT_32 u4Tid
, IN UINT_32 u4ReasonCode
)
5836 P_MSDU_INFO_T prTxMsduInfo
;
5837 P_ACTION_DELBA_FRAME_T prDelBaFrame
;
5838 P_BSS_INFO_T prBssInfo
;
5840 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmSendDelBaFrame()\n"));
5844 /* 3 <1> Block the message in case of invalid STA */
5845 if (!prStaRec
->fgIsInUse
) {
5846 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
5849 /* Check HT-capabale STA */
5850 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
5852 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
5853 prStaRec
->ucDesiredPhyTypeSet
));
5856 /* 4 <2> Construct the DELBA frame */
5857 prTxMsduInfo
= (P_MSDU_INFO_T
) cnmMgtPktAlloc(prAdapter
, ACTION_DELBA_FRAME_LEN
);
5859 if (!prTxMsduInfo
) {
5861 ("[Puff][%s]: (Warning) DELBA for TID=%ld was not sent (MSDU_INFO alloc failure)\n",
5866 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
5868 /* Fill the Action frame */
5870 (P_ACTION_DELBA_FRAME_T
) ((UINT_32
) (prTxMsduInfo
->prPacket
) + MAC_TX_RESERVED_FIELD
);
5871 prDelBaFrame
->u2FrameCtrl
= MAC_FRAME_ACTION
;
5872 #if CFG_SUPPORT_802_11W
5873 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
5874 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) DELBA is 80211w enabled\n", __func__
));
5875 prDelBaFrame
->u2FrameCtrl
|= MASK_FC_PROTECTED_FRAME
;
5879 prDelBaFrame
->u2DurationID
= 0;
5880 prDelBaFrame
->ucCategory
= CATEGORY_BLOCK_ACK_ACTION
;
5881 prDelBaFrame
->ucAction
= ACTION_DELBA
;
5883 prDelBaFrame
->u2DelBaParameterSet
= 0;
5884 prDelBaFrame
->u2DelBaParameterSet
|= ((fgIsInitiator
? ACTION_DELBA_INITIATOR_MASK
: 0));
5885 prDelBaFrame
->u2DelBaParameterSet
|=
5886 ((u4Tid
<< ACTION_DELBA_TID_OFFSET
) & ACTION_DELBA_TID_MASK
);
5887 prDelBaFrame
->u2ReasonCode
= u4ReasonCode
;
5889 COPY_MAC_ADDR(prDelBaFrame
->aucDestAddr
, prStaRec
->aucMacAddr
);
5890 COPY_MAC_ADDR(prDelBaFrame
->aucSrcAddr
, prBssInfo
->aucOwnMacAddr
);
5891 COPY_MAC_ADDR(prDelBaFrame
->aucBSSID
, prBssInfo
->aucBSSID
);
5893 /* 4 <3> Configure the MSDU_INFO and forward it to TXM */
5894 TX_SET_MMPDU(prAdapter
,
5896 prStaRec
->ucBssIndex
,
5897 (prStaRec
!= NULL
) ? (prStaRec
->ucIndex
) : (STA_REC_INDEX_NOT_FOUND
),
5898 WLAN_MAC_HEADER_LEN
, ACTION_DELBA_FRAME_LEN
, NULL
, MSDU_RATE_MODE_AUTO
);
5900 #if CFG_SUPPORT_802_11W
5901 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
5902 DBGLOG(RSN
, INFO
, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
5903 nicTxConfigPktOption(prTxMsduInfo
, MSDU_OPT_PROTECTED_FRAME
, TRUE
);
5907 /* TID and fgIsInitiator are needed when processing TX Done of the DELBA frame */
5908 prTxMsduInfo
->ucTID
= (UINT_8
) u4Tid
;
5909 prTxMsduInfo
->ucControlFlag
= (fgIsInitiator
? 1 : 0);
5911 nicTxEnqueueMsdu(prAdapter
, prTxMsduInfo
);
5914 ("[Puff][%s]: Send DELBA for TID=%ld Initiator=%d\n", __func__
, u4Tid
,
5919 /*----------------------------------------------------------------------------*/
5921 * @brief Callback function for the TX Done event for an ADDBA_RSP
5923 * @param prMsduInfo The TX packet
5924 * @param rWlanStatus WLAN_STATUS_SUCCESS if TX is successful
5926 * @return WLAN_STATUS_BUFFER_RETAINED is returned if the buffer shall not be freed by TXM
5928 /*----------------------------------------------------------------------------*/
5930 mqmCallbackAddBaRspSent(IN P_ADAPTER_T prAdapter
,
5931 IN P_MSDU_INFO_T prMsduInfo
, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus
)
5933 P_RX_BA_ENTRY_T prRxBaEntry
;
5934 P_STA_RECORD_T prStaRec
;
5939 /* ASSERT(prMsduInfo); */
5940 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prMsduInfo
->ucStaRecIndex
);
5943 prQM
= &prAdapter
->rQM
;
5945 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmCallbackAddBaRspSent()\n"));
5947 /* 4 <0> Check STA_REC status */
5948 /* Check STA_REC is inuse */
5949 if (!prStaRec
->fgIsInUse
) {
5950 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
5951 return WLAN_STATUS_SUCCESS
;
5953 /* Check HT-capabale STA */
5954 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
5956 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
5957 prStaRec
->ucDesiredPhyTypeSet
));
5958 return WLAN_STATUS_SUCCESS
; /* To free the received ADDBA_REQ directly */
5960 /* 4 <1> Find the corresponding BA entry */
5961 u4Tid
= prMsduInfo
->ucTID
; /* TID is stored in MSDU_INFO when composing the ADDBA_RSP frame */
5962 prRxBaEntry
= &prQM
->arRxBaTable
[u4Tid
];
5964 /* Note: Due to some reason, for example, receiving a DELBA, the BA entry may not be in state NEGO */
5965 /* 4 <2> INVALID state */
5968 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)(invalid BA)\n",
5969 __func__
, prStaRec
->ucIndex
, u4Tid
));
5971 /* 4 <3> NEGO, ACTIVE, or DELETING state */
5973 switch (rTxDoneStatus
) {
5974 /* 4 <Case 1> TX Success */
5975 case TX_RESULT_SUCCESS
:
5978 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)\n",
5979 __func__
, prStaRec
->ucIndex
, u4Tid
));
5982 /* 4 <Case 1.1> NEGO or ACTIVE state */
5983 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_DELETING
) {
5984 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
5985 BA_ENTRY_STATUS_ACTIVE
);
5987 /* 4 <Case 1.2> DELETING state */
5989 /* Deleting is on-going, so do nothing and wait for TX done of the DELBA frame */
5993 /* 4 <Case 2> TX Failure */
5997 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld Entry_Status=%d)(TX failed)\n",
5998 __func__
, prStaRec
->ucIndex
, u4Tid
, prRxBaEntry
->ucStatus
));
6000 /* 4 <Case 2.1> NEGO or ACTIVE state */
6001 /* Notify the host to delete the agreement */
6002 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_DELETING
) {
6003 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
6004 BA_ENTRY_STATUS_DELETING
);
6006 /* Send DELBA to the peer to ensure the BA state is synchronized */
6007 mqmSendDelBaFrame(prAdapter
, DELBA_ROLE_RECIPIENT
, prStaRec
, u4Tid
,
6008 STATUS_CODE_UNSPECIFIED_FAILURE
);
6010 /* 4 <Case 2.2> DELETING state */
6012 /* Deleting is on-going, so do nothing and wait for the TX done of the DELBA frame */
6021 return WLAN_STATUS_SUCCESS
; /* TXM shall release the packet */
6026 /*----------------------------------------------------------------------------*/
6028 * @brief Check if there is any idle RX BA
6030 * @param u4Param (not used)
6034 /*----------------------------------------------------------------------------*/
6035 VOID
mqmTimeoutCheckIdleRxBa(IN P_ADAPTER_T prAdapter
, IN ULONG ulParamPtr
)
6038 P_RX_BA_ENTRY_T prRxBa
;
6039 UINT_32 u4IdleCountThreshold
= 0;
6040 P_STA_RECORD_T prStaRec
;
6043 DBGLOG(QM
, WARN
, ("[Puff]: Enter mqmTimeoutIdleRxBaDetection()\n"));
6045 prQM
= &prAdapter
->rQM
;
6047 /* 4 <1> Restart the timer */
6048 cnmTimerStopTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6049 cnmTimerStartTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
,
6050 MQM_IDLE_RX_BA_CHECK_INTERVAL
);
6052 /* 4 <2> Increment the idle count for each idle BA */
6053 for (i
= 0; i
< CFG_NUM_OF_RX_BA_AGREEMENTS
; i
++) {
6055 prRxBa
= &prQM
->arRxBaTable
[i
];
6057 if (prRxBa
->ucStatus
== BA_ENTRY_STATUS_ACTIVE
) {
6059 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prRxBa
->ucStaRecIdx
);
6061 if (!prStaRec
->fgIsInUse
) {
6063 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
6066 /* Check HT-capabale STA */
6067 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
6069 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n",
6070 __func__
, prStaRec
->ucDesiredPhyTypeSet
));
6073 /* 4 <2.1> Idle detected, increment idle count and see if a DELBA should be sent */
6074 if (prRxBa
->u2SnapShotSN
== prStaRec
->au2CachedSeqCtrl
[prRxBa
->ucTid
]) {
6076 prRxBa
->ucIdleCount
++;
6078 ASSERT(prRxBa
->ucTid
< 8);
6079 switch (aucTid2ACI
[prRxBa
->ucTid
]) {
6081 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_BK
;
6084 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_BE
;
6087 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_VI
;
6090 u4IdleCountThreshold
= MQM_DEL_IDLE_RXBA_THRESHOLD_VO
;
6094 if (prRxBa
->ucIdleCount
>= u4IdleCountThreshold
) {
6095 mqmRxModifyBaEntryStatus(prAdapter
, prRxBa
,
6096 BA_ENTRY_STATUS_INVALID
);
6097 mqmSendDelBaFrame(prAdapter
, DELBA_ROLE_RECIPIENT
, prStaRec
,
6098 (UINT_32
) prRxBa
->ucTid
,
6099 REASON_CODE_PEER_TIME_OUT
);
6100 qmDelRxBaEntry(prAdapter
, prStaRec
->ucIndex
, prRxBa
->ucTid
,
6104 /* 4 <2.2> Activity detected */
6106 prRxBa
->u2SnapShotSN
= prStaRec
->au2CachedSeqCtrl
[prRxBa
->ucTid
];
6107 prRxBa
->ucIdleCount
= 0;
6108 continue; /* check the next BA entry */
6116 /*----------------------------------------------------------------------------*/
6118 * @brief Do RX BA entry state transition
6120 * @param prRxBaEntry The BA entry pointer
6121 * @param eStatus The state to transition to
6125 /*----------------------------------------------------------------------------*/
6127 mqmRxModifyBaEntryStatus(IN P_ADAPTER_T prAdapter
,
6128 IN P_RX_BA_ENTRY_T prRxBaEntry
, IN ENUM_BA_ENTRY_STATUS_T eStatus
)
6130 P_STA_RECORD_T prStaRec
;
6133 BOOLEAN fgResetScoreBoard
= FALSE
;
6135 ASSERT(prRxBaEntry
);
6137 prStaRec
= cnmGetStaRecByIndex(prAdapter
, prRxBaEntry
->ucStaRecIdx
);
6139 prQM
= &prAdapter
->rQM
;
6141 if (prRxBaEntry
->ucStatus
== (UINT_8
) eStatus
) {
6143 ("[Puff][%s]: eStatus are identical...\n", __func__
, prRxBaEntry
->ucStatus
));
6146 /* 4 <1> State transition from state X */
6147 switch (prRxBaEntry
->ucStatus
) {
6149 /* 4 <1.1> From (X = INVALID) to (ACTIVE or NEGO or DELETING) */
6150 case BA_ENTRY_STATUS_INVALID
:
6152 /* Associate the BA entry with the STA_REC when leaving INVALID state */
6153 kalMemCopy(&prQM
->arRxBaTable
[prRxBaEntry
->ucTid
], prRxBaEntry
,
6154 sizeof(RX_BA_ENTRY_T
));
6156 /* Increment the RX BA counter */
6157 prQM
->ucRxBaCount
++;
6158 ASSERT(prQM
->ucRxBaCount
<= CFG_NUM_OF_RX_BA_AGREEMENTS
);
6160 /* Since AMPDU may be received during INVALID state */
6161 fgResetScoreBoard
= TRUE
;
6163 /* Reset Idle Count since this BA entry is being activated now.
6164 * Note: If there is no ACTIVE entry, the idle detection timer will not be started.
6166 prRxBaEntry
->ucIdleCount
= 0;
6169 /* 4 <1.2> Other cases */
6174 /* 4 <2> State trasition to state Y */
6177 /* 4 <2.1> From (NEGO, ACTIVE, DELETING) to (Y=INVALID) */
6178 case BA_ENTRY_STATUS_INVALID
:
6180 /* Disassociate the BA entry with the STA_REC */
6181 kalMemZero(&prQM
->arRxBaTable
[prRxBaEntry
->ucTid
], sizeof(RX_BA_ENTRY_T
));
6183 /* Decrement the RX BA counter */
6184 prQM
->ucRxBaCount
--;
6185 ASSERT(prQM
->ucRxBaCount
< CFG_NUM_OF_RX_BA_AGREEMENTS
);
6188 fgResetScoreBoard
= TRUE
;
6190 /* If there is not any BA agreement, stop doing idle detection */
6191 if (prQM
->ucRxBaCount
== 0) {
6193 (prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
)) {
6194 cnmTimerStopTimer(prAdapter
,
6195 &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6196 MQM_CLEAR_FLAG(prAdapter
->u4FlagBitmap
,
6197 MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
);
6203 /* 4 <2.2> From (any) to (Y=ACTIVE) */
6204 case BA_ENTRY_STATUS_ACTIVE
:
6206 /* If there is at least one BA going into ACTIVE, start idle detection */
6207 if (!MQM_CHECK_FLAG(prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
)) {
6208 cnmTimerInitTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
, (PFN_MGMT_TIMEOUT_FUNC
) mqmTimeoutCheckIdleRxBa
, (ULONG
) NULL
); /* No parameter */
6210 cnmTimerStopTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
);
6212 #if MQM_IDLE_RX_BA_DETECTION
6213 cnmTimerStartTimer(prAdapter
, &prAdapter
->rMqmIdleRxBaDetectionTimer
,
6214 MQM_IDLE_RX_BA_CHECK_INTERVAL
);
6215 MQM_SET_FLAG(prAdapter
->u4FlagBitmap
, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED
);
6221 case BA_ENTRY_STATUS_NEGO
:
6226 if (fgResetScoreBoard
) {
6227 P_CMD_RESET_BA_SCOREBOARD_T prCmdBody
;
6229 prCmdBody
= (P_CMD_RESET_BA_SCOREBOARD_T
)
6230 cnmMemAlloc(prAdapter
, RAM_TYPE_BUF
, sizeof(CMD_RESET_BA_SCOREBOARD_T
));
6233 prCmdBody
->ucflag
= MAC_ADDR_TID_MATCH
;
6234 prCmdBody
->ucTID
= prRxBaEntry
->ucTid
;
6235 kalMemCopy(prCmdBody
->aucMacAddr
, prStaRec
->aucMacAddr
, PARAM_MAC_ADDR_LEN
);
6237 wlanoidResetBAScoreboard(prAdapter
, prCmdBody
, sizeof(CMD_RESET_BA_SCOREBOARD_T
));
6241 DBGLOG(QM
, WARN
, ("[Puff]QM: (RX_BA) [STA=%d TID=%d] status from %d to %d\n",
6242 prRxBaEntry
->ucStaRecIdx
, prRxBaEntry
->ucTid
,
6243 prRxBaEntry
->ucStatus
, eStatus
));
6245 prRxBaEntry
->ucStatus
= (UINT_8
) eStatus
;
6250 /*----------------------------------------------------------------------------*/
6258 /*----------------------------------------------------------------------------*/
6259 VOID
mqmHandleAddBaReq(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
)
6261 P_STA_RECORD_T prStaRec
;
6262 P_BSS_INFO_T prBssInfo
;
6263 P_ACTION_ADDBA_REQ_FRAME_T prAddBaReq
;
6264 ACTION_ADDBA_REQ_BODY_T rAddBaReqBody
;
6265 P_ACTION_ADDBA_RSP_FRAME_T prAddBaRsp
;
6266 ACTION_ADDBA_RSP_BODY_T rAddBaRspBody
;
6267 P_RX_BA_ENTRY_T prRxBaEntry
;
6268 P_MSDU_INFO_T prTxMsduInfo
;
6271 BOOLEAN fgIsReqAccepted
= TRUE
; /* Reject or accept the ADDBA_REQ */
6272 BOOLEAN fgIsNewEntryAdded
= FALSE
; /* Indicator: Whether a new RX BA entry will be added */
6275 UINT_32 u4StaRecIdx
;
6281 UINT_32 u4BuffSizeBT
;
6286 prStaRec
= prSwRfb
->prStaRec
;
6287 prQM
= &prAdapter
->rQM
;
6292 /* 4 <0> Check if this is an active HT-capable STA */
6293 /* Check STA_REC is inuse */
6294 if (!prStaRec
->fgIsInUse
) {
6296 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__
));
6299 /* Check HT-capabale STA */
6300 if (!(prStaRec
->ucDesiredPhyTypeSet
& PHY_TYPE_BIT_HT
)) {
6302 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__
,
6303 prStaRec
->ucDesiredPhyTypeSet
));
6304 break; /* To free the received ADDBA_REQ directly */
6306 /* 4 <1> Check user configurations and HW capabilities */
6307 /* Check configurations (QoS support, AMPDU RX support) */
6308 if ((!prAdapter
->rWifiVar
.fgSupportQoS
) ||
6309 (!prAdapter
->rWifiVar
.fgSupportAmpduRx
) || (!prStaRec
->fgRxAmpduEn
)) {
6311 ("[Puff][%s]: (Warning) BA ACK Policy not supported fgSupportQoS(%d), fgSupportAmpduRx(%d), fgRxAmpduEn(%d)\n",
6312 __func__
, prAdapter
->rWifiVar
.fgSupportQoS
,
6313 prAdapter
->rWifiVar
.fgSupportAmpduRx
, prStaRec
->fgRxAmpduEn
));
6314 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6316 /* Check capability */
6317 prAddBaReq
= ((P_ACTION_ADDBA_REQ_FRAME_T
) (prSwRfb
->pvHeader
));
6318 kalMemCopy((PUINT_8
) (&rAddBaReqBody
),
6319 (PUINT_8
) (&(prAddBaReq
->aucBAParameterSet
[0])), 6);
6320 if ((((rAddBaReqBody
.
6321 u2BAParameterSet
) & BA_PARAM_SET_ACK_POLICY_MASK
) >>
6322 BA_PARAM_SET_ACK_POLICY_MASK_OFFSET
)
6323 != BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA
) { /* Only Immediate_BA is supported */
6325 ("[Puff][%s]: (Warning) BA ACK Policy not supported (0x%08X)\n",
6326 __func__
, rAddBaReqBody
.u2BAParameterSet
));
6327 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6330 /* 4 <2> Determine the RX BA entry (existing or to be added) */
6331 /* Note: BA entry index = (TID, STA_REC index) */
6334 u2BAParameterSet
) & BA_PARAM_SET_TID_MASK
) >> BA_PARAM_SET_TID_MASK_OFFSET
);
6335 u4StaRecIdx
= prStaRec
->ucIndex
;
6337 ("[Puff][%s]: BA entry index = [TID(%d), STA_REC index(%d)]\n", __func__
,
6338 u4Tid
, u4StaRecIdx
));
6340 u2WinStart
= ((rAddBaReqBody
.u2BAStartSeqCtrl
) >> OFFSET_BAR_SSC_SN
);
6341 u2WinSize
= (((rAddBaReqBody
.u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
6342 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
6344 ("[Puff][%s]: BA entry info = [WinStart(%d), WinSize(%d)]\n", __func__
,
6345 u2WinStart
, u2WinSize
));
6348 if (fgIsReqAccepted
) {
6350 prRxBaEntry
= &prQM
->arRxBaTable
[u4Tid
];
6354 /* 4 <Case 2.1> INVALID state && BA entry available --> Add a new entry and accept */
6355 if (prQM
->ucRxBaCount
< CFG_NUM_OF_RX_BA_AGREEMENTS
) {
6357 fgIsNewEntryAdded
= qmAddRxBaEntry(prAdapter
,
6358 (UINT_8
) u4StaRecIdx
,
6360 u2WinStart
, u2WinSize
);
6362 if (!fgIsNewEntryAdded
) {
6364 ("[Puff][%s]: (Error) Free RX BA entry alloc failure\n"));
6365 fgIsReqAccepted
= FALSE
;
6368 ("[Puff][%s]: Create a new BA Entry\n"));
6371 /* 4 <Case 2.2> INVALID state && BA entry unavailable --> Reject the ADDBA_REQ */
6374 ("[Puff][%s]: (Warning) Free RX BA entry unavailable(req: %d)\n",
6375 __func__
, prQM
->ucRxBaCount
));
6376 fgIsReqAccepted
= FALSE
; /* Will send an ADDBA_RSP with DECLINED */
6380 /* 4 <Case 2.3> NEGO or DELETING state --> Ignore the ADDBA_REQ */
6381 /* For NEGO: do nothing. Wait for TX Done of ADDBA_RSP */
6382 /* For DELETING: do nothing. Wait for TX Done of DELBA */
6383 if (prRxBaEntry
->ucStatus
!= BA_ENTRY_STATUS_ACTIVE
) {
6385 ("[Puff][%s]: (Warning) ADDBA_REQ for TID=%ld is received during status:%d (Ignore)\n",
6386 __func__
, u4Tid
, prRxBaEntry
->ucStatus
));
6387 break; /* Ignore the ADDBA_REQ since the current state is NEGO */
6389 /* 4 <Case 2.4> ACTIVE state --> Accept */
6390 /* Send an ADDBA_RSP to accept the request again */
6394 /* 4 <3> Construct the ADDBA_RSP frame */
6396 (P_MSDU_INFO_T
) cnmMgtPktAlloc(prAdapter
, ACTION_ADDBA_RSP_FRAME_LEN
);
6397 prBssInfo
= GET_BSS_INFO_BY_INDEX(prAdapter
, prStaRec
->ucBssIndex
);
6399 if (!prTxMsduInfo
) {
6401 /* The peer may send an ADDBA_REQ message later.
6402 * Do nothing to the BA entry. No DELBA will be sent (because cnmMgtPktAlloc() may fail again).
6403 * No BA deletion event will be sent to the host (because cnmMgtPktAlloc() may fail again).
6406 ("[Puff][%s]: (Warning) ADDBA_RSP alloc failure\n", __func__
));
6408 if (fgIsNewEntryAdded
) { /* If a new entry has been created due to this ADDBA_REQ, delete it */
6409 ASSERT(prRxBaEntry
);
6410 mqmRxModifyBaEntryStatus(prAdapter
, prRxBaEntry
,
6411 BA_ENTRY_STATUS_INVALID
);
6414 break; /* Exit directly to free the ADDBA_REQ */
6417 /* Fill the ADDBA_RSP message */
6419 (P_ACTION_ADDBA_RSP_FRAME_T
) ((UINT_32
) (prTxMsduInfo
->prPacket
) +
6420 MAC_TX_RESERVED_FIELD
);
6421 prAddBaRsp
->u2FrameCtrl
= MAC_FRAME_ACTION
;
6423 #if CFG_SUPPORT_802_11W
6424 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
6426 ("[Puff][%s]: (Warning) ADDBA_RSP is 80211w enabled\n", __func__
));
6427 prAddBaReq
->u2FrameCtrl
|= MASK_FC_PROTECTED_FRAME
;
6430 prAddBaRsp
->u2DurationID
= 0;
6431 prAddBaRsp
->ucCategory
= CATEGORY_BLOCK_ACK_ACTION
;
6432 prAddBaRsp
->ucAction
= ACTION_ADDBA_RSP
;
6433 prAddBaRsp
->ucDialogToken
= prAddBaReq
->ucDialogToken
;
6436 ("[Puff][%s]: (Warning) ADDBA_RSP DurationID(%d) Category(%d) Action(%d) DialogToken(%d)\n",
6437 __func__
, prAddBaRsp
->u2DurationID
, prAddBaRsp
->ucCategory
,
6438 prAddBaRsp
->ucAction
, prAddBaRsp
->ucDialogToken
));
6440 if (fgIsReqAccepted
) {
6441 rAddBaRspBody
.u2StatusCode
= STATUS_CODE_SUCCESSFUL
;
6443 rAddBaRspBody
.u2StatusCode
= STATUS_CODE_REQ_DECLINED
;
6446 /* WinSize = min(WinSize in ADDBA_REQ, CFG_RX_BA_MAX_WINSIZE) */
6447 u4BuffSize
= (((rAddBaReqBody
.u2BAParameterSet
) & BA_PARAM_SET_BUFFER_SIZE_MASK
)
6448 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
);
6450 /*If ADDBA req WinSize<=0 => use default WinSize(16) */
6451 if ((u4BuffSize
> CFG_RX_BA_MAX_WINSIZE
) || (u4BuffSize
<= 0)) {
6452 u4BuffSize
= CFG_RX_BA_MAX_WINSIZE
;
6455 /* TODO: Call BT coexistence function to limit the winsize */
6456 u4BuffSizeBT
= bcmRequestBaWinSize();
6457 DBGLOG(QM
, WARN
, ("[Puff][%s]: (Warning) bcmRequestBaWinSize(%d)\n",
6458 __func__
, u4BuffSizeBT
));
6460 if (u4BuffSize
> u4BuffSizeBT
) {
6461 u4BuffSize
= u4BuffSizeBT
;
6463 #endif /* CFG_SUPPORT_BCM */
6465 rAddBaRspBody
.u2BAParameterSet
= (BA_POLICY_IMMEDIATE
|
6466 (u4Tid
<< BA_PARAM_SET_TID_MASK_OFFSET
) |
6468 BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET
));
6470 /* TODO: Determine the BA timeout value according to the default preference */
6471 rAddBaRspBody
.u2BATimeoutValue
= rAddBaReqBody
.u2BATimeoutValue
;
6474 ("[Puff][%s]: (Warning) ADDBA_RSP u4BuffSize(%d) StatusCode(%d) BAParameterSet(0x%08X) BATimeoutValue(%d)\n",
6475 __func__
, u4BuffSize
, rAddBaRspBody
.u2StatusCode
,
6476 rAddBaRspBody
.u2BAParameterSet
, rAddBaRspBody
.u2BATimeoutValue
));
6478 kalMemCopy((PUINT_8
) (&(prAddBaRsp
->aucStatusCode
[0])), (PUINT_8
) (&rAddBaRspBody
),
6481 COPY_MAC_ADDR(prAddBaRsp
->aucDestAddr
, prStaRec
->aucMacAddr
);
6482 COPY_MAC_ADDR(prAddBaRsp
->aucSrcAddr
, prBssInfo
->aucOwnMacAddr
);
6483 /* COPY_MAC_ADDR(prAddBaRsp->aucBSSID,g_aprBssInfo[prStaRec->ucNetTypeIndex]->aucBSSID); */
6484 COPY_MAC_ADDR(prAddBaRsp
->aucBSSID
, prAddBaReq
->aucBSSID
);
6487 /* 4 <4> Forward the ADDBA_RSP to TXM */
6488 TX_SET_MMPDU(prAdapter
,
6490 prStaRec
->ucBssIndex
,
6491 (prStaRec
!= NULL
) ? (prStaRec
->ucIndex
) : (STA_REC_INDEX_NOT_FOUND
),
6492 WLAN_MAC_HEADER_LEN
,
6493 ACTION_ADDBA_RSP_FRAME_LEN
,
6494 mqmCallbackAddBaRspSent
, MSDU_RATE_MODE_AUTO
);
6496 #if CFG_SUPPORT_802_11W
6497 if (rsnCheckBipKeyInstalled(prAdapter
, prStaRec
)) {
6498 DBGLOG(RSN
, INFO
, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
6499 nicTxConfigPktOption(prTxMsduInfo
, MSDU_OPT_PROTECTED_FRAME
, TRUE
);
6503 /* Note: prTxMsduInfo->ucTID is not used for transmitting the ADDBA_RSP.
6504 * However, when processing TX Done of this ADDBA_RSP, the TID value is needed, so
6505 * store the TID value in advance to prevent parsing the ADDBA_RSP frame
6507 prTxMsduInfo
->ucTID
= (UINT_8
) u4Tid
;
6509 nicTxEnqueueMsdu(prAdapter
, prTxMsduInfo
);
6512 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld)\n", __func__
,
6513 prStaRec
->ucIndex
, u4Tid
));
6517 /* 4 <5> Notify the host to start buffer reordering */
6518 if (fgIsNewEntryAdded
) { /* Only when a new BA entry is indeed added will the host be notified */
6519 ASSERT(fgIsReqAccepted
);
6521 prSwRfbEventToHost
= (P_SW_RFB_T
) cnmMgtPktAlloc(EVENT_RX_ADDBA_PACKET_LEN
);
6523 if (!prSwRfbEventToHost
) {
6525 /* Note: DELBA will not be sent since cnmMgtPktAlloc() may fail again. However, it does not
6526 * matter because upon receipt of AMPDUs without a RX BA agreement, MQM will send DELBA frames
6529 DBGLOG(MQM
, WARN
, ("MQM: (Warning) EVENT packet alloc failed\n"));
6531 /* Ensure that host and FW are synchronized */
6532 mqmRxModifyBaEntryStatus(prRxBaEntry
, BA_ENTRY_STATUS_INVALID
);
6534 break; /* Free the received ADDBA_REQ */
6537 prEventRxAddBa
= (P_EVENT_RX_ADDBA_T
) prSwRfbEventToHost
->pucBuffer
;
6538 prEventRxAddBa
->ucStaRecIdx
= (UINT_8
) u4StaRecIdx
;
6539 prEventRxAddBa
->u2Length
= EVENT_RX_ADDBA_PACKET_LEN
;
6540 prEventRxAddBa
->ucEID
= EVENT_ID_RX_ADDBA
;
6541 prEventRxAddBa
->ucSeqNum
= 0; /* Unsolicited event packet */
6542 prEventRxAddBa
->u2BAParameterSet
= rAddBaRspBody
.u2BAParameterSet
;
6543 prEventRxAddBa
->u2BAStartSeqCtrl
= rAddBaReqBody
.u2BAStartSeqCtrl
;
6544 prEventRxAddBa
->u2BATimeoutValue
= rAddBaReqBody
.u2BATimeoutValue
;
6545 prEventRxAddBa
->ucDialogToken
= prAddBaReq
->ucDialogToken
;
6548 ("MQM: (RX_BA) Event ADDBA ---> driver (STA=%ld TID=%ld WinStart=%d)\n",
6550 (prEventRxAddBa
->u2BAStartSeqCtrl
>> 4)));
6552 /* Configure the SW_RFB for the Event packet */
6553 RXM_SET_EVENT_PACKET(
6554 /* P_SW_RFB_T */ (P_SW_RFB_T
)
6556 /* HIF RX Packet pointer */
6557 (PUINT_8
) prEventRxAddBa
,
6558 /* HIF RX port number */ HIF_RX0_INDEX
6561 rxmSendEventToHost(prSwRfbEventToHost
);
6572 /*----------------------------------------------------------------------------*/
6580 /*----------------------------------------------------------------------------*/
6581 VOID
mqmHandleAddBaRsp(IN P_SW_RFB_T prSwRfb
)
6586 /*----------------------------------------------------------------------------*/
6594 /*----------------------------------------------------------------------------*/
6595 VOID
mqmHandleDelBa(IN P_SW_RFB_T prSwRfb
)
6600 /*----------------------------------------------------------------------------*/
6608 /*----------------------------------------------------------------------------*/
6609 VOID
mqmHandleBaActionFrame(IN P_ADAPTER_T prAdapter
, IN P_SW_RFB_T prSwRfb
)
6611 P_WLAN_ACTION_FRAME prRxFrame
;
6616 prRxFrame
= (P_WLAN_ACTION_FRAME
) prSwRfb
->pvHeader
;
6617 DBGLOG(RLM
, WARN
, ("[Puff][%s] Action(%d)\n", __func__
, prRxFrame
->ucAction
));
6619 switch (prRxFrame
->ucAction
) {
6621 case ACTION_ADDBA_REQ
:
6622 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) ADDBA_REQ <--- peer\n", __func__
));
6623 mqmHandleAddBaReq(prAdapter
, prSwRfb
);
6626 case ACTION_ADDBA_RSP
:
6627 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) ADDBA_RSP <--- peer\n", __func__
));
6628 mqmHandleAddBaRsp(prSwRfb
);
6632 DBGLOG(RLM
, WARN
, ("[Puff][%s] (RX_BA) DELBA <--- peer\n", __func__
));
6633 mqmHandleDelBa(prSwRfb
);
6637 DBGLOG(RLM
, WARN
, ("[Puff][%s] Unknown BA Action Frame\n", __func__
));