import PULS_20180308
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / drv_wlan / mt6630 / wlan / nic / que_mgt.c
CommitLineData
6fa3eb70
S
1/*
2** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#3 $
3*/
4
5/*! \file "que_mgt.c"
6 \brief TX/RX queues management
7
8 The main tasks of queue management include TC-based HIF TX flow control,
9 adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save
10 forwarding control, RX packet reordering, and RX BA agreement management.
11*/
12
13
14
15/*
16** $Log: que_mgt.c $
17**
18** 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
22**
23** 10 29 2013 tsaiyuan.hsu
24** [BORA00002222] MT6630 unified MAC RXM
25** fix the wlan index when rx control frames.
26**
27** 10 16 2013 terry.wu
28** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
29** Refine per-STA dequeue algorithm
30**
31** 09 25 2013 tsaiyuan.hsu
32** [BORA00002222] MT6630 unified MAC RXM
33** not check duplication for BMC packets.
34**
35** 09 25 2013 terry.wu
36** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
37** Add fast TC resource adjustment feature
38**
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.
42**
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.
46**
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
51**
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
56**
57** 08 07 2013 tsaiyuan.hsu
58** [BORA00002222] MT6630 unified MAC RXM
59** .
60**
61** 08 06 2013 tsaiyuan.hsu
62** [BORA00002222] MT6630 unified MAC RXM
63** change the sequence to retrive SSN by group4.
64**
65** 08 06 2013 terry.wu
66** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
67** Set BMC packet retry limit to unlimit
68**
69** 08 05 2013 terry.wu
70** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
71** 1. Change BMC Q resource counter to page
72**
73** 07 31 2013 terry.wu
74** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
75** 1. Fix NetDev binding issue
76**
77** 07 30 2013 wh.su
78** [BORA00002446] [MT6630] [Wi-Fi] [Driver] Update the security function code
79** Add Rx TKIP mic check
80**
81** 07 30 2013 tsaiyuan.hsu
82** [BORA00002222] MT6630 unified MAC RXM
83** add defragmentation.
84**
85** 07 29 2013 tsaiyuan.hsu
86** [BORA00002222] MT6630 unified MAC RXM
87** enable rx duplicate check.
88**
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
94**
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
99**
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
104**
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
109**
110** 07 04 2013 terry.wu
111** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
112** Update Tx path for 1x packet
113**
114** 07 04 2013 terry.wu
115** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
116** Update for 1st Connection.
117**
118** 07 03 2013 tsaiyuan.hsu
119** [BORA00002222] MT6630 unified MAC RXM
120** .
121**
122** 07 03 2013 tsaiyuan.hsu
123** [BORA00002222] MT6630 unified MAC RXM
124** 1. correct header offset
125** 2. tentatively disable duplicate check .
126**
127** 03 20 2013 tsaiyuan.hsu
128** [BORA00002222] MT6630 unified MAC RXM
129** add rx duplicate check.
130**
131** 03 12 2013 tsaiyuan.hsu
132** [BORA00002222] MT6630 unified MAC RXM
133** add rx data and mangement processing.
134**
135** 03 12 2013 terry.wu
136** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
137** Update Tx utility function for management frame
138**
139** 02 19 2013 cp.wu
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
143**
144** 01 28 2013 cm.chang
145** [BORA00002149] [MT6630 Wi-Fi] Initial software development
146** Sync CMD format
147**
148** 01 22 2013 cp.wu
149** [BORA00002253] [MT6630 Wi-Fi][Driver][Firmware] Add NLO and timeout mechanism to SCN module
150** modification for ucBssIndex migration
151**
152** 01 21 2013 terry.wu
153** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
154** Update TX path based on new ucBssIndex modifications.
155**
156** 01 15 2013 terry.wu
157** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
158** Update Tx done resource release mechanism.
159**
160** 12 27 2012 terry.wu
161** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
162** Update MQM index mapping mechanism
163** 1. TID to ACI
164** 2. ACI to SW TxQ
165** 3. ACI to network TC resource
166**
167** 12 21 2012 terry.wu
168** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
169** Update TxD template feature.
170**
171** 12 18 2012 terry.wu
172** [BORA00002207] [MT6630 Wi-Fi] TXM & MQM Implementation
173** Page count resource management.
174**
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)
179 *
180 * 03 02 2012 terry.wu
181 * NULL
182 * Sync CFG80211 modification from branch 2,2.
183 *
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.
187 *
188 * 11 22 2011 yuche.tsai
189 * NULL
190 * Code refine, remove one #if 0 code.
191 *
192 * 11 19 2011 eddie.chen
193 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
194 * Add xlog for tx
195 *
196 * 11 18 2011 yuche.tsai
197 * NULL
198 * CONFIG P2P support RSSI query, default turned off.
199 *
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
203 *
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.
207 *
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.
211 *
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.
215 *
216 * 11 10 2011 eddie.chen
217 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
218 * Use short name for xlog.
219 *
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.
223 *
224 * 11 10 2011 chinglan.wang
225 * NULL
226 * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP.
227 *
228 * 11 09 2011 chinglan.wang
229 * NULL
230 * [WiFi direct]Can't make P2P connect via PBC.
231 *
232 * 11 08 2011 eddie.chen
233 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
234 * Add xlog function.
235 *
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.
239 *
240 * 11 01 2011 chinglan.wang
241 * NULL
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..
244 *
245 * 10 25 2011 wh.su
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.
248 *
249 * 09 28 2011 tsaiyuan.hsu
250 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
251 * enlarge window size only by 4.
252 *
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.
256 *
257 * 08 23 2011 yuche.tsai
258 * NULL
259 * Fix multicast address list issue.
260 *
261 * 08 03 2011 tsaiyuan.hsu
262 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
263 * force window size at least 16.
264 *
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.
268 *
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.
272 *
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.
276 *
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.
280 *
281 * 05 31 2011 eddie.chen
282 * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931
283 * Fix the QM quota in MT5931.
284 *
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.
288 *
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.
292 *
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.
296 *
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..
300 *
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
305 * Add debug message.
306 *
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.
310 *
311 * 04 08 2011 eddie.chen
312 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
313 * Fix for sigma
314 *
315 * 03 28 2011 eddie.chen
316 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
317 * Fix Klockwork warning.
318 *
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.
322 *
323 * 03 15 2011 eddie.chen
324 * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter
325 * Add sw debug counter for QM.
326 *
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.
330 *
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
335 *
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
339 *
340 * 01 27 2011 tsaiyuan.hsu
341 * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support
342 * add roaming fsm
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.
347 *
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.
351 *
352 * 01 24 2011 eddie.chen
353 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
354 * Remove comments.
355 *
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.
359 *
360 * 01 14 2011 wh.su
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.
363 *
364 * 01 13 2011 eddie.chen
365 * [WCXRP00000322] Add WMM IE in beacon,
366Add per station flow control when STA is in PS
367 * Fix typo and compile error.
368 *
369 * 01 12 2011 eddie.chen
370 * [WCXRP00000322] Add WMM IE in beacon,
371Add per station flow control when STA is in PS
372 * Fix WMM parameter condition for STA
373 *
374 * 01 12 2011 eddie.chen
375 * [WCXRP00000322] Add WMM IE in beacon,
376Add 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
379 *
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
383 *
384 * 01 11 2011 eddie.chen
385 * [WCXRP00000322] Add WMM IE in beacon,
386Add per station flow control when STA is in PS
387
388 * Add per STA flow control when STA is in PS mode
389 *
390 * 01 03 2011 george.huang
391 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
392 * update prStaRec->fgIsUapsdSupported flag.
393 *
394 * 12 29 2010 eddie.chen
395 * [WCXRP00000322] Add WMM IE in beacon,
396Add per station flow control when STA is in PS
397
398 * Add WMM parameter for broadcast.
399 *
400 * 12 29 2010 eddie.chen
401 * [WCXRP00000322] Add WMM IE in beacon,
402Add per station flow control when STA is in PS
403
404 * 1) PS flow control event
405 *
406 * 2) WMM IE in beacon, assoc resp, probe resp
407 *
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
412 *
413 * 10 14 2010 wh.su
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.
416 *
417 * 10 14 2010 wh.su
418 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
419 * only MMPDU not check the netActive flag.
420 *
421 * 10 14 2010 wh.su
422 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
423 * not check the netActive flag for mgmt .
424 *
425 * 10 04 2010 cp.wu
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
428 *
429 * 09 21 2010 kevin.huang
430 * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
431 * Eliminate Linux Compile Warning
432 *
433 * 08 30 2010 yarco.yang
434 * NULL
435 * Fixed klockwork error message
436 *
437 * 08 18 2010 yarco.yang
438 * NULL
439 * 1. Fixed HW checksum offload function not work under Linux issue.
440 * 2. Add debug message.
441 *
442 * 08 10 2010 yarco.yang
443 * NULL
444 * Code refine
445 *
446 * 08 06 2010 yarco.yang
447 * NULL
448 * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action
449 *
450 * 07 26 2010 cp.wu
451 *
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
454 *
455 * 07 20 2010 yarco.yang
456 *
457 * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake
458 *
459 * 07 16 2010 yarco.yang
460 *
461 * 1. Support BSS Absence/Presence Event
462 * 2. Support STA change PS mode Event
463 * 3. Support BMC forwarding for AP mode.
464 *
465 * 07 14 2010 yarco.yang
466 *
467 * 1. Remove CFG_MQM_MIGRATION
468 * 2. Add CMD_UPDATE_WMM_PARMS command
469 *
470 * 07 13 2010 yarco.yang
471 *
472 * [WPD00003849]
473 * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing
474 *
475 * 07 09 2010 yarco.yang
476 *
477 * [MT6620 and MT5931] SW Migration: Add ADDBA support
478 *
479 * 07 08 2010 cp.wu
480 *
481 * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
482 *
483 * 07 08 2010 yarco.yang
484 * [WPD00003837][MT6620]Data Path Refine
485 * .
486 *
487 * 07 06 2010 yarco.yang
488 * [WPD00003837][MT6620]Data Path Refine
489 * Use fgInUse instead of fgIsValid for De-queue judgement
490 *
491 * 07 06 2010 yarco.yang
492 * [WPD00003837][MT6620]Data Path Refine
493 * For MMPDU, STA_REC will be decided by caller module
494 *
495 * 07 06 2010 yarco.yang
496 * [WPD00003837][MT6620]Data Path Refine
497 * Add MGMT Packet type for HIF_TX_HEADER
498 *
499 * 06 29 2010 yarco.yang
500 * [WPD00003837][MT6620]Data Path Refine
501 * replace g_rQM with Adpater->rQM
502 *
503 * 06 25 2010 cp.wu
504 * [WPD00003833][MT6620 and MT5931] Driver migration
505 * add API in que_mgt to retrieve sta-rec index for security frames.
506 *
507 * 06 23 2010 yarco.yang
508 * [WPD00003837][MT6620]Data Path Refine
509 * Merge g_arStaRec[] into adapter->arStaRec[]
510 *
511 * 06 21 2010 yarco.yang
512 * [WPD00003837][MT6620]Data Path Refine
513 * Support CFG_MQM_MIGRATION flag
514 *
515 * 06 11 2010 cp.wu
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
522 *
523 * 06 06 2010 kevin.huang
524 * [WPD00003832][MT6620 5931] Create driver base
525 * [MT6620 5931] Create driver base
526 *
527 * 03 31 2010 tehuang.liu
528 * [WPD00001943]Create WiFi test driver framework on WinXP
529 * Refined the debug msg
530 *
531 * 03 30 2010 cp.wu
532 * [WPD00001943]Create WiFi test driver framework on WinXP
533 * comment out one assertion which refer to undefined data member.
534 *
535 * 03 30 2010 tehuang.liu
536 * [WPD00001943]Create WiFi test driver framework on WinXP
537 * Enabled adaptive TC resource control
538 *
539 * 03 24 2010 jeffrey.chang
540 * [WPD00003826]Initial import for Linux port
541 * initial import for Linux port
542 *
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)
546 *
547 * 03 11 2010 tehuang.liu
548 * [WPD00001943]Create WiFi test driver framework on WinXP
549 * Fixed buffer leak when processing BAR frames
550 *
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
554 *
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)
558 *
559 * 02 25 2010 tehuang.liu
560 * [WPD00001943]Create WiFi test driver framework on WinXP
561 * Refined function qmDetermineStaRecIndex() for BMCAST packets
562 *
563 * 02 25 2010 tehuang.liu
564 * [WPD00001943]Create WiFi test driver framework on WinXP
565 * Enabled multi-STA TX path with fairness
566 *
567 * 02 24 2010 tehuang.liu
568 * [WPD00001943]Create WiFi test driver framework on WinXP
569 * Enabled dynamically activating and deactivating STA_RECs
570 *
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.
574 *
575 * 01 13 2010 tehuang.liu
576 * [WPD00001943]Create WiFi test driver framework on WinXP
577 * Enabled the 802.1x path
578 *
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
601** Initial version
602**
603*/
604
605/*******************************************************************************
606* C O M P I L E R F L A G S
607********************************************************************************
608*/
609
610/*******************************************************************************
611* E X T E R N A L R E F E R E N C E S
612********************************************************************************
613*/
614#include "precomp.h"
615#include "queue.h"
616
617extern UINT_8 g_arTdlsLink[MAXNUM_TDLS_PEER];
618
619/*******************************************************************************
620* C O N S T A N T S
621********************************************************************************
622*/
623
624/*******************************************************************************
625* D A T A T Y P E S
626********************************************************************************
627*/
628
629/*******************************************************************************
630* P U B L I C D A T A
631********************************************************************************
632*/
633OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM];
634
635const 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 */
644};
645
646const 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 */
651};
652
653const UINT_8 arNetwork2TcResource[HW_BSSID_NUM + 1][NET_TC_NUM] = {
654 /* HW Queue Set 1 */
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 */
661
662 /* HW Queue Set 2 */
663 /* {TC7_INDEX, TC6_INDEX, TC8_INDEX, TC9_INDEX, TC4_INDEX, TC10_INDEX}, */
664};
665
666const UINT_8 aucWmmAC2TcResourceSet1[WMM_AC_INDEX_NUM] = {
667 TC1_INDEX,
668 TC0_INDEX,
669 TC2_INDEX,
670 TC3_INDEX
671};
672
673#if NIC_TX_ENABLE_SECOND_HW_QUEUE
674const UINT_8 aucWmmAC2TcResourceSet2[WMM_AC_INDEX_NUM] = {
675 TC7_INDEX,
676 TC6_INDEX,
677 TC8_INDEX,
678 TC9_INDEX
679};
680#endif
681/*******************************************************************************
682* P R I V A T E D A T A
683********************************************************************************
684*/
685
686
687/*******************************************************************************
688* M A C R O S
689********************************************************************************
690*/
691
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 */ \
699 }
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; \
706 } \
707 /* ToDo[6630]: defragmentation */ \
708 if (prCurrSwRfb->fgFragFrame) { \
709 prCurrSwRfb = incRxDefragMPDU(prAdapter, prCurrSwRfb, prReturnedQue); \
710 if (prCurrSwRfb) { \
711 prRxStatus = prCurrSwRfb->prRxStatus; \
712 DBGLOG(QM, TRACE, ("defragmentation RxStatus=%x\n", prRxStatus)); \
713 } \
714 } \
715 if (prCurrSwRfb) { \
716 fgMicErr = FALSE; \
717 if (HAL_RX_STATUS_GET_SEC_MODE(prRxStatus) == CIPHER_SUITE_TKIP_WO_MIC) { \
718 if (prCurrSwRfb->prStaRec) { \
719 UINT_8 ucBssIndex; \
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); \
725 ASSERT(prBssInfo); \
726 if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { \
727 pucMicKey = &(prAdapter->rWifiVar.rAisSpecificBssInfo.aucRxMicKey[0]); \
728 } \
729 else { \
730 ASSERT(FALSE); \
731 /* pucMicKey = &prCurrSwRfb->prStaRec->aucRxMicKey[0]; */ \
732 } \
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")); \
737 fgMicErr = TRUE; \
738 } \
739 else if (tkipMicDecapsulate(prCurrSwRfb, pucMicKey) == FALSE) { \
740 fgMicErr = TRUE; \
741 } \
742 } \
743 if (fgMicErr) { \
744 DBGLOG(RX, ERROR, ("Mark NULL the Packet for TKIP Mic Error\n")); \
745 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; \
746 } \
747 } \
748 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb); \
749 }
750#endif
751
752
753/*******************************************************************************
754* F U N C T I O N D E C L A R A T I O N S
755********************************************************************************
756*/
757
758/*******************************************************************************
759* F U N C T I O N S
760********************************************************************************
761*/
762
763/*----------------------------------------------------------------------------*/
764/*!
765* \brief Init Queue Managment for TX
766*
767* \param[in] (none)
768*
769* \return (none)
770*/
771/*----------------------------------------------------------------------------*/
772VOID qmInit(IN P_ADAPTER_T prAdapter)
773{
774 UINT_32 u4Idx;
775#if QM_ADAPTIVE_TC_RESOURCE_CTRL
776 UINT_32 u4TotalMinReservedTcResource = 0;
777 UINT_32 u4TotalTcResource = 0;
778 UINT_32 u4TotalGurantedTcResource = 0;
779#endif
780
781 P_QUE_MGT_T prQM = &prAdapter->rQM;
782
783 /* DbgPrint("QM: Enter qmInit()\n"); */
784
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]));
788 }
789
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;
797
798 prQM->arRxBaTable[u4Idx].fgIsWaitingForPktWithSsn = FALSE;
799 prQM->arRxBaTable[u4Idx].fgHasBubble = FALSE;
800
801 cnmTimerInitTimer(prAdapter,
802 &(prQM->arRxBaTable[u4Idx].rReorderBubbleTimer),
803 (PFN_MGMT_TIMEOUT_FUNC) qmHandleReorderBubbleTimeout,
804 (ULONG) (&prQM->arRxBaTable[u4Idx]));
805
806 }
807 prQM->ucRxBaCount = 0;
808
809 kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout));
810
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;
815 }
816
817 ASSERT(prQM->u4TimeToAdjustTcResource && prQM->u4TimeToUpdateQueLen);
818
819 for(u4Idx = 0; u4Idx < TC_NUM; u4Idx++) {
820 prQM->au4CurrentTcResource[u4Idx] = prAdapter->rTxCtrl.rTc.au2MaxNumOfBuffer[u4Idx];
821
822 if(u4Idx != TC4_INDEX) {
823 u4TotalTcResource += prQM->au4CurrentTcResource[u4Idx];
824 u4TotalGurantedTcResource += prQM->au4GuaranteedTcResource[u4Idx];
825 u4TotalMinReservedTcResource += prQM->au4MinReservedTcResource[u4Idx];
826 }
827 }
828
829 /* Sanity Check */
830 if(u4TotalMinReservedTcResource > u4TotalTcResource) {
831 kalMemZero(prQM->au4MinReservedTcResource, sizeof(prQM->au4MinReservedTcResource));
832 }
833
834 if(u4TotalGurantedTcResource > u4TotalTcResource) {
835 kalMemZero(prQM->au4GuaranteedTcResource, sizeof(prQM->au4GuaranteedTcResource));
836 }
837
838 u4TotalGurantedTcResource = 0;
839
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];
844 }
845
846 if(u4Idx != TC4_INDEX) {
847 u4TotalGurantedTcResource += prQM->au4GuaranteedTcResource[u4Idx];
848 }
849 }
850
851 prQM->u4ResidualTcResource = u4TotalTcResource - u4TotalGurantedTcResource;
852
853 prQM->fgTcResourcePostAnnealing = FALSE;
854
855#if QM_FAST_TC_RESOURCE_CTRL
856 prQM->fgTcResourceFastReaction = FALSE;
857#endif
858
859#endif
860
861#if QM_TEST_MODE
862 prQM->u4PktCount = 0;
863
864#if QM_TEST_FAIR_FORWARDING
865
866 prQM->u4CurrentStaRecIndexToEnqueue = 0;
867 {
868 UINT_8 aucMacAddr[MAC_ADDR_LEN];
869 P_STA_RECORD_T prStaRec;
870
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;
878
879 prStaRec = &prAdapter->arStaRec[1];
880 ASSERT(prStaRec);
881
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);
887
888 }
889
890#endif
891
892#endif
893
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;
898 }
899
900 prQM->u4GlobalResourceUsedCount = 0;
901#endif
902
903 prQM->u4TxAllowedStaCount = 0;
904
905}
906
907#if QM_TEST_MODE
908VOID qmTestCases(IN P_ADAPTER_T prAdapter)
909{
910 P_QUE_MGT_T prQM = &prAdapter->rQM;
911
912 DbgPrint("QM: ** TEST MODE **\n");
913
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");
918 } else {
919 prAdapter->arStaRec[0].fgIsValid = TRUE;
920 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
921 }
922 }
923
924 if (QM_TEST_STA_REC_DEACTIVATION) {
925 /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */
926
927 if (prAdapter->arStaRec[0].fgIsValid) {
928
929 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
930 qmDeactivateStaRec(prAdapter, &prAdapter->arStaRec[0]);
931 } else {
932
933 UINT_8 aucMacAddr[MAC_ADDR_LEN];
934
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;
942
943 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
944 qmActivateStaRec(prAdapter, /* Adapter pointer */
945 0, /* STA_REC index from FW */
946 TRUE, /* fgIsQoS */
947 NETWORK_TYPE_AIS_INDEX, /* Network type */
948 TRUE, /* fgIsAp */
949 aucMacAddr /* MAC address */
950 );
951 }
952 }
953
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);
960 }
961 }
962
963}
964#endif
965
966/*----------------------------------------------------------------------------*/
967/*!
968* \brief Update a STA_REC
969*
970* \param[in] prAdapter Pointer to the Adapter instance
971* \param[in] prStaRec The pointer of the STA_REC
972*
973* \return (none)
974*/
975/*----------------------------------------------------------------------------*/
976VOID qmUpdateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
977{
978 P_BSS_INFO_T prBssInfo;
979 BOOLEAN fgIsTxAllowed = FALSE;
980
981 if (!prStaRec) {
982 return;
983 }
984
985 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
986
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;
993 }
994 }
995 /* 4 <2.2> OPEN security */
996 else {
997 fgIsTxAllowed = TRUE;
998 }
999 }
1000 /* 4 <x> Update StaRec */
1001 if (prStaRec->fgIsTxAllowed != fgIsTxAllowed) {
1002 if (fgIsTxAllowed) {
1003 prAdapter->rQM.u4TxAllowedStaCount++;
1004 } else {
1005 prAdapter->rQM.u4TxAllowedStaCount--;
1006 }
1007 }
1008
1009 prStaRec->fgIsTxAllowed = fgIsTxAllowed;
1010
1011}
1012
1013
1014/*----------------------------------------------------------------------------*/
1015/*!
1016* \brief Activate a STA_REC
1017*
1018* \param[in] prAdapter Pointer to the Adapter instance
1019* \param[in] prStaRec The pointer of the STA_REC
1020*
1021* \return (none)
1022*/
1023/*----------------------------------------------------------------------------*/
1024VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
1025{
1026 /* 4 <1> Deactivate first */
1027 if (!prStaRec) {
1028 return;
1029 }
1030
1031 if (prStaRec->fgIsValid) { /* The STA_REC has been activated */
1032 DBGLOG(QM, WARN,
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 */
1036 }
1037 /* 4 <2> Activate the STA_REC */
1038 /* Reset buffer count */
1039 prStaRec->ucFreeQuota = 0;
1040 prStaRec->ucFreeQuotaForDelivery = 0;
1041 prStaRec->ucFreeQuotaForNonDelivery = 0;
1042
1043 /* Init the STA_REC */
1044 prStaRec->fgIsValid = TRUE;
1045 prStaRec->fgIsInPS = FALSE;
1046
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);
1050
1051 nicTxGenerateDescTemplate(prAdapter, prStaRec);
1052
1053 qmUpdateStaRec(prAdapter, prStaRec);
1054
1055 /* Done in qmInit() or qmDeactivateStaRec() */
1056#if 0
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;
1060 }
1061#endif
1062
1063 DBGLOG(QM, INFO, ("QM: +STA[%ld]\n", (UINT_32) prStaRec->ucIndex));
1064}
1065
1066/*----------------------------------------------------------------------------*/
1067/*!
1068* \brief Deactivate a STA_REC
1069*
1070* \param[in] prAdapter Pointer to the Adapter instance
1071* \param[in] u4StaRecIdx The index of the STA_REC
1072*
1073* \return (none)
1074*/
1075/*----------------------------------------------------------------------------*/
1076VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
1077{
1078 UINT_32 i;
1079 P_MSDU_INFO_T prFlushedTxPacketList = NULL;
1080
1081 if (!prStaRec) {
1082 return;
1083 }
1084 /* 4 <1> Flush TX queues */
1085 prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, prStaRec->ucIndex);
1086
1087 if (prFlushedTxPacketList) {
1088 wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList);
1089 }
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);
1094 }
1095
1096 /* 4 <3> Deactivate the STA_REC */
1097 prStaRec->fgIsValid = FALSE;
1098 prStaRec->fgIsInPS = FALSE;
1099 prStaRec->fgIsTxKeyReady = FALSE;
1100
1101 /* Reset buffer count */
1102 prStaRec->ucFreeQuota = 0;
1103 prStaRec->ucFreeQuotaForDelivery = 0;
1104 prStaRec->ucFreeQuotaForNonDelivery = 0;
1105
1106 nicTxFreeDescTemplate(prAdapter, prStaRec);
1107
1108 qmUpdateStaRec(prAdapter, prStaRec);
1109
1110 DBGLOG(QM, INFO, ("QM: -STA[%u]\n", prStaRec->ucIndex));
1111}
1112
1113
1114/*----------------------------------------------------------------------------*/
1115/*!
1116* \brief Deactivate a STA_REC
1117*
1118* \param[in] prAdapter Pointer to the Adapter instance
1119* \param[in] ucBssIndex The index of the BSS
1120*
1121* \return (none)
1122*/
1123/*----------------------------------------------------------------------------*/
1124VOID qmFreeAllByBssIdx(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIndex)
1125{
1126
1127 P_QUE_MGT_T prQM;
1128 P_QUE_T prQue;
1129 QUE_T rNeedToFreeQue;
1130 QUE_T rTempQue;
1131 P_QUE_T prNeedToFreeQue;
1132 P_QUE_T prTempQue;
1133 P_MSDU_INFO_T prMsduInfo;
1134
1135
1136 prQM = &prAdapter->rQM;
1137 prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
1138
1139 QUEUE_INITIALIZE(&rNeedToFreeQue);
1140 QUEUE_INITIALIZE(&rTempQue);
1141
1142 prNeedToFreeQue = &rNeedToFreeQue;
1143 prTempQue = &rTempQue;
1144
1145 QUEUE_MOVE_ALL(prTempQue, prQue);
1146
1147 QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
1148 while (prMsduInfo) {
1149
1150 if (prMsduInfo->ucBssIndex == ucBssIndex) {
1151 QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T) prMsduInfo);
1152 } else {
1153 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo);
1154 }
1155
1156 QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
1157 }
1158 if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) {
1159 wlanProcessQueuedMsduInfo(prAdapter,
1160 (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue));
1161 }
1162
1163}
1164
1165/*----------------------------------------------------------------------------*/
1166/*!
1167* \brief Flush all TX queues
1168*
1169* \param[in] (none)
1170*
1171* \return The flushed packets (in a list of MSDU_INFOs)
1172*/
1173/*----------------------------------------------------------------------------*/
1174P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter)
1175{
1176 UINT_8 ucStaArrayIdx;
1177 UINT_8 ucQueArrayIdx;
1178
1179 P_MSDU_INFO_T prMsduInfoListHead;
1180 P_MSDU_INFO_T prMsduInfoListTail;
1181
1182 P_QUE_MGT_T prQM = &prAdapter->rQM;
1183
1184 DBGLOG(QM, TRACE, ("QM: Enter qmFlushTxQueues()\n"));
1185
1186 prMsduInfoListHead = NULL;
1187 prMsduInfoListTail = NULL;
1188
1189 /* Concatenate all MSDU_INFOs in per-STA queues */
1190 for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++) {
1191
1192 /* Always check each STA_REC when flushing packets no matter it is inactive or active */
1193#if 0
1194 if (!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid) {
1195 continue; /* Continue to check the next STA_REC */
1196 }
1197#endif
1198
1199 for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) {
1200 if (QUEUE_IS_EMPTY
1201 (&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))) {
1202 continue; /* Continue to check the next TX queue of the same STA */
1203 }
1204
1205 if (!prMsduInfoListHead) {
1206
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]);
1214 } else {
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]));
1220
1221 prMsduInfoListTail = (P_MSDU_INFO_T)
1222 QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].
1223 arTxQueue[ucQueArrayIdx]);
1224 }
1225
1226 QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].
1227 arTxQueue[ucQueArrayIdx]);
1228 }
1229 }
1230
1231 /* Flush per-Type queues */
1232 for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++) {
1233
1234 if (QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))) {
1235 continue; /* Continue to check the next TX queue of the same STA */
1236 }
1237
1238 if (!prMsduInfoListHead) {
1239
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]);
1245 } else {
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]));
1249
1250 prMsduInfoListTail = (P_MSDU_INFO_T)
1251 QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]);
1252 }
1253
1254 QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]);
1255
1256 }
1257
1258 if (prMsduInfoListTail) {
1259 /* Terminate the MSDU_INFO list with a NULL pointer */
1260 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL);
1261 }
1262
1263 return prMsduInfoListHead;
1264}
1265
1266
1267/*----------------------------------------------------------------------------*/
1268/*!
1269* \brief Flush TX packets for a particular STA
1270*
1271* \param[in] u4StaRecIdx STA_REC index
1272*
1273* \return The flushed packets (in a list of MSDU_INFOs)
1274*/
1275/*----------------------------------------------------------------------------*/
1276P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx)
1277{
1278 UINT_8 ucQueArrayIdx;
1279 P_MSDU_INFO_T prMsduInfoListHead;
1280 P_MSDU_INFO_T prMsduInfoListTail;
1281 P_STA_RECORD_T prStaRec;
1282
1283 DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx));
1284
1285 ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD);
1286
1287 prMsduInfoListHead = NULL;
1288 prMsduInfoListTail = NULL;
1289
1290 prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
1291 ASSERT(prStaRec);
1292
1293 /* No matter whether this is an activated STA_REC, do flush */
1294#if 0
1295 if (!prStaRec->fgIsValid) {
1296 return NULL;
1297 }
1298#endif
1299
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]))) {
1303 continue;
1304 }
1305
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]);
1312 } else {
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]));
1317
1318 prMsduInfoListTail =
1319 (P_MSDU_INFO_T) QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]);
1320 }
1321
1322 QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]);
1323
1324 }
1325
1326#if 0
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));
1331 } else {
1332 prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx);
1333 }
1334#endif
1335
1336 return prMsduInfoListHead;
1337
1338}
1339
1340/*----------------------------------------------------------------------------*/
1341/*!
1342* \brief Flush RX packets
1343*
1344* \param[in] (none)
1345*
1346* \return The flushed packets (in a list of SW_RFBs)
1347*/
1348/*----------------------------------------------------------------------------*/
1349P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter)
1350{
1351 UINT_32 i;
1352 P_SW_RFB_T prSwRfbListHead;
1353 P_SW_RFB_T prSwRfbListTail;
1354 P_QUE_MGT_T prQM = &prAdapter->rQM;
1355
1356 prSwRfbListHead = prSwRfbListTail = NULL;
1357
1358 DBGLOG(QM, TRACE, ("QM: Enter qmFlushRxQueues()\n"));
1359
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) {
1363
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));
1369 } else {
1370 /* Concatenate the MSDU_INFO list with the existing list */
1371 QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail,
1372 QUEUE_GET_HEAD(&
1373 (prQM->arRxBaTable[i].
1374 rReOrderQue)));
1375
1376 prSwRfbListTail = (P_SW_RFB_T)
1377 QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue));
1378 }
1379
1380 QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue));
1381
1382 } else {
1383 continue;
1384 }
1385 }
1386
1387 if (prSwRfbListTail) {
1388 /* Terminate the MSDU_INFO list with a NULL pointer */
1389 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1390 }
1391 return prSwRfbListHead;
1392
1393}
1394
1395
1396/*----------------------------------------------------------------------------*/
1397/*!
1398* \brief Flush RX packets with respect to a particular STA
1399*
1400* \param[in] u4StaRecIdx STA_REC index
1401* \param[in] u4Tid TID
1402*
1403* \return The flushed packets (in a list of SW_RFBs)
1404*/
1405/*----------------------------------------------------------------------------*/
1406P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx, IN UINT_32 u4Tid)
1407{
1408 /* UINT_32 i; */
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;
1413
1414 DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx));
1415
1416 prSwRfbListHead = prSwRfbListTail = NULL;
1417
1418 prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
1419 ASSERT(prStaRec);
1420
1421 /* No matter whether this is an activated STA_REC, do flush */
1422#if 0
1423 if (!prStaRec->fgIsValid) {
1424 return NULL;
1425 }
1426#endif
1427
1428 /* Obtain the RX BA Entry pointer */
1429 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]);
1430
1431 /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */
1432 if (prReorderQueParm) {
1433
1434 if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) {
1435
1436 prSwRfbListHead = (P_SW_RFB_T)
1437 QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue));
1438 prSwRfbListTail = (P_SW_RFB_T)
1439 QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue));
1440
1441
1442 QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue));
1443
1444 }
1445 }
1446
1447 if (prSwRfbListTail) {
1448 /* Terminate the MSDU_INFO list with a NULL pointer */
1449 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1450 }
1451 return prSwRfbListHead;
1452
1453
1454}
1455
1456P_QUE_T qmDetermineStaTxQueue(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo,
1457 OUT PUINT_8 pucTC)
1458{
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;
1463 UINT_8 ucTC;
1464 P_BSS_INFO_T prBssInfo;
1465 UINT_8 aucNextUP[WMM_AC_INDEX_NUM] =
1466 {1 /* BEtoBK */,
1467 1 /* na */,
1468 0 /* VItoBE */,
1469 4 /* VOtoVI */};
1470
1471 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
1472 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prMsduInfo->ucStaRecIndex);
1473
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 */
1478 }
1479
1480 eAci = WMM_AC_BE_INDEX;
1481 do {
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];
1488 } else {
1489 prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1];
1490 ucTC = TC1_INDEX;
1491 eAci = WMM_AC_BE_INDEX;
1492 DBGLOG(QM, WARN, ("Packet TID is not in [0~7]\n"));
1493 ASSERT(0);
1494 }
1495 if ((prBssInfo->arACQueParms[eAci].ucIsACMSet) && (eAci != WMM_AC_BK_INDEX)) {
1496 prMsduInfo->ucUserPriority = aucNextUP[eAci];
1497 fgCheckACMAgain = TRUE;
1498 }
1499 } else {
1500 prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_NON_QOS];
1501 ucTC = arNetwork2TcResource[prMsduInfo->ucBssIndex][NET_TC_NON_STAREC_NON_QOS_INDEX];
1502 }
1503
1504 if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) {
1505 ucTC = prAdapter->rWifiVar.ucTcRestrict;
1506 prTxQue = &prStaRec->arTxQueue[ucTC];
1507 }
1508
1509 } while (fgCheckACMAgain);
1510
1511 *pucTC = ucTC;
1512
1513 return prTxQue;
1514}
1515
1516VOID
1517qmSetTxPacketDescTemplate(IN P_ADAPTER_T prAdapter,
1518 IN P_MSDU_INFO_T prMsduInfo)
1519{
1520 P_STA_RECORD_T prStaRec =
1521 QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prMsduInfo->ucStaRecIndex);
1522
1523 /* Check the Tx descriptor template is valid */
1524 if (prStaRec && prStaRec->aprTxDescTemplate[prMsduInfo->ucUserPriority]) {
1525 prMsduInfo->fgIsTXDTemplateValid = TRUE;
1526 } else {
1527 if (prStaRec) {
1528 DBGLOG(QM, TRACE,
1529 ("Cannot get TXD template for STA[%u] QoS[%u] MSDU UP[%u]\n",
1530 prStaRec->ucIndex, prStaRec->fgIsQoS,
1531 prMsduInfo->ucUserPriority));
1532 }
1533 prMsduInfo->fgIsTXDTemplateValid = FALSE;
1534 }
1535}
1536
1537
1538/*----------------------------------------------------------------------------*/
1539/*!
1540* \brief Enqueue TX packets
1541*
1542* \param[in] prMsduInfoListHead Pointer to the list of TX packets
1543*
1544* \return The freed packets, which are not enqueued
1545*/
1546/*----------------------------------------------------------------------------*/
1547P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead)
1548{
1549 P_MSDU_INFO_T prMsduInfoReleaseList;
1550 P_MSDU_INFO_T prCurrentMsduInfo;
1551 P_MSDU_INFO_T prNextMsduInfo;
1552
1553 P_QUE_T prTxQue;
1554 QUE_T rNotEnqueuedQue;
1555
1556 UINT_8 ucTC;
1557 P_QUE_MGT_T prQM = &prAdapter->rQM;
1558 P_BSS_INFO_T prBssInfo;
1559 BOOLEAN fgDropPacket;
1560
1561 DBGLOG(QM, LOUD, ("Enter qmEnqueueTxPackets\n"));
1562
1563 ASSERT(prMsduInfoListHead);
1564
1565 prMsduInfoReleaseList = NULL;
1566 prCurrentMsduInfo = NULL;
1567 QUEUE_INITIALIZE(&rNotEnqueuedQue);
1568 prNextMsduInfo = prMsduInfoListHead;
1569
1570 do {
1571 prCurrentMsduInfo = prNextMsduInfo;
1572 prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo);
1573 ucTC = TC1_INDEX;
1574
1575 /* 4 <0> Sanity check of BSS_INFO */
1576 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prCurrentMsduInfo->ucBssIndex);
1577
1578 if (!prBssInfo) {
1579 /* No BSS_INFO */
1580 fgDropPacket = TRUE;
1581 } else if (IS_BSS_ACTIVE(prBssInfo)) {
1582 /* BSS active */
1583 fgDropPacket = FALSE;
1584 } else {
1585 /* BSS inactive */
1586 fgDropPacket = TRUE;
1587 }
1588
1589 if (!fgDropPacket) {
1590 /* 4 <1> Lookup the STA_REC index */
1591 /* The ucStaRecIndex will be set in this function */
1592 qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo);
1593
1594 DBGLOG(QM, LOUD,
1595 ("Enqueue MSDU by StaRec[%u]!\n", prCurrentMsduInfo->ucStaRecIndex));
1596
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];
1602
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);
1606 }
1607
1608 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23);
1609 break;
1610
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"));
1614
1615 prTxQue = &rNotEnqueuedQue;
1616
1617 TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_STA_DROP);
1618 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24);
1619 break;
1620
1621 default:
1622 prTxQue = qmDetermineStaTxQueue(prAdapter, prCurrentMsduInfo, &ucTC);
1623 break; /*default */
1624 } /* switch (prCurrentMsduInfo->ucStaRecIndex) */
1625
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));
1630
1631 if (prTxQue->u4NumElem >= prQM->u4MaxForwardBufferCount) {
1632 DBGLOG(QM, INFO,
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);
1637 }
1638 }
1639
1640 } else {
1641 DBGLOG(QM, TRACE,
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);
1647 }
1648
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).
1652 */
1653 prCurrentMsduInfo->ucTC = ucTC;
1654
1655 /* Check the Tx descriptor template is valid */
1656 qmSetTxPacketDescTemplate(prAdapter, prCurrentMsduInfo);
1657
1658 /* 4 <4> Enqueue the packet */
1659 QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T) prCurrentMsduInfo);
1660
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);
1665 }
1666#endif
1667
1668#if QM_TEST_MODE
1669 if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) {
1670 prQM->u4PktCount = 0;
1671 qmTestCases(prAdapter);
1672 }
1673#endif
1674
1675 DBGLOG(QM, LOUD, ("Current queue length = %u\n", prTxQue->u4NumElem));
1676 } while (prNextMsduInfo);
1677
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);
1681 }
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);
1686#endif
1687
1688 return prMsduInfoReleaseList;
1689}
1690
1691/*----------------------------------------------------------------------------*/
1692/*!
1693* \brief Determine the STA_REC index for a packet
1694*
1695* \param[in] prMsduInfo Pointer to the packet
1696*
1697* \return (none)
1698*/
1699/*----------------------------------------------------------------------------*/
1700VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
1701{
1702 UINT_32 i;
1703
1704 P_STA_RECORD_T prTempStaRec;
1705 P_BSS_INFO_T prBssInfo;
1706
1707 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
1708 prTempStaRec = NULL;
1709
1710 ASSERT(prMsduInfo);
1711
1712 DBGLOG(QM, LOUD, ("Msdu BSS Idx[%u] OpMode[%u] StaRecOfApExist[%u]\n",
1713 prMsduInfo->ucBssIndex,
1714 prBssInfo->eCurrentOPMode, prBssInfo->prStaRecOfAP ? TRUE : FALSE));
1715
1716 switch (prBssInfo->eCurrentOPMode) {
1717 case OP_MODE_IBSS:
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"));
1723 return;
1724 }
1725 break;
1726
1727 /* Infra Client/GC */
1728 case OP_MODE_INFRASTRUCTURE:
1729 case OP_MODE_BOW:
1730 if (prBssInfo->prStaRecOfAP) {
1731#if CFG_SUPPORT_TDLS
1732
1733 prTempStaRec =
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;
1739 return;
1740 }
1741 }
1742#endif
1743 /* 4 <2> Check if an AP STA is present */
1744 prTempStaRec = prBssInfo->prStaRecOfAP;
1745
1746 DBGLOG(QM, LOUD,
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));
1751
1752 if (prTempStaRec->fgIsInUse) {
1753 prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex;
1754 DBGLOG(QM, LOUD, ("TX with AP_STA[%u]\n", prTempStaRec->ucIndex));
1755 return;
1756 }
1757 }
1758 break;
1759
1760 case OP_MODE_P2P_DEVICE:
1761 break;
1762
1763 default:
1764 break;
1765 }
1766
1767
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));
1775 return;
1776 }
1777 }
1778 }
1779
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"));
1783
1784#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING)
1785 prMsduInfo->ucStaRecIndex = (UINT_8) prQM->u4CurrentStaRecIndexToEnqueue;
1786#endif
1787}
1788
1789P_STA_RECORD_T qmDetermineStaToBeDequeued(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StartStaRecIndex)
1790{
1791
1792 return NULL;
1793}
1794
1795P_QUE_T qmDequeueStaTxPackets(IN P_ADAPTER_T prAdapter)
1796{
1797
1798 return NULL;
1799}
1800
1801/*----------------------------------------------------------------------------*/
1802/*!
1803* \brief Dequeue TX packets from a STA_REC for a particular TC
1804*
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
1808*
1809* \return (none)
1810*/
1811/*----------------------------------------------------------------------------*/
1812UINT_32
1813qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter,
1814 OUT P_QUE_T prQue,
1815 IN UINT_8 ucTC,
1816 IN UINT_32 u4CurrentQuota, IN UINT_32 u4TotalQuota)
1817{
1818 UINT_32 ucLoop; /* Loop for */
1819
1820 UINT_32 u4CurStaIndex = 0;
1821 UINT_32 u4CurStaUsedResource = 0;
1822
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 */
1827
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;
1832
1833 BOOLEAN fgEndThisRound;
1834 P_QUE_MGT_T prQM = &prAdapter->rQM;
1835
1836 PUINT_8 pucPsStaFreeQuota;
1837
1838 /* Sanity Check */
1839 if (!u4CurrentQuota) {
1840 DBGLOG(TX, LOUD, ("(Fairness) Skip TC = %u u4CurrentQuota = %u\n",
1841 ucTC, u4CurrentQuota));
1842 return u4CurrentQuota;
1843 }
1844 /* 4 <1> Assign init value */
1845 u4AvaliableResource = u4CurrentQuota;
1846 u4MaxResourceLimit = u4TotalQuota;
1847
1848#if QM_FORWARDING_FAIRNESS
1849 u4CurStaIndex = prQM->au4HeadStaRecIndex[ucTC];
1850 u4CurStaUsedResource = prQM->au4ResourceUsedCount[ucTC];
1851#endif
1852
1853 fgEndThisRound = FALSE;
1854 ucLoop = 0;
1855 u4CurStaForwardFrameCount = 0;
1856
1857 DBGLOG(QM, LOUD, ("(Fairness) TC[%u] Init Head STA[%u] Resource[%u]\n",
1858 ucTC, u4CurStaIndex, u4AvaliableResource));
1859
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];
1864
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);
1869
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;
1875
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;
1885 } else {
1886 /* ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); */
1887 u4MaxForwardFrameCountLimit =
1888 prStaRec->ucFreeQuotaForNonDelivery;
1889 pucPsStaFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1890 }
1891
1892 }
1893
1894 /* fgIsInPS */
1895 /* Absent BSS handling */
1896 if (prBssInfo->fgIsNetAbsent) {
1897 if (u4MaxForwardFrameCountLimit > prBssInfo->ucBssFreeQuota) {
1898 u4MaxForwardFrameCountLimit = prBssInfo->ucBssFreeQuota;
1899 }
1900 }
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);
1905
1906 if ((u4CurStaForwardFrameCount >= u4MaxForwardFrameCountLimit) ||
1907 (u4CurStaUsedResource >= u4MaxResourceLimit)) {
1908 /* Exceeds Limit */
1909
1910 break;
1911 } else if (prDequeuedPkt->ucPageCount > u4AvaliableResource) {
1912 /* Avaliable Resource is not enough */
1913 if (!(prAdapter->rWifiVar.ucAlwaysResetUsedRes & BIT(0))) {
1914 fgEndThisRound = TRUE;
1915 }
1916 break;
1917 } else {
1918 /* Avaliable to be Tx */
1919
1920 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt,
1921 P_MSDU_INFO_T);
1922
1923 if (!QUEUE_IS_EMPTY(prCurrQueue)) {
1924 /* XXX: check all queues for STA */
1925 prDequeuedPkt->ucPsForwardingType =
1926 PS_FORWARDING_MORE_DATA_ENABLED;
1927 }
1928
1929 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt);
1930
1931 u4AvaliableResource -= prDequeuedPkt->ucPageCount;
1932 u4CurStaUsedResource += prDequeuedPkt->ucPageCount;
1933 u4CurStaForwardFrameCount++;
1934 }
1935
1936 }
1937
1938 /* AP mode: Update STA in PS Free quota */
1939 if (prStaRec->fgIsInPS && pucPsStaFreeQuota) {
1940 if ((*pucPsStaFreeQuota) >= u4CurStaForwardFrameCount) {
1941 (*pucPsStaFreeQuota) -= u4CurStaForwardFrameCount;
1942 } else {
1943 (*pucPsStaFreeQuota) = 0;
1944 }
1945 }
1946
1947 if (prBssInfo->fgIsNetAbsent) {
1948 if (prBssInfo->ucBssFreeQuota >= u4CurStaForwardFrameCount) {
1949 prBssInfo->ucBssFreeQuota -= u4CurStaForwardFrameCount;
1950 } else {
1951 prBssInfo->ucBssFreeQuota = 0;
1952 }
1953 }
1954 }
1955
1956 if (fgEndThisRound) {
1957 /* End this round */
1958 break;
1959 }
1960
1961 /* Prepare for next STA */
1962 ucLoop++;
1963 u4CurStaIndex++;
1964 u4CurStaIndex %= CFG_NUM_OF_STA_RECORD;
1965 u4CurStaUsedResource = 0;
1966 u4CurStaForwardFrameCount = 0;
1967 }
1968
1969
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;
1974 }
1975#if QM_FORWARDING_FAIRNESS
1976 prQM->au4HeadStaRecIndex[ucTC] = u4CurStaIndex;
1977 prQM->au4ResourceUsedCount[ucTC] = u4CurStaUsedResource;
1978#endif
1979
1980 DBGLOG(QM, LOUD, ("(Fairness) TC[%u] Scheduled Head STA[%u] Left Resource[%u]\n",
1981 ucTC, u4CurStaIndex, u4AvaliableResource));
1982
1983 return u4AvaliableResource;
1984}
1985
1986/*----------------------------------------------------------------------------*/
1987/*!
1988* \brief Dequeue TX packets from a per-Type-based Queue for a particular TC
1989*
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
1993*
1994* \return (none)
1995*/
1996/*----------------------------------------------------------------------------*/
1997VOID
1998qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter,
1999 OUT P_QUE_T prQue,
2000 IN UINT_8 ucTC,
2001 IN UINT_32 u4CurrentQuota, IN UINT_32 u4TotalQuota)
2002{
2003 UINT_32 u4AvaliableResource, u4LeftResource;
2004 UINT_32 u4MaxResourceLimit;
2005 UINT_32 u4TotalUsedResource = 0;
2006 P_QUE_MGT_T prQM;
2007 PFN_DEQUEUE_FUNCTION pfnDeQFunc[2];
2008 BOOLEAN fgChangeDeQFunc = TRUE;
2009 BOOLEAN fgGlobalQueFirst = TRUE;
2010
2011 DBGLOG(QM, LOUD, ("Enter %s (TC = %d, quota = %u)\n", __func__, ucTC, u4CurrentQuota));
2012
2013 /* TC5: Broadcast/Multicast data packets */
2014 if ((u4CurrentQuota == 0) || (ucTC != TC5_INDEX)) {
2015 return;
2016 }
2017
2018 prQM = &prAdapter->rQM;
2019
2020 u4AvaliableResource = u4CurrentQuota;
2021 u4MaxResourceLimit = u4TotalQuota;
2022#if QM_FORWARDING_FAIRNESS
2023 u4TotalUsedResource = prQM->u4GlobalResourceUsedCount;
2024 fgGlobalQueFirst = prQM->fgGlobalQFirst;
2025#endif
2026
2027 /* Dequeue function selection */
2028 if (fgGlobalQueFirst) {
2029 pfnDeQFunc[0] = qmDequeueTxPacketsFromGlobalQueue;
2030 pfnDeQFunc[1] = qmDequeueTxPacketsFromPerStaQueues;
2031 } else {
2032 pfnDeQFunc[0] = qmDequeueTxPacketsFromPerStaQueues;
2033 pfnDeQFunc[1] = qmDequeueTxPacketsFromGlobalQueue;
2034 }
2035
2036 /* 1st dequeue function */
2037 u4LeftResource = pfnDeQFunc[0] (prAdapter,
2038 prQue,
2039 ucTC,
2040 u4AvaliableResource,
2041 (u4MaxResourceLimit - u4TotalUsedResource));
2042
2043 /* dequeue function comsumes no resource, change */
2044 if ((u4LeftResource >= u4AvaliableResource) &&
2045 (u4AvaliableResource >= NIC_TX_MAX_PAGE_PER_FRAME)) {
2046
2047 fgChangeDeQFunc = TRUE;
2048 } else {
2049 u4TotalUsedResource += (u4AvaliableResource - u4LeftResource);
2050 /* Used resource exceeds limit, change */
2051 if (u4TotalUsedResource >= u4MaxResourceLimit) {
2052 fgChangeDeQFunc = TRUE;
2053 }
2054 }
2055
2056 if (fgChangeDeQFunc) {
2057 fgGlobalQueFirst = !fgGlobalQueFirst;
2058 u4TotalUsedResource = 0;
2059 }
2060
2061 /* 2nd dequeue function */
2062 u4LeftResource = pfnDeQFunc[1] (prAdapter, prQue, ucTC, u4LeftResource, u4MaxResourceLimit);
2063
2064#if QM_FORWARDING_FAIRNESS
2065 prQM->fgGlobalQFirst = fgGlobalQueFirst;
2066 prQM->u4GlobalResourceUsedCount = u4TotalUsedResource;
2067#endif
2068
2069} /* qmDequeueTxPacketsFromPerTypeQueues */
2070
2071/*----------------------------------------------------------------------------*/
2072/*!
2073* \brief Dequeue TX packets from a QM global Queue for a particular TC
2074*
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
2078*
2079* \return (none)
2080*/
2081/*----------------------------------------------------------------------------*/
2082UINT_32
2083qmDequeueTxPacketsFromGlobalQueue(IN P_ADAPTER_T prAdapter,
2084 OUT P_QUE_T prQue,
2085 IN UINT_8 ucTC,
2086 IN UINT_32 u4CurrentQuota, IN UINT_32 u4TotalQuota)
2087{
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;
2093 QUE_T rMergeQue;
2094 P_QUE_T prMergeQue;
2095 P_QUE_MGT_T prQM;
2096
2097 DBGLOG(QM, LOUD, ("Enter %s (TC = %d, quota = %u)\n", __func__, ucTC, u4CurrentQuota));
2098
2099 /* TC5: Broadcast/Multicast data packets */
2100 if (u4CurrentQuota == 0) {
2101 return u4CurrentQuota;
2102 }
2103
2104 prQM = &prAdapter->rQM;
2105
2106 /* 4 <1> Determine the queue */
2107 prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
2108 u4AvaliableResource = u4CurrentQuota;
2109 prDequeuedPkt = NULL;
2110 prBurstEndPkt = NULL;
2111
2112 QUEUE_INITIALIZE(&rMergeQue);
2113 prMergeQue = &rMergeQue;
2114
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) {
2119 break;
2120 } else {
2121 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
2122 ASSERT(prDequeuedPkt->ucTC == ucTC);
2123 ASSERT(prDequeuedPkt->ucBssIndex <= MAX_BSS_INDEX);
2124
2125 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prDequeuedPkt->ucBssIndex);
2126
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);
2133 } else {
2134 QUEUE_INSERT_TAIL(prMergeQue,
2135 (P_QUE_ENTRY_T) prDequeuedPkt);
2136 }
2137 } else {
2138 QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL);
2139 wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt);
2140 }
2141 }
2142 }
2143
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);
2148 }
2149
2150 return u4AvaliableResource;
2151}
2152
2153/*----------------------------------------------------------------------------*/
2154/*!
2155* \brief Dequeue TX packets to send to HIF TX
2156*
2157* \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2158*
2159* \return The list of dequeued TX packets
2160*/
2161/*----------------------------------------------------------------------------*/
2162P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus)
2163{
2164 INT_32 i;
2165 P_MSDU_INFO_T prReturnedPacketListHead;
2166 QUE_T rReturnedQue;
2167 UINT_32 u4MaxQuotaLimit;
2168
2169 DBGLOG(QM, LOUD, ("Enter qmDequeueTxPackets\n"));
2170
2171 QUEUE_INITIALIZE(&rReturnedQue);
2172
2173 prReturnedPacketListHead = NULL;
2174
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));
2178
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;
2184 } else {
2185 u4MaxQuotaLimit = (UINT_32) prTcqStatus->au2MaxNumOfPage[i];
2186 }
2187
2188 qmDequeueTxPacketsFromPerStaQueues(prAdapter,
2189 &rReturnedQue,
2190 (UINT_8) i,
2191 (UINT_32) prTcqStatus->au2FreePageCount[i],
2192 u4MaxQuotaLimit);
2193
2194 /* The aggregate number of dequeued packets */
2195 DBGLOG(QM, LOUD, ("DQA)[%u](%lu)\n", i, rReturnedQue.u4NumElem));
2196 }
2197
2198 /* TC5 (BMCAST or non-QoS packets) */
2199 qmDequeueTxPacketsFromPerTypeQueues(prAdapter,
2200 &rReturnedQue,
2201 TC5_INDEX,
2202 prTcqStatus->au2FreePageCount[TC5_INDEX],
2203 prTcqStatus->au2MaxNumOfPage[TC5_INDEX]);
2204
2205 DBGLOG(QM, LOUD,
2206 ("Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem));
2207
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);
2211 }
2212
2213 return prReturnedPacketListHead;
2214}
2215
2216#if CFG_SUPPORT_MULTITHREAD
2217/*----------------------------------------------------------------------------*/
2218/*!
2219* \brief Dequeue TX packets to send to HIF TX
2220*
2221* \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2222*
2223* \return The list of dequeued TX packets
2224*/
2225/*----------------------------------------------------------------------------*/
2226P_MSDU_INFO_T qmDequeueTxPacketsMthread(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus)
2227{
2228
2229 /* INT_32 i; */
2230 P_MSDU_INFO_T prReturnedPacketListHead;
2231 /* QUE_T rReturnedQue; */
2232 /* UINT_32 u4MaxQuotaLimit; */
2233 P_MSDU_INFO_T prMsduInfo, prNextMsduInfo;
2234
2235 KAL_SPIN_LOCK_DECLARATION();
2236
2237 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2238
2239 prReturnedPacketListHead = qmDequeueTxPackets(prAdapter, prTcqStatus);
2240
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;
2250 }
2251
2252 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2253
2254 return prReturnedPacketListHead;
2255}
2256
2257/*----------------------------------------------------------------------------*/
2258/*!
2259* \brief Adjust the TC quotas according to traffic demands
2260*
2261* \param[out] prTcqAdjust The resulting adjustment
2262* \param[in] prTcqStatus Info about the current TC quotas and counters
2263*
2264* \return (none)
2265*/
2266/*----------------------------------------------------------------------------*/
2267BOOLEAN
2268qmAdjustTcQuotasMthread(IN P_ADAPTER_T prAdapter,
2269 OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus)
2270{
2271#if QM_ADAPTIVE_TC_RESOURCE_CTRL
2272 UINT_32 i;
2273 P_QUE_MGT_T prQM = &prAdapter->rQM;
2274
2275 KAL_SPIN_LOCK_DECLARATION();
2276
2277 /* Must initialize */
2278 for (i = 0; i < QM_ACTIVE_TC_NUM; i++) {
2279 prTcqAdjust->acVariation[i] = 0;
2280 }
2281
2282 /* 4 <1> If TC resource is not just adjusted, exit directly */
2283 if (!prQM->fgTcResourcePostAnnealing) {
2284 return FALSE;
2285 }
2286 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2287 else {
2288 INT_32 i4TotalExtraQuota = 0;
2289 INT_32 ai4ExtraQuota[QM_ACTIVE_TC_NUM];
2290 BOOLEAN fgResourceRedistributed = TRUE;
2291
2292 /* Must initialize */
2293 for (i = 0; i < TC_NUM; i++) {
2294 prTcqAdjust->acVariation[i] = 0;
2295 }
2296
2297 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2298 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TC_RESOURCE);
2299
2300 /* Obtain the free-to-distribute resource */
2301 for (i = 0; i < QM_ACTIVE_TC_NUM; i++) {
2302 ai4ExtraQuota[i] =
2303 (INT_32) prTcqStatus->au2MaxNumOfBuffer[i] -
2304 (INT_32) prQM->au4CurrentTcResource[i];
2305
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;
2310 }
2311
2312 i4TotalExtraQuota += ai4ExtraQuota[i];
2313 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2314 }
2315 }
2316
2317 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TC_RESOURCE);
2318
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;
2325 }
2326
2327 i4TotalExtraQuota += ai4ExtraQuota[i];
2328 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2329 }
2330 }
2331
2332 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2333 prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed);
2334
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);
2340
2341 prTcqStatus->au2FreeBufferCount[i] += prTcqAdjust->acVariation[i];
2342 prTcqStatus->au2MaxNumOfBuffer[i] += prTcqAdjust->acVariation[i];
2343
2344 ASSERT(prTcqStatus->au2FreeBufferCount[i] >= 0);
2345 ASSERT(prTcqStatus->au2MaxNumOfBuffer[i] >= 0);
2346 }
2347
2348#if QM_FAST_TC_RESOURCE_CTRL
2349 prQM->fgTcResourceFastReaction = FALSE;
2350#endif
2351 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2352 }
2353
2354 return TRUE;
2355#else
2356 return FALSE;
2357#endif
2358}
2359#endif
2360
2361
2362/*----------------------------------------------------------------------------*/
2363/*!
2364* \brief Adjust the TC quotas according to traffic demands
2365*
2366* \param[out] prTcqAdjust The resulting adjustment
2367* \param[in] prTcqStatus Info about the current TC quotas and counters
2368*
2369* \return (none)
2370*/
2371/*----------------------------------------------------------------------------*/
2372BOOLEAN
2373qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter,
2374 OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus)
2375{
2376#if QM_ADAPTIVE_TC_RESOURCE_CTRL
2377 UINT_32 i;
2378 P_QUE_MGT_T prQM = &prAdapter->rQM;
2379
2380 /* Must initialize */
2381 for (i = 0; i < QM_ACTIVE_TC_NUM; i++) {
2382 prTcqAdjust->acVariation[i] = 0;
2383 }
2384
2385 /* 4 <1> If TC resource is not just adjusted, exit directly */
2386 if (!prQM->fgTcResourcePostAnnealing) {
2387 return FALSE;
2388 }
2389 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2390 else {
2391 INT_32 i4TotalExtraQuota = 0;
2392 INT_32 ai4ExtraQuota[QM_ACTIVE_TC_NUM];
2393 BOOLEAN fgResourceRedistributed = TRUE;
2394
2395 /* Obtain the free-to-distribute resource */
2396 for (i = 0; i < QM_ACTIVE_TC_NUM; i++) {
2397 ai4ExtraQuota[i] =
2398 (INT_32) prTcqStatus->au2MaxNumOfBuffer[i] -
2399 (INT_32) prQM->au4CurrentTcResource[i];
2400
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;
2405 }
2406
2407 i4TotalExtraQuota += ai4ExtraQuota[i];
2408 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2409 }
2410 }
2411
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;
2418 }
2419
2420 i4TotalExtraQuota += ai4ExtraQuota[i];
2421 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2422 }
2423 }
2424
2425 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2426 prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed);
2427
2428#if QM_FAST_TC_RESOURCE_CTRL
2429 prQM->fgTcResourceFastReaction = FALSE;
2430#endif
2431
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]));
2440#endif
2441 }
2442
2443 return TRUE;
2444#else
2445 return FALSE;
2446#endif
2447}
2448
2449#if QM_ADAPTIVE_TC_RESOURCE_CTRL
2450/*----------------------------------------------------------------------------*/
2451/*!
2452* \brief Update the average TX queue length for the TC resource control mechanism
2453*
2454* \param (none)
2455*
2456* \return (none)
2457*/
2458/*----------------------------------------------------------------------------*/
2459VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter)
2460{
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;
2465
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++) {
2468 u4CurrQueLen = 0;
2469
2470 /* Calculate per-STA queue length */
2471 for (u4StaRecIdx = 0; u4StaRecIdx < CFG_NUM_OF_STA_RECORD; u4StaRecIdx++) {
2472 prStaRec = cnmGetStaRecByIndex(prAdapter, u4StaRecIdx);
2473 if (prStaRec) {
2474 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
2475
2476 /* If the STA is activated, get the queue length */
2477 if ((prStaRec->fgIsValid) && (!prBssInfo->fgIsNetAbsent)) {
2478 u4CurrQueLen += (prStaRec->arTxQueue[u4Tc].u4NumElem);
2479 }
2480 }
2481 }
2482
2483 if (u4Tc == TC5_INDEX) {
2484 /* Update the queue length for TC5 (BMCAST) */
2485 u4CurrQueLen += prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem;
2486 }
2487
2488 if (prQM->au4AverageQueLen[u4Tc] == 0){
2489 prQM->au4AverageQueLen[u4Tc] = (u4CurrQueLen << prQM->u4QueLenMovingAverage);
2490 }
2491 else{
2492 prQM->au4AverageQueLen[u4Tc] -= (prQM->au4AverageQueLen[u4Tc] >> prQM->u4QueLenMovingAverage);
2493 prQM->au4AverageQueLen[u4Tc] += (u4CurrQueLen);
2494 }
2495 }
2496#if 0
2497 /* Update the queue length for TC5 (BMCAST) */
2498 u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem;
2499
2500 if (prQM->au4AverageQueLen[TC5_INDEX] == 0) {
2501 prQM->au4AverageQueLen[TC5_INDEX] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR);
2502 } else {
2503 prQM->au4AverageQueLen[TC5_INDEX] -=
2504 (prQM->au4AverageQueLen[TC5_INDEX] >> QM_QUE_LEN_MOVING_AVE_FACTOR);
2505 prQM->au4AverageQueLen[TC5_INDEX] += (u4CurrQueLen);
2506 }
2507#endif
2508}
2509
2510#if 1
2511VOID
2512qmAllocateResidualTcResource(
2513 IN P_ADAPTER_T prAdapter,
2514 IN PINT_32 ai4TcResDemand,
2515 IN PUINT_32 pu4ResidualResource,
2516 IN PUINT_32 pu4ShareCount
2517 )
2518{
2519 P_QUE_MGT_T prQM = &prAdapter->rQM;
2520 UINT_32 u4Share = 0 ;
2521 UINT_32 u4TcIdx;
2522 UINT_8 ucIdx;
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;
2527
2528 /* If there is no resource left, exit directly */
2529 if (u4ResidualResource == 0){
2530 return;
2531 }
2532
2533 /* This shall not happen */
2534 if (u4ShareCount == 0){
2535 prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource;
2536 DBGLOG(QM, ERROR, ("QM: (Error) u4ShareCount = 0\n"));
2537 return;
2538 }
2539
2540 /* Share the residual resource evenly */
2541 u4Share = (u4ResidualResource / u4ShareCount);
2542 if(u4Share){
2543 for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; u4TcIdx++){
2544 /* Skip TC4 (not adjustable) */
2545 if (u4TcIdx == TC4_INDEX) {
2546 continue;
2547 }
2548
2549 if (ai4TcResDemand[u4TcIdx] > 0){
2550 if (ai4TcResDemand[u4TcIdx] > u4Share){
2551 prQM->au4CurrentTcResource[u4TcIdx] += u4Share;
2552 u4ResidualResource -= u4Share;
2553 ai4TcResDemand[u4TcIdx] -= u4Share;
2554 }
2555 else{
2556 prQM->au4CurrentTcResource[u4TcIdx] += ai4TcResDemand[u4TcIdx];
2557 u4ResidualResource -= ai4TcResDemand[u4TcIdx];
2558 ai4TcResDemand[u4TcIdx] = 0;
2559 }
2560 }
2561 }
2562 }
2563
2564 /* By priority, allocate the left resource that is not divisible by u4Share */
2565 ucIdx = 0;
2566 while(u4ResidualResource) {
2567 u4TcIdx = au4AdjTc[ucIdx];
2568
2569 if (ai4TcResDemand[u4TcIdx]){
2570 prQM->au4CurrentTcResource[u4TcIdx]++;
2571 u4ResidualResource--;
2572 ai4TcResDemand[u4TcIdx]--;
2573
2574 if(ai4TcResDemand[u4TcIdx] == 0) {
2575 u4ShareCount--;
2576 }
2577 }
2578
2579 if(u4ShareCount <= 0) {
2580 break;
2581 }
2582
2583 ucIdx++;
2584 ucIdx %= u4AdjTcSize;
2585 }
2586
2587 /* Allocate the left resource */
2588 prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource;
2589
2590 *pu4ResidualResource = u4ResidualResource;
2591 *pu4ShareCount = u4ShareCount;
2592
2593}
2594
2595
2596/*----------------------------------------------------------------------------*/
2597/*!
2598* \brief Assign TX resource for each TC according to TX queue length and current assignment
2599*
2600* \param (none)
2601*
2602* \return (none)
2603*/
2604/*----------------------------------------------------------------------------*/
2605VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter)
2606{
2607 INT_32 i4TotalResourceDemand = 0;
2608 UINT_32 u4ResidualResource = 0;
2609 UINT_32 u4TcIdx;
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;
2614
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
2617 */
2618
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) {
2624 continue;
2625 }
2626
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]);
2630
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;
2634 }
2635
2636 i4TotalResourceDemand += ai4TcResDemand[u4TcIdx];
2637 }
2638
2639 //4 <2> Case 1: Demand <= Total Resource
2640 if(i4TotalResourceDemand <= 0) {
2641
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);
2646
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) {
2651 continue;
2652 }
2653
2654 prQM->au4CurrentTcResource[u4TcIdx] += (ai4TcResDemand[u4TcIdx] + u4Share);
2655
2656 /* Every TC is fully satisfied */
2657 ai4TcResDemand[u4TcIdx] = 0;
2658
2659 /* The left resource will be allocated to TC3 */
2660 u4ResidualResource -= u4Share;
2661 }
2662
2663 /* 4 <2.3> Allocate the left resource to TC3 (VO) */
2664 prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource);
2665
2666 }
2667 /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */
2668 else {
2669
2670 u4ResidualResource = prQM->u4ResidualTcResource;
2671
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) {
2676 continue;
2677 }
2678
2679 /* The demand can be fulfilled with the guaranteed resource amount */
2680 if ((prQM->au4CurrentTcResource[u4TcIdx] + ai4TcResDemand[u4TcIdx]) <=
2681 prQM->au4GuaranteedTcResource[u4TcIdx]){
2682
2683 prQM->au4CurrentTcResource[u4TcIdx] += ai4TcResDemand[u4TcIdx];
2684 u4ResidualResource +=
2685 (prQM->au4GuaranteedTcResource[u4TcIdx] - prQM->au4CurrentTcResource[u4TcIdx]);
2686 ai4TcResDemand[u4TcIdx] = 0;
2687 }
2688
2689 /* The demand can not be fulfilled with the guaranteed resource amount */
2690 else{
2691 ai4TcResDemand[u4TcIdx] -=
2692 (prQM->au4GuaranteedTcResource[u4TcIdx] - prQM->au4CurrentTcResource[u4TcIdx]);
2693
2694 prQM->au4CurrentTcResource[u4TcIdx] = prQM->au4GuaranteedTcResource[u4TcIdx];
2695 u4ShareCount++;
2696 }
2697 }
2698
2699 //4 <3.2> Allocate the residual resource
2700 qmAllocateResidualTcResource(prAdapter, ai4TcResDemand, &u4ResidualResource, &u4ShareCount);
2701 }
2702
2703 prQM->fgTcResourcePostAnnealing = TRUE;
2704
2705#if QM_PRINT_TC_RESOURCE_CTRL
2706 /* Debug print */
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]));
2711#endif
2712
2713}
2714#else
2715VOID
2716qmReassignTcResource(
2717 IN P_ADAPTER_T prAdapter
2718 )
2719{
2720 INT_32 i4TotalResourceDemand = 0;
2721 UINT_32 u4ResidualResource = 0;
2722 UINT_32 u4TcIdx;
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;
2727
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
2730 */
2731
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) {
2737 continue;
2738 }
2739
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]);
2743
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;
2747 }
2748
2749 i4TotalResourceDemand += ai4PerTcResourceDemand[u4TcIdx];
2750 }
2751
2752 //4 <2> Case 1: Demand <= Total Resource
2753 if(i4TotalResourceDemand <= 0) {
2754#if 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) {
2759 continue;
2760 }
2761
2762 prQM->au4CurrentTcResource[u4TcIdx] += ai4PerTcResourceDemand[u4TcIdx];
2763 }
2764
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);
2769
2770 for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; u4TcIdx++){
2771 /* Skip TC4 (not adjustable) */
2772 if (u4TcIdx == TC4_INDEX) {
2773 continue;
2774 }
2775
2776 prQM->au4CurrentTcResource[u4TcIdx] += u4Share;
2777
2778 /* Every TC is fully satisfied */
2779 ai4PerTcResourceDemand[u4TcIdx] = 0;
2780
2781 /* The left resource will be allocated to TC3 */
2782 u4ResidualResource -= u4Share;
2783 }
2784#else
2785 /* Optimization */
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);
2790
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) {
2795 continue;
2796 }
2797
2798 prQM->au4CurrentTcResource[u4TcIdx] += (ai4PerTcResourceDemand[u4TcIdx] + u4Share);
2799
2800 /* Every TC is fully satisfied */
2801 ai4PerTcResourceDemand[u4TcIdx] = 0;
2802
2803 /* The left resource will be allocated to TC3 */
2804 u4ResidualResource -= u4Share;
2805 }
2806#endif
2807
2808 //4 <2.3> Allocate the left resource to TC3 (VO)
2809 prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource);
2810
2811 }
2812
2813 //4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC
2814 else{
2815 u4ResidualResource = prQM->u4ResidualTcResource;
2816
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) {
2821 continue;
2822 }
2823
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;
2829 }
2830
2831 /* The demand can not be fulfilled with the guaranteed resource amount */
2832 else{
2833 ai4PerTcResourceDemand[u4TcIdx] -= (prQM->au4GuaranteedTcResource[u4TcIdx] - prQM->au4CurrentTcResource[u4TcIdx]);
2834 prQM->au4CurrentTcResource[u4TcIdx] = prQM->au4GuaranteedTcResource[u4TcIdx];
2835 u4ShareCount++;
2836 }
2837 }
2838
2839 //4 <3.2> Allocate the residual resource
2840 do{
2841 /* If there is no resource left, exit directly */
2842 if (u4ResidualResource == 0){
2843 break;
2844 }
2845
2846 /* This shall not happen */
2847 if (u4ShareCount == 0){
2848 prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource;
2849 DBGLOG(QM, ERROR, ("QM: (Error) u4ShareCount = 0\n"));
2850 break;
2851 }
2852
2853 /* Share the residual resource evenly */
2854 u4Share = (u4ResidualResource / u4ShareCount);
2855 if(u4Share){
2856 for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; u4TcIdx++){
2857 /* Skip TC4 (not adjustable) */
2858 if (u4TcIdx == TC4_INDEX) {
2859 continue;
2860 }
2861
2862 if (ai4PerTcResourceDemand[u4TcIdx]){
2863 if (ai4PerTcResourceDemand[u4TcIdx] - u4Share){
2864 prQM->au4CurrentTcResource[u4TcIdx] += u4Share;
2865 u4ResidualResource -= u4Share;
2866 ai4PerTcResourceDemand[u4TcIdx] -= u4Share;
2867 }
2868 else{
2869 prQM->au4CurrentTcResource[u4TcIdx] += ai4PerTcResourceDemand[u4TcIdx];
2870 u4ResidualResource -= ai4PerTcResourceDemand[u4TcIdx];
2871 ai4PerTcResourceDemand[u4TcIdx] = 0;
2872 }
2873 }
2874 }
2875 }
2876
2877 /* By priority, allocate the left resource that is not divisible by u4Share */
2878 if (u4ResidualResource == 0){
2879 break;
2880 }
2881
2882 if (ai4PerTcResourceDemand[TC3_INDEX]){ /* VO */
2883 prQM->au4CurrentTcResource[TC3_INDEX]++;
2884 if (--u4ResidualResource == 0) {
2885 break;
2886 }
2887 }
2888
2889 if (ai4PerTcResourceDemand[TC2_INDEX]){ /* VI */
2890 prQM->au4CurrentTcResource[TC2_INDEX]++;
2891 if (--u4ResidualResource == 0) {
2892 break;
2893 }
2894 }
2895
2896 if (ai4PerTcResourceDemand[TC5_INDEX]){ /* BMCAST */
2897 prQM->au4CurrentTcResource[TC5_INDEX]++;
2898 if (--u4ResidualResource == 0) {
2899 break;
2900 }
2901 }
2902
2903 if (ai4PerTcResourceDemand[TC1_INDEX]){ /* BE */
2904 prQM->au4CurrentTcResource[TC1_INDEX]++;
2905 if (--u4ResidualResource == 0) {
2906 break;
2907 }
2908 }
2909
2910 if (ai4PerTcResourceDemand[TC0_INDEX]){ /* BK */
2911 prQM->au4CurrentTcResource[TC0_INDEX]++;
2912 if (--u4ResidualResource == 0) {
2913 break;
2914 }
2915 }
2916
2917 /* Allocate the left resource */
2918 prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource;
2919
2920 }while(FALSE);
2921 }
2922
2923 prQM->fgTcResourcePostAnnealing = TRUE;
2924
2925#if QM_PRINT_TC_RESOURCE_CTRL
2926 /* Debug print */
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]));
2934#endif
2935
2936}
2937#endif
2938
2939/*----------------------------------------------------------------------------*/
2940/*!
2941* \brief Adjust TX resource for each TC according to TX queue length and current assignment
2942*
2943* \param (none)
2944*
2945* \return (none)
2946*/
2947/*----------------------------------------------------------------------------*/
2948VOID qmDoAdaptiveTcResourceCtrl(IN P_ADAPTER_T prAdapter)
2949{
2950 P_QUE_MGT_T prQM = &prAdapter->rQM;
2951
2952 /* 4 <0> Check to update queue length or not */
2953 if (--prQM->u4TimeToUpdateQueLen) {
2954 return;
2955 }
2956 /* 4 <1> Update TC queue length */
2957 prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN;
2958 qmUpdateAverageTxQueLen(prAdapter);
2959
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;
2967 }
2968
2969 /* The last assignment has been applied */
2970 else {
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);
2977 }
2978#endif
2979 }
2980 }
2981
2982 /* Debug */
2983#if QM_PRINT_TC_RESOURCE_CTRL
2984 do {
2985 UINT_32 u4Tc;
2986
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)
2996 ));
2997 break;
2998 }
2999 }
3000 } while (FALSE);
3001#endif
3002
3003}
3004
3005#if QM_FAST_TC_RESOURCE_CTRL
3006VOID qmCheckForFastTcResourceCtrl(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTc)
3007{
3008 P_QUE_MGT_T prQM = &prAdapter->rQM;
3009
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;
3015
3016 DBGLOG(QM, LOUD, ("Trigger TC Resource adjustment for TC[%u]\n", ucTc));
3017 }
3018}
3019#endif
3020
3021#endif
3022
3023
3024/*----------------------------------------------------------------------------*/
3025/* RX-Related Queue Management */
3026/*----------------------------------------------------------------------------*/
3027/*----------------------------------------------------------------------------*/
3028/*!
3029* \brief Init Queue Managment for RX
3030*
3031* \param[in] (none)
3032*
3033* \return (none)
3034*/
3035/*----------------------------------------------------------------------------*/
3036VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter)
3037{
3038 /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */
3039 /* TODO */
3040}
3041
3042
3043/*----------------------------------------------------------------------------*/
3044/*!
3045* \brief Handle RX packets (buffer reordering)
3046*
3047* \param[in] prSwRfbListHead The list of RX packets
3048*
3049* \return The list of packets which are not buffered for reordering
3050*/
3051/*----------------------------------------------------------------------------*/
3052P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead)
3053{
3054
3055#if CFG_RX_REORDERING_ENABLED
3056 /* UINT_32 i; */
3057 P_SW_RFB_T prCurrSwRfb;
3058 P_SW_RFB_T prNextSwRfb;
3059 P_HW_MAC_RX_DESC_T prRxStatus;
3060 QUE_T rReturnedQue;
3061 P_QUE_T prReturnedQue;
3062 PUINT_8 pucEthDestAddr;
3063 BOOLEAN fgIsBMC, fgIsHTran;
3064 BOOLEAN fgMicErr;
3065
3066 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3067
3068 DEBUGFUNC("qmHandleRxPackets");
3069
3070 ASSERT(prSwRfbListHead);
3071
3072 prReturnedQue = &rReturnedQue;
3073
3074 QUEUE_INITIALIZE(prReturnedQue);
3075 prNextSwRfb = prSwRfbListHead;
3076
3077 do {
3078 prCurrSwRfb = prNextSwRfb;
3079 prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb);
3080
3081 /* prHifRxHdr = prCurrSwRfb->prHifRxHdr; // TODO: (Tehuang) Use macro to obtain the pointer */
3082 prRxStatus = prCurrSwRfb->prRxStatus;
3083
3084 /* TODO: (Tehuang) Check if relaying */
3085 prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST;
3086
3087 /* Decide the Destination */
3088#if CFG_RX_PKTS_DUMP
3089 if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) {
3090 DBGLOG(SW4, INFO,
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));
3097
3098 DBGLOG_MEM8(SW4, TRACE, (PUINT_8) prCurrSwRfb->pvHeader,
3099 prCurrSwRfb->u2PacketLen);
3100 }
3101#endif
3102
3103 fgIsBMC = HAL_RX_STATUS_IS_BC(prRxStatus) | HAL_RX_STATUS_IS_MC(prRxStatus);
3104 fgIsHTran = FALSE;
3105 if (HAL_RX_STATUS_GET_HEADER_TRAN(prRxStatus) == TRUE) { /* (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){ */
3106
3107 UINT_8 ucBssIndex;
3108 P_BSS_INFO_T prBssInfo;
3109 UINT_8 aucTaAddr[MAC_ADDR_LEN];
3110
3111 fgIsHTran = TRUE;
3112 pucEthDestAddr = prCurrSwRfb->pvHeader;
3113
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);
3119 ASSERT(0);
3120 }
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);
3128 DBGLOG(QM, TRACE,
3129 ("Re-search the staRec = %d, mac = " MACSTR
3130 ", byteCnt= %d\n", prCurrSwRfb->ucStaRecIdx,
3131 MAC2STR(aucTaAddr), prRxStatus->u2RxByteCount));
3132 }
3133
3134 if (prCurrSwRfb->prStaRec == NULL) {
3135 DBGLOG(QM, TRACE,
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);
3142 continue;
3143 }
3144
3145 prCurrSwRfb->ucWlanIdx = prCurrSwRfb->prStaRec->ucWlanIndex;
3146 GLUE_SET_PKT_BSS_IDX(prCurrSwRfb->pvPacket,
3147 secGetBssIdxByWlanIdx(prAdapter,
3148 prCurrSwRfb->ucWlanIdx));
3149 }
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)) {
3153
3154 ucBssIndex = prCurrSwRfb->prStaRec->ucBssIndex;
3155 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
3156 /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */
3157 /* */
3158
3159
3160 /* if ((OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) { */
3161 /* fgIsBMC = HAL_RX_STATUS_IS_BC(prRxStatus) | HAL_RX_STATUS_IS_MC(prRxStatus); */
3162 /* } */
3163
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,
3171 prCurrSwRfb)) {
3172 DBGLOG(QM, WARN,
3173 ("Mark NULL the Packet for Dropped Packet %u\n",
3174 ucBssIndex));
3175 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3176 QUEUE_INSERT_TAIL(prReturnedQue,
3177 (P_QUE_ENTRY_T) prCurrSwRfb);
3178 continue;
3179 }
3180#endif /* CFG_SUPPORT_PASSPOINT */
3181 } else {
3182 DBGLOG(QM, TRACE,
3183 ("Mark NULL the Packet for inactive Bss %u\n",
3184 ucBssIndex));
3185 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3186 QUEUE_INSERT_TAIL(prReturnedQue,
3187 (P_QUE_ENTRY_T) prCurrSwRfb);
3188 continue;
3189 }
3190
3191 } else {
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);
3196 continue;
3197 }
3198
3199 }
4b9e9796 3200#if CFG_SUPPORT_WAPI
6fa3eb70 3201 /* Todo:: Move the data class error check here */
4b9e9796
S
3202 if (prCurrSwRfb->u2PacketLen > ETHER_HEADER_LEN) {
3203 PUINT_8 pc = (PUINT_8) prCurrSwRfb->pvHeader;
3204 UINT_16 u2Etype = 0;
3205 u2Etype = (pc[ETHER_TYPE_LEN_OFFSET] << 8) | (pc[ETHER_TYPE_LEN_OFFSET + 1]);
3206 /* for wapi integrity test. WPI_1x packet should be always in non-encrypted mode.
3207 if we received any WPI(0x88b4) packet that is encrypted, drop here. */
3208 if (u2Etype == ETH_WPI_1X &&
3209 HAL_RX_STATUS_GET_SEC_MODE(prRxStatus) != 0) {
3210 DBGLOG(QM, INFO, ("drop wpi packet with sec mode\n"));
3211 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3212 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
3213 continue;
3214 }
3215 }
3216#endif
6fa3eb70
S
3217 if (prCurrSwRfb->fgReorderBuffer && !fgIsBMC && fgIsHTran) {
3218 /* If this packet should dropped or indicated to the host immediately,
3219 * it should be enqueued into the rReturnedQue with specific flags. If
3220 * this packet should be buffered for reordering, it should be enqueued
3221 * into the reordering queue in the STA_REC rather than into the
3222 * rReturnedQue.
3223 */
3224 qmProcessPktWithReordering(prAdapter, prCurrSwRfb, prReturnedQue);
3225
3226 } else if (prCurrSwRfb->fgDataFrame) {
3227 /* Check Class Error */
3228 {
3229 if (secCheckClassError
3230 (prAdapter, prCurrSwRfb, prCurrSwRfb->prStaRec) == TRUE) {
3231 P_RX_BA_ENTRY_T prReorderQueParm = NULL;
3232
3233 /* Invalid BA aggrement */
3234 if (fgIsHTran) {
3235 UINT_16 u2FrameCtrl = 0;
3236
3237 u2FrameCtrl = HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prCurrSwRfb->prRxStatusGroup4);
3238 // Check FC type, if DATA, then no-reordering
3239 if((u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_DATA){
3240 DBGLOG(QM, TRACE, ("FC [0x%04X], no-reordering...\n", u2FrameCtrl));
3241 }
3242 else {
3243 prReorderQueParm = ((prCurrSwRfb->prStaRec->aprRxReorderParamRefTbl)[prCurrSwRfb->ucTid]);
3244 }
3245 }
3246
3247 if (prReorderQueParm && prReorderQueParm->fgIsValid
3248 && !fgIsBMC) {
3249 qmProcessPktWithReordering(prAdapter, prCurrSwRfb,
3250 prReturnedQue);
3251 } else {
3252 qmHandleRxPackets_AOSP_1;
3253 }
3254 } else {
3255 DBGLOG(QM, TRACE, ("Mark NULL the Packet for class error\n"));
3256 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3257 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
3258 }
3259 }
3260 } else {
3261 P_WLAN_MAC_HEADER_T prWlanMacHeader;
3262
3263 ASSERT(prCurrSwRfb->pvHeader);
3264
3265 prWlanMacHeader = (P_WLAN_MAC_HEADER_T) prCurrSwRfb->pvHeader;
3266 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3267
3268 switch (prWlanMacHeader->u2FrameCtrl & MASK_FRAME_TYPE) {
3269 /* BAR frame */
3270 case MAC_FRAME_BLOCK_ACK_REQ:
3271 qmProcessBarFrame(prAdapter, prCurrSwRfb, prReturnedQue);
3272 break;
3273 default:
3274 DBGLOG(QM, TRACE,
3275 ("Mark NULL the Packet for non-interesting type\n"));
3276 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
3277 break;
3278 }
3279 }
3280
3281 } while (prNextSwRfb);
3282
3283
3284 /* The returned list of SW_RFBs must end with a NULL pointer */
3285 if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) {
3286 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(prReturnedQue), NULL);
3287 }
3288
3289 return (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue);
3290
3291#else
3292
3293 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3294 return prSwRfbListHead;
3295
3296#endif
3297
3298}
3299
3300/*----------------------------------------------------------------------------*/
3301/*!
3302* \brief Reorder the received packet
3303*
3304* \param[in] prSwRfb The RX packet to process
3305* \param[out] prReturnedQue The queue for indicating packets
3306*
3307* \return (none)
3308*/
3309/*----------------------------------------------------------------------------*/
3310VOID
3311qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter,
3312 IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
3313{
3314
3315
3316 P_STA_RECORD_T prStaRec;
3317 P_HW_MAC_RX_DESC_T prRxStatus;
3318 P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4 = NULL;
3319 P_RX_BA_ENTRY_T prReorderQueParm;
3320
3321 UINT_32 u4SeqNo;
3322 UINT_32 u4WinStart;
3323 UINT_32 u4WinEnd;
3324 P_QUE_T prReorderQue;
3325 /* P_SW_RFB_T prReorderedSwRfb; */
3326
3327 DEBUGFUNC("qmProcessPktWithReordering");
3328
3329 ASSERT(prSwRfb);
3330 ASSERT(prReturnedQue);
3331 ASSERT(prSwRfb->prRxStatus);
3332
3333 /* Incorrect STA_REC index */
3334 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
3335 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3336 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3337 DBGLOG(QM, WARN, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
3338 prSwRfb->ucStaRecIdx));
3339 authSendDeauthFrame(prAdapter,
3340 NULL,
3341 NULL,
3342 prSwRfb, REASON_CODE_CLASS_3_ERR, (PFN_TX_DONE_HANDLER) NULL);
3343 /* ASSERT(0); */
3344 return;
3345 }
3346
3347 /* Check whether the STA_REC is activated */
3348 prStaRec = prSwRfb->prStaRec;
3349 ASSERT(prStaRec);
3350
3351 prRxStatus = prSwRfb->prRxStatus;
3352 prSwRfb->ucTid = (UINT_8) (HAL_RX_STATUS_GET_TID(prRxStatus));
3353 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3354
3355#if 0
3356 if (!(prStaRec->fgIsValid)) {
3357 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3358 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3359 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3360 DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC\n"));
3361 /* ASSERT(0); */
3362 return;
3363 }
3364#endif
3365
3366 /* Check whether the BA agreement exists */
3367 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3368 if (!prReorderQueParm || !(prReorderQueParm->fgIsValid)) {
3369 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3370 prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
3371 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3372 DBGLOG(QM, TRACE, ("Reordering for a NULL ReorderQueParm\n"));
3373 return;
3374 }
3375
3376 prRxStatusGroup4 = prSwRfb->prRxStatusGroup4;
3377 if (prRxStatusGroup4 == NULL) {
3378 DBGLOG(QM, ERROR, ("prRxStatusGroup4 is NULL !!!\n"));
3379 DBGLOG(QM, ERROR,
3380 ("prSwRfb->pvHeader is 0x%p !!!\n", (PUINT_32) prSwRfb->pvHeader));
3381 DBGLOG(QM, ERROR, ("prSwRfb->u2PacketLen is %d !!!\n", prSwRfb->u2PacketLen));
3382 DBGLOG(QM, ERROR, ("========= START TO DUMP prSwRfb =========\n"));
3383 DBGLOG_MEM8(QM, ERROR, prSwRfb->pvHeader, prSwRfb->u2PacketLen);
3384 DBGLOG(QM, ERROR, ("========= END OF DUMP prSwRfb =========\n"));
3385 ASSERT(prRxStatusGroup4);
3386 }
3387
3388
3389 prSwRfb->u2SSN =
3390 HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4) >> RX_STATUS_SEQ_NUM_OFFSET;
3391
3392 /* Start to reorder packets */
3393 u4SeqNo = (UINT_32) (prSwRfb->u2SSN);
3394 prReorderQue = &(prReorderQueParm->rReOrderQue);
3395 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
3396 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
3397
3398 /* Debug */
3399 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3400
3401 /* Case 1: Fall within */
3402 if /* 0 - start - sn - end - 4095 */
3403 (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd))
3404 /* 0 - end - start - sn - 4095 */
3405 || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo))
3406 /* 0 - sn - end - start - 4095 */
3407 || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) {
3408
3409 qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3410
3411#if QM_RX_WIN_SSN_AUTO_ADVANCING
3412 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3413 /* Let the first received packet pass the reorder check */
3414 DBGLOG(QM, LOUD,
3415 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart,
3416 u4WinEnd));
3417
3418 prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo;
3419 prReorderQueParm->u2WinEnd =
3420 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3421 1) % MAX_SEQ_NO_COUNT;
3422 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3423 }
3424#endif
3425
3426
3427 qmPopOutDueToFallWithin(prAdapter, prReorderQueParm, prReturnedQue);
3428 }
3429 /* Case 2: Fall ahead */
3430 else if
3431 /* 0 - start - end - sn - (start+2048) - 4095 */
3432 (((u4WinStart < u4WinEnd)
3433 && (u4WinEnd < u4SeqNo)
3434 && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT)))
3435 /* 0 - sn - (start+2048) - start - end - 4095 */
3436 || ((u4SeqNo < u4WinStart)
3437 && (u4WinStart < u4WinEnd)
3438 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))
3439 /* 0 - end - sn - (start+2048) - start - 4095 */
3440 || ((u4WinEnd < u4SeqNo)
3441 && (u4SeqNo < u4WinStart)
3442 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) {
3443
3444
3445#if QM_RX_WIN_SSN_AUTO_ADVANCING
3446 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3447 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3448 }
3449#endif
3450
3451 qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3452
3453 /* Advance the window after inserting a new tail */
3454 prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo;
3455 prReorderQueParm->u2WinStart =
3456 (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) +
3457 MAX_SEQ_NO_COUNT + 1)
3458 % MAX_SEQ_NO_COUNT);
3459
3460 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3461
3462 }
3463 /* Case 3: Fall behind */
3464 else {
3465
3466#if QM_RX_WIN_SSN_AUTO_ADVANCING
3467#if QM_RX_INIT_FALL_BEHIND_PASS
3468 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3469 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3470 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3471 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3472 return;
3473 }
3474#endif
3475#endif
3476
3477 /* An erroneous packet */
3478 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3479 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3480 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3481 return;
3482 }
3483
3484 return;
3485
3486}
3487
3488
3489VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
3490{
3491
3492 P_STA_RECORD_T prStaRec;
3493 P_HW_MAC_RX_DESC_T prRxStatus;
3494 P_RX_BA_ENTRY_T prReorderQueParm;
3495 P_CTRL_BAR_FRAME_T prBarCtrlFrame;
3496
3497 UINT_32 u4SSN;
3498 UINT_32 u4WinStart;
3499 UINT_32 u4WinEnd;
3500 P_QUE_T prReorderQue;
3501 /* P_SW_RFB_T prReorderedSwRfb; */
3502
3503 ASSERT(prSwRfb);
3504 ASSERT(prReturnedQue);
3505 ASSERT(prSwRfb->prRxStatus);
3506 ASSERT(prSwRfb->pvHeader);
3507
3508 prRxStatus = prSwRfb->prRxStatus;
3509
3510 prBarCtrlFrame = (P_CTRL_BAR_FRAME_T) prSwRfb->pvHeader;
3511
3512 prSwRfb->ucTid =
3513 (*((PUINT_16) ((PUINT_8) prBarCtrlFrame + CTRL_BAR_BAR_CONTROL_OFFSET))) >>
3514 BAR_CONTROL_TID_INFO_OFFSET;
3515 prSwRfb->u2SSN =
3516 (*((PUINT_16) ((PUINT_8) prBarCtrlFrame + CTRL_BAR_BAR_INFORMATION_OFFSET))) >>
3517 OFFSET_BAR_SSC_SN;
3518
3519 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3520 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3521
3522 /* Incorrect STA_REC index */
3523 prSwRfb->ucStaRecIdx = secLookupStaRecIndexFromTA(prAdapter, prBarCtrlFrame->aucSrcAddr);
3524 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
3525 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
3526 prSwRfb->ucStaRecIdx));
3527 /* ASSERT(0); */
3528 return;
3529 }
3530
3531 /* Check whether the STA_REC is activated */
3532 prSwRfb->prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3533 prStaRec = prSwRfb->prStaRec;
3534 if (prStaRec == NULL) {
3535 /* ASSERT(prStaRec); */
3536 return;
3537 }
3538#if 0
3539 if (!(prStaRec->fgIsValid)) {
3540 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3541 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
3542 /* ASSERT(0); */
3543 return;
3544 }
3545#endif
3546
3547 /* Check whether the BA agreement exists */
3548 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3549 if (!prReorderQueParm) {
3550 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3551 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
3552 /* ASSERT(0); */
3553 return;
3554 }
3555
3556
3557 u4SSN = (UINT_32) (prSwRfb->u2SSN);
3558 prReorderQue = &(prReorderQueParm->rReOrderQue);
3559 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
3560 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
3561
3562 if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) {
3563 prReorderQueParm->u2WinStart = (UINT_16) u4SSN;
3564 prReorderQueParm->u2WinEnd =
3565 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3566 1) % MAX_SEQ_NO_COUNT;
3567 DBGLOG(QM, TRACE,
3568 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, u4SSN,
3569 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3570 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3571 } else {
3572 DBGLOG(QM, TRACE,
3573 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SSN, u4WinStart,
3574 u4WinEnd));
3575 }
3576}
3577
3578
3579
3580VOID
3581qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb,
3582 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3583{
3584 P_SW_RFB_T prExaminedQueuedSwRfb;
3585 P_QUE_T prReorderQue;
3586 ASSERT(prSwRfb);
3587 ASSERT(prReorderQueParm);
3588 ASSERT(prReturnedQue);
3589
3590 prReorderQue = &(prReorderQueParm->rReOrderQue);
3591 prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3592
3593 /* There are no packets queued in the Reorder Queue */
3594 if (prExaminedQueuedSwRfb == NULL) {
3595 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
3596 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3597 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3598 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
3599 prReorderQue->u4NumElem++;
3600 }
3601
3602 /* Determine the insert position */
3603 else {
3604 do {
3605 /* Case 1: Terminate. A duplicate packet */
3606 if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) {
3607 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3608 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3609 return;
3610 }
3611
3612 /* Case 2: Terminate. The insert point is found */
3613 else if (qmCompareSnIsLessThan((prSwRfb->u2SSN),
3614 (prExaminedQueuedSwRfb->u2SSN))) {
3615 break;
3616 }
3617
3618 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3619 else {
3620 prExaminedQueuedSwRfb =
3621 (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext);
3622 }
3623 } while (prExaminedQueuedSwRfb);
3624
3625 /* Update the Reorder Queue Parameters according to the found insert position */
3626 if (prExaminedQueuedSwRfb == NULL) {
3627 /* The received packet shall be placed at the tail */
3628 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
3629 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3630 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
3631 prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb);
3632 } else {
3633 ((P_QUE_ENTRY_T) prSwRfb)->prPrev =
3634 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev;
3635 ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb;
3636 if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) {
3637 /* The received packet will become the head */
3638 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3639 } else {
3640 (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext =
3641 (P_QUE_ENTRY_T) prSwRfb;
3642 }
3643 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb;
3644 }
3645
3646 prReorderQue->u4NumElem++;
3647
3648 }
3649
3650}
3651
3652
3653VOID
3654qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb,
3655 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3656{
3657 P_QUE_T prReorderQue;
3658 ASSERT(prSwRfb);
3659 ASSERT(prReorderQueParm);
3660 ASSERT(prReturnedQue);
3661
3662 prReorderQue = &(prReorderQueParm->rReOrderQue);
3663
3664 /* There are no packets queued in the Reorder Queue */
3665 if (QUEUE_IS_EMPTY(prReorderQue)) {
3666 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
3667 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3668 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3669 } else {
3670 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
3671 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3672 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
3673 }
3674 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
3675 prReorderQue->u4NumElem++;
3676
3677}
3678
3679
3680VOID
3681qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter,
3682 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3683{
3684 P_SW_RFB_T prReorderedSwRfb;
3685 P_QUE_T prReorderQue;
3686 BOOLEAN fgDequeuHead, fgMissing;
3687 OS_SYSTIME rCurrentTime, rMissTimeout;
3688
3689 prReorderQue = &(prReorderQueParm->rReOrderQue);
3690
3691 fgMissing = FALSE;
3692 rCurrentTime = 0;
3693 rMissTimeout = g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid];
3694 if (rMissTimeout) {
3695 fgMissing = TRUE;
3696 GET_CURRENT_SYSTIME(&rCurrentTime);
3697 }
3698
3699 /* Check whether any packet can be indicated to the higher layer */
3700 while (TRUE) {
3701 if (QUEUE_IS_EMPTY(prReorderQue)) {
3702 break;
3703 }
3704
3705 /* Always examine the head packet */
3706 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3707 fgDequeuHead = FALSE;
3708
3709 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3710 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3711
3712 fgDequeuHead = TRUE;
3713 prReorderQueParm->u2WinStart =
3714 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3715 }
3716 /* SN > WinStart, break to update WinEnd */
3717 else {
3718 /* Start bubble timer */
3719 if (!prReorderQueParm->fgHasBubble) {
3720 cnmTimerStartTimer(prAdapter,
3721 &(prReorderQueParm->rReorderBubbleTimer),
3722 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3723 prReorderQueParm->fgHasBubble = TRUE;
3724 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
3725
3726 DBGLOG(QM, TRACE,
3727 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3728 prReorderQueParm->ucStaRecIdx, prReorderedSwRfb->ucTid,
3729 prReorderQueParm->u2FirstBubbleSn,
3730 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3731 }
3732
3733 if ((fgMissing == TRUE) &&
3734 CHECK_FOR_TIMEOUT(rCurrentTime, rMissTimeout,
3735 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3736 DBGLOG(QM, TRACE,
3737 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3738 prReorderQueParm->ucTid, prReorderedSwRfb->u2SSN));
3739 fgDequeuHead = TRUE;
3740 prReorderQueParm->u2WinStart =
3741 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3742
3743 fgMissing = FALSE;
3744 } else
3745 break;
3746 }
3747
3748
3749 /* Dequeue the head packet */
3750 if (fgDequeuHead) {
3751
3752 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3753 prReorderQue->prHead = NULL;
3754 prReorderQue->prTail = NULL;
3755 } else {
3756 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3757 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3758 }
3759 prReorderQue->u4NumElem--;
3760 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3761 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3762 }
3763 }
3764
3765 if (QUEUE_IS_EMPTY(prReorderQue)) {
3766 rMissTimeout = 0;
3767 } else {
3768 if (fgMissing == FALSE) {
3769 GET_CURRENT_SYSTIME(&rMissTimeout);
3770 }
3771 }
3772
3773 /* After WinStart has been determined, update the WinEnd */
3774 prReorderQueParm->u2WinEnd =
3775 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3776 1) % MAX_SEQ_NO_COUNT);
3777
3778}
3779
3780VOID
3781qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter,
3782 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3783{
3784 P_SW_RFB_T prReorderedSwRfb;
3785 P_QUE_T prReorderQue;
3786 BOOLEAN fgDequeuHead;
3787
3788 prReorderQue = &(prReorderQueParm->rReOrderQue);
3789
3790 /* Check whether any packet can be indicated to the higher layer */
3791 while (TRUE) {
3792 if (QUEUE_IS_EMPTY(prReorderQue)) {
3793 break;
3794 }
3795
3796 /* Always examine the head packet */
3797 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3798 fgDequeuHead = FALSE;
3799
3800 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3801 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3802
3803 fgDequeuHead = TRUE;
3804 prReorderQueParm->u2WinStart =
3805 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3806 }
3807
3808 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3809 else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN),
3810 (UINT_32) (prReorderQueParm->u2WinStart))) {
3811
3812 fgDequeuHead = TRUE;
3813
3814 }
3815
3816 /* SN > WinStart, break to update WinEnd */
3817 else {
3818 /* Start bubble timer */
3819 if (!prReorderQueParm->fgHasBubble) {
3820 cnmTimerStartTimer(prAdapter,
3821 &(prReorderQueParm->rReorderBubbleTimer),
3822 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3823 prReorderQueParm->fgHasBubble = TRUE;
3824 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
3825
3826 DBGLOG(QM, TRACE,
3827 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3828 prReorderQueParm->ucStaRecIdx, prReorderedSwRfb->ucTid,
3829 prReorderQueParm->u2FirstBubbleSn,
3830 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3831 }
3832 break;
3833 }
3834
3835
3836 /* Dequeue the head packet */
3837 if (fgDequeuHead) {
3838
3839 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3840 prReorderQue->prHead = NULL;
3841 prReorderQue->prTail = NULL;
3842 } else {
3843 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3844 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3845 }
3846 prReorderQue->u4NumElem--;
3847 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3848 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3849 }
3850 }
3851
3852 /* After WinStart has been determined, update the WinEnd */
3853 prReorderQueParm->u2WinEnd =
3854 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3855 1) % MAX_SEQ_NO_COUNT);
3856
3857}
3858
3859VOID qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
3860{
3861 P_RX_BA_ENTRY_T prReorderQueParm = (P_RX_BA_ENTRY_T) ulParamPtr;
3862 P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL;
3863 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent;
3864
3865 KAL_SPIN_LOCK_DECLARATION();
3866
3867 if (!prReorderQueParm->fgIsValid) {
3868 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3869 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3870 return;
3871 }
3872
3873 if (!prReorderQueParm->fgHasBubble) {
3874 DBGLOG(QM, TRACE,
3875 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3876 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3877 return;
3878 }
3879
3880 DBGLOG(QM, TRACE, ("QM:(Bub Timeout) STA[%u] TID[%u] BubSN[%u]\n",
3881 prReorderQueParm->ucStaRecIdx,
3882 prReorderQueParm->ucTid, prReorderQueParm->u2FirstBubbleSn));
3883
3884 /* Generate a self-inited event to Rx path */
3885 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
3886 QUEUE_REMOVE_HEAD(&prAdapter->rRxCtrl.rFreeSwRfbList, prSwRfb, P_SW_RFB_T);
3887 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
3888
3889 if (prSwRfb) {
3890 prCheckReorderEvent = (P_EVENT_CHECK_REORDER_BUBBLE_T) prSwRfb->pucRecvBuff;
3891
3892 prSwRfb->ucPacketType = RX_PKT_TYPE_SW_DEFINED;
3893
3894 prSwRfb->prRxStatus->u2PktTYpe = RXM_RXD_PKT_TYPE_SW_EVENT;
3895
3896 prCheckReorderEvent->ucEID = EVENT_ID_CHECK_REORDER_BUBBLE;
3897 prCheckReorderEvent->ucSeqNum = 0;
3898
3899 prCheckReorderEvent->ucStaRecIdx = prReorderQueParm->ucStaRecIdx;
3900 prCheckReorderEvent->ucTid = prReorderQueParm->ucTid;
3901 prCheckReorderEvent->u2Length = sizeof(EVENT_CHECK_REORDER_BUBBLE_T);
3902
3903 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
3904 QUEUE_INSERT_TAIL(&prAdapter->rRxCtrl.rReceivedRfbList, &prSwRfb->rQueEntry);
3905 RX_INC_CNT(&prAdapter->rRxCtrl, RX_MPDU_TOTAL_COUNT);
3906 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
3907
3908 DBGLOG(QM, LOUD, ("QM:(Bub Check Event Sent) STA[%u] TID[%u]\n",
3909 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3910
3911 nicRxProcessRFBs(prAdapter);
3912
3913 DBGLOG(QM, LOUD, ("QM:(Bub Check Event Handled) STA[%u] TID[%u]\n",
3914 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3915 } else {
3916 DBGLOG(QM, TRACE,
3917 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bub check event alloc failed\n",
3918 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3919
3920 cnmTimerStartTimer(prAdapter, &(prReorderQueParm->rReorderBubbleTimer),
3921 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3922
3923 DBGLOG(QM, TRACE, ("QM:(Bub Timer Restart) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3924 prReorderQueParm->ucStaRecIdx,
3925 prReorderQueParm->ucTid,
3926 prReorderQueParm->u2FirstBubbleSn,
3927 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3928 }
3929
3930 return;
3931}
3932
3933VOID qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
3934{
3935 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent =
3936 (P_EVENT_CHECK_REORDER_BUBBLE_T) prEvent;
3937 P_RX_BA_ENTRY_T prReorderQueParm;
3938 P_QUE_T prReorderQue;
3939 QUE_T rReturnedQue;
3940 P_QUE_T prReturnedQue = &rReturnedQue;
3941 P_SW_RFB_T prReorderedSwRfb, prSwRfb;
3942
3943 QUEUE_INITIALIZE(prReturnedQue);
3944
3945 /* Get target Rx BA entry */
3946 prReorderQueParm = qmLookupRxBaEntry(prAdapter,
3947 prCheckReorderEvent->ucStaRecIdx,
3948 prCheckReorderEvent->ucTid);
3949
3950 /* Sanity Check */
3951 if (!prReorderQueParm) {
3952 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3953 prCheckReorderEvent->ucStaRecIdx, prCheckReorderEvent->ucTid));
3954 return;
3955 }
3956
3957 if (!prReorderQueParm->fgIsValid) {
3958 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3959 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3960 return;
3961 }
3962
3963 if (!prReorderQueParm->fgHasBubble) {
3964 DBGLOG(QM, TRACE,
3965 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3966 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3967 return;
3968 }
3969
3970 prReorderQue = &(prReorderQueParm->rReOrderQue);
3971
3972 if (QUEUE_IS_EMPTY(prReorderQue)) {
3973 prReorderQueParm->fgHasBubble = FALSE;
3974
3975 DBGLOG(QM, TRACE,
3976 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3977 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3978
3979 return;
3980 }
3981
3982 DBGLOG(QM, TRACE, ("QM:(Bub Check Event Got) STA[%u] TID[%u]\n",
3983 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3984
3985 /* Expected bubble timeout => pop out packets before win_end */
3986 if (prReorderQueParm->u2FirstBubbleSn == prReorderQueParm->u2WinStart) {
3987
3988 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_TAIL(prReorderQue);
3989
3990 prReorderQueParm->u2WinStart = prReorderedSwRfb->u2SSN + 1;
3991 prReorderQueParm->u2WinEnd =
3992 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3993 1) % MAX_SEQ_NO_COUNT;
3994
3995 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3996
3997 DBGLOG(QM, TRACE, ("QM:(Bub Flush) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3998 prReorderQueParm->ucStaRecIdx,
3999 prReorderQueParm->ucTid,
4000 prReorderQueParm->u2FirstBubbleSn,
4001 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
4002
4003 if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) {
4004 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(prReturnedQue), NULL);
4005
4006 prSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue);
4007 while (prSwRfb) {
4008 DBGLOG(QM, TRACE,
4009 ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out SN[%u]\n",
4010 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid,
4011 prSwRfb->u2SSN));
4012
4013 prSwRfb =
4014 (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb);
4015 }
4016
4017 wlanProcessQueuedSwRfb(prAdapter,
4018 (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue));
4019 } else {
4020 DBGLOG(QM, TRACE, ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out 0 packet\n",
4021 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
4022 }
4023
4024 prReorderQueParm->fgHasBubble = FALSE;
4025 }
4026 /* First bubble has been filled but others exist */
4027 else {
4028 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
4029 cnmTimerStartTimer(prAdapter, &(prReorderQueParm->rReorderBubbleTimer),
4030 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
4031
4032 DBGLOG(QM, TRACE, ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
4033 prReorderQueParm->ucStaRecIdx,
4034 prReorderQueParm->ucTid,
4035 prReorderQueParm->u2FirstBubbleSn,
4036 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
4037 }
4038
4039 return;
4040}
4041
4042
4043BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater)
4044{
4045 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
4046 if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) { /* Shall be <= */
4047 return FALSE;
4048 }
4049
4050 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
4051 else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) {
4052 return TRUE;
4053 }
4054
4055 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
4056 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
4057 else {
4058 return u4SnLess < u4SnGreater;
4059 }
4060}
4061
4062
4063/*----------------------------------------------------------------------------*/
4064/*!
4065* \brief Handle Mailbox RX messages
4066*
4067* \param[in] prMailboxRxMsg The received Mailbox message from the FW
4068*
4069* \return (none)
4070*/
4071/*----------------------------------------------------------------------------*/
4072VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg)
4073{
4074 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
4075 /* TODO */
4076}
4077
4078
4079/*----------------------------------------------------------------------------*/
4080/*!
4081* \brief Handle ADD RX BA Event from the FW
4082*
4083* \param[in] prAdapter Adapter pointer
4084* \param[in] prEvent The event packet from the FW
4085*
4086* \return (none)
4087*/
4088/*----------------------------------------------------------------------------*/
4089VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4090{
4091 P_EVENT_RX_ADDBA_T prEventRxAddBa;
4092 P_STA_RECORD_T prStaRec;
4093 UINT_32 u4Tid;
4094 UINT_32 u4WinSize;
4095
4096 DBGLOG(QM, INFO, ("QM:Event +RxBa\n"));
4097
4098 prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent;
4099 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx);
4100
4101 if (!prStaRec) {
4102 /* Invalid STA_REC index, discard the event packet */
4103 /* ASSERT(0); */
4104 DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
4105 return;
4106 }
4107#if 0
4108 if (!(prStaRec->fgIsValid)) {
4109 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4110 DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
4111 /* ASSERT(0); */
4112 /* return; */
4113 }
4114#endif
4115
4116 u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK)
4117 >> BA_PARAM_SET_TID_MASK_OFFSET);
4118
4119 u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
4120 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
4121
4122 if (!qmAddRxBaEntry(prAdapter,
4123 prStaRec->ucIndex,
4124 (UINT_8) u4Tid,
4125 (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN),
4126 (UINT_16) u4WinSize)) {
4127
4128 /* FW shall ensure the availabiilty of the free-to-use BA entry */
4129 DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n"));
4130 ASSERT(0);
4131 }
4132
4133}
4134
4135/*----------------------------------------------------------------------------*/
4136/*!
4137* \brief Handle DEL RX BA Event from the FW
4138*
4139* \param[in] prAdapter Adapter pointer
4140* \param[in] prEvent The event packet from the FW
4141*
4142* \return (none)
4143*/
4144/*----------------------------------------------------------------------------*/
4145VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4146{
4147 P_EVENT_RX_DELBA_T prEventRxDelBa;
4148 P_STA_RECORD_T prStaRec;
4149
4150 /* DbgPrint("QM:Event -RxBa\n"); */
4151
4152 prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent;
4153 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx);
4154
4155 if (!prStaRec) {
4156 /* Invalid STA_REC index, discard the event packet */
4157 /* ASSERT(0); */
4158 return;
4159 }
4160#if 0
4161 if (!(prStaRec->fgIsValid)) {
4162 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4163 /* ASSERT(0); */
4164 return;
4165 }
4166#endif
4167
4168 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE);
4169
4170}
4171
4172P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid)
4173{
4174 int i;
4175 P_QUE_MGT_T prQM = &prAdapter->rQM;
4176
4177 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
4178
4179 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
4180 if (prQM->arRxBaTable[i].fgIsValid) {
4181 if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) &&
4182 (prQM->arRxBaTable[i].ucTid == ucTid)) {
4183 return &prQM->arRxBaTable[i];
4184 }
4185 }
4186 }
4187 return NULL;
4188}
4189
4190BOOL
4191qmAddRxBaEntry(IN P_ADAPTER_T prAdapter,
4192 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize)
4193{
4194 int i;
4195 P_RX_BA_ENTRY_T prRxBaEntry = NULL;
4196 P_STA_RECORD_T prStaRec;
4197 P_QUE_MGT_T prQM = &prAdapter->rQM;
4198
4199 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
4200
4201 if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
4202 /* Invalid STA_REC index, discard the event packet */
4203 DBGLOG(QM, WARN,
4204 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
4205 ucStaRecIdx));
4206 return FALSE;
4207 }
4208
4209 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
4210 ASSERT(prStaRec);
4211
4212 /* if(!(prStaRec->fgIsValid)){ */
4213 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
4214 /* return FALSE; */
4215 /* } */
4216
4217 /* 4 <1> Delete before adding */
4218 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4219 if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) {
4220 qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */
4221 }
4222 /* 4 <2> Add a new BA entry */
4223 /* No available entry to store the BA agreement info. Retrun FALSE. */
4224 if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) {
4225 DBGLOG(QM, ERROR,
4226 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount));
4227 return FALSE;
4228 } else {
4229 /* Find the free-to-use BA entry */
4230 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
4231 if (!prQM->arRxBaTable[i].fgIsValid) {
4232 prRxBaEntry = &(prQM->arRxBaTable[i]);
4233 prQM->ucRxBaCount++;
4234 DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount));
4235 break;
4236 }
4237 }
4238
4239 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
4240 u2WinSize += CFG_RX_BA_INC_SIZE;
4241 if (prRxBaEntry) {
4242 prRxBaEntry->ucStaRecIdx = ucStaRecIdx;
4243 prRxBaEntry->ucTid = ucTid;
4244 prRxBaEntry->u2WinStart = u2WinStart;
4245 prRxBaEntry->u2WinSize = u2WinSize;
4246 prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT);
4247 prRxBaEntry->fgIsValid = TRUE;
4248 prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE;
4249 prRxBaEntry->fgHasBubble = FALSE;
4250
4251 g_arMissTimeout[ucStaRecIdx][ucTid] = 0;
4252
4253 DBGLOG(QM, INFO,
4254 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
4255 ucStaRecIdx, ucTid, prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd,
4256 prRxBaEntry->u2WinSize));
4257
4258 /* Update the BA entry reference table for per-packet lookup */
4259 prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry;
4260 } else {
4261 /* This shall not happen because FW should keep track of the usage of RX BA entries */
4262 DBGLOG(QM, ERROR,
4263 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount));
4264 return FALSE;
4265 }
4266 }
4267
4268 return TRUE;
4269}
4270
4271VOID
4272qmDelRxBaEntry(IN P_ADAPTER_T prAdapter,
4273 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost)
4274{
4275 P_RX_BA_ENTRY_T prRxBaEntry;
4276 P_STA_RECORD_T prStaRec;
4277 P_SW_RFB_T prFlushedPacketList = NULL;
4278 P_QUE_MGT_T prQM = &prAdapter->rQM;
4279
4280 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
4281
4282 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
4283 ASSERT(prStaRec);
4284
4285#if 0
4286 if (!(prStaRec->fgIsValid)) {
4287 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
4288 return;
4289 }
4290#endif
4291
4292 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4293 prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid];
4294
4295 if (prRxBaEntry) {
4296
4297 prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid);
4298
4299 if (prFlushedPacketList) {
4300
4301 if (fgFlushToHost) {
4302 wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList);
4303 } else {
4304
4305 P_SW_RFB_T prSwRfb;
4306 P_SW_RFB_T prNextSwRfb;
4307 prSwRfb = prFlushedPacketList;
4308
4309 do {
4310 prNextSwRfb =
4311 (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)
4312 prSwRfb);
4313 nicRxReturnRFB(prAdapter, prSwRfb);
4314 prSwRfb = prNextSwRfb;
4315 } while (prSwRfb);
4316
4317 }
4318
4319
4320 }
4321
4322 if (prRxBaEntry->fgHasBubble) {
4323 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], DELBA\n",
4324 prRxBaEntry->ucStaRecIdx, prRxBaEntry->ucTid));
4325
4326 cnmTimerStopTimer(prAdapter, &prRxBaEntry->rReorderBubbleTimer);
4327 prRxBaEntry->fgHasBubble = FALSE;
4328 }
4329#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
4330 /* Update RX BA entry state. Note that RX queue flush is not done here */
4331 prRxBaEntry->fgIsValid = FALSE;
4332 prQM->ucRxBaCount--;
4333
4334 /* Debug */
4335#if 0
4336 DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount);
4337#endif
4338
4339 /* Update STA RX BA table */
4340 prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL;
4341#endif
4342
4343 DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid));
4344
4345 }
4346
4347
4348 /* Debug */
4349#if CFG_HIF_RX_STARVATION_WARNING
4350 {
4351 P_RX_CTRL_T prRxCtrl;
4352 prRxCtrl = &prAdapter->rRxCtrl;
4353 DBGLOG(QM, TRACE,
4354 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt,
4355 prRxCtrl->u4DequeuedCnt));
4356 }
4357#endif
4358}
4359
4360VOID
4361mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter,
4362 IN PUINT_8 pucIE, IN P_STA_RECORD_T prStaRec)
4363{
4364 P_IE_WMM_INFO_T prIeWmmInfo;
4365 UINT_8 ucQosInfo;
4366 UINT_8 ucQosInfoAC;
4367 UINT_8 ucBmpAC;
4368 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4369
4370 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4371 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4372
4373 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4374 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4375 if (IE_LEN(pucIE) != 7) {
4376 break; /* WMM Info IE with a wrong length */
4377 }
4378
4379 prStaRec->fgIsQoS = TRUE;
4380 prStaRec->fgIsWmmSupported = TRUE;
4381
4382 prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE;
4383 ucQosInfo = prIeWmmInfo->ucQosInfo;
4384 ucQosInfoAC = ucQosInfo & BITS(0, 3);
4385
4386 if(IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd))
4387 prStaRec->fgIsUapsdSupported = (ucQosInfoAC) ? TRUE : FALSE;
4388 else
4389 prStaRec->fgIsUapsdSupported = FALSE;
4390
4391 ucBmpAC = 0;
4392
4393 if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) {
4394 ucBmpAC |= BIT(ACI_VO);
4395 }
4396 if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) {
4397 ucBmpAC |= BIT(ACI_VI);
4398 }
4399 if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) {
4400 ucBmpAC |= BIT(ACI_BE);
4401 }
4402 if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) {
4403 ucBmpAC |= BIT(ACI_BK);
4404 }
4405 prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC;
4406 prStaRec->ucUapsdSp = (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5;
4407 break;
4408
4409 default:
4410 /* Other WMM QoS IEs. Ignore any */
4411 break;
4412 }
4413 }
4414}
4415
4416/*----------------------------------------------------------------------------*/
4417/*!
4418* \brief To process WMM related IEs in ASSOC_RSP
4419*
4420* \param[in] prAdapter Adapter pointer
4421* \param[in] prSwRfb The received frame
4422* \param[in] pucIE The pointer to the first IE in the frame
4423* \param[in] u2IELength The total length of IEs in the frame
4424*
4425* \return none
4426*/
4427/*----------------------------------------------------------------------------*/
4428VOID
4429mqmProcessAssocReq(IN P_ADAPTER_T prAdapter,
4430 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4431{
4432 P_STA_RECORD_T prStaRec;
4433 UINT_16 u2Offset;
4434 PUINT_8 pucIEStart;
4435 UINT_32 u4Flags;
4436
4437 DEBUGFUNC("mqmProcessAssocReq");
4438
4439 ASSERT(prSwRfb);
4440 ASSERT(pucIE);
4441
4442 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4443 ASSERT(prStaRec);
4444
4445 if (prStaRec == NULL) {
4446 return;
4447 }
4448
4449 prStaRec->fgIsQoS = FALSE;
4450 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
4451
4452 pucIEStart = pucIE;
4453
4454 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4455 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4456 return;
4457 }
4458
4459
4460 /* Determine whether QoS is enabled with the association */
4461 else {
4462 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4463 switch (IE_ID(pucIE)) {
4464 case ELEM_ID_VENDOR:
4465 mqmParseAssocReqWmmIe(prAdapter, pucIE, prStaRec);
4466
4467 prStaRec->u4Flags = 0;
4468#if CFG_SUPPORT_MTK_SYNERGY
4469 if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, &u4Flags)) {
4470 prStaRec->u4Flags = u4Flags;
4471 }
4472#endif
4473
4474 break;
4475
4476 case ELEM_ID_HT_CAP:
4477 /* Some client won't put the WMM IE if client is 802.11n */
4478 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
4479 prStaRec->fgIsQoS = TRUE;
4480 }
4481 break;
4482 default:
4483 break;
4484 }
4485 }
4486
4487 DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4488
4489 }
4490}
4491
4492VOID
4493mqmParseAssocRspWmmIe(IN PUINT_8 pucIE, IN P_STA_RECORD_T prStaRec)
4494{
4495 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4496
4497 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4498 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4499
4500 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4501 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4502 if (IE_LEN(pucIE) != 24) {
4503 break; /* WMM Info IE with a wrong length */
4504 }
4505 prStaRec->fgIsQoS = TRUE;
4506 break;
4507
4508 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4509 if (IE_LEN(pucIE) != 7) {
4510 break; /* WMM Info IE with a wrong length */
4511 }
4512 prStaRec->fgIsQoS = TRUE;
4513 break;
4514
4515 default:
4516 /* Other WMM QoS IEs. Ignore any */
4517 break;
4518 }
4519 }
4520}
4521
4522/*----------------------------------------------------------------------------*/
4523/*!
4524* \brief To process WMM related IEs in ASSOC_RSP
4525*
4526* \param[in] prAdapter Adapter pointer
4527* \param[in] prSwRfb The received frame
4528* \param[in] pucIE The pointer to the first IE in the frame
4529* \param[in] u2IELength The total length of IEs in the frame
4530*
4531* \return none
4532*/
4533/*----------------------------------------------------------------------------*/
4534VOID
4535mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter,
4536 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4537{
4538 P_STA_RECORD_T prStaRec;
4539 UINT_16 u2Offset;
4540 PUINT_8 pucIEStart;
4541 UINT_32 u4Flags;
4542
4543 DEBUGFUNC("mqmProcessAssocRsp");
4544
4545 ASSERT(prSwRfb);
4546 ASSERT(pucIE);
4547
4548 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4549 ASSERT(prStaRec);
4550
4551 if (prStaRec == NULL) {
4552 return;
4553 }
4554
4555 prStaRec->fgIsQoS = FALSE;
4556
4557 pucIEStart = pucIE;
4558
4559 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
4560 prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.ucQoS));
4561
4562 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4563 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
4564 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4565 return;
4566 }
4567
4568 /* Determine whether QoS is enabled with the association */
4569 else {
4570 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4571 switch (IE_ID(pucIE)) {
4572 case ELEM_ID_VENDOR:
4573 /* Process WMM related IE */
4574 mqmParseAssocRspWmmIe(pucIE, prStaRec);
4575
4576 prStaRec->u4Flags = 0;
4577#if CFG_SUPPORT_MTK_SYNERGY
4578 if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, &u4Flags)) {
4579 prStaRec->u4Flags = u4Flags;
4580 }
4581#endif
4582
4583 break;
4584
4585 case ELEM_ID_HT_CAP:
4586 /* Some AP won't put the WMM IE if client is 802.11n */
4587 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
4588 prStaRec->fgIsQoS = TRUE;
4589 }
4590 break;
4591 default:
4592 break;
4593 }
4594 }
4595
4596 /* Parse AC parameters and write to HW CRs */
4597 if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) {
4598 mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE);
4599 }
4600
4601 DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4602 if (prStaRec->fgIsWmmSupported) {
4603 nicQmUpdateWmmParms(prAdapter, prStaRec->ucBssIndex);
4604 }
4605 }
4606}
4607
4608/*----------------------------------------------------------------------------*/
4609/*!
4610* \brief
4611*
4612* \param[in]
4613*
4614* \return none
4615*/
4616/*----------------------------------------------------------------------------*/
4617VOID
4618mqmProcessBcn(IN P_ADAPTER_T prAdapter,
4619 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4620{
4621 P_BSS_INFO_T prBssInfo;
4622 BOOLEAN fgNewParameter;
4623 UINT_8 i;
4624
4625 ASSERT(prAdapter);
4626 ASSERT(prSwRfb);
4627 ASSERT(pucIE);
4628
4629 DBGLOG(QM, TRACE, ("Enter %s\n", __func__));
4630
4631 fgNewParameter = FALSE;
4632
4633 for (i = 0; i < BSS_INFO_NUM; i++) {
4634 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, i);
4635
4636 if (IS_BSS_ACTIVE(prBssInfo)) {
4637 if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE &&
4638 prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) {
4639 /* P2P client or AIS infra STA */
4640 if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID,
4641 ((P_WLAN_MAC_MGMT_HEADER_T)
4642 (prSwRfb->pvHeader))->aucBSSID)) {
4643
4644 fgNewParameter = mqmParseEdcaParameters(prAdapter,
4645 prSwRfb, pucIE,
4646 u2IELength, FALSE);
4647 }
4648 }
4649
4650 /* Appy new parameters if necessary */
4651 if (fgNewParameter) {
4652 /* DBGLOG(QM, INFO, ("Update EDCA parameter for BSS[%u]\n", prBssInfo->ucBssIndex)); */
4653 nicQmUpdateWmmParms(prAdapter, prBssInfo->ucBssIndex);
4654 fgNewParameter = FALSE;
4655 }
4656 } /* end of IS_BSS_ACTIVE() */
4657 }
4658}
4659
4660BOOLEAN
4661mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucIE,
4662 IN BOOLEAN fgForceOverride)
4663{
4664 P_AC_QUE_PARMS_T prAcQueParams;
4665 P_IE_WMM_PARAM_T prIeWmmParam;
4666 ENUM_WMM_ACI_T eAci;
4667 BOOLEAN fgNewParameter = FALSE;
4668
4669 do {
4670 if (IE_LEN(pucIE) != 24) {
4671 break; /* WMM Param IE with a wrong length */
4672 }
4673
4674 prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE;
4675
4676 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
4677 if(!fgForceOverride) {
4678 if(mqmCompareEdcaParameters(prIeWmmParam, prBssInfo)) {
4679 fgNewParameter = FALSE;
4680 break;
4681 }
4682 }
4683
4684 fgNewParameter = TRUE;
4685 /* Update Parameter Set Count */
4686 prBssInfo->ucWmmParamSetCount = (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT);
4687 /* Update EDCA parameters */
4688 for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
4689 prAcQueParams = &prBssInfo->arACQueParms[eAci];
4690 mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams);
4691 DBGLOG(QM, INFO, ("BSS[%u]: eAci[%d] ACM[%d] Aifsn[%d] CWmin/max[%d/%d]"
4692 "TxopLimit[%d] NewParameter[%d]\n",
4693 prBssInfo->ucBssIndex, eAci, prAcQueParams->ucIsACMSet, prAcQueParams->u2Aifsn,
4694 prAcQueParams->u2CWmin, prAcQueParams->u2CWmax, prAcQueParams->u2TxopLimit, fgNewParameter));
4695 }
4696 }while(FALSE);
4697
4698 return fgNewParameter;
4699}
4700
4701/*----------------------------------------------------------------------------*/
4702/*!
4703* \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
4704*
4705* \param[in] prAdapter Adapter pointer
4706* \param[in] prSwRfb The received frame
4707* \param[in] pucIE The pointer to the first IE in the frame
4708* \param[in] u2IELength The total length of IEs in the frame
4709* \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
4710*
4711* \return none
4712*/
4713/*----------------------------------------------------------------------------*/
4714BOOLEAN
4715mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter,
4716 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength,
4717 IN BOOLEAN fgForceOverride)
4718{
4719 P_STA_RECORD_T prStaRec;
4720 UINT_16 u2Offset;
4721 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4722 P_BSS_INFO_T prBssInfo;
4723 BOOLEAN fgNewParameter = FALSE;
4724
4725 DEBUGFUNC("mqmParseEdcaParameters");
4726
4727 if (!prSwRfb) {
4728 return FALSE;
4729 }
4730
4731 if (!pucIE) {
4732 return FALSE;
4733 }
4734
4735 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4736 /* ASSERT(prStaRec); */
4737
4738 if (prStaRec == NULL) {
4739 return FALSE;
4740 }
4741
4742 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
4743 prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS));
4744
4745 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS) || (!prStaRec->fgIsWmmSupported)
4746 || (!prStaRec->fgIsQoS)) {
4747 return FALSE;
4748 }
4749
4750 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
4751
4752 /* Goal: Obtain the EDCA parameters */
4753 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4754 switch (IE_ID(pucIE)) {
4755 case ELEM_ID_WMM:
4756 if (!((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4757 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3)))) {
4758 break;
4759 }
4760
4761 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4762 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4763 fgNewParameter = mqmUpdateEdcaParameters(prBssInfo, pucIE, fgForceOverride);
4764 break;
4765
4766 default:
4767 /* Other WMM QoS IEs. Ignore */
4768 break;
4769 }
4770
4771 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4772 break;
4773 default:
4774 break;
4775 }
4776 }
4777
4778 return fgNewParameter;
4779}
4780
4781BOOLEAN mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam, IN P_BSS_INFO_T prBssInfo)
4782{
4783 P_AC_QUE_PARMS_T prAcQueParams;
4784 P_WMM_AC_PARAM_T prWmmAcParams;
4785 ENUM_WMM_ACI_T eAci;
4786
4787 /* return FALSE; */
4788
4789 /* Check Set Count */
4790 if (prBssInfo->ucWmmParamSetCount != (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)) {
4791 return FALSE;
4792 }
4793
4794 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
4795 prAcQueParams = &prBssInfo->arACQueParms[eAci];
4796 prWmmAcParams = &prIeWmmParam->arAcParam[eAci];
4797
4798 /* ACM */
4799 if (prAcQueParams->ucIsACMSet !=
4800 ((prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE)) {
4801 return FALSE;
4802 }
4803
4804 /* AIFSN */
4805 if (prAcQueParams->u2Aifsn != (prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_AIFSN)) {
4806 return FALSE;
4807 }
4808
4809 /* CW Max */
4810 if (prAcQueParams->u2CWmax !=
4811 (BIT((prWmmAcParams->ucEcw & WMM_ECW_WMAX_MASK) >> WMM_ECW_WMAX_OFFSET) - 1)) {
4812 return FALSE;
4813 }
4814
4815 /* CW Min */
4816 if (prAcQueParams->u2CWmin != (BIT(prWmmAcParams->ucEcw & WMM_ECW_WMIN_MASK) - 1)) {
4817 return FALSE;
4818 }
4819
4820 if (prAcQueParams->u2TxopLimit != prWmmAcParams->u2TxopLimit) {
4821 return FALSE;
4822 }
4823 }
4824
4825 return TRUE;
4826}
4827
4828
4829/*----------------------------------------------------------------------------*/
4830/*!
4831* \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
4832*
4833* \param[in] prAdapter Adapter pointer
4834* \param[in] prIeWmmParam The pointer to the WMM Parameter IE
4835* \param[in] u4AcOffset The offset specifying the AC queue for parsing
4836* \param[in] prHwAcParams The parameter structure used to configure the HW CRs
4837*
4838* \return none
4839*/
4840/*----------------------------------------------------------------------------*/
4841VOID
4842mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam,
4843 IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams)
4844{
4845 P_WMM_AC_PARAM_T prAcParam = &prIeWmmParam->arAcParam[u4AcOffset];
4846
4847 prAcQueParams->ucIsACMSet = (prAcParam->ucAciAifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE;
4848
4849 prAcQueParams->u2Aifsn = (prAcParam->ucAciAifsn & WMM_ACIAIFSN_AIFSN);
4850
4851 prAcQueParams->u2CWmax =
4852 BIT((prAcParam->ucEcw & WMM_ECW_WMAX_MASK) >> WMM_ECW_WMAX_OFFSET) - 1;
4853
4854 prAcQueParams->u2CWmin = BIT(prAcParam->ucEcw & WMM_ECW_WMIN_MASK) - 1;
4855
4856 WLAN_GET_FIELD_16(&prAcParam->u2TxopLimit, &prAcQueParams->u2TxopLimit);
4857
4858 prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME;
4859
4860}
4861
4862
4863/*----------------------------------------------------------------------------*/
4864/*!
4865* \brief To parse WMM/11n related IEs in scan results (only for AP peers)
4866*
4867* \param[in] prAdapter Adapter pointer
4868* \param[in] prScanResult The scan result which shall be parsed to obtain needed info
4869* \param[out] prStaRec The obtained info is stored in the STA_REC
4870*
4871* \return none
4872*/
4873/*----------------------------------------------------------------------------*/
4874VOID
4875mqmProcessScanResult(IN P_ADAPTER_T prAdapter,
4876 IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec)
4877{
4878 PUINT_8 pucIE;
4879 UINT_16 u2IELength;
4880 UINT_16 u2Offset;
4881 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4882 BOOLEAN fgIsHtVht;
4883
4884 DEBUGFUNC("mqmProcessScanResult");
4885
4886 ASSERT(prScanResult);
4887 ASSERT(prStaRec);
4888
4889 /* Reset the flag before parsing */
4890 prStaRec->fgIsWmmSupported = FALSE;
4891 prStaRec->fgIsUapsdSupported = FALSE;
4892 prStaRec->fgIsQoS = FALSE;
4893
4894 fgIsHtVht = FALSE;
4895
4896 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4897 return;
4898 }
4899
4900 u2IELength = prScanResult->u2IELength;
4901 pucIE = prScanResult->aucIEBuf;
4902
4903 /* <1> Determine whether the peer supports WMM/QoS and UAPSDU */
4904 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4905 switch (IE_ID(pucIE)) {
4906
4907 case ELEM_ID_EXTENDED_CAP:
4908#if CFG_SUPPORT_TDLS
4909 TdlsBssExtCapParse(prStaRec, pucIE);
4910#endif /* CFG_SUPPORT_TDLS */
4911 break;
4912
4913 case ELEM_ID_WMM:
4914 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4915 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4916
4917 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4918 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4919 if (IE_LEN(pucIE) != 24) {
4920 break; /* WMM Param IE with a wrong length */
4921 } else {
4922 prStaRec->fgIsWmmSupported = TRUE;
4923 prStaRec->fgIsUapsdSupported =
4924 (((((P_IE_WMM_PARAM_T) pucIE)->
4925 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
4926 FALSE);
4927 }
4928 break;
4929
4930 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4931 if (IE_LEN(pucIE) != 7) {
4932 break; /* WMM Info IE with a wrong length */
4933 } else {
4934 prStaRec->fgIsWmmSupported = TRUE;
4935 prStaRec->fgIsUapsdSupported =
4936 (((((P_IE_WMM_INFO_T) pucIE)->
4937 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
4938 FALSE);
4939 }
4940 break;
4941
4942 default:
4943 /* A WMM QoS IE that doesn't matter. Ignore it. */
4944 break;
4945 }
4946 }
4947 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4948
4949 break;
4950
4951 default:
4952 /* A WMM IE that doesn't matter. Ignore it. */
4953 break;
4954 }
4955 }
4956
4957 /* <1> Determine QoS */
4958 if (prStaRec->ucDesiredPhyTypeSet & (PHY_TYPE_SET_802_11N | PHY_TYPE_SET_802_11AC)) {
4959 fgIsHtVht = TRUE;
4960 }
4961
4962 if (fgIsHtVht || prStaRec->fgIsWmmSupported) {
4963 prStaRec->fgIsQoS = TRUE;
4964 }
4965}
4966
4967
4968/*----------------------------------------------------------------------------*/
4969/*!
4970* @brief Generate the WMM Info IE by Param
4971*
4972* \param[in] prAdapter Adapter pointer
4973* @param prMsduInfo The TX MMPDU
4974*
4975* @return (none)
4976*/
4977/*----------------------------------------------------------------------------*/
4978UINT_32
4979mqmFillWmmInfoIE(P_UINT_8 pucOutBuf,
4980 BOOLEAN fgSupportUAPSD,
4981 UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp)
4982{
4983 P_IE_WMM_INFO_T prIeWmmInfo;
4984 UINT_32 ucUapsd[] = {
4985 WMM_QOS_INFO_BE_UAPSD,
4986 WMM_QOS_INFO_BK_UAPSD,
4987 WMM_QOS_INFO_VI_UAPSD,
4988 WMM_QOS_INFO_VO_UAPSD
4989 };
4990 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4991
4992 ASSERT(pucOutBuf);
4993
4994 prIeWmmInfo = (P_IE_WMM_INFO_T) pucOutBuf;
4995
4996 prIeWmmInfo->ucId = ELEM_ID_WMM;
4997 prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4998
4999 /* WMM-2.2.1 WMM Information Element Field Values */
5000 prIeWmmInfo->aucOui[0] = aucWfaOui[0];
5001 prIeWmmInfo->aucOui[1] = aucWfaOui[1];
5002 prIeWmmInfo->aucOui[2] = aucWfaOui[2];
5003 prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
5004 prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
5005
5006 prIeWmmInfo->ucVersion = VERSION_WMM;
5007 prIeWmmInfo->ucQosInfo = 0;
5008
5009 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5010 if (fgSupportUAPSD) {
5011 UINT_8 ucQosInfo = 0;
5012 UINT_8 i;
5013
5014 /* Static U-APSD setting */
5015 for (i = ACI_BE; i <= ACI_VO; i++) {
5016 if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) {
5017 ucQosInfo |= (UINT_8) ucUapsd[i];
5018 }
5019 }
5020
5021 if (ucBmpDeliveryAC & ucBmpTriggerAC) {
5022 switch (ucUapsdSp) {
5023 case WMM_MAX_SP_LENGTH_ALL:
5024 ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
5025 break;
5026
5027 case WMM_MAX_SP_LENGTH_2:
5028 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
5029 break;
5030
5031 case WMM_MAX_SP_LENGTH_4:
5032 ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
5033 break;
5034
5035 case WMM_MAX_SP_LENGTH_6:
5036 ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
5037 break;
5038
5039 default:
5040 DBGLOG(QM, INFO, ("MQM: Incorrect SP length\n"));
5041 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
5042 break;
5043 }
5044 }
5045 prIeWmmInfo->ucQosInfo = ucQosInfo;
5046
5047 }
5048
5049 /* Increment the total IE length for the Element ID and Length fields. */
5050 return IE_SIZE(prIeWmmInfo);
5051}
5052
5053
5054/*----------------------------------------------------------------------------*/
5055/*!
5056* @brief Generate the WMM Info IE
5057*
5058* \param[in] prAdapter Adapter pointer
5059* @param prMsduInfo The TX MMPDU
5060*
5061* @return (none)
5062*/
5063/*----------------------------------------------------------------------------*/
5064UINT_32
5065mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter,
5066 P_BSS_INFO_T prBssInfo, P_STA_RECORD_T prStaRec, P_UINT_8 pucOutBuf)
5067{
5068 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo;
5069 BOOLEAN fgSupportUapsd;
5070
5071 ASSERT(pucOutBuf);
5072
5073 /* In case QoS is not turned off, exit directly */
5074 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5075 return 0;
5076 }
5077
5078 if (prStaRec == NULL) {
5079 return 0;
5080 }
5081
5082 if (!prStaRec->fgIsWmmSupported) {
5083 return 0;
5084 }
5085
5086 prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
5087
5088 fgSupportUapsd = (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)
5089 && prStaRec->fgIsUapsdSupported);
5090
5091 return mqmFillWmmInfoIE(pucOutBuf,
5092 fgSupportUapsd,
5093 prPmProfSetupInfo->ucBmpDeliveryAC,
5094 prPmProfSetupInfo->ucBmpTriggerAC, prPmProfSetupInfo->ucUapsdSp);
5095}
5096
5097/*----------------------------------------------------------------------------*/
5098/*!
5099* @brief Generate the WMM Info IE
5100*
5101* \param[in] prAdapter Adapter pointer
5102* @param prMsduInfo The TX MMPDU
5103*
5104* @return (none)
5105*/
5106/*----------------------------------------------------------------------------*/
5107VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
5108{
5109 P_BSS_INFO_T prBssInfo;
5110 P_STA_RECORD_T prStaRec;
5111 UINT_32 u4Length;
5112
5113 DEBUGFUNC("mqmGenerateWmmInfoIE");
5114
5115 ASSERT(prMsduInfo);
5116
5117 /* In case QoS is not turned off, exit directly */
5118 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5119 return;
5120 }
5121
5122 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5123 ASSERT(prStaRec);
5124
5125 if (prStaRec == NULL) {
5126 return;
5127 }
5128
5129 if (!prStaRec->fgIsWmmSupported) {
5130 return;
5131 }
5132
5133 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
5134
5135 u4Length = mqmGenerateWmmInfoIEByStaRec(prAdapter,
5136 prBssInfo,
5137 prStaRec,
5138 ((PUINT_8) prMsduInfo->prPacket +
5139 prMsduInfo->u2FrameLength));
5140
5141 prMsduInfo->u2FrameLength += u4Length;
5142}
5143
5144/*----------------------------------------------------------------------------*/
5145/*!
5146* @brief Generate the WMM Param IE
5147*
5148* \param[in] prAdapter Adapter pointer
5149* @param prMsduInfo The TX MMPDU
5150*
5151* @return (none)
5152*/
5153/*----------------------------------------------------------------------------*/
5154VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
5155{
5156 P_IE_WMM_PARAM_T prIeWmmParam;
5157
5158 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
5159
5160 UINT_8 aucACI[] = {
5161 WMM_ACI_AC_BE,
5162 WMM_ACI_AC_BK,
5163 WMM_ACI_AC_VI,
5164 WMM_ACI_AC_VO
5165 };
5166
5167 P_BSS_INFO_T prBssInfo;
5168 P_STA_RECORD_T prStaRec;
5169 ENUM_WMM_ACI_T eAci;
5170 P_WMM_AC_PARAM_T prAcParam;
5171
5172 DEBUGFUNC("mqmGenerateWmmParamIE");
5173 DBGLOG(QM, LOUD, ("\n"));
5174
5175 ASSERT(prMsduInfo);
5176
5177 /* In case QoS is not turned off, exit directly */
5178 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5179 return;
5180 }
5181
5182 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5183
5184 if (prStaRec) {
5185 if (!prStaRec->fgIsQoS) {
5186 return;
5187 }
5188 }
5189
5190 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
5191
5192 if (!prBssInfo->fgIsQBSS) {
5193 return;
5194 }
5195
5196 prIeWmmParam = (P_IE_WMM_PARAM_T)
5197 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
5198
5199 prIeWmmParam->ucId = ELEM_ID_WMM;
5200 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
5201
5202 /* WMM-2.2.1 WMM Information Element Field Values */
5203 prIeWmmParam->aucOui[0] = aucWfaOui[0];
5204 prIeWmmParam->aucOui[1] = aucWfaOui[1];
5205 prIeWmmParam->aucOui[2] = aucWfaOui[2];
5206 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
5207 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
5208
5209 prIeWmmParam->ucVersion = VERSION_WMM;
5210 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
5211
5212 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5213 if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) {
5214 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
5215 }
5216
5217 /* EDCA parameter */
5218
5219 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
5220 prAcParam = &prIeWmmParam->arAcParam[eAci];
5221
5222 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5223 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5224 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5225 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5226 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5227 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5228
5229 /* ACI */
5230 prAcParam->ucAciAifsn = aucACI[eAci];
5231 /* ACM */
5232 if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) {
5233 prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM;
5234 }
5235 /* AIFSN */
5236 prAcParam->ucAciAifsn |=
5237 (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & WMM_ACIAIFSN_AIFSN);
5238
5239 /* ECW Min */
5240 prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & WMM_ECW_WMIN_MASK);
5241 /* ECW Max */
5242 prAcParam->ucEcw |=
5243 ((prBssInfo->
5244 aucCWmaxLog2ForBcast[eAci] << WMM_ECW_WMAX_OFFSET) & WMM_ECW_WMAX_MASK);
5245
5246 /* Txop limit */
5247 WLAN_SET_FIELD_16(&prAcParam->u2TxopLimit,
5248 prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
5249
5250 }
5251
5252 /* Increment the total IE length for the Element ID and Length fields. */
5253 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam);
5254
5255}
5256
5257
5258#if CFG_SUPPORT_TDLS
5259/*----------------------------------------------------------------------------*/
5260/*!
5261* @brief Generate the WMM Param IE
5262*
5263* \param[in] prAdapter Adapter pointer
5264* @param prMsduInfo The TX MMPDU
5265*
5266* @return (none)
5267*/
5268/*----------------------------------------------------------------------------*/
5269UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pOutBuf)
5270{
5271 P_IE_WMM_PARAM_T prIeWmmParam;
5272
5273 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
5274
5275 UINT_8 aucACI[] = {
5276 WMM_ACI_AC_BE,
5277 WMM_ACI_AC_BK,
5278 WMM_ACI_AC_VI,
5279 WMM_ACI_AC_VO
5280 };
5281
5282 ENUM_WMM_ACI_T eAci;
5283 P_WMM_AC_PARAM_T prAcParam;
5284
5285 DEBUGFUNC("mqmGenerateWmmParamIE");
5286 DBGLOG(QM, LOUD, ("\n"));
5287
5288 ASSERT(pOutBuf);
5289
5290
5291 /* In case QoS is not turned off, exit directly */
5292 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5293 return WLAN_STATUS_SUCCESS;
5294 }
5295
5296
5297 if (!prBssInfo->fgIsQBSS) {
5298 return WLAN_STATUS_SUCCESS;
5299 }
5300
5301
5302
5303 prIeWmmParam = (P_IE_WMM_PARAM_T) pOutBuf;
5304
5305
5306 prIeWmmParam->ucId = ELEM_ID_WMM;
5307 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
5308
5309 /* WMM-2.2.1 WMM Information Element Field Values */
5310 prIeWmmParam->aucOui[0] = aucWfaOui[0];
5311 prIeWmmParam->aucOui[1] = aucWfaOui[1];
5312 prIeWmmParam->aucOui[2] = aucWfaOui[2];
5313 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
5314 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
5315
5316 prIeWmmParam->ucVersion = VERSION_WMM;
5317 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
5318
5319 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5320 if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) {
5321 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
5322 }
5323
5324 /* EDCA parameter */
5325
5326 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
5327 prAcParam = &prIeWmmParam->arAcParam[eAci];
5328
5329 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5330 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5331 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5332 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5333 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5334 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5335
5336 /* ACI */
5337 prAcParam->ucAciAifsn = aucACI[eAci];
5338 /* ACM */
5339 if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) {
5340 prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM;
5341 }
5342 /* AIFSN */
5343 prAcParam->ucAciAifsn |=
5344 (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & WMM_ACIAIFSN_AIFSN);
5345
5346 /* ECW Min */
5347 prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & WMM_ECW_WMIN_MASK);
5348 /* ECW Max */
5349 prAcParam->ucEcw |=
5350 ((prBssInfo->
5351 aucCWmaxLog2ForBcast[eAci] << WMM_ECW_WMAX_OFFSET) & WMM_ECW_WMAX_MASK);
5352
5353 /* Txop limit */
5354 WLAN_SET_FIELD_16(&prAcParam->u2TxopLimit,
5355 prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
5356
5357 }
5358
5359 /* Increment the total IE length for the Element ID and Length fields. */
5360 return IE_SIZE(prIeWmmParam);
5361
5362
5363}
5364
5365
5366#endif
5367
5368ENUM_FRAME_ACTION_T
5369qmGetFrameAction(IN P_ADAPTER_T prAdapter,
5370 IN UINT_8 ucBssIndex,
5371 IN UINT_8 ucStaRecIdx,
5372 IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType)
5373{
5374 ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_TX_PKT;
5375 P_BSS_INFO_T prBssInfo;
5376 P_STA_RECORD_T prStaRec;
5377 /* P_WLAN_MAC_HEADER_T prWlanFrame; */
5378 /* UINT_16 u2TxFrameCtrl; */
5379
5380 DEBUGFUNC("qmGetFrameAction");
5381
5382 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
5383 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx);
5384
5385 do {
5386 /* 4 <1> Tx, if FORCE_TX is set */
5387 if (prMsduInfo) {
5388 if (prMsduInfo->ucControlFlag & MSDU_CONTROL_FLAG_FORCE_TX) {
5389 eFrameAction = FRAME_ACTION_TX_PKT;
5390 break;
5391 }
5392 }
5393 /* 4 <2> Drop, if BSS is inactive */
5394 if (!IS_BSS_ACTIVE(prBssInfo)) {
5395 DBGLOG(QM, TRACE,
5396 ("Drop packets (BSS[%u] is INACTIVE)\n", prBssInfo->ucBssIndex));
5397 eFrameAction = FRAME_ACTION_DROP_PKT;
5398 break;
5399 }
5400 /* 4 <3> Check based on StaRec */
5401 if (prStaRec) {
5402 /* 4 <3.1> Drop, if StaRec is not in use */
5403 if (!prStaRec->fgIsInUse) {
5404 DBGLOG(QM, TRACE,
5405 ("Drop packets (Sta[%u] not in USE)\n", prStaRec->ucIndex));
5406 eFrameAction = FRAME_ACTION_DROP_PKT;
5407 break;
5408 }
5409 /* 4 <3.2> Sta in PS */
5410 if (prStaRec->fgIsInPS) {
5411 /* 4 <3.2.1> Tx, if resource is enough */
5412 if (nicTxGetResource
5413 (prAdapter,
5414 nicTxGetFrameResourceType(eFrameType,
5415 prMsduInfo)) >=
5416 QM_MGMT_QUEUED_THRESHOLD) {
5417 eFrameAction = FRAME_ACTION_TX_PKT;
5418 break;
5419 }
5420 /* 4 <3.2.2> Queue, if resource is not enough */
5421 else {
5422 DBGLOG(QM, TRACE,
5423 ("Queue packets (Sta[%u] in PS)\n",
5424 prStaRec->ucIndex));
5425 eFrameAction = FRAME_ACTION_QUEUE_PKT;
5426 break;
5427 }
5428 }
5429 }
5430 /* 4 <4> Queue, if BSS is absent */
5431 if (prBssInfo->fgIsNetAbsent) {
5432 DBGLOG(QM, TRACE,
5433 ("Queue packets (BSS[%u] Absent)\n", prBssInfo->ucBssIndex));
5434 eFrameAction = FRAME_ACTION_QUEUE_PKT;
5435 break;
5436 }
5437
5438 } while (FALSE);
5439
5440 return eFrameAction;
5441}
5442
5443
5444/*----------------------------------------------------------------------------*/
5445/*!
5446* \brief Handle BSS change operation Event from the FW
5447*
5448* \param[in] prAdapter Adapter pointer
5449* \param[in] prEvent The event packet from the FW
5450*
5451* \return (none)
5452*/
5453/*----------------------------------------------------------------------------*/
5454VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5455{
5456 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus;
5457 P_BSS_INFO_T prBssInfo;
5458 BOOLEAN fgIsNetAbsentOld;
5459
5460 prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent;
5461 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prEventBssStatus->ucBssIndex);
5462 fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent;
5463 prBssInfo->fgIsNetAbsent = prEventBssStatus->ucIsAbsent;
5464 prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota;
5465
5466 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
5467 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
5468
5469 DBGLOG(QM, INFO, ("NAF=%d,%d,%d\n",
5470 prEventBssStatus->ucBssIndex, prBssInfo->fgIsNetAbsent,
5471 prBssInfo->ucBssFreeQuota));
5472
5473 if (!prBssInfo->fgIsNetAbsent) {
5474 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27);
5475 } else {
5476 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28);
5477 }
5478 /* From Absent to Present */
5479 if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) {
5480 kalSetEvent(prAdapter->prGlueInfo);
5481 }
5482}
5483
5484
5485/*----------------------------------------------------------------------------*/
5486/*!
5487* \brief Handle STA change PS mode Event from the FW
5488*
5489* \param[in] prAdapter Adapter pointer
5490* \param[in] prEvent The event packet from the FW
5491*
5492* \return (none)
5493*/
5494/*----------------------------------------------------------------------------*/
5495VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5496{
5497 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode;
5498 P_STA_RECORD_T prStaRec;
5499 BOOLEAN fgIsInPSOld;
5500
5501 /* DbgPrint("QM:Event -RxBa\n"); */
5502
5503 prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent;
5504 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx);
5505 /* ASSERT(prStaRec); */
5506
5507 if (prStaRec) {
5508
5509 fgIsInPSOld = prStaRec->fgIsInPS;
5510 prStaRec->fgIsInPS = prEventStaChangePsMode->ucIsInPs;
5511
5512 qmUpdateFreeQuota(prAdapter,
5513 prStaRec,
5514 prEventStaChangePsMode->ucUpdateMode,
5515 prEventStaChangePsMode->ucFreeQuota);
5516
5517 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
5518 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
5519
5520
5521 DBGLOG(QM, INFO, ("PS=%d,%d\n",
5522 prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
5523
5524 /* From PS to Awake */
5525 if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) {
5526 kalSetEvent(prAdapter->prGlueInfo);
5527 }
5528 }
5529}
5530
5531/*----------------------------------------------------------------------------*/
5532/*!
5533* \brief Update STA free quota Event from FW
5534*
5535* \param[in] prAdapter Adapter pointer
5536* \param[in] prEvent The event packet from the FW
5537*
5538* \return (none)
5539*/
5540/*----------------------------------------------------------------------------*/
5541VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5542{
5543 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota;
5544 P_STA_RECORD_T prStaRec;
5545
5546
5547 prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent;
5548 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx);
5549 /* 2013/08/30
5550 * Station Record possible been freed.
5551 */
5552 /* ASSERT(prStaRec); */
5553
5554 if (prStaRec) {
5555 if (prStaRec->fgIsInPS) {
5556 qmUpdateFreeQuota(prAdapter,
5557 prStaRec,
5558 prEventStaUpdateFreeQuota->ucUpdateMode,
5559 prEventStaUpdateFreeQuota->ucFreeQuota);
5560
5561 kalSetEvent(prAdapter->prGlueInfo);
5562 }
5563#if 0
5564 DBGLOG(QM, TRACE,
5565 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
5566 prEventStaUpdateFreeQuota->ucStaRecIdx,
5567 prEventStaUpdateFreeQuota->ucUpdateMode,
5568 prEventStaUpdateFreeQuota->ucFreeQuota));
5569#endif
5570
5571 DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n",
5572 prEventStaUpdateFreeQuota->ucStaRecIdx,
5573 prEventStaUpdateFreeQuota->ucUpdateMode,
5574 prEventStaUpdateFreeQuota->ucFreeQuota));
5575
5576
5577 }
5578
5579}
5580
5581
5582/*----------------------------------------------------------------------------*/
5583/*!
5584* \brief Update STA free quota
5585*
5586* \param[in] prStaRec the STA
5587* \param[in] ucUpdateMode the method to update free quota
5588* \param[in] ucFreeQuota the value for update
5589*
5590* \return (none)
5591*/
5592/*----------------------------------------------------------------------------*/
5593VOID
5594qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter,
5595 IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota)
5596{
5597
5598 UINT_8 ucFreeQuotaForNonDelivery;
5599 UINT_8 ucFreeQuotaForDelivery;
5600
5601 ASSERT(prStaRec);
5602 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
5603 prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota));
5604
5605 if (!prStaRec->fgIsInPS)
5606 return;
5607
5608 switch (ucUpdateMode) {
5609 case FREE_QUOTA_UPDATE_MODE_INIT:
5610 case FREE_QUOTA_UPDATE_MODE_OVERWRITE:
5611 prStaRec->ucFreeQuota = ucFreeQuota;
5612 break;
5613 case FREE_QUOTA_UPDATE_MODE_INCREASE:
5614 prStaRec->ucFreeQuota += ucFreeQuota;
5615 break;
5616 case FREE_QUOTA_UPDATE_MODE_DECREASE:
5617 prStaRec->ucFreeQuota -= ucFreeQuota;
5618 break;
5619 default:
5620 ASSERT(0);
5621 }
5622
5623 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota));
5624
5625 ucFreeQuota = prStaRec->ucFreeQuota;
5626
5627 ucFreeQuotaForNonDelivery = 0;
5628 ucFreeQuotaForDelivery = 0;
5629
5630 if (ucFreeQuota > 0) {
5631 if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
5632 /* && prAdapter->rWifiVar.fgSupportQoS
5633 && prAdapter->rWifiVar.fgSupportUAPSD */) {
5634 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
5635
5636 if (prStaRec->ucFreeQuotaForNonDelivery > 0
5637 && prStaRec->ucFreeQuotaForDelivery > 0) {
5638 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
5639 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5640 } else if (prStaRec->ucFreeQuotaForNonDelivery == 0
5641 && prStaRec->ucFreeQuotaForDelivery == 0) {
5642 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
5643 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5644 } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) {
5645 /* NonDelivery is not busy */
5646 if (ucFreeQuota >= 3) {
5647 ucFreeQuotaForNonDelivery = 2;
5648 ucFreeQuotaForDelivery =
5649 ucFreeQuota - ucFreeQuotaForNonDelivery;
5650 } else {
5651 ucFreeQuotaForDelivery = ucFreeQuota;
5652 ucFreeQuotaForNonDelivery = 0;
5653 }
5654 } else if (prStaRec->ucFreeQuotaForDelivery > 0) {
5655 /* Delivery is not busy */
5656 if (ucFreeQuota >= 3) {
5657 ucFreeQuotaForDelivery = 2;
5658 ucFreeQuotaForNonDelivery =
5659 ucFreeQuota - ucFreeQuotaForDelivery;
5660 } else {
5661 ucFreeQuotaForNonDelivery = ucFreeQuota;
5662 ucFreeQuotaForDelivery = 0;
5663 }
5664 }
5665
5666 } else {
5667 /* !prStaRec->fgIsUapsdSupported */
5668 ucFreeQuotaForNonDelivery = ucFreeQuota;
5669 ucFreeQuotaForDelivery = 0;
5670 }
5671 }
5672 /* ucFreeQuota > 0 */
5673 prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery;
5674 prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery;
5675
5676 DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
5677 prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery));
5678
5679}
5680
5681/*----------------------------------------------------------------------------*/
5682/*!
5683* \brief Return the reorder queued RX packets
5684*
5685* \param[in] (none)
5686*
5687* \return The number of queued RX packets
5688*/
5689/*----------------------------------------------------------------------------*/
5690UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter)
5691{
5692 UINT_32 i, u4Total;
5693 P_QUE_MGT_T prQM = &prAdapter->rQM;
5694 u4Total = 0;
5695 /* XXX The summation may impact the performance */
5696 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
5697 u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem;
5698#if DBG && 0
5699 if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) {
5700 ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0);
5701 }
5702#endif
5703 }
5704 ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2));
5705 return u4Total;
5706}
5707
5708/*----------------------------------------------------------------------------*/
5709/*!
5710* \brief Dump current queue status
5711*
5712* \param[in] (none)
5713*
5714* \return (none)
5715*/
5716/*----------------------------------------------------------------------------*/
5717VOID qmDumpQueueStatus(IN P_ADAPTER_T prAdapter)
5718{
5719 P_TX_CTRL_T prTxCtrl;
5720 P_QUE_MGT_T prQM;
5721 P_GLUE_INFO_T prGlueInfo;
5722 UINT_32 i;
5723 UINT_32 u4TotalBufferCount, u4TotalPageCount, u4CurBufferCount, u4CurPageCount;
5724
5725 DEBUGFUNC(("%s", __func__));
5726
5727 prTxCtrl = &prAdapter->rTxCtrl;
5728 prQM = &prAdapter->rQM;
5729 prGlueInfo = prAdapter->prGlueInfo;
5730 u4TotalBufferCount = 0;
5731 u4TotalPageCount = 0;
5732 u4CurBufferCount = 0;
5733 u4CurPageCount = 0;
5734
5735 DBGLOG(SW4, INFO, ("\n------<Dump QUEUE Status>------\n"));
5736
5737 for(i = TC0_INDEX; i < TC_NUM; i++) {
5738 DBGLOG(SW4, INFO, ("TC%u ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5739 i,
5740 prTxCtrl->rTc.au2MaxNumOfBuffer[i],
5741 prTxCtrl->rTc.au2MaxNumOfPage[i],
5742 prTxCtrl->rTc.au2FreeBufferCount[i],
5743 prTxCtrl->rTc.au2FreePageCount[i]));
5744
5745 u4TotalBufferCount += prTxCtrl->rTc.au2MaxNumOfBuffer[i];
5746 u4TotalPageCount += prTxCtrl->rTc.au2MaxNumOfPage[i];
5747 u4CurBufferCount += prTxCtrl->rTc.au2FreeBufferCount[i];
5748 u4CurPageCount += prTxCtrl->rTc.au2FreePageCount[i];
5749 }
5750
5751 DBGLOG(SW4, INFO, ("ToT ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5752 u4TotalBufferCount, u4TotalPageCount, u4CurBufferCount, u4CurPageCount));
5753
5754 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5755
5756#if QM_ADAPTIVE_TC_RESOURCE_CTRL
5757 for(i = TC0_INDEX; i < TC_NUM; i++) {
5758
5759 DBGLOG(SW4, INFO,("TC%u AvgQLen[%04u] minRsv[%02u] CurTcRes[%02u] GrtdTcRes[%02u]\n",
5760 i,
5761 QM_GET_TX_QUEUE_LEN(prAdapter, i),
5762 prQM->au4MinReservedTcResource[i],
5763 prQM->au4CurrentTcResource[i],
5764 prQM->au4GuaranteedTcResource[i]));
5765 }
5766
5767 DBGLOG(SW4, INFO,("Resource Residual[%u] ExtraRsv[%u]\n",
5768 prQM->u4ResidualTcResource,
5769 prQM->u4ExtraReservedTcResource));
5770 DBGLOG(SW4, INFO,("QueLenMovingAvg[%u] Time2AdjResource[%u] Time2UpdateQLen[%u]\n",
5771 prQM->u4QueLenMovingAverage,
5772 prQM->u4TimeToAdjustTcResource,
5773 prQM->u4TimeToUpdateQueLen));
5774#endif
5775
5776 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5777
5778#if QM_FORWARDING_FAIRNESS
5779 for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) {
5780 DBGLOG(SW4, INFO,
5781 ("TC%u HeadSta[%u] ResourceUsedCount[%u]\n", i, prQM->au4HeadStaRecIndex[i],
5782 prQM->au4ResourceUsedCount[i]));
5783 }
5784#endif
5785
5786 DBGLOG(SW4, INFO, ("BMC or unknown TxQueue Len[%u]\n", prQM->arTxQueue[0].u4NumElem));
5787 DBGLOG(SW4, INFO,
5788 ("Pending QLen Normal[%u] Sec[%u]\n", prGlueInfo->i4TxPendingFrameNum,
5789 prGlueInfo->i4TxPendingSecurityFrameNum));
5790
5791#if defined(LINUX)
5792 for (i = 0; i < HW_BSSID_NUM; i++) {
5793 DBGLOG(SW4, INFO, ("Pending BSS[%u] QLen[%u:%u:%u:%u]\n",
5794 i,
5795 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][0],
5796 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][1],
5797 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][2],
5798 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][3]));
5799 }
5800#endif
5801 DBGLOG(SW4, INFO, ("Pending FWD CNT[%d]\n", prTxCtrl->i4PendingFwdFrameCount));
5802 DBGLOG(SW4, INFO, ("Pending MGMT CNT[%d]\n", prTxCtrl->i4TxMgmtPendingNum));
5803
5804 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5805
5806 DBGLOG(SW4, INFO, ("Total RFB[%u]\n", CFG_RX_MAX_PKT_NUM));
5807 DBGLOG(SW4, INFO, ("rFreeSwRfbList[%u]\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem));
5808 DBGLOG(SW4, INFO,
5809 ("rReceivedRfbList[%u]\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem));
5810 DBGLOG(SW4, INFO,
5811 ("rIndicatedRfbList[%u]\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem));
5812 DBGLOG(SW4, INFO, ("ucNumIndPacket[%u]\n", prAdapter->rRxCtrl.ucNumIndPacket));
5813 DBGLOG(SW4, INFO, ("ucNumRetainedPacket[%u]\n", prAdapter->rRxCtrl.ucNumRetainedPacket));
5814
5815 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5816 DBGLOG(SW4, INFO, ("CMD: FreeCmd[%u/%u] PendingCmd[%u] Cmd2Tx[%u]\n",
5817 prAdapter->rFreeCmdList.u4NumElem,
5818 CFG_TX_MAX_CMD_PKT_NUM,
5819 prAdapter->rPendingCmdQueue.u4NumElem, prGlueInfo->rCmdQueue.u4NumElem));
5820 DBGLOG(SW4, INFO, ("MGMT: FreeMgmt[%u/%u] PendingMgmt[%u]\n",
5821 prAdapter->rTxCtrl.rFreeMsduInfoList.u4NumElem,
5822 CFG_TX_MAX_PKT_NUM, prAdapter->rTxCtrl.rTxMgmtTxingQueue.u4NumElem));
5823
5824
5825 DBGLOG(SW4, INFO, ("---------------------------------\n\n"));
5826}
5827
5828
5829
5830
5831
5832#if CFG_M0VE_BA_TO_DRIVER
5833/*----------------------------------------------------------------------------*/
5834/*!
5835* @brief Send DELBA Action frame
5836*
5837* @param fgIsInitiator DELBA_ROLE_INITIATOR or DELBA_ROLE_RECIPIENT
5838* @param prStaRec Pointer to the STA_REC of the receiving peer
5839* @param u4Tid TID of the BA entry
5840* @param u4ReasonCode The reason code carried in the Action frame
5841*
5842* @return (none)
5843*/
5844/*----------------------------------------------------------------------------*/
5845VOID
5846mqmSendDelBaFrame(IN P_ADAPTER_T prAdapter,
5847 IN BOOLEAN fgIsInitiator,
5848 IN P_STA_RECORD_T prStaRec, IN UINT_32 u4Tid, IN UINT_32 u4ReasonCode)
5849{
5850
5851 P_MSDU_INFO_T prTxMsduInfo;
5852 P_ACTION_DELBA_FRAME_T prDelBaFrame;
5853 P_BSS_INFO_T prBssInfo;
5854
5855 DBGLOG(QM, WARN, ("[Puff]: Enter mqmSendDelBaFrame()\n"));
5856
5857 ASSERT(prStaRec);
5858
5859 /* 3 <1> Block the message in case of invalid STA */
5860 if (!prStaRec->fgIsInUse) {
5861 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
5862 return;
5863 }
5864 /* Check HT-capabale STA */
5865 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
5866 DBGLOG(QM, WARN,
5867 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
5868 prStaRec->ucDesiredPhyTypeSet));
5869 return;
5870 }
5871 /* 4 <2> Construct the DELBA frame */
5872 prTxMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, ACTION_DELBA_FRAME_LEN);
5873
5874 if (!prTxMsduInfo) {
5875 DBGLOG(QM, WARN,
5876 ("[Puff][%s]: (Warning) DELBA for TID=%ld was not sent (MSDU_INFO alloc failure)\n",
5877 __func__, u4Tid));
5878 return;
5879 }
5880
5881 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
5882
5883 /* Fill the Action frame */
5884 prDelBaFrame =
5885 (P_ACTION_DELBA_FRAME_T) ((UINT_32) (prTxMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
5886 prDelBaFrame->u2FrameCtrl = MAC_FRAME_ACTION;
5887#if CFG_SUPPORT_802_11W
5888 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
5889 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) DELBA is 80211w enabled\n", __func__));
5890 prDelBaFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
5891 }
5892#endif
5893
5894 prDelBaFrame->u2DurationID = 0;
5895 prDelBaFrame->ucCategory = CATEGORY_BLOCK_ACK_ACTION;
5896 prDelBaFrame->ucAction = ACTION_DELBA;
5897
5898 prDelBaFrame->u2DelBaParameterSet = 0;
5899 prDelBaFrame->u2DelBaParameterSet |= ((fgIsInitiator ? ACTION_DELBA_INITIATOR_MASK : 0));
5900 prDelBaFrame->u2DelBaParameterSet |=
5901 ((u4Tid << ACTION_DELBA_TID_OFFSET) & ACTION_DELBA_TID_MASK);
5902 prDelBaFrame->u2ReasonCode = u4ReasonCode;
5903
5904 COPY_MAC_ADDR(prDelBaFrame->aucDestAddr, prStaRec->aucMacAddr);
5905 COPY_MAC_ADDR(prDelBaFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr);
5906 COPY_MAC_ADDR(prDelBaFrame->aucBSSID, prBssInfo->aucBSSID);
5907
5908 /* 4 <3> Configure the MSDU_INFO and forward it to TXM */
5909 TX_SET_MMPDU(prAdapter,
5910 prTxMsduInfo,
5911 prStaRec->ucBssIndex,
5912 (prStaRec != NULL) ? (prStaRec->ucIndex) : (STA_REC_INDEX_NOT_FOUND),
5913 WLAN_MAC_HEADER_LEN, ACTION_DELBA_FRAME_LEN, NULL, MSDU_RATE_MODE_AUTO);
5914
5915#if CFG_SUPPORT_802_11W
5916 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
5917 DBGLOG(RSN, INFO, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
5918 nicTxConfigPktOption(prTxMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
5919 }
5920#endif
5921
5922 /* TID and fgIsInitiator are needed when processing TX Done of the DELBA frame */
5923 prTxMsduInfo->ucTID = (UINT_8) u4Tid;
5924 prTxMsduInfo->ucControlFlag = (fgIsInitiator ? 1 : 0);
5925
5926 nicTxEnqueueMsdu(prAdapter, prTxMsduInfo);
5927
5928 DBGLOG(QM, WARN,
5929 ("[Puff][%s]: Send DELBA for TID=%ld Initiator=%d\n", __func__, u4Tid,
5930 fgIsInitiator));
5931}
5932
5933
5934/*----------------------------------------------------------------------------*/
5935/*!
5936* @brief Callback function for the TX Done event for an ADDBA_RSP
5937*
5938* @param prMsduInfo The TX packet
5939* @param rWlanStatus WLAN_STATUS_SUCCESS if TX is successful
5940*
5941* @return WLAN_STATUS_BUFFER_RETAINED is returned if the buffer shall not be freed by TXM
5942*/
5943/*----------------------------------------------------------------------------*/
5944WLAN_STATUS
5945mqmCallbackAddBaRspSent(IN P_ADAPTER_T prAdapter,
5946 IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus)
5947{
5948 P_RX_BA_ENTRY_T prRxBaEntry;
5949 P_STA_RECORD_T prStaRec;
5950 P_QUE_MGT_T prQM;
5951
5952 UINT_32 u4Tid = 0;
5953
5954 /* ASSERT(prMsduInfo); */
5955 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5956 ASSERT(prStaRec);
5957
5958 prQM = &prAdapter->rQM;
5959
5960 DBGLOG(QM, WARN, ("[Puff]: Enter mqmCallbackAddBaRspSent()\n"));
5961
5962 /* 4 <0> Check STA_REC status */
5963 /* Check STA_REC is inuse */
5964 if (!prStaRec->fgIsInUse) {
5965 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
5966 return WLAN_STATUS_SUCCESS;
5967 }
5968 /* Check HT-capabale STA */
5969 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
5970 DBGLOG(QM, WARN,
5971 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
5972 prStaRec->ucDesiredPhyTypeSet));
5973 return WLAN_STATUS_SUCCESS; /* To free the received ADDBA_REQ directly */
5974 }
5975 /* 4 <1> Find the corresponding BA entry */
5976 u4Tid = prMsduInfo->ucTID; /* TID is stored in MSDU_INFO when composing the ADDBA_RSP frame */
5977 prRxBaEntry = &prQM->arRxBaTable[u4Tid];
5978
5979 /* Note: Due to some reason, for example, receiving a DELBA, the BA entry may not be in state NEGO */
5980 /* 4 <2> INVALID state */
5981 if (!prRxBaEntry) {
5982 DBGLOG(QM, WARN,
5983 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)(invalid BA)\n",
5984 __func__, prStaRec->ucIndex, u4Tid));
5985 }
5986 /* 4 <3> NEGO, ACTIVE, or DELETING state */
5987 else {
5988 switch (rTxDoneStatus) {
5989 /* 4 <Case 1> TX Success */
5990 case TX_RESULT_SUCCESS:
5991
5992 DBGLOG(QM, WARN,
5993 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)\n",
5994 __func__, prStaRec->ucIndex, u4Tid));
5995
5996
5997 /* 4 <Case 1.1> NEGO or ACTIVE state */
5998 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_DELETING) {
5999 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
6000 BA_ENTRY_STATUS_ACTIVE);
6001 }
6002 /* 4 <Case 1.2> DELETING state */
6003 /* else */
6004 /* Deleting is on-going, so do nothing and wait for TX done of the DELBA frame */
6005
6006 break;
6007
6008 /* 4 <Case 2> TX Failure */
6009 default:
6010
6011 DBGLOG(QM, WARN,
6012 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld Entry_Status=%d)(TX failed)\n",
6013 __func__, prStaRec->ucIndex, u4Tid, prRxBaEntry->ucStatus));
6014
6015 /* 4 <Case 2.1> NEGO or ACTIVE state */
6016 /* Notify the host to delete the agreement */
6017 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_DELETING) {
6018 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
6019 BA_ENTRY_STATUS_DELETING);
6020
6021 /* Send DELBA to the peer to ensure the BA state is synchronized */
6022 mqmSendDelBaFrame(prAdapter, DELBA_ROLE_RECIPIENT, prStaRec, u4Tid,
6023 STATUS_CODE_UNSPECIFIED_FAILURE);
6024 }
6025 /* 4 <Case 2.2> DELETING state */
6026 /* else */
6027 /* Deleting is on-going, so do nothing and wait for the TX done of the DELBA frame */
6028
6029 break;
6030 }
6031
6032
6033 }
6034
6035
6036 return WLAN_STATUS_SUCCESS; /* TXM shall release the packet */
6037
6038}
6039
6040
6041/*----------------------------------------------------------------------------*/
6042/*!
6043* @brief Check if there is any idle RX BA
6044*
6045* @param u4Param (not used)
6046*
6047* @return (none)
6048*/
6049/*----------------------------------------------------------------------------*/
6050VOID mqmTimeoutCheckIdleRxBa(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
6051{
6052 INT_8 i;
6053 P_RX_BA_ENTRY_T prRxBa;
6054 UINT_32 u4IdleCountThreshold = 0;
6055 P_STA_RECORD_T prStaRec;
6056 P_QUE_MGT_T prQM;
6057
6058 DBGLOG(QM, WARN, ("[Puff]: Enter mqmTimeoutIdleRxBaDetection()\n"));
6059
6060 prQM = &prAdapter->rQM;
6061
6062 /* 4 <1> Restart the timer */
6063 cnmTimerStopTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer);
6064 cnmTimerStartTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer,
6065 MQM_IDLE_RX_BA_CHECK_INTERVAL);
6066
6067 /* 4 <2> Increment the idle count for each idle BA */
6068 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
6069
6070 prRxBa = &prQM->arRxBaTable[i];
6071
6072 if (prRxBa->ucStatus == BA_ENTRY_STATUS_ACTIVE) {
6073
6074 prStaRec = cnmGetStaRecByIndex(prAdapter, prRxBa->ucStaRecIdx);
6075
6076 if (!prStaRec->fgIsInUse) {
6077 DBGLOG(QM, WARN,
6078 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
6079 ASSERT(0);
6080 }
6081 /* Check HT-capabale STA */
6082 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
6083 DBGLOG(QM, WARN,
6084 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n",
6085 __func__, prStaRec->ucDesiredPhyTypeSet));
6086 ASSERT(0);
6087 }
6088 /* 4 <2.1> Idle detected, increment idle count and see if a DELBA should be sent */
6089 if (prRxBa->u2SnapShotSN == prStaRec->au2CachedSeqCtrl[prRxBa->ucTid]) {
6090
6091 prRxBa->ucIdleCount++;
6092
6093 ASSERT(prRxBa->ucTid < 8);
6094 switch (aucTid2ACI[prRxBa->ucTid]) {
6095 case 0: /* BK */
6096 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_BK;
6097 break;
6098 case 1: /* BE */
6099 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_BE;
6100 break;
6101 case 2: /* VI */
6102 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_VI;
6103 break;
6104 case 3: /* VO */
6105 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_VO;
6106 break;
6107 }
6108
6109 if (prRxBa->ucIdleCount >= u4IdleCountThreshold) {
6110 mqmRxModifyBaEntryStatus(prAdapter, prRxBa,
6111 BA_ENTRY_STATUS_INVALID);
6112 mqmSendDelBaFrame(prAdapter, DELBA_ROLE_RECIPIENT, prStaRec,
6113 (UINT_32) prRxBa->ucTid,
6114 REASON_CODE_PEER_TIME_OUT);
6115 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prRxBa->ucTid,
6116 TRUE);
6117 }
6118 }
6119 /* 4 <2.2> Activity detected */
6120 else {
6121 prRxBa->u2SnapShotSN = prStaRec->au2CachedSeqCtrl[prRxBa->ucTid];
6122 prRxBa->ucIdleCount = 0;
6123 continue; /* check the next BA entry */
6124 }
6125 }
6126 }
6127
6128}
6129
6130
6131/*----------------------------------------------------------------------------*/
6132/*!
6133* @brief Do RX BA entry state transition
6134*
6135* @param prRxBaEntry The BA entry pointer
6136* @param eStatus The state to transition to
6137*
6138* @return (none)
6139*/
6140/*----------------------------------------------------------------------------*/
6141VOID
6142mqmRxModifyBaEntryStatus(IN P_ADAPTER_T prAdapter,
6143 IN P_RX_BA_ENTRY_T prRxBaEntry, IN ENUM_BA_ENTRY_STATUS_T eStatus)
6144{
6145 P_STA_RECORD_T prStaRec;
6146 P_QUE_MGT_T prQM;
6147
6148 BOOLEAN fgResetScoreBoard = FALSE;
6149
6150 ASSERT(prRxBaEntry);
6151
6152 prStaRec = cnmGetStaRecByIndex(prAdapter, prRxBaEntry->ucStaRecIdx);
6153 ASSERT(prStaRec);
6154 prQM = &prAdapter->rQM;
6155
6156 if (prRxBaEntry->ucStatus == (UINT_8) eStatus) {
6157 DBGLOG(QM, WARN,
6158 ("[Puff][%s]: eStatus are identical...\n", __func__, prRxBaEntry->ucStatus));
6159 return;
6160 }
6161 /* 4 <1> State transition from state X */
6162 switch (prRxBaEntry->ucStatus) {
6163
6164 /* 4 <1.1> From (X = INVALID) to (ACTIVE or NEGO or DELETING) */
6165 case BA_ENTRY_STATUS_INVALID:
6166
6167 /* Associate the BA entry with the STA_REC when leaving INVALID state */
6168 kalMemCopy(&prQM->arRxBaTable[prRxBaEntry->ucTid], prRxBaEntry,
6169 sizeof(RX_BA_ENTRY_T));
6170
6171 /* Increment the RX BA counter */
6172 prQM->ucRxBaCount++;
6173 ASSERT(prQM->ucRxBaCount <= CFG_NUM_OF_RX_BA_AGREEMENTS);
6174
6175 /* Since AMPDU may be received during INVALID state */
6176 fgResetScoreBoard = TRUE;
6177
6178 /* Reset Idle Count since this BA entry is being activated now.
6179 * Note: If there is no ACTIVE entry, the idle detection timer will not be started.
6180 */
6181 prRxBaEntry->ucIdleCount = 0;
6182 break;
6183
6184 /* 4 <1.2> Other cases */
6185 default:
6186 break;
6187 }
6188
6189 /* 4 <2> State trasition to state Y */
6190 switch (eStatus) {
6191
6192 /* 4 <2.1> From (NEGO, ACTIVE, DELETING) to (Y=INVALID) */
6193 case BA_ENTRY_STATUS_INVALID:
6194
6195 /* Disassociate the BA entry with the STA_REC */
6196 kalMemZero(&prQM->arRxBaTable[prRxBaEntry->ucTid], sizeof(RX_BA_ENTRY_T));
6197
6198 /* Decrement the RX BA counter */
6199 prQM->ucRxBaCount--;
6200 ASSERT(prQM->ucRxBaCount < CFG_NUM_OF_RX_BA_AGREEMENTS);
6201
6202 /* (TBC) */
6203 fgResetScoreBoard = TRUE;
6204
6205 /* If there is not any BA agreement, stop doing idle detection */
6206 if (prQM->ucRxBaCount == 0) {
6207 if (MQM_CHECK_FLAG
6208 (prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED)) {
6209 cnmTimerStopTimer(prAdapter,
6210 &prAdapter->rMqmIdleRxBaDetectionTimer);
6211 MQM_CLEAR_FLAG(prAdapter->u4FlagBitmap,
6212 MQM_FLAG_IDLE_RX_BA_TIMER_STARTED);
6213 }
6214 }
6215
6216 break;
6217
6218 /* 4 <2.2> From (any) to (Y=ACTIVE) */
6219 case BA_ENTRY_STATUS_ACTIVE:
6220
6221 /* If there is at least one BA going into ACTIVE, start idle detection */
6222 if (!MQM_CHECK_FLAG(prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED)) {
6223 cnmTimerInitTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer, (PFN_MGMT_TIMEOUT_FUNC) mqmTimeoutCheckIdleRxBa, (ULONG) NULL); /* No parameter */
6224
6225 cnmTimerStopTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer);
6226
6227#if MQM_IDLE_RX_BA_DETECTION
6228 cnmTimerStartTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer,
6229 MQM_IDLE_RX_BA_CHECK_INTERVAL);
6230 MQM_SET_FLAG(prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED);
6231#endif
6232 }
6233
6234 break;
6235
6236 case BA_ENTRY_STATUS_NEGO:
6237 default:
6238 break;
6239 }
6240
6241 if (fgResetScoreBoard) {
6242 P_CMD_RESET_BA_SCOREBOARD_T prCmdBody;
6243
6244 prCmdBody = (P_CMD_RESET_BA_SCOREBOARD_T)
6245 cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_RESET_BA_SCOREBOARD_T));
6246 ASSERT(prCmdBody);
6247
6248 prCmdBody->ucflag = MAC_ADDR_TID_MATCH;
6249 prCmdBody->ucTID = prRxBaEntry->ucTid;
6250 kalMemCopy(prCmdBody->aucMacAddr, prStaRec->aucMacAddr, PARAM_MAC_ADDR_LEN);
6251
6252 wlanoidResetBAScoreboard(prAdapter, prCmdBody, sizeof(CMD_RESET_BA_SCOREBOARD_T));
6253
6254 }
6255
6256 DBGLOG(QM, WARN, ("[Puff]QM: (RX_BA) [STA=%d TID=%d] status from %d to %d\n",
6257 prRxBaEntry->ucStaRecIdx, prRxBaEntry->ucTid,
6258 prRxBaEntry->ucStatus, eStatus));
6259
6260 prRxBaEntry->ucStatus = (UINT_8) eStatus;
6261
6262}
6263
6264
6265/*----------------------------------------------------------------------------*/
6266/*!
6267* \brief
6268*
6269* \param[in]
6270*
6271* \return none
6272*/
6273/*----------------------------------------------------------------------------*/
6274VOID mqmHandleAddBaReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
6275{
6276 P_STA_RECORD_T prStaRec;
6277 P_BSS_INFO_T prBssInfo;
6278 P_ACTION_ADDBA_REQ_FRAME_T prAddBaReq;
6279 ACTION_ADDBA_REQ_BODY_T rAddBaReqBody;
6280 P_ACTION_ADDBA_RSP_FRAME_T prAddBaRsp;
6281 ACTION_ADDBA_RSP_BODY_T rAddBaRspBody;
6282 P_RX_BA_ENTRY_T prRxBaEntry;
6283 P_MSDU_INFO_T prTxMsduInfo;
6284 P_QUE_MGT_T prQM;
6285
6286 BOOLEAN fgIsReqAccepted = TRUE; /* Reject or accept the ADDBA_REQ */
6287 BOOLEAN fgIsNewEntryAdded = FALSE; /* Indicator: Whether a new RX BA entry will be added */
6288
6289 UINT_32 u4Tid;
6290 UINT_32 u4StaRecIdx;
6291 UINT_16 u2WinStart;
6292 UINT_16 u2WinSize;
6293 UINT_32 u4BuffSize;
6294
6295#if CFG_SUPPORT_BCM
6296 UINT_32 u4BuffSizeBT;
6297#endif
6298
6299 ASSERT(prSwRfb);
6300
6301 prStaRec = prSwRfb->prStaRec;
6302 prQM = &prAdapter->rQM;
6303
6304 do {
6305
6306
6307 /* 4 <0> Check if this is an active HT-capable STA */
6308 /* Check STA_REC is inuse */
6309 if (!prStaRec->fgIsInUse) {
6310 DBGLOG(QM, WARN,
6311 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
6312 break;
6313 }
6314 /* Check HT-capabale STA */
6315 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
6316 DBGLOG(QM, WARN,
6317 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
6318 prStaRec->ucDesiredPhyTypeSet));
6319 break; /* To free the received ADDBA_REQ directly */
6320 }
6321 /* 4 <1> Check user configurations and HW capabilities */
6322 /* Check configurations (QoS support, AMPDU RX support) */
6323 if ((!prAdapter->rWifiVar.fgSupportQoS) ||
6324 (!prAdapter->rWifiVar.fgSupportAmpduRx) || (!prStaRec->fgRxAmpduEn)) {
6325 DBGLOG(QM, WARN,
6326 ("[Puff][%s]: (Warning) BA ACK Policy not supported fgSupportQoS(%d), fgSupportAmpduRx(%d), fgRxAmpduEn(%d)\n",
6327 __func__, prAdapter->rWifiVar.fgSupportQoS,
6328 prAdapter->rWifiVar.fgSupportAmpduRx, prStaRec->fgRxAmpduEn));
6329 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6330 }
6331 /* Check capability */
6332 prAddBaReq = ((P_ACTION_ADDBA_REQ_FRAME_T) (prSwRfb->pvHeader));
6333 kalMemCopy((PUINT_8) (&rAddBaReqBody),
6334 (PUINT_8) (&(prAddBaReq->aucBAParameterSet[0])), 6);
6335 if ((((rAddBaReqBody.
6336 u2BAParameterSet) & BA_PARAM_SET_ACK_POLICY_MASK) >>
6337 BA_PARAM_SET_ACK_POLICY_MASK_OFFSET)
6338 != BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA) { /* Only Immediate_BA is supported */
6339 DBGLOG(QM, WARN,
6340 ("[Puff][%s]: (Warning) BA ACK Policy not supported (0x%08X)\n",
6341 __func__, rAddBaReqBody.u2BAParameterSet));
6342 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6343 }
6344
6345 /* 4 <2> Determine the RX BA entry (existing or to be added) */
6346 /* Note: BA entry index = (TID, STA_REC index) */
6347 u4Tid =
6348 (((rAddBaReqBody.
6349 u2BAParameterSet) & BA_PARAM_SET_TID_MASK) >> BA_PARAM_SET_TID_MASK_OFFSET);
6350 u4StaRecIdx = prStaRec->ucIndex;
6351 DBGLOG(QM, WARN,
6352 ("[Puff][%s]: BA entry index = [TID(%d), STA_REC index(%d)]\n", __func__,
6353 u4Tid, u4StaRecIdx));
6354
6355 u2WinStart = ((rAddBaReqBody.u2BAStartSeqCtrl) >> OFFSET_BAR_SSC_SN);
6356 u2WinSize = (((rAddBaReqBody.u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
6357 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
6358 DBGLOG(QM, WARN,
6359 ("[Puff][%s]: BA entry info = [WinStart(%d), WinSize(%d)]\n", __func__,
6360 u2WinStart, u2WinSize));
6361
6362
6363 if (fgIsReqAccepted) {
6364
6365 prRxBaEntry = &prQM->arRxBaTable[u4Tid];
6366
6367 if (!prRxBaEntry) {
6368
6369 /* 4 <Case 2.1> INVALID state && BA entry available --> Add a new entry and accept */
6370 if (prQM->ucRxBaCount < CFG_NUM_OF_RX_BA_AGREEMENTS) {
6371
6372 fgIsNewEntryAdded = qmAddRxBaEntry(prAdapter,
6373 (UINT_8) u4StaRecIdx,
6374 (UINT_8) u4Tid,
6375 u2WinStart, u2WinSize);
6376
6377 if (!fgIsNewEntryAdded) {
6378 DBGLOG(QM, ERROR,
6379 ("[Puff][%s]: (Error) Free RX BA entry alloc failure\n"));
6380 fgIsReqAccepted = FALSE;
6381 } else {
6382 DBGLOG(QM, WARN,
6383 ("[Puff][%s]: Create a new BA Entry\n"));
6384 }
6385 }
6386 /* 4 <Case 2.2> INVALID state && BA entry unavailable --> Reject the ADDBA_REQ */
6387 else {
6388 DBGLOG(QM, WARN,
6389 ("[Puff][%s]: (Warning) Free RX BA entry unavailable(req: %d)\n",
6390 __func__, prQM->ucRxBaCount));
6391 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6392 }
6393 } else {
6394
6395 /* 4 <Case 2.3> NEGO or DELETING state --> Ignore the ADDBA_REQ */
6396 /* For NEGO: do nothing. Wait for TX Done of ADDBA_RSP */
6397 /* For DELETING: do nothing. Wait for TX Done of DELBA */
6398 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_ACTIVE) {
6399 DBGLOG(QM, WARN,
6400 ("[Puff][%s]: (Warning) ADDBA_REQ for TID=%ld is received during status:%d (Ignore)\n",
6401 __func__, u4Tid, prRxBaEntry->ucStatus));
6402 break; /* Ignore the ADDBA_REQ since the current state is NEGO */
6403 }
6404 /* 4 <Case 2.4> ACTIVE state --> Accept */
6405 /* Send an ADDBA_RSP to accept the request again */
6406 /* else */
6407 }
6408 }
6409 /* 4 <3> Construct the ADDBA_RSP frame */
6410 prTxMsduInfo =
6411 (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, ACTION_ADDBA_RSP_FRAME_LEN);
6412 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
6413
6414 if (!prTxMsduInfo) {
6415
6416 /* The peer may send an ADDBA_REQ message later.
6417 * Do nothing to the BA entry. No DELBA will be sent (because cnmMgtPktAlloc() may fail again).
6418 * No BA deletion event will be sent to the host (because cnmMgtPktAlloc() may fail again).
6419 */
6420 DBGLOG(QM, WARN,
6421 ("[Puff][%s]: (Warning) ADDBA_RSP alloc failure\n", __func__));
6422
6423 if (fgIsNewEntryAdded) { /* If a new entry has been created due to this ADDBA_REQ, delete it */
6424 ASSERT(prRxBaEntry);
6425 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
6426 BA_ENTRY_STATUS_INVALID);
6427 }
6428
6429 break; /* Exit directly to free the ADDBA_REQ */
6430 }
6431
6432 /* Fill the ADDBA_RSP message */
6433 prAddBaRsp =
6434 (P_ACTION_ADDBA_RSP_FRAME_T) ((UINT_32) (prTxMsduInfo->prPacket) +
6435 MAC_TX_RESERVED_FIELD);
6436 prAddBaRsp->u2FrameCtrl = MAC_FRAME_ACTION;
6437
6438#if CFG_SUPPORT_802_11W
6439 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
6440 DBGLOG(QM, WARN,
6441 ("[Puff][%s]: (Warning) ADDBA_RSP is 80211w enabled\n", __func__));
6442 prAddBaReq->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
6443 }
6444#endif
6445 prAddBaRsp->u2DurationID = 0;
6446 prAddBaRsp->ucCategory = CATEGORY_BLOCK_ACK_ACTION;
6447 prAddBaRsp->ucAction = ACTION_ADDBA_RSP;
6448 prAddBaRsp->ucDialogToken = prAddBaReq->ucDialogToken;
6449
6450 DBGLOG(QM, WARN,
6451 ("[Puff][%s]: (Warning) ADDBA_RSP DurationID(%d) Category(%d) Action(%d) DialogToken(%d)\n",
6452 __func__, prAddBaRsp->u2DurationID, prAddBaRsp->ucCategory,
6453 prAddBaRsp->ucAction, prAddBaRsp->ucDialogToken));
6454
6455 if (fgIsReqAccepted) {
6456 rAddBaRspBody.u2StatusCode = STATUS_CODE_SUCCESSFUL;
6457 } else {
6458 rAddBaRspBody.u2StatusCode = STATUS_CODE_REQ_DECLINED;
6459 }
6460
6461 /* WinSize = min(WinSize in ADDBA_REQ, CFG_RX_BA_MAX_WINSIZE) */
6462 u4BuffSize = (((rAddBaReqBody.u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
6463 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
6464
6465 /*If ADDBA req WinSize<=0 => use default WinSize(16) */
6466 if ((u4BuffSize > CFG_RX_BA_MAX_WINSIZE) || (u4BuffSize <= 0)) {
6467 u4BuffSize = CFG_RX_BA_MAX_WINSIZE;
6468 }
6469#if CFG_SUPPORT_BCM
6470 /* TODO: Call BT coexistence function to limit the winsize */
6471 u4BuffSizeBT = bcmRequestBaWinSize();
6472 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) bcmRequestBaWinSize(%d)\n",
6473 __func__, u4BuffSizeBT));
6474
6475 if (u4BuffSize > u4BuffSizeBT) {
6476 u4BuffSize = u4BuffSizeBT;
6477 }
6478#endif /* CFG_SUPPORT_BCM */
6479
6480 rAddBaRspBody.u2BAParameterSet = (BA_POLICY_IMMEDIATE |
6481 (u4Tid << BA_PARAM_SET_TID_MASK_OFFSET) |
6482 (u4BuffSize <<
6483 BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET));
6484
6485 /* TODO: Determine the BA timeout value according to the default preference */
6486 rAddBaRspBody.u2BATimeoutValue = rAddBaReqBody.u2BATimeoutValue;
6487
6488 DBGLOG(QM, WARN,
6489 ("[Puff][%s]: (Warning) ADDBA_RSP u4BuffSize(%d) StatusCode(%d) BAParameterSet(0x%08X) BATimeoutValue(%d)\n",
6490 __func__, u4BuffSize, rAddBaRspBody.u2StatusCode,
6491 rAddBaRspBody.u2BAParameterSet, rAddBaRspBody.u2BATimeoutValue));
6492
6493 kalMemCopy((PUINT_8) (&(prAddBaRsp->aucStatusCode[0])), (PUINT_8) (&rAddBaRspBody),
6494 6);
6495
6496 COPY_MAC_ADDR(prAddBaRsp->aucDestAddr, prStaRec->aucMacAddr);
6497 COPY_MAC_ADDR(prAddBaRsp->aucSrcAddr, prBssInfo->aucOwnMacAddr);
6498 /* COPY_MAC_ADDR(prAddBaRsp->aucBSSID,g_aprBssInfo[prStaRec->ucNetTypeIndex]->aucBSSID); */
6499 COPY_MAC_ADDR(prAddBaRsp->aucBSSID, prAddBaReq->aucBSSID);
6500
6501
6502 /* 4 <4> Forward the ADDBA_RSP to TXM */
6503 TX_SET_MMPDU(prAdapter,
6504 prTxMsduInfo,
6505 prStaRec->ucBssIndex,
6506 (prStaRec != NULL) ? (prStaRec->ucIndex) : (STA_REC_INDEX_NOT_FOUND),
6507 WLAN_MAC_HEADER_LEN,
6508 ACTION_ADDBA_RSP_FRAME_LEN,
6509 mqmCallbackAddBaRspSent, MSDU_RATE_MODE_AUTO);
6510
6511#if CFG_SUPPORT_802_11W
6512 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
6513 DBGLOG(RSN, INFO, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
6514 nicTxConfigPktOption(prTxMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
6515 }
6516#endif
6517
6518 /* Note: prTxMsduInfo->ucTID is not used for transmitting the ADDBA_RSP.
6519 * However, when processing TX Done of this ADDBA_RSP, the TID value is needed, so
6520 * store the TID value in advance to prevent parsing the ADDBA_RSP frame
6521 */
6522 prTxMsduInfo->ucTID = (UINT_8) u4Tid;
6523
6524 nicTxEnqueueMsdu(prAdapter, prTxMsduInfo);
6525
6526 DBGLOG(QM, WARN,
6527 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld)\n", __func__,
6528 prStaRec->ucIndex, u4Tid));
6529
6530
6531#if 0
6532 /* 4 <5> Notify the host to start buffer reordering */
6533 if (fgIsNewEntryAdded) { /* Only when a new BA entry is indeed added will the host be notified */
6534 ASSERT(fgIsReqAccepted);
6535
6536 prSwRfbEventToHost = (P_SW_RFB_T) cnmMgtPktAlloc(EVENT_RX_ADDBA_PACKET_LEN);
6537
6538 if (!prSwRfbEventToHost) {
6539
6540 /* Note: DELBA will not be sent since cnmMgtPktAlloc() may fail again. However, it does not
6541 * matter because upon receipt of AMPDUs without a RX BA agreement, MQM will send DELBA frames
6542 */
6543
6544 DBGLOG(MQM, WARN, ("MQM: (Warning) EVENT packet alloc failed\n"));
6545
6546 /* Ensure that host and FW are synchronized */
6547 mqmRxModifyBaEntryStatus(prRxBaEntry, BA_ENTRY_STATUS_INVALID);
6548
6549 break; /* Free the received ADDBA_REQ */
6550 } else {
6551
6552 prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prSwRfbEventToHost->pucBuffer;
6553 prEventRxAddBa->ucStaRecIdx = (UINT_8) u4StaRecIdx;
6554 prEventRxAddBa->u2Length = EVENT_RX_ADDBA_PACKET_LEN;
6555 prEventRxAddBa->ucEID = EVENT_ID_RX_ADDBA;
6556 prEventRxAddBa->ucSeqNum = 0; /* Unsolicited event packet */
6557 prEventRxAddBa->u2BAParameterSet = rAddBaRspBody.u2BAParameterSet;
6558 prEventRxAddBa->u2BAStartSeqCtrl = rAddBaReqBody.u2BAStartSeqCtrl;
6559 prEventRxAddBa->u2BATimeoutValue = rAddBaReqBody.u2BATimeoutValue;
6560 prEventRxAddBa->ucDialogToken = prAddBaReq->ucDialogToken;
6561
6562 DBGLOG(MQM, INFO,
6563 ("MQM: (RX_BA) Event ADDBA ---> driver (STA=%ld TID=%ld WinStart=%d)\n",
6564 u4StaRecIdx, u4Tid,
6565 (prEventRxAddBa->u2BAStartSeqCtrl >> 4)));
6566
6567 /* Configure the SW_RFB for the Event packet */
6568 RXM_SET_EVENT_PACKET(
6569 /* P_SW_RFB_T */ (P_SW_RFB_T)
6570 prSwRfbEventToHost,
6571 /* HIF RX Packet pointer */
6572 (PUINT_8) prEventRxAddBa,
6573 /* HIF RX port number */ HIF_RX0_INDEX
6574 );
6575
6576 rxmSendEventToHost(prSwRfbEventToHost);
6577 }
6578
6579 }
6580#endif
6581
6582
6583 } while (FALSE);
6584
6585}
6586
6587/*----------------------------------------------------------------------------*/
6588/*!
6589* \brief
6590*
6591* \param[in]
6592*
6593* \return none
6594*/
6595/*----------------------------------------------------------------------------*/
6596VOID mqmHandleAddBaRsp(IN P_SW_RFB_T prSwRfb)
6597{
6598
6599}
6600
6601/*----------------------------------------------------------------------------*/
6602/*!
6603* \brief
6604*
6605* \param[in]
6606*
6607* \return none
6608*/
6609/*----------------------------------------------------------------------------*/
6610VOID mqmHandleDelBa(IN P_SW_RFB_T prSwRfb)
6611{
6612
6613}
6614
6615/*----------------------------------------------------------------------------*/
6616/*!
6617* \brief
6618*
6619* \param[in]
6620*
6621* \return none
6622*/
6623/*----------------------------------------------------------------------------*/
6624VOID mqmHandleBaActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
6625{
6626 P_WLAN_ACTION_FRAME prRxFrame;
6627
6628 ASSERT(prAdapter);
6629 ASSERT(prSwRfb);
6630
6631 prRxFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader;
6632 DBGLOG(RLM, WARN, ("[Puff][%s] Action(%d)\n", __func__, prRxFrame->ucAction));
6633
6634 switch (prRxFrame->ucAction) {
6635
6636 case ACTION_ADDBA_REQ:
6637 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) ADDBA_REQ <--- peer\n", __func__));
6638 mqmHandleAddBaReq(prAdapter, prSwRfb);
6639 break;
6640
6641 case ACTION_ADDBA_RSP:
6642 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) ADDBA_RSP <--- peer\n", __func__));
6643 mqmHandleAddBaRsp(prSwRfb);
6644 break;
6645
6646 case ACTION_DELBA:
6647 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) DELBA <--- peer\n", __func__));
6648 mqmHandleDelBa(prSwRfb);
6649 break;
6650
6651 default:
6652 DBGLOG(RLM, WARN, ("[Puff][%s] Unknown BA Action Frame\n", __func__));
6653 break;
6654 }
6655
6656
6657
6658}
6659
6660#endif