import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / drv_wlan / mt6630 / wlan / nic / que_mgt.c
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,
366 Add 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,
371 Add 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,
376 Add per station flow control when STA is in PS
377 * 1) Check Bss if support QoS before adding WMMIE
378 * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control
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,
386 Add 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,
396 Add 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,
402 Add 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
617 extern 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 */
633 OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM];
634
635 const UINT_8 aucTid2ACI[TX_DESC_TID_NUM] = {
636 WMM_AC_BE_INDEX, /* TID0 */
637 WMM_AC_BK_INDEX, /* TID1 */
638 WMM_AC_BK_INDEX, /* TID2 */
639 WMM_AC_BE_INDEX, /* TID3 */
640 WMM_AC_VI_INDEX, /* TID4 */
641 WMM_AC_VI_INDEX, /* TID5 */
642 WMM_AC_VO_INDEX, /* TID6 */
643 WMM_AC_VO_INDEX /* TID7 */
644 };
645
646 const UINT_8 aucACI2TxQIdx[WMM_AC_INDEX_NUM] = {
647 TX_QUEUE_INDEX_AC1, /* WMM_AC_BE_INDEX */
648 TX_QUEUE_INDEX_AC0, /* WMM_AC_BK_INDEX */
649 TX_QUEUE_INDEX_AC2, /* WMM_AC_VI_INDEX */
650 TX_QUEUE_INDEX_AC3 /* WMM_AC_VO_INDEX */
651 };
652
653 const 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
666 const 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
674 const 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 /*----------------------------------------------------------------------------*/
772 VOID 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
908 VOID 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 /*----------------------------------------------------------------------------*/
976 VOID 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 /*----------------------------------------------------------------------------*/
1024 VOID 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 /*----------------------------------------------------------------------------*/
1076 VOID 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 /*----------------------------------------------------------------------------*/
1124 VOID 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 /*----------------------------------------------------------------------------*/
1174 P_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 /*----------------------------------------------------------------------------*/
1276 P_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 /*----------------------------------------------------------------------------*/
1349 P_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 /*----------------------------------------------------------------------------*/
1406 P_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
1456 P_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
1516 VOID
1517 qmSetTxPacketDescTemplate(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 /*----------------------------------------------------------------------------*/
1547 P_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 /*----------------------------------------------------------------------------*/
1700 VOID 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
1789 P_STA_RECORD_T qmDetermineStaToBeDequeued(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StartStaRecIndex)
1790 {
1791
1792 return NULL;
1793 }
1794
1795 P_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 /*----------------------------------------------------------------------------*/
1812 UINT_32
1813 qmDequeueTxPacketsFromPerStaQueues(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 /*----------------------------------------------------------------------------*/
1997 VOID
1998 qmDequeueTxPacketsFromPerTypeQueues(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 /*----------------------------------------------------------------------------*/
2082 UINT_32
2083 qmDequeueTxPacketsFromGlobalQueue(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 /*----------------------------------------------------------------------------*/
2162 P_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 /*----------------------------------------------------------------------------*/
2226 P_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 /*----------------------------------------------------------------------------*/
2267 BOOLEAN
2268 qmAdjustTcQuotasMthread(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 /*----------------------------------------------------------------------------*/
2372 BOOLEAN
2373 qmAdjustTcQuotas(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 /*----------------------------------------------------------------------------*/
2459 VOID 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
2511 VOID
2512 qmAllocateResidualTcResource(
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 /*----------------------------------------------------------------------------*/
2605 VOID 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
2715 VOID
2716 qmReassignTcResource(
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 /*----------------------------------------------------------------------------*/
2948 VOID 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
3006 VOID 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 /*----------------------------------------------------------------------------*/
3036 VOID 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 /*----------------------------------------------------------------------------*/
3052 P_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 }
3200 /* Todo:: Move the data class error check here */
3201
3202 if (prCurrSwRfb->fgReorderBuffer && !fgIsBMC && fgIsHTran) {
3203 /* If this packet should dropped or indicated to the host immediately,
3204 * it should be enqueued into the rReturnedQue with specific flags. If
3205 * this packet should be buffered for reordering, it should be enqueued
3206 * into the reordering queue in the STA_REC rather than into the
3207 * rReturnedQue.
3208 */
3209 qmProcessPktWithReordering(prAdapter, prCurrSwRfb, prReturnedQue);
3210
3211 } else if (prCurrSwRfb->fgDataFrame) {
3212 /* Check Class Error */
3213 {
3214 if (secCheckClassError
3215 (prAdapter, prCurrSwRfb, prCurrSwRfb->prStaRec) == TRUE) {
3216 P_RX_BA_ENTRY_T prReorderQueParm = NULL;
3217
3218 /* Invalid BA aggrement */
3219 if (fgIsHTran) {
3220 UINT_16 u2FrameCtrl = 0;
3221
3222 u2FrameCtrl = HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prCurrSwRfb->prRxStatusGroup4);
3223 // Check FC type, if DATA, then no-reordering
3224 if((u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_DATA){
3225 DBGLOG(QM, TRACE, ("FC [0x%04X], no-reordering...\n", u2FrameCtrl));
3226 }
3227 else {
3228 prReorderQueParm = ((prCurrSwRfb->prStaRec->aprRxReorderParamRefTbl)[prCurrSwRfb->ucTid]);
3229 }
3230 }
3231
3232 if (prReorderQueParm && prReorderQueParm->fgIsValid
3233 && !fgIsBMC) {
3234 qmProcessPktWithReordering(prAdapter, prCurrSwRfb,
3235 prReturnedQue);
3236 } else {
3237 qmHandleRxPackets_AOSP_1;
3238 }
3239 } else {
3240 DBGLOG(QM, TRACE, ("Mark NULL the Packet for class error\n"));
3241 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3242 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
3243 }
3244 }
3245 } else {
3246 P_WLAN_MAC_HEADER_T prWlanMacHeader;
3247
3248 ASSERT(prCurrSwRfb->pvHeader);
3249
3250 prWlanMacHeader = (P_WLAN_MAC_HEADER_T) prCurrSwRfb->pvHeader;
3251 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3252
3253 switch (prWlanMacHeader->u2FrameCtrl & MASK_FRAME_TYPE) {
3254 /* BAR frame */
3255 case MAC_FRAME_BLOCK_ACK_REQ:
3256 qmProcessBarFrame(prAdapter, prCurrSwRfb, prReturnedQue);
3257 break;
3258 default:
3259 DBGLOG(QM, TRACE,
3260 ("Mark NULL the Packet for non-interesting type\n"));
3261 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
3262 break;
3263 }
3264 }
3265
3266 } while (prNextSwRfb);
3267
3268
3269 /* The returned list of SW_RFBs must end with a NULL pointer */
3270 if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) {
3271 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(prReturnedQue), NULL);
3272 }
3273
3274 return (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue);
3275
3276 #else
3277
3278 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
3279 return prSwRfbListHead;
3280
3281 #endif
3282
3283 }
3284
3285 /*----------------------------------------------------------------------------*/
3286 /*!
3287 * \brief Reorder the received packet
3288 *
3289 * \param[in] prSwRfb The RX packet to process
3290 * \param[out] prReturnedQue The queue for indicating packets
3291 *
3292 * \return (none)
3293 */
3294 /*----------------------------------------------------------------------------*/
3295 VOID
3296 qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter,
3297 IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
3298 {
3299
3300
3301 P_STA_RECORD_T prStaRec;
3302 P_HW_MAC_RX_DESC_T prRxStatus;
3303 P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4 = NULL;
3304 P_RX_BA_ENTRY_T prReorderQueParm;
3305
3306 UINT_32 u4SeqNo;
3307 UINT_32 u4WinStart;
3308 UINT_32 u4WinEnd;
3309 P_QUE_T prReorderQue;
3310 /* P_SW_RFB_T prReorderedSwRfb; */
3311
3312 DEBUGFUNC("qmProcessPktWithReordering");
3313
3314 ASSERT(prSwRfb);
3315 ASSERT(prReturnedQue);
3316 ASSERT(prSwRfb->prRxStatus);
3317
3318 /* Incorrect STA_REC index */
3319 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
3320 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3321 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3322 DBGLOG(QM, WARN, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
3323 prSwRfb->ucStaRecIdx));
3324 authSendDeauthFrame(prAdapter,
3325 NULL,
3326 NULL,
3327 prSwRfb, REASON_CODE_CLASS_3_ERR, (PFN_TX_DONE_HANDLER) NULL);
3328 /* ASSERT(0); */
3329 return;
3330 }
3331
3332 /* Check whether the STA_REC is activated */
3333 prStaRec = prSwRfb->prStaRec;
3334 ASSERT(prStaRec);
3335
3336 prRxStatus = prSwRfb->prRxStatus;
3337 prSwRfb->ucTid = (UINT_8) (HAL_RX_STATUS_GET_TID(prRxStatus));
3338 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3339
3340 #if 0
3341 if (!(prStaRec->fgIsValid)) {
3342 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3343 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3344 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3345 DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC\n"));
3346 /* ASSERT(0); */
3347 return;
3348 }
3349 #endif
3350
3351 /* Check whether the BA agreement exists */
3352 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3353 if (!prReorderQueParm || !(prReorderQueParm->fgIsValid)) {
3354 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3355 prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
3356 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3357 DBGLOG(QM, TRACE, ("Reordering for a NULL ReorderQueParm\n"));
3358 return;
3359 }
3360
3361 prRxStatusGroup4 = prSwRfb->prRxStatusGroup4;
3362 if (prRxStatusGroup4 == NULL) {
3363 DBGLOG(QM, ERROR, ("prRxStatusGroup4 is NULL !!!\n"));
3364 DBGLOG(QM, ERROR,
3365 ("prSwRfb->pvHeader is 0x%p !!!\n", (PUINT_32) prSwRfb->pvHeader));
3366 DBGLOG(QM, ERROR, ("prSwRfb->u2PacketLen is %d !!!\n", prSwRfb->u2PacketLen));
3367 DBGLOG(QM, ERROR, ("========= START TO DUMP prSwRfb =========\n"));
3368 DBGLOG_MEM8(QM, ERROR, prSwRfb->pvHeader, prSwRfb->u2PacketLen);
3369 DBGLOG(QM, ERROR, ("========= END OF DUMP prSwRfb =========\n"));
3370 ASSERT(prRxStatusGroup4);
3371 }
3372
3373
3374 prSwRfb->u2SSN =
3375 HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4) >> RX_STATUS_SEQ_NUM_OFFSET;
3376
3377 /* Start to reorder packets */
3378 u4SeqNo = (UINT_32) (prSwRfb->u2SSN);
3379 prReorderQue = &(prReorderQueParm->rReOrderQue);
3380 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
3381 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
3382
3383 /* Debug */
3384 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3385
3386 /* Case 1: Fall within */
3387 if /* 0 - start - sn - end - 4095 */
3388 (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd))
3389 /* 0 - end - start - sn - 4095 */
3390 || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo))
3391 /* 0 - sn - end - start - 4095 */
3392 || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) {
3393
3394 qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3395
3396 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3397 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3398 /* Let the first received packet pass the reorder check */
3399 DBGLOG(QM, LOUD,
3400 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart,
3401 u4WinEnd));
3402
3403 prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo;
3404 prReorderQueParm->u2WinEnd =
3405 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3406 1) % MAX_SEQ_NO_COUNT;
3407 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3408 }
3409 #endif
3410
3411
3412 qmPopOutDueToFallWithin(prAdapter, prReorderQueParm, prReturnedQue);
3413 }
3414 /* Case 2: Fall ahead */
3415 else if
3416 /* 0 - start - end - sn - (start+2048) - 4095 */
3417 (((u4WinStart < u4WinEnd)
3418 && (u4WinEnd < u4SeqNo)
3419 && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT)))
3420 /* 0 - sn - (start+2048) - start - end - 4095 */
3421 || ((u4SeqNo < u4WinStart)
3422 && (u4WinStart < u4WinEnd)
3423 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))
3424 /* 0 - end - sn - (start+2048) - start - 4095 */
3425 || ((u4WinEnd < u4SeqNo)
3426 && (u4SeqNo < u4WinStart)
3427 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) {
3428
3429
3430 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3431 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3432 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3433 }
3434 #endif
3435
3436 qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3437
3438 /* Advance the window after inserting a new tail */
3439 prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo;
3440 prReorderQueParm->u2WinStart =
3441 (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) +
3442 MAX_SEQ_NO_COUNT + 1)
3443 % MAX_SEQ_NO_COUNT);
3444
3445 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3446
3447 }
3448 /* Case 3: Fall behind */
3449 else {
3450
3451 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3452 #if QM_RX_INIT_FALL_BEHIND_PASS
3453 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
3454 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
3455 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3456 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3457 return;
3458 }
3459 #endif
3460 #endif
3461
3462 /* An erroneous packet */
3463 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3464 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3465 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
3466 return;
3467 }
3468
3469 return;
3470
3471 }
3472
3473
3474 VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
3475 {
3476
3477 P_STA_RECORD_T prStaRec;
3478 P_HW_MAC_RX_DESC_T prRxStatus;
3479 P_RX_BA_ENTRY_T prReorderQueParm;
3480 P_CTRL_BAR_FRAME_T prBarCtrlFrame;
3481
3482 UINT_32 u4SSN;
3483 UINT_32 u4WinStart;
3484 UINT_32 u4WinEnd;
3485 P_QUE_T prReorderQue;
3486 /* P_SW_RFB_T prReorderedSwRfb; */
3487
3488 ASSERT(prSwRfb);
3489 ASSERT(prReturnedQue);
3490 ASSERT(prSwRfb->prRxStatus);
3491 ASSERT(prSwRfb->pvHeader);
3492
3493 prRxStatus = prSwRfb->prRxStatus;
3494
3495 prBarCtrlFrame = (P_CTRL_BAR_FRAME_T) prSwRfb->pvHeader;
3496
3497 prSwRfb->ucTid =
3498 (*((PUINT_16) ((PUINT_8) prBarCtrlFrame + CTRL_BAR_BAR_CONTROL_OFFSET))) >>
3499 BAR_CONTROL_TID_INFO_OFFSET;
3500 prSwRfb->u2SSN =
3501 (*((PUINT_16) ((PUINT_8) prBarCtrlFrame + CTRL_BAR_BAR_INFORMATION_OFFSET))) >>
3502 OFFSET_BAR_SSC_SN;
3503
3504 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3505 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3506
3507 /* Incorrect STA_REC index */
3508 prSwRfb->ucStaRecIdx = secLookupStaRecIndexFromTA(prAdapter, prBarCtrlFrame->aucSrcAddr);
3509 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
3510 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
3511 prSwRfb->ucStaRecIdx));
3512 /* ASSERT(0); */
3513 return;
3514 }
3515
3516 /* Check whether the STA_REC is activated */
3517 prSwRfb->prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3518 prStaRec = prSwRfb->prStaRec;
3519 if (prStaRec == NULL) {
3520 /* ASSERT(prStaRec); */
3521 return;
3522 }
3523 #if 0
3524 if (!(prStaRec->fgIsValid)) {
3525 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3526 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
3527 /* ASSERT(0); */
3528 return;
3529 }
3530 #endif
3531
3532 /* Check whether the BA agreement exists */
3533 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3534 if (!prReorderQueParm) {
3535 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3536 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
3537 /* ASSERT(0); */
3538 return;
3539 }
3540
3541
3542 u4SSN = (UINT_32) (prSwRfb->u2SSN);
3543 prReorderQue = &(prReorderQueParm->rReOrderQue);
3544 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
3545 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
3546
3547 if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) {
3548 prReorderQueParm->u2WinStart = (UINT_16) u4SSN;
3549 prReorderQueParm->u2WinEnd =
3550 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3551 1) % MAX_SEQ_NO_COUNT;
3552 DBGLOG(QM, TRACE,
3553 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, u4SSN,
3554 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3555 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3556 } else {
3557 DBGLOG(QM, TRACE,
3558 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SSN, u4WinStart,
3559 u4WinEnd));
3560 }
3561 }
3562
3563
3564
3565 VOID
3566 qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb,
3567 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3568 {
3569 P_SW_RFB_T prExaminedQueuedSwRfb;
3570 P_QUE_T prReorderQue;
3571 ASSERT(prSwRfb);
3572 ASSERT(prReorderQueParm);
3573 ASSERT(prReturnedQue);
3574
3575 prReorderQue = &(prReorderQueParm->rReOrderQue);
3576 prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3577
3578 /* There are no packets queued in the Reorder Queue */
3579 if (prExaminedQueuedSwRfb == NULL) {
3580 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
3581 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3582 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3583 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
3584 prReorderQue->u4NumElem++;
3585 }
3586
3587 /* Determine the insert position */
3588 else {
3589 do {
3590 /* Case 1: Terminate. A duplicate packet */
3591 if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) {
3592 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3593 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
3594 return;
3595 }
3596
3597 /* Case 2: Terminate. The insert point is found */
3598 else if (qmCompareSnIsLessThan((prSwRfb->u2SSN),
3599 (prExaminedQueuedSwRfb->u2SSN))) {
3600 break;
3601 }
3602
3603 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3604 else {
3605 prExaminedQueuedSwRfb =
3606 (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext);
3607 }
3608 } while (prExaminedQueuedSwRfb);
3609
3610 /* Update the Reorder Queue Parameters according to the found insert position */
3611 if (prExaminedQueuedSwRfb == NULL) {
3612 /* The received packet shall be placed at the tail */
3613 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
3614 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3615 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
3616 prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb);
3617 } else {
3618 ((P_QUE_ENTRY_T) prSwRfb)->prPrev =
3619 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev;
3620 ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb;
3621 if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) {
3622 /* The received packet will become the head */
3623 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3624 } else {
3625 (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext =
3626 (P_QUE_ENTRY_T) prSwRfb;
3627 }
3628 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb;
3629 }
3630
3631 prReorderQue->u4NumElem++;
3632
3633 }
3634
3635 }
3636
3637
3638 VOID
3639 qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb,
3640 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3641 {
3642 P_QUE_T prReorderQue;
3643 ASSERT(prSwRfb);
3644 ASSERT(prReorderQueParm);
3645 ASSERT(prReturnedQue);
3646
3647 prReorderQue = &(prReorderQueParm->rReOrderQue);
3648
3649 /* There are no packets queued in the Reorder Queue */
3650 if (QUEUE_IS_EMPTY(prReorderQue)) {
3651 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
3652 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3653 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3654 } else {
3655 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
3656 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3657 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
3658 }
3659 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
3660 prReorderQue->u4NumElem++;
3661
3662 }
3663
3664
3665 VOID
3666 qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter,
3667 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3668 {
3669 P_SW_RFB_T prReorderedSwRfb;
3670 P_QUE_T prReorderQue;
3671 BOOLEAN fgDequeuHead, fgMissing;
3672 OS_SYSTIME rCurrentTime, rMissTimeout;
3673
3674 prReorderQue = &(prReorderQueParm->rReOrderQue);
3675
3676 fgMissing = FALSE;
3677 rCurrentTime = 0;
3678 rMissTimeout = g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid];
3679 if (rMissTimeout) {
3680 fgMissing = TRUE;
3681 GET_CURRENT_SYSTIME(&rCurrentTime);
3682 }
3683
3684 /* Check whether any packet can be indicated to the higher layer */
3685 while (TRUE) {
3686 if (QUEUE_IS_EMPTY(prReorderQue)) {
3687 break;
3688 }
3689
3690 /* Always examine the head packet */
3691 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3692 fgDequeuHead = FALSE;
3693
3694 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3695 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3696
3697 fgDequeuHead = TRUE;
3698 prReorderQueParm->u2WinStart =
3699 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3700 }
3701 /* SN > WinStart, break to update WinEnd */
3702 else {
3703 /* Start bubble timer */
3704 if (!prReorderQueParm->fgHasBubble) {
3705 cnmTimerStartTimer(prAdapter,
3706 &(prReorderQueParm->rReorderBubbleTimer),
3707 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3708 prReorderQueParm->fgHasBubble = TRUE;
3709 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
3710
3711 DBGLOG(QM, TRACE,
3712 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3713 prReorderQueParm->ucStaRecIdx, prReorderedSwRfb->ucTid,
3714 prReorderQueParm->u2FirstBubbleSn,
3715 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3716 }
3717
3718 if ((fgMissing == TRUE) &&
3719 CHECK_FOR_TIMEOUT(rCurrentTime, rMissTimeout,
3720 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3721 DBGLOG(QM, TRACE,
3722 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3723 prReorderQueParm->ucTid, prReorderedSwRfb->u2SSN));
3724 fgDequeuHead = TRUE;
3725 prReorderQueParm->u2WinStart =
3726 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3727
3728 fgMissing = FALSE;
3729 } else
3730 break;
3731 }
3732
3733
3734 /* Dequeue the head packet */
3735 if (fgDequeuHead) {
3736
3737 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3738 prReorderQue->prHead = NULL;
3739 prReorderQue->prTail = NULL;
3740 } else {
3741 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3742 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3743 }
3744 prReorderQue->u4NumElem--;
3745 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3746 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3747 }
3748 }
3749
3750 if (QUEUE_IS_EMPTY(prReorderQue)) {
3751 rMissTimeout = 0;
3752 } else {
3753 if (fgMissing == FALSE) {
3754 GET_CURRENT_SYSTIME(&rMissTimeout);
3755 }
3756 }
3757
3758 /* After WinStart has been determined, update the WinEnd */
3759 prReorderQueParm->u2WinEnd =
3760 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3761 1) % MAX_SEQ_NO_COUNT);
3762
3763 }
3764
3765 VOID
3766 qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter,
3767 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3768 {
3769 P_SW_RFB_T prReorderedSwRfb;
3770 P_QUE_T prReorderQue;
3771 BOOLEAN fgDequeuHead;
3772
3773 prReorderQue = &(prReorderQueParm->rReOrderQue);
3774
3775 /* Check whether any packet can be indicated to the higher layer */
3776 while (TRUE) {
3777 if (QUEUE_IS_EMPTY(prReorderQue)) {
3778 break;
3779 }
3780
3781 /* Always examine the head packet */
3782 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3783 fgDequeuHead = FALSE;
3784
3785 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3786 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3787
3788 fgDequeuHead = TRUE;
3789 prReorderQueParm->u2WinStart =
3790 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3791 }
3792
3793 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3794 else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN),
3795 (UINT_32) (prReorderQueParm->u2WinStart))) {
3796
3797 fgDequeuHead = TRUE;
3798
3799 }
3800
3801 /* SN > WinStart, break to update WinEnd */
3802 else {
3803 /* Start bubble timer */
3804 if (!prReorderQueParm->fgHasBubble) {
3805 cnmTimerStartTimer(prAdapter,
3806 &(prReorderQueParm->rReorderBubbleTimer),
3807 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3808 prReorderQueParm->fgHasBubble = TRUE;
3809 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
3810
3811 DBGLOG(QM, TRACE,
3812 ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3813 prReorderQueParm->ucStaRecIdx, prReorderedSwRfb->ucTid,
3814 prReorderQueParm->u2FirstBubbleSn,
3815 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3816 }
3817 break;
3818 }
3819
3820
3821 /* Dequeue the head packet */
3822 if (fgDequeuHead) {
3823
3824 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3825 prReorderQue->prHead = NULL;
3826 prReorderQue->prTail = NULL;
3827 } else {
3828 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3829 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3830 }
3831 prReorderQue->u4NumElem--;
3832 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3833 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3834 }
3835 }
3836
3837 /* After WinStart has been determined, update the WinEnd */
3838 prReorderQueParm->u2WinEnd =
3839 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3840 1) % MAX_SEQ_NO_COUNT);
3841
3842 }
3843
3844 VOID qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
3845 {
3846 P_RX_BA_ENTRY_T prReorderQueParm = (P_RX_BA_ENTRY_T) ulParamPtr;
3847 P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL;
3848 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent;
3849
3850 KAL_SPIN_LOCK_DECLARATION();
3851
3852 if (!prReorderQueParm->fgIsValid) {
3853 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3854 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3855 return;
3856 }
3857
3858 if (!prReorderQueParm->fgHasBubble) {
3859 DBGLOG(QM, TRACE,
3860 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3861 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3862 return;
3863 }
3864
3865 DBGLOG(QM, TRACE, ("QM:(Bub Timeout) STA[%u] TID[%u] BubSN[%u]\n",
3866 prReorderQueParm->ucStaRecIdx,
3867 prReorderQueParm->ucTid, prReorderQueParm->u2FirstBubbleSn));
3868
3869 /* Generate a self-inited event to Rx path */
3870 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
3871 QUEUE_REMOVE_HEAD(&prAdapter->rRxCtrl.rFreeSwRfbList, prSwRfb, P_SW_RFB_T);
3872 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
3873
3874 if (prSwRfb) {
3875 prCheckReorderEvent = (P_EVENT_CHECK_REORDER_BUBBLE_T) prSwRfb->pucRecvBuff;
3876
3877 prSwRfb->ucPacketType = RX_PKT_TYPE_SW_DEFINED;
3878
3879 prSwRfb->prRxStatus->u2PktTYpe = RXM_RXD_PKT_TYPE_SW_EVENT;
3880
3881 prCheckReorderEvent->ucEID = EVENT_ID_CHECK_REORDER_BUBBLE;
3882 prCheckReorderEvent->ucSeqNum = 0;
3883
3884 prCheckReorderEvent->ucStaRecIdx = prReorderQueParm->ucStaRecIdx;
3885 prCheckReorderEvent->ucTid = prReorderQueParm->ucTid;
3886 prCheckReorderEvent->u2Length = sizeof(EVENT_CHECK_REORDER_BUBBLE_T);
3887
3888 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
3889 QUEUE_INSERT_TAIL(&prAdapter->rRxCtrl.rReceivedRfbList, &prSwRfb->rQueEntry);
3890 RX_INC_CNT(&prAdapter->rRxCtrl, RX_MPDU_TOTAL_COUNT);
3891 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
3892
3893 DBGLOG(QM, LOUD, ("QM:(Bub Check Event Sent) STA[%u] TID[%u]\n",
3894 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3895
3896 nicRxProcessRFBs(prAdapter);
3897
3898 DBGLOG(QM, LOUD, ("QM:(Bub Check Event Handled) STA[%u] TID[%u]\n",
3899 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3900 } else {
3901 DBGLOG(QM, TRACE,
3902 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bub check event alloc failed\n",
3903 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3904
3905 cnmTimerStartTimer(prAdapter, &(prReorderQueParm->rReorderBubbleTimer),
3906 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
3907
3908 DBGLOG(QM, TRACE, ("QM:(Bub Timer Restart) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3909 prReorderQueParm->ucStaRecIdx,
3910 prReorderQueParm->ucTid,
3911 prReorderQueParm->u2FirstBubbleSn,
3912 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3913 }
3914
3915 return;
3916 }
3917
3918 VOID qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
3919 {
3920 P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent =
3921 (P_EVENT_CHECK_REORDER_BUBBLE_T) prEvent;
3922 P_RX_BA_ENTRY_T prReorderQueParm;
3923 P_QUE_T prReorderQue;
3924 QUE_T rReturnedQue;
3925 P_QUE_T prReturnedQue = &rReturnedQue;
3926 P_SW_RFB_T prReorderedSwRfb, prSwRfb;
3927
3928 QUEUE_INITIALIZE(prReturnedQue);
3929
3930 /* Get target Rx BA entry */
3931 prReorderQueParm = qmLookupRxBaEntry(prAdapter,
3932 prCheckReorderEvent->ucStaRecIdx,
3933 prCheckReorderEvent->ucTid);
3934
3935 /* Sanity Check */
3936 if (!prReorderQueParm) {
3937 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3938 prCheckReorderEvent->ucStaRecIdx, prCheckReorderEvent->ucTid));
3939 return;
3940 }
3941
3942 if (!prReorderQueParm->fgIsValid) {
3943 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n",
3944 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3945 return;
3946 }
3947
3948 if (!prReorderQueParm->fgHasBubble) {
3949 DBGLOG(QM, TRACE,
3950 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3951 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3952 return;
3953 }
3954
3955 prReorderQue = &(prReorderQueParm->rReOrderQue);
3956
3957 if (QUEUE_IS_EMPTY(prReorderQue)) {
3958 prReorderQueParm->fgHasBubble = FALSE;
3959
3960 DBGLOG(QM, TRACE,
3961 ("QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n",
3962 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3963
3964 return;
3965 }
3966
3967 DBGLOG(QM, TRACE, ("QM:(Bub Check Event Got) STA[%u] TID[%u]\n",
3968 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
3969
3970 /* Expected bubble timeout => pop out packets before win_end */
3971 if (prReorderQueParm->u2FirstBubbleSn == prReorderQueParm->u2WinStart) {
3972
3973 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_TAIL(prReorderQue);
3974
3975 prReorderQueParm->u2WinStart = prReorderedSwRfb->u2SSN + 1;
3976 prReorderQueParm->u2WinEnd =
3977 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3978 1) % MAX_SEQ_NO_COUNT;
3979
3980 qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, prReturnedQue);
3981
3982 DBGLOG(QM, TRACE, ("QM:(Bub Flush) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
3983 prReorderQueParm->ucStaRecIdx,
3984 prReorderQueParm->ucTid,
3985 prReorderQueParm->u2FirstBubbleSn,
3986 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3987
3988 if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) {
3989 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(prReturnedQue), NULL);
3990
3991 prSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue);
3992 while (prSwRfb) {
3993 DBGLOG(QM, TRACE,
3994 ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out SN[%u]\n",
3995 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid,
3996 prSwRfb->u2SSN));
3997
3998 prSwRfb =
3999 (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb);
4000 }
4001
4002 wlanProcessQueuedSwRfb(prAdapter,
4003 (P_SW_RFB_T) QUEUE_GET_HEAD(prReturnedQue));
4004 } else {
4005 DBGLOG(QM, TRACE, ("QM:(Bub Flush) STA[%u] TID[%u] Pop Out 0 packet\n",
4006 prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid));
4007 }
4008
4009 prReorderQueParm->fgHasBubble = FALSE;
4010 }
4011 /* First bubble has been filled but others exist */
4012 else {
4013 prReorderQueParm->u2FirstBubbleSn = prReorderQueParm->u2WinStart;
4014 cnmTimerStartTimer(prAdapter, &(prReorderQueParm->rReorderBubbleTimer),
4015 QM_RX_BA_ENTRY_MISS_TIMEOUT_MS);
4016
4017 DBGLOG(QM, TRACE, ("QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n",
4018 prReorderQueParm->ucStaRecIdx,
4019 prReorderQueParm->ucTid,
4020 prReorderQueParm->u2FirstBubbleSn,
4021 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
4022 }
4023
4024 return;
4025 }
4026
4027
4028 BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater)
4029 {
4030 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
4031 if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) { /* Shall be <= */
4032 return FALSE;
4033 }
4034
4035 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
4036 else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) {
4037 return TRUE;
4038 }
4039
4040 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
4041 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
4042 else {
4043 return u4SnLess < u4SnGreater;
4044 }
4045 }
4046
4047
4048 /*----------------------------------------------------------------------------*/
4049 /*!
4050 * \brief Handle Mailbox RX messages
4051 *
4052 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
4053 *
4054 * \return (none)
4055 */
4056 /*----------------------------------------------------------------------------*/
4057 VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg)
4058 {
4059 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
4060 /* TODO */
4061 }
4062
4063
4064 /*----------------------------------------------------------------------------*/
4065 /*!
4066 * \brief Handle ADD RX BA Event from the FW
4067 *
4068 * \param[in] prAdapter Adapter pointer
4069 * \param[in] prEvent The event packet from the FW
4070 *
4071 * \return (none)
4072 */
4073 /*----------------------------------------------------------------------------*/
4074 VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4075 {
4076 P_EVENT_RX_ADDBA_T prEventRxAddBa;
4077 P_STA_RECORD_T prStaRec;
4078 UINT_32 u4Tid;
4079 UINT_32 u4WinSize;
4080
4081 DBGLOG(QM, INFO, ("QM:Event +RxBa\n"));
4082
4083 prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent;
4084 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx);
4085
4086 if (!prStaRec) {
4087 /* Invalid STA_REC index, discard the event packet */
4088 /* ASSERT(0); */
4089 DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
4090 return;
4091 }
4092 #if 0
4093 if (!(prStaRec->fgIsValid)) {
4094 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4095 DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
4096 /* ASSERT(0); */
4097 /* return; */
4098 }
4099 #endif
4100
4101 u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK)
4102 >> BA_PARAM_SET_TID_MASK_OFFSET);
4103
4104 u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
4105 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
4106
4107 if (!qmAddRxBaEntry(prAdapter,
4108 prStaRec->ucIndex,
4109 (UINT_8) u4Tid,
4110 (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN),
4111 (UINT_16) u4WinSize)) {
4112
4113 /* FW shall ensure the availabiilty of the free-to-use BA entry */
4114 DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n"));
4115 ASSERT(0);
4116 }
4117
4118 }
4119
4120 /*----------------------------------------------------------------------------*/
4121 /*!
4122 * \brief Handle DEL RX BA Event from the FW
4123 *
4124 * \param[in] prAdapter Adapter pointer
4125 * \param[in] prEvent The event packet from the FW
4126 *
4127 * \return (none)
4128 */
4129 /*----------------------------------------------------------------------------*/
4130 VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4131 {
4132 P_EVENT_RX_DELBA_T prEventRxDelBa;
4133 P_STA_RECORD_T prStaRec;
4134
4135 /* DbgPrint("QM:Event -RxBa\n"); */
4136
4137 prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent;
4138 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx);
4139
4140 if (!prStaRec) {
4141 /* Invalid STA_REC index, discard the event packet */
4142 /* ASSERT(0); */
4143 return;
4144 }
4145 #if 0
4146 if (!(prStaRec->fgIsValid)) {
4147 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
4148 /* ASSERT(0); */
4149 return;
4150 }
4151 #endif
4152
4153 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE);
4154
4155 }
4156
4157 P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid)
4158 {
4159 int i;
4160 P_QUE_MGT_T prQM = &prAdapter->rQM;
4161
4162 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
4163
4164 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
4165 if (prQM->arRxBaTable[i].fgIsValid) {
4166 if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) &&
4167 (prQM->arRxBaTable[i].ucTid == ucTid)) {
4168 return &prQM->arRxBaTable[i];
4169 }
4170 }
4171 }
4172 return NULL;
4173 }
4174
4175 BOOL
4176 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter,
4177 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize)
4178 {
4179 int i;
4180 P_RX_BA_ENTRY_T prRxBaEntry = NULL;
4181 P_STA_RECORD_T prStaRec;
4182 P_QUE_MGT_T prQM = &prAdapter->rQM;
4183
4184 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
4185
4186 if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
4187 /* Invalid STA_REC index, discard the event packet */
4188 DBGLOG(QM, WARN,
4189 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
4190 ucStaRecIdx));
4191 return FALSE;
4192 }
4193
4194 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
4195 ASSERT(prStaRec);
4196
4197 /* if(!(prStaRec->fgIsValid)){ */
4198 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
4199 /* return FALSE; */
4200 /* } */
4201
4202 /* 4 <1> Delete before adding */
4203 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4204 if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) {
4205 qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */
4206 }
4207 /* 4 <2> Add a new BA entry */
4208 /* No available entry to store the BA agreement info. Retrun FALSE. */
4209 if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) {
4210 DBGLOG(QM, ERROR,
4211 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount));
4212 return FALSE;
4213 } else {
4214 /* Find the free-to-use BA entry */
4215 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
4216 if (!prQM->arRxBaTable[i].fgIsValid) {
4217 prRxBaEntry = &(prQM->arRxBaTable[i]);
4218 prQM->ucRxBaCount++;
4219 DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount));
4220 break;
4221 }
4222 }
4223
4224 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
4225 u2WinSize += CFG_RX_BA_INC_SIZE;
4226 if (prRxBaEntry) {
4227 prRxBaEntry->ucStaRecIdx = ucStaRecIdx;
4228 prRxBaEntry->ucTid = ucTid;
4229 prRxBaEntry->u2WinStart = u2WinStart;
4230 prRxBaEntry->u2WinSize = u2WinSize;
4231 prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT);
4232 prRxBaEntry->fgIsValid = TRUE;
4233 prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE;
4234 prRxBaEntry->fgHasBubble = FALSE;
4235
4236 g_arMissTimeout[ucStaRecIdx][ucTid] = 0;
4237
4238 DBGLOG(QM, INFO,
4239 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
4240 ucStaRecIdx, ucTid, prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd,
4241 prRxBaEntry->u2WinSize));
4242
4243 /* Update the BA entry reference table for per-packet lookup */
4244 prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry;
4245 } else {
4246 /* This shall not happen because FW should keep track of the usage of RX BA entries */
4247 DBGLOG(QM, ERROR,
4248 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount));
4249 return FALSE;
4250 }
4251 }
4252
4253 return TRUE;
4254 }
4255
4256 VOID
4257 qmDelRxBaEntry(IN P_ADAPTER_T prAdapter,
4258 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost)
4259 {
4260 P_RX_BA_ENTRY_T prRxBaEntry;
4261 P_STA_RECORD_T prStaRec;
4262 P_SW_RFB_T prFlushedPacketList = NULL;
4263 P_QUE_MGT_T prQM = &prAdapter->rQM;
4264
4265 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
4266
4267 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
4268 ASSERT(prStaRec);
4269
4270 #if 0
4271 if (!(prStaRec->fgIsValid)) {
4272 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
4273 return;
4274 }
4275 #endif
4276
4277 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
4278 prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid];
4279
4280 if (prRxBaEntry) {
4281
4282 prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid);
4283
4284 if (prFlushedPacketList) {
4285
4286 if (fgFlushToHost) {
4287 wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList);
4288 } else {
4289
4290 P_SW_RFB_T prSwRfb;
4291 P_SW_RFB_T prNextSwRfb;
4292 prSwRfb = prFlushedPacketList;
4293
4294 do {
4295 prNextSwRfb =
4296 (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)
4297 prSwRfb);
4298 nicRxReturnRFB(prAdapter, prSwRfb);
4299 prSwRfb = prNextSwRfb;
4300 } while (prSwRfb);
4301
4302 }
4303
4304
4305 }
4306
4307 if (prRxBaEntry->fgHasBubble) {
4308 DBGLOG(QM, TRACE, ("QM:(Bub Check Cancel) STA[%u] TID[%u], DELBA\n",
4309 prRxBaEntry->ucStaRecIdx, prRxBaEntry->ucTid));
4310
4311 cnmTimerStopTimer(prAdapter, &prRxBaEntry->rReorderBubbleTimer);
4312 prRxBaEntry->fgHasBubble = FALSE;
4313 }
4314 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
4315 /* Update RX BA entry state. Note that RX queue flush is not done here */
4316 prRxBaEntry->fgIsValid = FALSE;
4317 prQM->ucRxBaCount--;
4318
4319 /* Debug */
4320 #if 0
4321 DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount);
4322 #endif
4323
4324 /* Update STA RX BA table */
4325 prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL;
4326 #endif
4327
4328 DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid));
4329
4330 }
4331
4332
4333 /* Debug */
4334 #if CFG_HIF_RX_STARVATION_WARNING
4335 {
4336 P_RX_CTRL_T prRxCtrl;
4337 prRxCtrl = &prAdapter->rRxCtrl;
4338 DBGLOG(QM, TRACE,
4339 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt,
4340 prRxCtrl->u4DequeuedCnt));
4341 }
4342 #endif
4343 }
4344
4345 VOID
4346 mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter,
4347 IN PUINT_8 pucIE, IN P_STA_RECORD_T prStaRec)
4348 {
4349 P_IE_WMM_INFO_T prIeWmmInfo;
4350 UINT_8 ucQosInfo;
4351 UINT_8 ucQosInfoAC;
4352 UINT_8 ucBmpAC;
4353 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4354
4355 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4356 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4357
4358 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4359 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4360 if (IE_LEN(pucIE) != 7) {
4361 break; /* WMM Info IE with a wrong length */
4362 }
4363
4364 prStaRec->fgIsQoS = TRUE;
4365 prStaRec->fgIsWmmSupported = TRUE;
4366
4367 prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE;
4368 ucQosInfo = prIeWmmInfo->ucQosInfo;
4369 ucQosInfoAC = ucQosInfo & BITS(0, 3);
4370
4371 if(IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd))
4372 prStaRec->fgIsUapsdSupported = (ucQosInfoAC) ? TRUE : FALSE;
4373 else
4374 prStaRec->fgIsUapsdSupported = FALSE;
4375
4376 ucBmpAC = 0;
4377
4378 if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) {
4379 ucBmpAC |= BIT(ACI_VO);
4380 }
4381 if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) {
4382 ucBmpAC |= BIT(ACI_VI);
4383 }
4384 if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) {
4385 ucBmpAC |= BIT(ACI_BE);
4386 }
4387 if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) {
4388 ucBmpAC |= BIT(ACI_BK);
4389 }
4390 prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC;
4391 prStaRec->ucUapsdSp = (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5;
4392 break;
4393
4394 default:
4395 /* Other WMM QoS IEs. Ignore any */
4396 break;
4397 }
4398 }
4399 }
4400
4401 /*----------------------------------------------------------------------------*/
4402 /*!
4403 * \brief To process WMM related IEs in ASSOC_RSP
4404 *
4405 * \param[in] prAdapter Adapter pointer
4406 * \param[in] prSwRfb The received frame
4407 * \param[in] pucIE The pointer to the first IE in the frame
4408 * \param[in] u2IELength The total length of IEs in the frame
4409 *
4410 * \return none
4411 */
4412 /*----------------------------------------------------------------------------*/
4413 VOID
4414 mqmProcessAssocReq(IN P_ADAPTER_T prAdapter,
4415 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4416 {
4417 P_STA_RECORD_T prStaRec;
4418 UINT_16 u2Offset;
4419 PUINT_8 pucIEStart;
4420 UINT_32 u4Flags;
4421
4422 DEBUGFUNC("mqmProcessAssocReq");
4423
4424 ASSERT(prSwRfb);
4425 ASSERT(pucIE);
4426
4427 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4428 ASSERT(prStaRec);
4429
4430 if (prStaRec == NULL) {
4431 return;
4432 }
4433
4434 prStaRec->fgIsQoS = FALSE;
4435 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
4436
4437 pucIEStart = pucIE;
4438
4439 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4440 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4441 return;
4442 }
4443
4444
4445 /* Determine whether QoS is enabled with the association */
4446 else {
4447 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4448 switch (IE_ID(pucIE)) {
4449 case ELEM_ID_VENDOR:
4450 mqmParseAssocReqWmmIe(prAdapter, pucIE, prStaRec);
4451
4452 prStaRec->u4Flags = 0;
4453 #if CFG_SUPPORT_MTK_SYNERGY
4454 if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, &u4Flags)) {
4455 prStaRec->u4Flags = u4Flags;
4456 }
4457 #endif
4458
4459 break;
4460
4461 case ELEM_ID_HT_CAP:
4462 /* Some client won't put the WMM IE if client is 802.11n */
4463 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
4464 prStaRec->fgIsQoS = TRUE;
4465 }
4466 break;
4467 default:
4468 break;
4469 }
4470 }
4471
4472 DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4473
4474 }
4475 }
4476
4477 VOID
4478 mqmParseAssocRspWmmIe(IN PUINT_8 pucIE, IN P_STA_RECORD_T prStaRec)
4479 {
4480 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4481
4482 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4483 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4484
4485 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4486 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4487 if (IE_LEN(pucIE) != 24) {
4488 break; /* WMM Info IE with a wrong length */
4489 }
4490 prStaRec->fgIsQoS = TRUE;
4491 break;
4492
4493 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4494 if (IE_LEN(pucIE) != 7) {
4495 break; /* WMM Info IE with a wrong length */
4496 }
4497 prStaRec->fgIsQoS = TRUE;
4498 break;
4499
4500 default:
4501 /* Other WMM QoS IEs. Ignore any */
4502 break;
4503 }
4504 }
4505 }
4506
4507 /*----------------------------------------------------------------------------*/
4508 /*!
4509 * \brief To process WMM related IEs in ASSOC_RSP
4510 *
4511 * \param[in] prAdapter Adapter pointer
4512 * \param[in] prSwRfb The received frame
4513 * \param[in] pucIE The pointer to the first IE in the frame
4514 * \param[in] u2IELength The total length of IEs in the frame
4515 *
4516 * \return none
4517 */
4518 /*----------------------------------------------------------------------------*/
4519 VOID
4520 mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter,
4521 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4522 {
4523 P_STA_RECORD_T prStaRec;
4524 UINT_16 u2Offset;
4525 PUINT_8 pucIEStart;
4526 UINT_32 u4Flags;
4527
4528 DEBUGFUNC("mqmProcessAssocRsp");
4529
4530 ASSERT(prSwRfb);
4531 ASSERT(pucIE);
4532
4533 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4534 ASSERT(prStaRec);
4535
4536 if (prStaRec == NULL) {
4537 return;
4538 }
4539
4540 prStaRec->fgIsQoS = FALSE;
4541
4542 pucIEStart = pucIE;
4543
4544 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
4545 prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.ucQoS));
4546
4547 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
4548 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
4549 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4550 return;
4551 }
4552
4553 /* Determine whether QoS is enabled with the association */
4554 else {
4555 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4556 switch (IE_ID(pucIE)) {
4557 case ELEM_ID_VENDOR:
4558 /* Process WMM related IE */
4559 mqmParseAssocRspWmmIe(pucIE, prStaRec);
4560
4561 prStaRec->u4Flags = 0;
4562 #if CFG_SUPPORT_MTK_SYNERGY
4563 if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, &u4Flags)) {
4564 prStaRec->u4Flags = u4Flags;
4565 }
4566 #endif
4567
4568 break;
4569
4570 case ELEM_ID_HT_CAP:
4571 /* Some AP won't put the WMM IE if client is 802.11n */
4572 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
4573 prStaRec->fgIsQoS = TRUE;
4574 }
4575 break;
4576 default:
4577 break;
4578 }
4579 }
4580
4581 /* Parse AC parameters and write to HW CRs */
4582 if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) {
4583 mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE);
4584 }
4585
4586 DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4587 if (prStaRec->fgIsWmmSupported) {
4588 nicQmUpdateWmmParms(prAdapter, prStaRec->ucBssIndex);
4589 }
4590 }
4591 }
4592
4593 /*----------------------------------------------------------------------------*/
4594 /*!
4595 * \brief
4596 *
4597 * \param[in]
4598 *
4599 * \return none
4600 */
4601 /*----------------------------------------------------------------------------*/
4602 VOID
4603 mqmProcessBcn(IN P_ADAPTER_T prAdapter,
4604 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
4605 {
4606 P_BSS_INFO_T prBssInfo;
4607 BOOLEAN fgNewParameter;
4608 UINT_8 i;
4609
4610 ASSERT(prAdapter);
4611 ASSERT(prSwRfb);
4612 ASSERT(pucIE);
4613
4614 DBGLOG(QM, TRACE, ("Enter %s\n", __func__));
4615
4616 fgNewParameter = FALSE;
4617
4618 for (i = 0; i < BSS_INFO_NUM; i++) {
4619 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, i);
4620
4621 if (IS_BSS_ACTIVE(prBssInfo)) {
4622 if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE &&
4623 prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) {
4624 /* P2P client or AIS infra STA */
4625 if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID,
4626 ((P_WLAN_MAC_MGMT_HEADER_T)
4627 (prSwRfb->pvHeader))->aucBSSID)) {
4628
4629 fgNewParameter = mqmParseEdcaParameters(prAdapter,
4630 prSwRfb, pucIE,
4631 u2IELength, FALSE);
4632 }
4633 }
4634
4635 /* Appy new parameters if necessary */
4636 if (fgNewParameter) {
4637 /* DBGLOG(QM, INFO, ("Update EDCA parameter for BSS[%u]\n", prBssInfo->ucBssIndex)); */
4638 nicQmUpdateWmmParms(prAdapter, prBssInfo->ucBssIndex);
4639 fgNewParameter = FALSE;
4640 }
4641 } /* end of IS_BSS_ACTIVE() */
4642 }
4643 }
4644
4645 BOOLEAN
4646 mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucIE,
4647 IN BOOLEAN fgForceOverride)
4648 {
4649 P_AC_QUE_PARMS_T prAcQueParams;
4650 P_IE_WMM_PARAM_T prIeWmmParam;
4651 ENUM_WMM_ACI_T eAci;
4652 BOOLEAN fgNewParameter = FALSE;
4653
4654 do {
4655 if (IE_LEN(pucIE) != 24) {
4656 break; /* WMM Param IE with a wrong length */
4657 }
4658
4659 prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE;
4660
4661 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
4662 if(!fgForceOverride) {
4663 if(mqmCompareEdcaParameters(prIeWmmParam, prBssInfo)) {
4664 fgNewParameter = FALSE;
4665 break;
4666 }
4667 }
4668
4669 fgNewParameter = TRUE;
4670 /* Update Parameter Set Count */
4671 prBssInfo->ucWmmParamSetCount = (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT);
4672 /* Update EDCA parameters */
4673 for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
4674 prAcQueParams = &prBssInfo->arACQueParms[eAci];
4675 mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams);
4676 DBGLOG(QM, INFO, ("BSS[%u]: eAci[%d] ACM[%d] Aifsn[%d] CWmin/max[%d/%d]"
4677 "TxopLimit[%d] NewParameter[%d]\n",
4678 prBssInfo->ucBssIndex, eAci, prAcQueParams->ucIsACMSet, prAcQueParams->u2Aifsn,
4679 prAcQueParams->u2CWmin, prAcQueParams->u2CWmax, prAcQueParams->u2TxopLimit, fgNewParameter));
4680 }
4681 }while(FALSE);
4682
4683 return fgNewParameter;
4684 }
4685
4686 /*----------------------------------------------------------------------------*/
4687 /*!
4688 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
4689 *
4690 * \param[in] prAdapter Adapter pointer
4691 * \param[in] prSwRfb The received frame
4692 * \param[in] pucIE The pointer to the first IE in the frame
4693 * \param[in] u2IELength The total length of IEs in the frame
4694 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
4695 *
4696 * \return none
4697 */
4698 /*----------------------------------------------------------------------------*/
4699 BOOLEAN
4700 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter,
4701 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength,
4702 IN BOOLEAN fgForceOverride)
4703 {
4704 P_STA_RECORD_T prStaRec;
4705 UINT_16 u2Offset;
4706 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4707 P_BSS_INFO_T prBssInfo;
4708 BOOLEAN fgNewParameter = FALSE;
4709
4710 DEBUGFUNC("mqmParseEdcaParameters");
4711
4712 if (!prSwRfb) {
4713 return FALSE;
4714 }
4715
4716 if (!pucIE) {
4717 return FALSE;
4718 }
4719
4720 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4721 /* ASSERT(prStaRec); */
4722
4723 if (prStaRec == NULL) {
4724 return FALSE;
4725 }
4726
4727 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
4728 prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS));
4729
4730 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS) || (!prStaRec->fgIsWmmSupported)
4731 || (!prStaRec->fgIsQoS)) {
4732 return FALSE;
4733 }
4734
4735 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
4736
4737 /* Goal: Obtain the EDCA parameters */
4738 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4739 switch (IE_ID(pucIE)) {
4740 case ELEM_ID_WMM:
4741 if (!((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4742 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3)))) {
4743 break;
4744 }
4745
4746 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4747 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4748 fgNewParameter = mqmUpdateEdcaParameters(prBssInfo, pucIE, fgForceOverride);
4749 break;
4750
4751 default:
4752 /* Other WMM QoS IEs. Ignore */
4753 break;
4754 }
4755
4756 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4757 break;
4758 default:
4759 break;
4760 }
4761 }
4762
4763 return fgNewParameter;
4764 }
4765
4766 BOOLEAN mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam, IN P_BSS_INFO_T prBssInfo)
4767 {
4768 P_AC_QUE_PARMS_T prAcQueParams;
4769 P_WMM_AC_PARAM_T prWmmAcParams;
4770 ENUM_WMM_ACI_T eAci;
4771
4772 /* return FALSE; */
4773
4774 /* Check Set Count */
4775 if (prBssInfo->ucWmmParamSetCount != (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)) {
4776 return FALSE;
4777 }
4778
4779 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
4780 prAcQueParams = &prBssInfo->arACQueParms[eAci];
4781 prWmmAcParams = &prIeWmmParam->arAcParam[eAci];
4782
4783 /* ACM */
4784 if (prAcQueParams->ucIsACMSet !=
4785 ((prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE)) {
4786 return FALSE;
4787 }
4788
4789 /* AIFSN */
4790 if (prAcQueParams->u2Aifsn != (prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_AIFSN)) {
4791 return FALSE;
4792 }
4793
4794 /* CW Max */
4795 if (prAcQueParams->u2CWmax !=
4796 (BIT((prWmmAcParams->ucEcw & WMM_ECW_WMAX_MASK) >> WMM_ECW_WMAX_OFFSET) - 1)) {
4797 return FALSE;
4798 }
4799
4800 /* CW Min */
4801 if (prAcQueParams->u2CWmin != (BIT(prWmmAcParams->ucEcw & WMM_ECW_WMIN_MASK) - 1)) {
4802 return FALSE;
4803 }
4804
4805 if (prAcQueParams->u2TxopLimit != prWmmAcParams->u2TxopLimit) {
4806 return FALSE;
4807 }
4808 }
4809
4810 return TRUE;
4811 }
4812
4813
4814 /*----------------------------------------------------------------------------*/
4815 /*!
4816 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
4817 *
4818 * \param[in] prAdapter Adapter pointer
4819 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
4820 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
4821 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
4822 *
4823 * \return none
4824 */
4825 /*----------------------------------------------------------------------------*/
4826 VOID
4827 mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam,
4828 IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams)
4829 {
4830 P_WMM_AC_PARAM_T prAcParam = &prIeWmmParam->arAcParam[u4AcOffset];
4831
4832 prAcQueParams->ucIsACMSet = (prAcParam->ucAciAifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE;
4833
4834 prAcQueParams->u2Aifsn = (prAcParam->ucAciAifsn & WMM_ACIAIFSN_AIFSN);
4835
4836 prAcQueParams->u2CWmax =
4837 BIT((prAcParam->ucEcw & WMM_ECW_WMAX_MASK) >> WMM_ECW_WMAX_OFFSET) - 1;
4838
4839 prAcQueParams->u2CWmin = BIT(prAcParam->ucEcw & WMM_ECW_WMIN_MASK) - 1;
4840
4841 WLAN_GET_FIELD_16(&prAcParam->u2TxopLimit, &prAcQueParams->u2TxopLimit);
4842
4843 prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME;
4844
4845 }
4846
4847
4848 /*----------------------------------------------------------------------------*/
4849 /*!
4850 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
4851 *
4852 * \param[in] prAdapter Adapter pointer
4853 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
4854 * \param[out] prStaRec The obtained info is stored in the STA_REC
4855 *
4856 * \return none
4857 */
4858 /*----------------------------------------------------------------------------*/
4859 VOID
4860 mqmProcessScanResult(IN P_ADAPTER_T prAdapter,
4861 IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec)
4862 {
4863 PUINT_8 pucIE;
4864 UINT_16 u2IELength;
4865 UINT_16 u2Offset;
4866 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4867 BOOLEAN fgIsHtVht;
4868
4869 DEBUGFUNC("mqmProcessScanResult");
4870
4871 ASSERT(prScanResult);
4872 ASSERT(prStaRec);
4873
4874 /* Reset the flag before parsing */
4875 prStaRec->fgIsWmmSupported = FALSE;
4876 prStaRec->fgIsUapsdSupported = FALSE;
4877 prStaRec->fgIsQoS = FALSE;
4878
4879 fgIsHtVht = FALSE;
4880
4881 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
4882 return;
4883 }
4884
4885 u2IELength = prScanResult->u2IELength;
4886 pucIE = prScanResult->aucIEBuf;
4887
4888 /* <1> Determine whether the peer supports WMM/QoS and UAPSDU */
4889 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4890 switch (IE_ID(pucIE)) {
4891
4892 case ELEM_ID_EXTENDED_CAP:
4893 #if CFG_SUPPORT_TDLS
4894 TdlsBssExtCapParse(prStaRec, pucIE);
4895 #endif /* CFG_SUPPORT_TDLS */
4896 break;
4897
4898 case ELEM_ID_WMM:
4899 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4900 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
4901
4902 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
4903 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4904 if (IE_LEN(pucIE) != 24) {
4905 break; /* WMM Param IE with a wrong length */
4906 } else {
4907 prStaRec->fgIsWmmSupported = TRUE;
4908 prStaRec->fgIsUapsdSupported =
4909 (((((P_IE_WMM_PARAM_T) pucIE)->
4910 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
4911 FALSE);
4912 }
4913 break;
4914
4915 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4916 if (IE_LEN(pucIE) != 7) {
4917 break; /* WMM Info IE with a wrong length */
4918 } else {
4919 prStaRec->fgIsWmmSupported = TRUE;
4920 prStaRec->fgIsUapsdSupported =
4921 (((((P_IE_WMM_INFO_T) pucIE)->
4922 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
4923 FALSE);
4924 }
4925 break;
4926
4927 default:
4928 /* A WMM QoS IE that doesn't matter. Ignore it. */
4929 break;
4930 }
4931 }
4932 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4933
4934 break;
4935
4936 default:
4937 /* A WMM IE that doesn't matter. Ignore it. */
4938 break;
4939 }
4940 }
4941
4942 /* <1> Determine QoS */
4943 if (prStaRec->ucDesiredPhyTypeSet & (PHY_TYPE_SET_802_11N | PHY_TYPE_SET_802_11AC)) {
4944 fgIsHtVht = TRUE;
4945 }
4946
4947 if (fgIsHtVht || prStaRec->fgIsWmmSupported) {
4948 prStaRec->fgIsQoS = TRUE;
4949 }
4950 }
4951
4952
4953 /*----------------------------------------------------------------------------*/
4954 /*!
4955 * @brief Generate the WMM Info IE by Param
4956 *
4957 * \param[in] prAdapter Adapter pointer
4958 * @param prMsduInfo The TX MMPDU
4959 *
4960 * @return (none)
4961 */
4962 /*----------------------------------------------------------------------------*/
4963 UINT_32
4964 mqmFillWmmInfoIE(P_UINT_8 pucOutBuf,
4965 BOOLEAN fgSupportUAPSD,
4966 UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp)
4967 {
4968 P_IE_WMM_INFO_T prIeWmmInfo;
4969 UINT_32 ucUapsd[] = {
4970 WMM_QOS_INFO_BE_UAPSD,
4971 WMM_QOS_INFO_BK_UAPSD,
4972 WMM_QOS_INFO_VI_UAPSD,
4973 WMM_QOS_INFO_VO_UAPSD
4974 };
4975 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4976
4977 ASSERT(pucOutBuf);
4978
4979 prIeWmmInfo = (P_IE_WMM_INFO_T) pucOutBuf;
4980
4981 prIeWmmInfo->ucId = ELEM_ID_WMM;
4982 prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4983
4984 /* WMM-2.2.1 WMM Information Element Field Values */
4985 prIeWmmInfo->aucOui[0] = aucWfaOui[0];
4986 prIeWmmInfo->aucOui[1] = aucWfaOui[1];
4987 prIeWmmInfo->aucOui[2] = aucWfaOui[2];
4988 prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
4989 prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
4990
4991 prIeWmmInfo->ucVersion = VERSION_WMM;
4992 prIeWmmInfo->ucQosInfo = 0;
4993
4994 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4995 if (fgSupportUAPSD) {
4996 UINT_8 ucQosInfo = 0;
4997 UINT_8 i;
4998
4999 /* Static U-APSD setting */
5000 for (i = ACI_BE; i <= ACI_VO; i++) {
5001 if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) {
5002 ucQosInfo |= (UINT_8) ucUapsd[i];
5003 }
5004 }
5005
5006 if (ucBmpDeliveryAC & ucBmpTriggerAC) {
5007 switch (ucUapsdSp) {
5008 case WMM_MAX_SP_LENGTH_ALL:
5009 ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
5010 break;
5011
5012 case WMM_MAX_SP_LENGTH_2:
5013 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
5014 break;
5015
5016 case WMM_MAX_SP_LENGTH_4:
5017 ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
5018 break;
5019
5020 case WMM_MAX_SP_LENGTH_6:
5021 ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
5022 break;
5023
5024 default:
5025 DBGLOG(QM, INFO, ("MQM: Incorrect SP length\n"));
5026 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
5027 break;
5028 }
5029 }
5030 prIeWmmInfo->ucQosInfo = ucQosInfo;
5031
5032 }
5033
5034 /* Increment the total IE length for the Element ID and Length fields. */
5035 return IE_SIZE(prIeWmmInfo);
5036 }
5037
5038
5039 /*----------------------------------------------------------------------------*/
5040 /*!
5041 * @brief Generate the WMM Info IE
5042 *
5043 * \param[in] prAdapter Adapter pointer
5044 * @param prMsduInfo The TX MMPDU
5045 *
5046 * @return (none)
5047 */
5048 /*----------------------------------------------------------------------------*/
5049 UINT_32
5050 mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter,
5051 P_BSS_INFO_T prBssInfo, P_STA_RECORD_T prStaRec, P_UINT_8 pucOutBuf)
5052 {
5053 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo;
5054 BOOLEAN fgSupportUapsd;
5055
5056 ASSERT(pucOutBuf);
5057
5058 /* In case QoS is not turned off, exit directly */
5059 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5060 return 0;
5061 }
5062
5063 if (prStaRec == NULL) {
5064 return 0;
5065 }
5066
5067 if (!prStaRec->fgIsWmmSupported) {
5068 return 0;
5069 }
5070
5071 prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
5072
5073 fgSupportUapsd = (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)
5074 && prStaRec->fgIsUapsdSupported);
5075
5076 return mqmFillWmmInfoIE(pucOutBuf,
5077 fgSupportUapsd,
5078 prPmProfSetupInfo->ucBmpDeliveryAC,
5079 prPmProfSetupInfo->ucBmpTriggerAC, prPmProfSetupInfo->ucUapsdSp);
5080 }
5081
5082 /*----------------------------------------------------------------------------*/
5083 /*!
5084 * @brief Generate the WMM Info IE
5085 *
5086 * \param[in] prAdapter Adapter pointer
5087 * @param prMsduInfo The TX MMPDU
5088 *
5089 * @return (none)
5090 */
5091 /*----------------------------------------------------------------------------*/
5092 VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
5093 {
5094 P_BSS_INFO_T prBssInfo;
5095 P_STA_RECORD_T prStaRec;
5096 UINT_32 u4Length;
5097
5098 DEBUGFUNC("mqmGenerateWmmInfoIE");
5099
5100 ASSERT(prMsduInfo);
5101
5102 /* In case QoS is not turned off, exit directly */
5103 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5104 return;
5105 }
5106
5107 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5108 ASSERT(prStaRec);
5109
5110 if (prStaRec == NULL) {
5111 return;
5112 }
5113
5114 if (!prStaRec->fgIsWmmSupported) {
5115 return;
5116 }
5117
5118 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
5119
5120 u4Length = mqmGenerateWmmInfoIEByStaRec(prAdapter,
5121 prBssInfo,
5122 prStaRec,
5123 ((PUINT_8) prMsduInfo->prPacket +
5124 prMsduInfo->u2FrameLength));
5125
5126 prMsduInfo->u2FrameLength += u4Length;
5127 }
5128
5129 /*----------------------------------------------------------------------------*/
5130 /*!
5131 * @brief Generate the WMM Param IE
5132 *
5133 * \param[in] prAdapter Adapter pointer
5134 * @param prMsduInfo The TX MMPDU
5135 *
5136 * @return (none)
5137 */
5138 /*----------------------------------------------------------------------------*/
5139 VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
5140 {
5141 P_IE_WMM_PARAM_T prIeWmmParam;
5142
5143 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
5144
5145 UINT_8 aucACI[] = {
5146 WMM_ACI_AC_BE,
5147 WMM_ACI_AC_BK,
5148 WMM_ACI_AC_VI,
5149 WMM_ACI_AC_VO
5150 };
5151
5152 P_BSS_INFO_T prBssInfo;
5153 P_STA_RECORD_T prStaRec;
5154 ENUM_WMM_ACI_T eAci;
5155 P_WMM_AC_PARAM_T prAcParam;
5156
5157 DEBUGFUNC("mqmGenerateWmmParamIE");
5158 DBGLOG(QM, LOUD, ("\n"));
5159
5160 ASSERT(prMsduInfo);
5161
5162 /* In case QoS is not turned off, exit directly */
5163 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5164 return;
5165 }
5166
5167 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5168
5169 if (prStaRec) {
5170 if (!prStaRec->fgIsQoS) {
5171 return;
5172 }
5173 }
5174
5175 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
5176
5177 if (!prBssInfo->fgIsQBSS) {
5178 return;
5179 }
5180
5181 prIeWmmParam = (P_IE_WMM_PARAM_T)
5182 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
5183
5184 prIeWmmParam->ucId = ELEM_ID_WMM;
5185 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
5186
5187 /* WMM-2.2.1 WMM Information Element Field Values */
5188 prIeWmmParam->aucOui[0] = aucWfaOui[0];
5189 prIeWmmParam->aucOui[1] = aucWfaOui[1];
5190 prIeWmmParam->aucOui[2] = aucWfaOui[2];
5191 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
5192 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
5193
5194 prIeWmmParam->ucVersion = VERSION_WMM;
5195 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
5196
5197 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5198 if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) {
5199 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
5200 }
5201
5202 /* EDCA parameter */
5203
5204 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
5205 prAcParam = &prIeWmmParam->arAcParam[eAci];
5206
5207 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5208 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5209 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5210 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5211 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5212 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5213
5214 /* ACI */
5215 prAcParam->ucAciAifsn = aucACI[eAci];
5216 /* ACM */
5217 if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) {
5218 prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM;
5219 }
5220 /* AIFSN */
5221 prAcParam->ucAciAifsn |=
5222 (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & WMM_ACIAIFSN_AIFSN);
5223
5224 /* ECW Min */
5225 prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & WMM_ECW_WMIN_MASK);
5226 /* ECW Max */
5227 prAcParam->ucEcw |=
5228 ((prBssInfo->
5229 aucCWmaxLog2ForBcast[eAci] << WMM_ECW_WMAX_OFFSET) & WMM_ECW_WMAX_MASK);
5230
5231 /* Txop limit */
5232 WLAN_SET_FIELD_16(&prAcParam->u2TxopLimit,
5233 prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
5234
5235 }
5236
5237 /* Increment the total IE length for the Element ID and Length fields. */
5238 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam);
5239
5240 }
5241
5242
5243 #if CFG_SUPPORT_TDLS
5244 /*----------------------------------------------------------------------------*/
5245 /*!
5246 * @brief Generate the WMM Param IE
5247 *
5248 * \param[in] prAdapter Adapter pointer
5249 * @param prMsduInfo The TX MMPDU
5250 *
5251 * @return (none)
5252 */
5253 /*----------------------------------------------------------------------------*/
5254 UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pOutBuf)
5255 {
5256 P_IE_WMM_PARAM_T prIeWmmParam;
5257
5258 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
5259
5260 UINT_8 aucACI[] = {
5261 WMM_ACI_AC_BE,
5262 WMM_ACI_AC_BK,
5263 WMM_ACI_AC_VI,
5264 WMM_ACI_AC_VO
5265 };
5266
5267 ENUM_WMM_ACI_T eAci;
5268 P_WMM_AC_PARAM_T prAcParam;
5269
5270 DEBUGFUNC("mqmGenerateWmmParamIE");
5271 DBGLOG(QM, LOUD, ("\n"));
5272
5273 ASSERT(pOutBuf);
5274
5275
5276 /* In case QoS is not turned off, exit directly */
5277 if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) {
5278 return WLAN_STATUS_SUCCESS;
5279 }
5280
5281
5282 if (!prBssInfo->fgIsQBSS) {
5283 return WLAN_STATUS_SUCCESS;
5284 }
5285
5286
5287
5288 prIeWmmParam = (P_IE_WMM_PARAM_T) pOutBuf;
5289
5290
5291 prIeWmmParam->ucId = ELEM_ID_WMM;
5292 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
5293
5294 /* WMM-2.2.1 WMM Information Element Field Values */
5295 prIeWmmParam->aucOui[0] = aucWfaOui[0];
5296 prIeWmmParam->aucOui[1] = aucWfaOui[1];
5297 prIeWmmParam->aucOui[2] = aucWfaOui[2];
5298 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
5299 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
5300
5301 prIeWmmParam->ucVersion = VERSION_WMM;
5302 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
5303
5304 /* UAPSD intial queue configurations (delivery and trigger enabled) */
5305 if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) {
5306 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
5307 }
5308
5309 /* EDCA parameter */
5310
5311 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
5312 prAcParam = &prIeWmmParam->arAcParam[eAci];
5313
5314 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
5315 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */
5316 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
5317 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
5318 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
5319 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
5320
5321 /* ACI */
5322 prAcParam->ucAciAifsn = aucACI[eAci];
5323 /* ACM */
5324 if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) {
5325 prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM;
5326 }
5327 /* AIFSN */
5328 prAcParam->ucAciAifsn |=
5329 (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & WMM_ACIAIFSN_AIFSN);
5330
5331 /* ECW Min */
5332 prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & WMM_ECW_WMIN_MASK);
5333 /* ECW Max */
5334 prAcParam->ucEcw |=
5335 ((prBssInfo->
5336 aucCWmaxLog2ForBcast[eAci] << WMM_ECW_WMAX_OFFSET) & WMM_ECW_WMAX_MASK);
5337
5338 /* Txop limit */
5339 WLAN_SET_FIELD_16(&prAcParam->u2TxopLimit,
5340 prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
5341
5342 }
5343
5344 /* Increment the total IE length for the Element ID and Length fields. */
5345 return IE_SIZE(prIeWmmParam);
5346
5347
5348 }
5349
5350
5351 #endif
5352
5353 ENUM_FRAME_ACTION_T
5354 qmGetFrameAction(IN P_ADAPTER_T prAdapter,
5355 IN UINT_8 ucBssIndex,
5356 IN UINT_8 ucStaRecIdx,
5357 IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType)
5358 {
5359 ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_TX_PKT;
5360 P_BSS_INFO_T prBssInfo;
5361 P_STA_RECORD_T prStaRec;
5362 /* P_WLAN_MAC_HEADER_T prWlanFrame; */
5363 /* UINT_16 u2TxFrameCtrl; */
5364
5365 DEBUGFUNC("qmGetFrameAction");
5366
5367 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
5368 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx);
5369
5370 do {
5371 /* 4 <1> Tx, if FORCE_TX is set */
5372 if (prMsduInfo) {
5373 if (prMsduInfo->ucControlFlag & MSDU_CONTROL_FLAG_FORCE_TX) {
5374 eFrameAction = FRAME_ACTION_TX_PKT;
5375 break;
5376 }
5377 }
5378 /* 4 <2> Drop, if BSS is inactive */
5379 if (!IS_BSS_ACTIVE(prBssInfo)) {
5380 DBGLOG(QM, TRACE,
5381 ("Drop packets (BSS[%u] is INACTIVE)\n", prBssInfo->ucBssIndex));
5382 eFrameAction = FRAME_ACTION_DROP_PKT;
5383 break;
5384 }
5385 /* 4 <3> Check based on StaRec */
5386 if (prStaRec) {
5387 /* 4 <3.1> Drop, if StaRec is not in use */
5388 if (!prStaRec->fgIsInUse) {
5389 DBGLOG(QM, TRACE,
5390 ("Drop packets (Sta[%u] not in USE)\n", prStaRec->ucIndex));
5391 eFrameAction = FRAME_ACTION_DROP_PKT;
5392 break;
5393 }
5394 /* 4 <3.2> Sta in PS */
5395 if (prStaRec->fgIsInPS) {
5396 /* 4 <3.2.1> Tx, if resource is enough */
5397 if (nicTxGetResource
5398 (prAdapter,
5399 nicTxGetFrameResourceType(eFrameType,
5400 prMsduInfo)) >=
5401 QM_MGMT_QUEUED_THRESHOLD) {
5402 eFrameAction = FRAME_ACTION_TX_PKT;
5403 break;
5404 }
5405 /* 4 <3.2.2> Queue, if resource is not enough */
5406 else {
5407 DBGLOG(QM, TRACE,
5408 ("Queue packets (Sta[%u] in PS)\n",
5409 prStaRec->ucIndex));
5410 eFrameAction = FRAME_ACTION_QUEUE_PKT;
5411 break;
5412 }
5413 }
5414 }
5415 /* 4 <4> Queue, if BSS is absent */
5416 if (prBssInfo->fgIsNetAbsent) {
5417 DBGLOG(QM, TRACE,
5418 ("Queue packets (BSS[%u] Absent)\n", prBssInfo->ucBssIndex));
5419 eFrameAction = FRAME_ACTION_QUEUE_PKT;
5420 break;
5421 }
5422
5423 } while (FALSE);
5424
5425 return eFrameAction;
5426 }
5427
5428
5429 /*----------------------------------------------------------------------------*/
5430 /*!
5431 * \brief Handle BSS change operation Event from the FW
5432 *
5433 * \param[in] prAdapter Adapter pointer
5434 * \param[in] prEvent The event packet from the FW
5435 *
5436 * \return (none)
5437 */
5438 /*----------------------------------------------------------------------------*/
5439 VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5440 {
5441 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus;
5442 P_BSS_INFO_T prBssInfo;
5443 BOOLEAN fgIsNetAbsentOld;
5444
5445 prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent;
5446 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prEventBssStatus->ucBssIndex);
5447 fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent;
5448 prBssInfo->fgIsNetAbsent = prEventBssStatus->ucIsAbsent;
5449 prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota;
5450
5451 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
5452 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
5453
5454 DBGLOG(QM, INFO, ("NAF=%d,%d,%d\n",
5455 prEventBssStatus->ucBssIndex, prBssInfo->fgIsNetAbsent,
5456 prBssInfo->ucBssFreeQuota));
5457
5458 if (!prBssInfo->fgIsNetAbsent) {
5459 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27);
5460 } else {
5461 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28);
5462 }
5463 /* From Absent to Present */
5464 if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) {
5465 kalSetEvent(prAdapter->prGlueInfo);
5466 }
5467 }
5468
5469
5470 /*----------------------------------------------------------------------------*/
5471 /*!
5472 * \brief Handle STA change PS mode Event from the FW
5473 *
5474 * \param[in] prAdapter Adapter pointer
5475 * \param[in] prEvent The event packet from the FW
5476 *
5477 * \return (none)
5478 */
5479 /*----------------------------------------------------------------------------*/
5480 VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5481 {
5482 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode;
5483 P_STA_RECORD_T prStaRec;
5484 BOOLEAN fgIsInPSOld;
5485
5486 /* DbgPrint("QM:Event -RxBa\n"); */
5487
5488 prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent;
5489 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx);
5490 /* ASSERT(prStaRec); */
5491
5492 if (prStaRec) {
5493
5494 fgIsInPSOld = prStaRec->fgIsInPS;
5495 prStaRec->fgIsInPS = prEventStaChangePsMode->ucIsInPs;
5496
5497 qmUpdateFreeQuota(prAdapter,
5498 prStaRec,
5499 prEventStaChangePsMode->ucUpdateMode,
5500 prEventStaChangePsMode->ucFreeQuota);
5501
5502 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
5503 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
5504
5505
5506 DBGLOG(QM, INFO, ("PS=%d,%d\n",
5507 prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
5508
5509 /* From PS to Awake */
5510 if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) {
5511 kalSetEvent(prAdapter->prGlueInfo);
5512 }
5513 }
5514 }
5515
5516 /*----------------------------------------------------------------------------*/
5517 /*!
5518 * \brief Update STA free quota Event from FW
5519 *
5520 * \param[in] prAdapter Adapter pointer
5521 * \param[in] prEvent The event packet from the FW
5522 *
5523 * \return (none)
5524 */
5525 /*----------------------------------------------------------------------------*/
5526 VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
5527 {
5528 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota;
5529 P_STA_RECORD_T prStaRec;
5530
5531
5532 prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent;
5533 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx);
5534 /* 2013/08/30
5535 * Station Record possible been freed.
5536 */
5537 /* ASSERT(prStaRec); */
5538
5539 if (prStaRec) {
5540 if (prStaRec->fgIsInPS) {
5541 qmUpdateFreeQuota(prAdapter,
5542 prStaRec,
5543 prEventStaUpdateFreeQuota->ucUpdateMode,
5544 prEventStaUpdateFreeQuota->ucFreeQuota);
5545
5546 kalSetEvent(prAdapter->prGlueInfo);
5547 }
5548 #if 0
5549 DBGLOG(QM, TRACE,
5550 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
5551 prEventStaUpdateFreeQuota->ucStaRecIdx,
5552 prEventStaUpdateFreeQuota->ucUpdateMode,
5553 prEventStaUpdateFreeQuota->ucFreeQuota));
5554 #endif
5555
5556 DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n",
5557 prEventStaUpdateFreeQuota->ucStaRecIdx,
5558 prEventStaUpdateFreeQuota->ucUpdateMode,
5559 prEventStaUpdateFreeQuota->ucFreeQuota));
5560
5561
5562 }
5563
5564 }
5565
5566
5567 /*----------------------------------------------------------------------------*/
5568 /*!
5569 * \brief Update STA free quota
5570 *
5571 * \param[in] prStaRec the STA
5572 * \param[in] ucUpdateMode the method to update free quota
5573 * \param[in] ucFreeQuota the value for update
5574 *
5575 * \return (none)
5576 */
5577 /*----------------------------------------------------------------------------*/
5578 VOID
5579 qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter,
5580 IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota)
5581 {
5582
5583 UINT_8 ucFreeQuotaForNonDelivery;
5584 UINT_8 ucFreeQuotaForDelivery;
5585
5586 ASSERT(prStaRec);
5587 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
5588 prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota));
5589
5590 if (!prStaRec->fgIsInPS)
5591 return;
5592
5593 switch (ucUpdateMode) {
5594 case FREE_QUOTA_UPDATE_MODE_INIT:
5595 case FREE_QUOTA_UPDATE_MODE_OVERWRITE:
5596 prStaRec->ucFreeQuota = ucFreeQuota;
5597 break;
5598 case FREE_QUOTA_UPDATE_MODE_INCREASE:
5599 prStaRec->ucFreeQuota += ucFreeQuota;
5600 break;
5601 case FREE_QUOTA_UPDATE_MODE_DECREASE:
5602 prStaRec->ucFreeQuota -= ucFreeQuota;
5603 break;
5604 default:
5605 ASSERT(0);
5606 }
5607
5608 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota));
5609
5610 ucFreeQuota = prStaRec->ucFreeQuota;
5611
5612 ucFreeQuotaForNonDelivery = 0;
5613 ucFreeQuotaForDelivery = 0;
5614
5615 if (ucFreeQuota > 0) {
5616 if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
5617 /* && prAdapter->rWifiVar.fgSupportQoS
5618 && prAdapter->rWifiVar.fgSupportUAPSD */) {
5619 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
5620
5621 if (prStaRec->ucFreeQuotaForNonDelivery > 0
5622 && prStaRec->ucFreeQuotaForDelivery > 0) {
5623 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
5624 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5625 } else if (prStaRec->ucFreeQuotaForNonDelivery == 0
5626 && prStaRec->ucFreeQuotaForDelivery == 0) {
5627 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
5628 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5629 } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) {
5630 /* NonDelivery is not busy */
5631 if (ucFreeQuota >= 3) {
5632 ucFreeQuotaForNonDelivery = 2;
5633 ucFreeQuotaForDelivery =
5634 ucFreeQuota - ucFreeQuotaForNonDelivery;
5635 } else {
5636 ucFreeQuotaForDelivery = ucFreeQuota;
5637 ucFreeQuotaForNonDelivery = 0;
5638 }
5639 } else if (prStaRec->ucFreeQuotaForDelivery > 0) {
5640 /* Delivery is not busy */
5641 if (ucFreeQuota >= 3) {
5642 ucFreeQuotaForDelivery = 2;
5643 ucFreeQuotaForNonDelivery =
5644 ucFreeQuota - ucFreeQuotaForDelivery;
5645 } else {
5646 ucFreeQuotaForNonDelivery = ucFreeQuota;
5647 ucFreeQuotaForDelivery = 0;
5648 }
5649 }
5650
5651 } else {
5652 /* !prStaRec->fgIsUapsdSupported */
5653 ucFreeQuotaForNonDelivery = ucFreeQuota;
5654 ucFreeQuotaForDelivery = 0;
5655 }
5656 }
5657 /* ucFreeQuota > 0 */
5658 prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery;
5659 prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery;
5660
5661 DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
5662 prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery));
5663
5664 }
5665
5666 /*----------------------------------------------------------------------------*/
5667 /*!
5668 * \brief Return the reorder queued RX packets
5669 *
5670 * \param[in] (none)
5671 *
5672 * \return The number of queued RX packets
5673 */
5674 /*----------------------------------------------------------------------------*/
5675 UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter)
5676 {
5677 UINT_32 i, u4Total;
5678 P_QUE_MGT_T prQM = &prAdapter->rQM;
5679 u4Total = 0;
5680 /* XXX The summation may impact the performance */
5681 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
5682 u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem;
5683 #if DBG && 0
5684 if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) {
5685 ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0);
5686 }
5687 #endif
5688 }
5689 ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2));
5690 return u4Total;
5691 }
5692
5693 /*----------------------------------------------------------------------------*/
5694 /*!
5695 * \brief Dump current queue status
5696 *
5697 * \param[in] (none)
5698 *
5699 * \return (none)
5700 */
5701 /*----------------------------------------------------------------------------*/
5702 VOID qmDumpQueueStatus(IN P_ADAPTER_T prAdapter)
5703 {
5704 P_TX_CTRL_T prTxCtrl;
5705 P_QUE_MGT_T prQM;
5706 P_GLUE_INFO_T prGlueInfo;
5707 UINT_32 i;
5708 UINT_32 u4TotalBufferCount, u4TotalPageCount, u4CurBufferCount, u4CurPageCount;
5709
5710 DEBUGFUNC(("%s", __func__));
5711
5712 prTxCtrl = &prAdapter->rTxCtrl;
5713 prQM = &prAdapter->rQM;
5714 prGlueInfo = prAdapter->prGlueInfo;
5715 u4TotalBufferCount = 0;
5716 u4TotalPageCount = 0;
5717 u4CurBufferCount = 0;
5718 u4CurPageCount = 0;
5719
5720 DBGLOG(SW4, INFO, ("\n------<Dump QUEUE Status>------\n"));
5721
5722 for(i = TC0_INDEX; i < TC_NUM; i++) {
5723 DBGLOG(SW4, INFO, ("TC%u ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5724 i,
5725 prTxCtrl->rTc.au2MaxNumOfBuffer[i],
5726 prTxCtrl->rTc.au2MaxNumOfPage[i],
5727 prTxCtrl->rTc.au2FreeBufferCount[i],
5728 prTxCtrl->rTc.au2FreePageCount[i]));
5729
5730 u4TotalBufferCount += prTxCtrl->rTc.au2MaxNumOfBuffer[i];
5731 u4TotalPageCount += prTxCtrl->rTc.au2MaxNumOfPage[i];
5732 u4CurBufferCount += prTxCtrl->rTc.au2FreeBufferCount[i];
5733 u4CurPageCount += prTxCtrl->rTc.au2FreePageCount[i];
5734 }
5735
5736 DBGLOG(SW4, INFO, ("ToT ResCount: Max[%02u/%03u] Free[%02u/%03u]\n",
5737 u4TotalBufferCount, u4TotalPageCount, u4CurBufferCount, u4CurPageCount));
5738
5739 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5740
5741 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
5742 for(i = TC0_INDEX; i < TC_NUM; i++) {
5743
5744 DBGLOG(SW4, INFO,("TC%u AvgQLen[%04u] minRsv[%02u] CurTcRes[%02u] GrtdTcRes[%02u]\n",
5745 i,
5746 QM_GET_TX_QUEUE_LEN(prAdapter, i),
5747 prQM->au4MinReservedTcResource[i],
5748 prQM->au4CurrentTcResource[i],
5749 prQM->au4GuaranteedTcResource[i]));
5750 }
5751
5752 DBGLOG(SW4, INFO,("Resource Residual[%u] ExtraRsv[%u]\n",
5753 prQM->u4ResidualTcResource,
5754 prQM->u4ExtraReservedTcResource));
5755 DBGLOG(SW4, INFO,("QueLenMovingAvg[%u] Time2AdjResource[%u] Time2UpdateQLen[%u]\n",
5756 prQM->u4QueLenMovingAverage,
5757 prQM->u4TimeToAdjustTcResource,
5758 prQM->u4TimeToUpdateQueLen));
5759 #endif
5760
5761 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5762
5763 #if QM_FORWARDING_FAIRNESS
5764 for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) {
5765 DBGLOG(SW4, INFO,
5766 ("TC%u HeadSta[%u] ResourceUsedCount[%u]\n", i, prQM->au4HeadStaRecIndex[i],
5767 prQM->au4ResourceUsedCount[i]));
5768 }
5769 #endif
5770
5771 DBGLOG(SW4, INFO, ("BMC or unknown TxQueue Len[%u]\n", prQM->arTxQueue[0].u4NumElem));
5772 DBGLOG(SW4, INFO,
5773 ("Pending QLen Normal[%u] Sec[%u]\n", prGlueInfo->i4TxPendingFrameNum,
5774 prGlueInfo->i4TxPendingSecurityFrameNum));
5775
5776 #if defined(LINUX)
5777 for (i = 0; i < HW_BSSID_NUM; i++) {
5778 DBGLOG(SW4, INFO, ("Pending BSS[%u] QLen[%u:%u:%u:%u]\n",
5779 i,
5780 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][0],
5781 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][1],
5782 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][2],
5783 prGlueInfo->ai4TxPendingFrameNumPerQueue[i][3]));
5784 }
5785 #endif
5786 DBGLOG(SW4, INFO, ("Pending FWD CNT[%d]\n", prTxCtrl->i4PendingFwdFrameCount));
5787 DBGLOG(SW4, INFO, ("Pending MGMT CNT[%d]\n", prTxCtrl->i4TxMgmtPendingNum));
5788
5789 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5790
5791 DBGLOG(SW4, INFO, ("Total RFB[%u]\n", CFG_RX_MAX_PKT_NUM));
5792 DBGLOG(SW4, INFO, ("rFreeSwRfbList[%u]\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem));
5793 DBGLOG(SW4, INFO,
5794 ("rReceivedRfbList[%u]\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem));
5795 DBGLOG(SW4, INFO,
5796 ("rIndicatedRfbList[%u]\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem));
5797 DBGLOG(SW4, INFO, ("ucNumIndPacket[%u]\n", prAdapter->rRxCtrl.ucNumIndPacket));
5798 DBGLOG(SW4, INFO, ("ucNumRetainedPacket[%u]\n", prAdapter->rRxCtrl.ucNumRetainedPacket));
5799
5800 DBGLOG(SW4, INFO, ("---------------------------------\n"));
5801 DBGLOG(SW4, INFO, ("CMD: FreeCmd[%u/%u] PendingCmd[%u] Cmd2Tx[%u]\n",
5802 prAdapter->rFreeCmdList.u4NumElem,
5803 CFG_TX_MAX_CMD_PKT_NUM,
5804 prAdapter->rPendingCmdQueue.u4NumElem, prGlueInfo->rCmdQueue.u4NumElem));
5805 DBGLOG(SW4, INFO, ("MGMT: FreeMgmt[%u/%u] PendingMgmt[%u]\n",
5806 prAdapter->rTxCtrl.rFreeMsduInfoList.u4NumElem,
5807 CFG_TX_MAX_PKT_NUM, prAdapter->rTxCtrl.rTxMgmtTxingQueue.u4NumElem));
5808
5809
5810 DBGLOG(SW4, INFO, ("---------------------------------\n\n"));
5811 }
5812
5813
5814
5815
5816
5817 #if CFG_M0VE_BA_TO_DRIVER
5818 /*----------------------------------------------------------------------------*/
5819 /*!
5820 * @brief Send DELBA Action frame
5821 *
5822 * @param fgIsInitiator DELBA_ROLE_INITIATOR or DELBA_ROLE_RECIPIENT
5823 * @param prStaRec Pointer to the STA_REC of the receiving peer
5824 * @param u4Tid TID of the BA entry
5825 * @param u4ReasonCode The reason code carried in the Action frame
5826 *
5827 * @return (none)
5828 */
5829 /*----------------------------------------------------------------------------*/
5830 VOID
5831 mqmSendDelBaFrame(IN P_ADAPTER_T prAdapter,
5832 IN BOOLEAN fgIsInitiator,
5833 IN P_STA_RECORD_T prStaRec, IN UINT_32 u4Tid, IN UINT_32 u4ReasonCode)
5834 {
5835
5836 P_MSDU_INFO_T prTxMsduInfo;
5837 P_ACTION_DELBA_FRAME_T prDelBaFrame;
5838 P_BSS_INFO_T prBssInfo;
5839
5840 DBGLOG(QM, WARN, ("[Puff]: Enter mqmSendDelBaFrame()\n"));
5841
5842 ASSERT(prStaRec);
5843
5844 /* 3 <1> Block the message in case of invalid STA */
5845 if (!prStaRec->fgIsInUse) {
5846 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
5847 return;
5848 }
5849 /* Check HT-capabale STA */
5850 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
5851 DBGLOG(QM, WARN,
5852 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
5853 prStaRec->ucDesiredPhyTypeSet));
5854 return;
5855 }
5856 /* 4 <2> Construct the DELBA frame */
5857 prTxMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, ACTION_DELBA_FRAME_LEN);
5858
5859 if (!prTxMsduInfo) {
5860 DBGLOG(QM, WARN,
5861 ("[Puff][%s]: (Warning) DELBA for TID=%ld was not sent (MSDU_INFO alloc failure)\n",
5862 __func__, u4Tid));
5863 return;
5864 }
5865
5866 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
5867
5868 /* Fill the Action frame */
5869 prDelBaFrame =
5870 (P_ACTION_DELBA_FRAME_T) ((UINT_32) (prTxMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
5871 prDelBaFrame->u2FrameCtrl = MAC_FRAME_ACTION;
5872 #if CFG_SUPPORT_802_11W
5873 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
5874 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) DELBA is 80211w enabled\n", __func__));
5875 prDelBaFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
5876 }
5877 #endif
5878
5879 prDelBaFrame->u2DurationID = 0;
5880 prDelBaFrame->ucCategory = CATEGORY_BLOCK_ACK_ACTION;
5881 prDelBaFrame->ucAction = ACTION_DELBA;
5882
5883 prDelBaFrame->u2DelBaParameterSet = 0;
5884 prDelBaFrame->u2DelBaParameterSet |= ((fgIsInitiator ? ACTION_DELBA_INITIATOR_MASK : 0));
5885 prDelBaFrame->u2DelBaParameterSet |=
5886 ((u4Tid << ACTION_DELBA_TID_OFFSET) & ACTION_DELBA_TID_MASK);
5887 prDelBaFrame->u2ReasonCode = u4ReasonCode;
5888
5889 COPY_MAC_ADDR(prDelBaFrame->aucDestAddr, prStaRec->aucMacAddr);
5890 COPY_MAC_ADDR(prDelBaFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr);
5891 COPY_MAC_ADDR(prDelBaFrame->aucBSSID, prBssInfo->aucBSSID);
5892
5893 /* 4 <3> Configure the MSDU_INFO and forward it to TXM */
5894 TX_SET_MMPDU(prAdapter,
5895 prTxMsduInfo,
5896 prStaRec->ucBssIndex,
5897 (prStaRec != NULL) ? (prStaRec->ucIndex) : (STA_REC_INDEX_NOT_FOUND),
5898 WLAN_MAC_HEADER_LEN, ACTION_DELBA_FRAME_LEN, NULL, MSDU_RATE_MODE_AUTO);
5899
5900 #if CFG_SUPPORT_802_11W
5901 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
5902 DBGLOG(RSN, INFO, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
5903 nicTxConfigPktOption(prTxMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
5904 }
5905 #endif
5906
5907 /* TID and fgIsInitiator are needed when processing TX Done of the DELBA frame */
5908 prTxMsduInfo->ucTID = (UINT_8) u4Tid;
5909 prTxMsduInfo->ucControlFlag = (fgIsInitiator ? 1 : 0);
5910
5911 nicTxEnqueueMsdu(prAdapter, prTxMsduInfo);
5912
5913 DBGLOG(QM, WARN,
5914 ("[Puff][%s]: Send DELBA for TID=%ld Initiator=%d\n", __func__, u4Tid,
5915 fgIsInitiator));
5916 }
5917
5918
5919 /*----------------------------------------------------------------------------*/
5920 /*!
5921 * @brief Callback function for the TX Done event for an ADDBA_RSP
5922 *
5923 * @param prMsduInfo The TX packet
5924 * @param rWlanStatus WLAN_STATUS_SUCCESS if TX is successful
5925 *
5926 * @return WLAN_STATUS_BUFFER_RETAINED is returned if the buffer shall not be freed by TXM
5927 */
5928 /*----------------------------------------------------------------------------*/
5929 WLAN_STATUS
5930 mqmCallbackAddBaRspSent(IN P_ADAPTER_T prAdapter,
5931 IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus)
5932 {
5933 P_RX_BA_ENTRY_T prRxBaEntry;
5934 P_STA_RECORD_T prStaRec;
5935 P_QUE_MGT_T prQM;
5936
5937 UINT_32 u4Tid = 0;
5938
5939 /* ASSERT(prMsduInfo); */
5940 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
5941 ASSERT(prStaRec);
5942
5943 prQM = &prAdapter->rQM;
5944
5945 DBGLOG(QM, WARN, ("[Puff]: Enter mqmCallbackAddBaRspSent()\n"));
5946
5947 /* 4 <0> Check STA_REC status */
5948 /* Check STA_REC is inuse */
5949 if (!prStaRec->fgIsInUse) {
5950 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
5951 return WLAN_STATUS_SUCCESS;
5952 }
5953 /* Check HT-capabale STA */
5954 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
5955 DBGLOG(QM, WARN,
5956 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
5957 prStaRec->ucDesiredPhyTypeSet));
5958 return WLAN_STATUS_SUCCESS; /* To free the received ADDBA_REQ directly */
5959 }
5960 /* 4 <1> Find the corresponding BA entry */
5961 u4Tid = prMsduInfo->ucTID; /* TID is stored in MSDU_INFO when composing the ADDBA_RSP frame */
5962 prRxBaEntry = &prQM->arRxBaTable[u4Tid];
5963
5964 /* Note: Due to some reason, for example, receiving a DELBA, the BA entry may not be in state NEGO */
5965 /* 4 <2> INVALID state */
5966 if (!prRxBaEntry) {
5967 DBGLOG(QM, WARN,
5968 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)(invalid BA)\n",
5969 __func__, prStaRec->ucIndex, u4Tid));
5970 }
5971 /* 4 <3> NEGO, ACTIVE, or DELETING state */
5972 else {
5973 switch (rTxDoneStatus) {
5974 /* 4 <Case 1> TX Success */
5975 case TX_RESULT_SUCCESS:
5976
5977 DBGLOG(QM, WARN,
5978 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%d)(TX successful)\n",
5979 __func__, prStaRec->ucIndex, u4Tid));
5980
5981
5982 /* 4 <Case 1.1> NEGO or ACTIVE state */
5983 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_DELETING) {
5984 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
5985 BA_ENTRY_STATUS_ACTIVE);
5986 }
5987 /* 4 <Case 1.2> DELETING state */
5988 /* else */
5989 /* Deleting is on-going, so do nothing and wait for TX done of the DELBA frame */
5990
5991 break;
5992
5993 /* 4 <Case 2> TX Failure */
5994 default:
5995
5996 DBGLOG(QM, WARN,
5997 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld Entry_Status=%d)(TX failed)\n",
5998 __func__, prStaRec->ucIndex, u4Tid, prRxBaEntry->ucStatus));
5999
6000 /* 4 <Case 2.1> NEGO or ACTIVE state */
6001 /* Notify the host to delete the agreement */
6002 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_DELETING) {
6003 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
6004 BA_ENTRY_STATUS_DELETING);
6005
6006 /* Send DELBA to the peer to ensure the BA state is synchronized */
6007 mqmSendDelBaFrame(prAdapter, DELBA_ROLE_RECIPIENT, prStaRec, u4Tid,
6008 STATUS_CODE_UNSPECIFIED_FAILURE);
6009 }
6010 /* 4 <Case 2.2> DELETING state */
6011 /* else */
6012 /* Deleting is on-going, so do nothing and wait for the TX done of the DELBA frame */
6013
6014 break;
6015 }
6016
6017
6018 }
6019
6020
6021 return WLAN_STATUS_SUCCESS; /* TXM shall release the packet */
6022
6023 }
6024
6025
6026 /*----------------------------------------------------------------------------*/
6027 /*!
6028 * @brief Check if there is any idle RX BA
6029 *
6030 * @param u4Param (not used)
6031 *
6032 * @return (none)
6033 */
6034 /*----------------------------------------------------------------------------*/
6035 VOID mqmTimeoutCheckIdleRxBa(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
6036 {
6037 INT_8 i;
6038 P_RX_BA_ENTRY_T prRxBa;
6039 UINT_32 u4IdleCountThreshold = 0;
6040 P_STA_RECORD_T prStaRec;
6041 P_QUE_MGT_T prQM;
6042
6043 DBGLOG(QM, WARN, ("[Puff]: Enter mqmTimeoutIdleRxBaDetection()\n"));
6044
6045 prQM = &prAdapter->rQM;
6046
6047 /* 4 <1> Restart the timer */
6048 cnmTimerStopTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer);
6049 cnmTimerStartTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer,
6050 MQM_IDLE_RX_BA_CHECK_INTERVAL);
6051
6052 /* 4 <2> Increment the idle count for each idle BA */
6053 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
6054
6055 prRxBa = &prQM->arRxBaTable[i];
6056
6057 if (prRxBa->ucStatus == BA_ENTRY_STATUS_ACTIVE) {
6058
6059 prStaRec = cnmGetStaRecByIndex(prAdapter, prRxBa->ucStaRecIdx);
6060
6061 if (!prStaRec->fgIsInUse) {
6062 DBGLOG(QM, WARN,
6063 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
6064 ASSERT(0);
6065 }
6066 /* Check HT-capabale STA */
6067 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
6068 DBGLOG(QM, WARN,
6069 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n",
6070 __func__, prStaRec->ucDesiredPhyTypeSet));
6071 ASSERT(0);
6072 }
6073 /* 4 <2.1> Idle detected, increment idle count and see if a DELBA should be sent */
6074 if (prRxBa->u2SnapShotSN == prStaRec->au2CachedSeqCtrl[prRxBa->ucTid]) {
6075
6076 prRxBa->ucIdleCount++;
6077
6078 ASSERT(prRxBa->ucTid < 8);
6079 switch (aucTid2ACI[prRxBa->ucTid]) {
6080 case 0: /* BK */
6081 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_BK;
6082 break;
6083 case 1: /* BE */
6084 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_BE;
6085 break;
6086 case 2: /* VI */
6087 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_VI;
6088 break;
6089 case 3: /* VO */
6090 u4IdleCountThreshold = MQM_DEL_IDLE_RXBA_THRESHOLD_VO;
6091 break;
6092 }
6093
6094 if (prRxBa->ucIdleCount >= u4IdleCountThreshold) {
6095 mqmRxModifyBaEntryStatus(prAdapter, prRxBa,
6096 BA_ENTRY_STATUS_INVALID);
6097 mqmSendDelBaFrame(prAdapter, DELBA_ROLE_RECIPIENT, prStaRec,
6098 (UINT_32) prRxBa->ucTid,
6099 REASON_CODE_PEER_TIME_OUT);
6100 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prRxBa->ucTid,
6101 TRUE);
6102 }
6103 }
6104 /* 4 <2.2> Activity detected */
6105 else {
6106 prRxBa->u2SnapShotSN = prStaRec->au2CachedSeqCtrl[prRxBa->ucTid];
6107 prRxBa->ucIdleCount = 0;
6108 continue; /* check the next BA entry */
6109 }
6110 }
6111 }
6112
6113 }
6114
6115
6116 /*----------------------------------------------------------------------------*/
6117 /*!
6118 * @brief Do RX BA entry state transition
6119 *
6120 * @param prRxBaEntry The BA entry pointer
6121 * @param eStatus The state to transition to
6122 *
6123 * @return (none)
6124 */
6125 /*----------------------------------------------------------------------------*/
6126 VOID
6127 mqmRxModifyBaEntryStatus(IN P_ADAPTER_T prAdapter,
6128 IN P_RX_BA_ENTRY_T prRxBaEntry, IN ENUM_BA_ENTRY_STATUS_T eStatus)
6129 {
6130 P_STA_RECORD_T prStaRec;
6131 P_QUE_MGT_T prQM;
6132
6133 BOOLEAN fgResetScoreBoard = FALSE;
6134
6135 ASSERT(prRxBaEntry);
6136
6137 prStaRec = cnmGetStaRecByIndex(prAdapter, prRxBaEntry->ucStaRecIdx);
6138 ASSERT(prStaRec);
6139 prQM = &prAdapter->rQM;
6140
6141 if (prRxBaEntry->ucStatus == (UINT_8) eStatus) {
6142 DBGLOG(QM, WARN,
6143 ("[Puff][%s]: eStatus are identical...\n", __func__, prRxBaEntry->ucStatus));
6144 return;
6145 }
6146 /* 4 <1> State transition from state X */
6147 switch (prRxBaEntry->ucStatus) {
6148
6149 /* 4 <1.1> From (X = INVALID) to (ACTIVE or NEGO or DELETING) */
6150 case BA_ENTRY_STATUS_INVALID:
6151
6152 /* Associate the BA entry with the STA_REC when leaving INVALID state */
6153 kalMemCopy(&prQM->arRxBaTable[prRxBaEntry->ucTid], prRxBaEntry,
6154 sizeof(RX_BA_ENTRY_T));
6155
6156 /* Increment the RX BA counter */
6157 prQM->ucRxBaCount++;
6158 ASSERT(prQM->ucRxBaCount <= CFG_NUM_OF_RX_BA_AGREEMENTS);
6159
6160 /* Since AMPDU may be received during INVALID state */
6161 fgResetScoreBoard = TRUE;
6162
6163 /* Reset Idle Count since this BA entry is being activated now.
6164 * Note: If there is no ACTIVE entry, the idle detection timer will not be started.
6165 */
6166 prRxBaEntry->ucIdleCount = 0;
6167 break;
6168
6169 /* 4 <1.2> Other cases */
6170 default:
6171 break;
6172 }
6173
6174 /* 4 <2> State trasition to state Y */
6175 switch (eStatus) {
6176
6177 /* 4 <2.1> From (NEGO, ACTIVE, DELETING) to (Y=INVALID) */
6178 case BA_ENTRY_STATUS_INVALID:
6179
6180 /* Disassociate the BA entry with the STA_REC */
6181 kalMemZero(&prQM->arRxBaTable[prRxBaEntry->ucTid], sizeof(RX_BA_ENTRY_T));
6182
6183 /* Decrement the RX BA counter */
6184 prQM->ucRxBaCount--;
6185 ASSERT(prQM->ucRxBaCount < CFG_NUM_OF_RX_BA_AGREEMENTS);
6186
6187 /* (TBC) */
6188 fgResetScoreBoard = TRUE;
6189
6190 /* If there is not any BA agreement, stop doing idle detection */
6191 if (prQM->ucRxBaCount == 0) {
6192 if (MQM_CHECK_FLAG
6193 (prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED)) {
6194 cnmTimerStopTimer(prAdapter,
6195 &prAdapter->rMqmIdleRxBaDetectionTimer);
6196 MQM_CLEAR_FLAG(prAdapter->u4FlagBitmap,
6197 MQM_FLAG_IDLE_RX_BA_TIMER_STARTED);
6198 }
6199 }
6200
6201 break;
6202
6203 /* 4 <2.2> From (any) to (Y=ACTIVE) */
6204 case BA_ENTRY_STATUS_ACTIVE:
6205
6206 /* If there is at least one BA going into ACTIVE, start idle detection */
6207 if (!MQM_CHECK_FLAG(prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED)) {
6208 cnmTimerInitTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer, (PFN_MGMT_TIMEOUT_FUNC) mqmTimeoutCheckIdleRxBa, (ULONG) NULL); /* No parameter */
6209
6210 cnmTimerStopTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer);
6211
6212 #if MQM_IDLE_RX_BA_DETECTION
6213 cnmTimerStartTimer(prAdapter, &prAdapter->rMqmIdleRxBaDetectionTimer,
6214 MQM_IDLE_RX_BA_CHECK_INTERVAL);
6215 MQM_SET_FLAG(prAdapter->u4FlagBitmap, MQM_FLAG_IDLE_RX_BA_TIMER_STARTED);
6216 #endif
6217 }
6218
6219 break;
6220
6221 case BA_ENTRY_STATUS_NEGO:
6222 default:
6223 break;
6224 }
6225
6226 if (fgResetScoreBoard) {
6227 P_CMD_RESET_BA_SCOREBOARD_T prCmdBody;
6228
6229 prCmdBody = (P_CMD_RESET_BA_SCOREBOARD_T)
6230 cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_RESET_BA_SCOREBOARD_T));
6231 ASSERT(prCmdBody);
6232
6233 prCmdBody->ucflag = MAC_ADDR_TID_MATCH;
6234 prCmdBody->ucTID = prRxBaEntry->ucTid;
6235 kalMemCopy(prCmdBody->aucMacAddr, prStaRec->aucMacAddr, PARAM_MAC_ADDR_LEN);
6236
6237 wlanoidResetBAScoreboard(prAdapter, prCmdBody, sizeof(CMD_RESET_BA_SCOREBOARD_T));
6238
6239 }
6240
6241 DBGLOG(QM, WARN, ("[Puff]QM: (RX_BA) [STA=%d TID=%d] status from %d to %d\n",
6242 prRxBaEntry->ucStaRecIdx, prRxBaEntry->ucTid,
6243 prRxBaEntry->ucStatus, eStatus));
6244
6245 prRxBaEntry->ucStatus = (UINT_8) eStatus;
6246
6247 }
6248
6249
6250 /*----------------------------------------------------------------------------*/
6251 /*!
6252 * \brief
6253 *
6254 * \param[in]
6255 *
6256 * \return none
6257 */
6258 /*----------------------------------------------------------------------------*/
6259 VOID mqmHandleAddBaReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
6260 {
6261 P_STA_RECORD_T prStaRec;
6262 P_BSS_INFO_T prBssInfo;
6263 P_ACTION_ADDBA_REQ_FRAME_T prAddBaReq;
6264 ACTION_ADDBA_REQ_BODY_T rAddBaReqBody;
6265 P_ACTION_ADDBA_RSP_FRAME_T prAddBaRsp;
6266 ACTION_ADDBA_RSP_BODY_T rAddBaRspBody;
6267 P_RX_BA_ENTRY_T prRxBaEntry;
6268 P_MSDU_INFO_T prTxMsduInfo;
6269 P_QUE_MGT_T prQM;
6270
6271 BOOLEAN fgIsReqAccepted = TRUE; /* Reject or accept the ADDBA_REQ */
6272 BOOLEAN fgIsNewEntryAdded = FALSE; /* Indicator: Whether a new RX BA entry will be added */
6273
6274 UINT_32 u4Tid;
6275 UINT_32 u4StaRecIdx;
6276 UINT_16 u2WinStart;
6277 UINT_16 u2WinSize;
6278 UINT_32 u4BuffSize;
6279
6280 #if CFG_SUPPORT_BCM
6281 UINT_32 u4BuffSizeBT;
6282 #endif
6283
6284 ASSERT(prSwRfb);
6285
6286 prStaRec = prSwRfb->prStaRec;
6287 prQM = &prAdapter->rQM;
6288
6289 do {
6290
6291
6292 /* 4 <0> Check if this is an active HT-capable STA */
6293 /* Check STA_REC is inuse */
6294 if (!prStaRec->fgIsInUse) {
6295 DBGLOG(QM, WARN,
6296 ("[Puff][%s]: (Warning) sta_rec is not inuse\n", __func__));
6297 break;
6298 }
6299 /* Check HT-capabale STA */
6300 if (!(prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT)) {
6301 DBGLOG(QM, WARN,
6302 ("[Puff][%s]: (Warning) sta is NOT HT-capable(0x%08X)\n", __func__,
6303 prStaRec->ucDesiredPhyTypeSet));
6304 break; /* To free the received ADDBA_REQ directly */
6305 }
6306 /* 4 <1> Check user configurations and HW capabilities */
6307 /* Check configurations (QoS support, AMPDU RX support) */
6308 if ((!prAdapter->rWifiVar.fgSupportQoS) ||
6309 (!prAdapter->rWifiVar.fgSupportAmpduRx) || (!prStaRec->fgRxAmpduEn)) {
6310 DBGLOG(QM, WARN,
6311 ("[Puff][%s]: (Warning) BA ACK Policy not supported fgSupportQoS(%d), fgSupportAmpduRx(%d), fgRxAmpduEn(%d)\n",
6312 __func__, prAdapter->rWifiVar.fgSupportQoS,
6313 prAdapter->rWifiVar.fgSupportAmpduRx, prStaRec->fgRxAmpduEn));
6314 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6315 }
6316 /* Check capability */
6317 prAddBaReq = ((P_ACTION_ADDBA_REQ_FRAME_T) (prSwRfb->pvHeader));
6318 kalMemCopy((PUINT_8) (&rAddBaReqBody),
6319 (PUINT_8) (&(prAddBaReq->aucBAParameterSet[0])), 6);
6320 if ((((rAddBaReqBody.
6321 u2BAParameterSet) & BA_PARAM_SET_ACK_POLICY_MASK) >>
6322 BA_PARAM_SET_ACK_POLICY_MASK_OFFSET)
6323 != BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA) { /* Only Immediate_BA is supported */
6324 DBGLOG(QM, WARN,
6325 ("[Puff][%s]: (Warning) BA ACK Policy not supported (0x%08X)\n",
6326 __func__, rAddBaReqBody.u2BAParameterSet));
6327 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6328 }
6329
6330 /* 4 <2> Determine the RX BA entry (existing or to be added) */
6331 /* Note: BA entry index = (TID, STA_REC index) */
6332 u4Tid =
6333 (((rAddBaReqBody.
6334 u2BAParameterSet) & BA_PARAM_SET_TID_MASK) >> BA_PARAM_SET_TID_MASK_OFFSET);
6335 u4StaRecIdx = prStaRec->ucIndex;
6336 DBGLOG(QM, WARN,
6337 ("[Puff][%s]: BA entry index = [TID(%d), STA_REC index(%d)]\n", __func__,
6338 u4Tid, u4StaRecIdx));
6339
6340 u2WinStart = ((rAddBaReqBody.u2BAStartSeqCtrl) >> OFFSET_BAR_SSC_SN);
6341 u2WinSize = (((rAddBaReqBody.u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
6342 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
6343 DBGLOG(QM, WARN,
6344 ("[Puff][%s]: BA entry info = [WinStart(%d), WinSize(%d)]\n", __func__,
6345 u2WinStart, u2WinSize));
6346
6347
6348 if (fgIsReqAccepted) {
6349
6350 prRxBaEntry = &prQM->arRxBaTable[u4Tid];
6351
6352 if (!prRxBaEntry) {
6353
6354 /* 4 <Case 2.1> INVALID state && BA entry available --> Add a new entry and accept */
6355 if (prQM->ucRxBaCount < CFG_NUM_OF_RX_BA_AGREEMENTS) {
6356
6357 fgIsNewEntryAdded = qmAddRxBaEntry(prAdapter,
6358 (UINT_8) u4StaRecIdx,
6359 (UINT_8) u4Tid,
6360 u2WinStart, u2WinSize);
6361
6362 if (!fgIsNewEntryAdded) {
6363 DBGLOG(QM, ERROR,
6364 ("[Puff][%s]: (Error) Free RX BA entry alloc failure\n"));
6365 fgIsReqAccepted = FALSE;
6366 } else {
6367 DBGLOG(QM, WARN,
6368 ("[Puff][%s]: Create a new BA Entry\n"));
6369 }
6370 }
6371 /* 4 <Case 2.2> INVALID state && BA entry unavailable --> Reject the ADDBA_REQ */
6372 else {
6373 DBGLOG(QM, WARN,
6374 ("[Puff][%s]: (Warning) Free RX BA entry unavailable(req: %d)\n",
6375 __func__, prQM->ucRxBaCount));
6376 fgIsReqAccepted = FALSE; /* Will send an ADDBA_RSP with DECLINED */
6377 }
6378 } else {
6379
6380 /* 4 <Case 2.3> NEGO or DELETING state --> Ignore the ADDBA_REQ */
6381 /* For NEGO: do nothing. Wait for TX Done of ADDBA_RSP */
6382 /* For DELETING: do nothing. Wait for TX Done of DELBA */
6383 if (prRxBaEntry->ucStatus != BA_ENTRY_STATUS_ACTIVE) {
6384 DBGLOG(QM, WARN,
6385 ("[Puff][%s]: (Warning) ADDBA_REQ for TID=%ld is received during status:%d (Ignore)\n",
6386 __func__, u4Tid, prRxBaEntry->ucStatus));
6387 break; /* Ignore the ADDBA_REQ since the current state is NEGO */
6388 }
6389 /* 4 <Case 2.4> ACTIVE state --> Accept */
6390 /* Send an ADDBA_RSP to accept the request again */
6391 /* else */
6392 }
6393 }
6394 /* 4 <3> Construct the ADDBA_RSP frame */
6395 prTxMsduInfo =
6396 (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, ACTION_ADDBA_RSP_FRAME_LEN);
6397 prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
6398
6399 if (!prTxMsduInfo) {
6400
6401 /* The peer may send an ADDBA_REQ message later.
6402 * Do nothing to the BA entry. No DELBA will be sent (because cnmMgtPktAlloc() may fail again).
6403 * No BA deletion event will be sent to the host (because cnmMgtPktAlloc() may fail again).
6404 */
6405 DBGLOG(QM, WARN,
6406 ("[Puff][%s]: (Warning) ADDBA_RSP alloc failure\n", __func__));
6407
6408 if (fgIsNewEntryAdded) { /* If a new entry has been created due to this ADDBA_REQ, delete it */
6409 ASSERT(prRxBaEntry);
6410 mqmRxModifyBaEntryStatus(prAdapter, prRxBaEntry,
6411 BA_ENTRY_STATUS_INVALID);
6412 }
6413
6414 break; /* Exit directly to free the ADDBA_REQ */
6415 }
6416
6417 /* Fill the ADDBA_RSP message */
6418 prAddBaRsp =
6419 (P_ACTION_ADDBA_RSP_FRAME_T) ((UINT_32) (prTxMsduInfo->prPacket) +
6420 MAC_TX_RESERVED_FIELD);
6421 prAddBaRsp->u2FrameCtrl = MAC_FRAME_ACTION;
6422
6423 #if CFG_SUPPORT_802_11W
6424 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
6425 DBGLOG(QM, WARN,
6426 ("[Puff][%s]: (Warning) ADDBA_RSP is 80211w enabled\n", __func__));
6427 prAddBaReq->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
6428 }
6429 #endif
6430 prAddBaRsp->u2DurationID = 0;
6431 prAddBaRsp->ucCategory = CATEGORY_BLOCK_ACK_ACTION;
6432 prAddBaRsp->ucAction = ACTION_ADDBA_RSP;
6433 prAddBaRsp->ucDialogToken = prAddBaReq->ucDialogToken;
6434
6435 DBGLOG(QM, WARN,
6436 ("[Puff][%s]: (Warning) ADDBA_RSP DurationID(%d) Category(%d) Action(%d) DialogToken(%d)\n",
6437 __func__, prAddBaRsp->u2DurationID, prAddBaRsp->ucCategory,
6438 prAddBaRsp->ucAction, prAddBaRsp->ucDialogToken));
6439
6440 if (fgIsReqAccepted) {
6441 rAddBaRspBody.u2StatusCode = STATUS_CODE_SUCCESSFUL;
6442 } else {
6443 rAddBaRspBody.u2StatusCode = STATUS_CODE_REQ_DECLINED;
6444 }
6445
6446 /* WinSize = min(WinSize in ADDBA_REQ, CFG_RX_BA_MAX_WINSIZE) */
6447 u4BuffSize = (((rAddBaReqBody.u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
6448 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
6449
6450 /*If ADDBA req WinSize<=0 => use default WinSize(16) */
6451 if ((u4BuffSize > CFG_RX_BA_MAX_WINSIZE) || (u4BuffSize <= 0)) {
6452 u4BuffSize = CFG_RX_BA_MAX_WINSIZE;
6453 }
6454 #if CFG_SUPPORT_BCM
6455 /* TODO: Call BT coexistence function to limit the winsize */
6456 u4BuffSizeBT = bcmRequestBaWinSize();
6457 DBGLOG(QM, WARN, ("[Puff][%s]: (Warning) bcmRequestBaWinSize(%d)\n",
6458 __func__, u4BuffSizeBT));
6459
6460 if (u4BuffSize > u4BuffSizeBT) {
6461 u4BuffSize = u4BuffSizeBT;
6462 }
6463 #endif /* CFG_SUPPORT_BCM */
6464
6465 rAddBaRspBody.u2BAParameterSet = (BA_POLICY_IMMEDIATE |
6466 (u4Tid << BA_PARAM_SET_TID_MASK_OFFSET) |
6467 (u4BuffSize <<
6468 BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET));
6469
6470 /* TODO: Determine the BA timeout value according to the default preference */
6471 rAddBaRspBody.u2BATimeoutValue = rAddBaReqBody.u2BATimeoutValue;
6472
6473 DBGLOG(QM, WARN,
6474 ("[Puff][%s]: (Warning) ADDBA_RSP u4BuffSize(%d) StatusCode(%d) BAParameterSet(0x%08X) BATimeoutValue(%d)\n",
6475 __func__, u4BuffSize, rAddBaRspBody.u2StatusCode,
6476 rAddBaRspBody.u2BAParameterSet, rAddBaRspBody.u2BATimeoutValue));
6477
6478 kalMemCopy((PUINT_8) (&(prAddBaRsp->aucStatusCode[0])), (PUINT_8) (&rAddBaRspBody),
6479 6);
6480
6481 COPY_MAC_ADDR(prAddBaRsp->aucDestAddr, prStaRec->aucMacAddr);
6482 COPY_MAC_ADDR(prAddBaRsp->aucSrcAddr, prBssInfo->aucOwnMacAddr);
6483 /* COPY_MAC_ADDR(prAddBaRsp->aucBSSID,g_aprBssInfo[prStaRec->ucNetTypeIndex]->aucBSSID); */
6484 COPY_MAC_ADDR(prAddBaRsp->aucBSSID, prAddBaReq->aucBSSID);
6485
6486
6487 /* 4 <4> Forward the ADDBA_RSP to TXM */
6488 TX_SET_MMPDU(prAdapter,
6489 prTxMsduInfo,
6490 prStaRec->ucBssIndex,
6491 (prStaRec != NULL) ? (prStaRec->ucIndex) : (STA_REC_INDEX_NOT_FOUND),
6492 WLAN_MAC_HEADER_LEN,
6493 ACTION_ADDBA_RSP_FRAME_LEN,
6494 mqmCallbackAddBaRspSent, MSDU_RATE_MODE_AUTO);
6495
6496 #if CFG_SUPPORT_802_11W
6497 if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
6498 DBGLOG(RSN, INFO, ("Set MSDU_OPT_PROTECTED_FRAME\n"));
6499 nicTxConfigPktOption(prTxMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
6500 }
6501 #endif
6502
6503 /* Note: prTxMsduInfo->ucTID is not used for transmitting the ADDBA_RSP.
6504 * However, when processing TX Done of this ADDBA_RSP, the TID value is needed, so
6505 * store the TID value in advance to prevent parsing the ADDBA_RSP frame
6506 */
6507 prTxMsduInfo->ucTID = (UINT_8) u4Tid;
6508
6509 nicTxEnqueueMsdu(prAdapter, prTxMsduInfo);
6510
6511 DBGLOG(QM, WARN,
6512 ("[Puff][%s]: (RX_BA) ADDBA_RSP ---> peer (STA=%d TID=%ld)\n", __func__,
6513 prStaRec->ucIndex, u4Tid));
6514
6515
6516 #if 0
6517 /* 4 <5> Notify the host to start buffer reordering */
6518 if (fgIsNewEntryAdded) { /* Only when a new BA entry is indeed added will the host be notified */
6519 ASSERT(fgIsReqAccepted);
6520
6521 prSwRfbEventToHost = (P_SW_RFB_T) cnmMgtPktAlloc(EVENT_RX_ADDBA_PACKET_LEN);
6522
6523 if (!prSwRfbEventToHost) {
6524
6525 /* Note: DELBA will not be sent since cnmMgtPktAlloc() may fail again. However, it does not
6526 * matter because upon receipt of AMPDUs without a RX BA agreement, MQM will send DELBA frames
6527 */
6528
6529 DBGLOG(MQM, WARN, ("MQM: (Warning) EVENT packet alloc failed\n"));
6530
6531 /* Ensure that host and FW are synchronized */
6532 mqmRxModifyBaEntryStatus(prRxBaEntry, BA_ENTRY_STATUS_INVALID);
6533
6534 break; /* Free the received ADDBA_REQ */
6535 } else {
6536
6537 prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prSwRfbEventToHost->pucBuffer;
6538 prEventRxAddBa->ucStaRecIdx = (UINT_8) u4StaRecIdx;
6539 prEventRxAddBa->u2Length = EVENT_RX_ADDBA_PACKET_LEN;
6540 prEventRxAddBa->ucEID = EVENT_ID_RX_ADDBA;
6541 prEventRxAddBa->ucSeqNum = 0; /* Unsolicited event packet */
6542 prEventRxAddBa->u2BAParameterSet = rAddBaRspBody.u2BAParameterSet;
6543 prEventRxAddBa->u2BAStartSeqCtrl = rAddBaReqBody.u2BAStartSeqCtrl;
6544 prEventRxAddBa->u2BATimeoutValue = rAddBaReqBody.u2BATimeoutValue;
6545 prEventRxAddBa->ucDialogToken = prAddBaReq->ucDialogToken;
6546
6547 DBGLOG(MQM, INFO,
6548 ("MQM: (RX_BA) Event ADDBA ---> driver (STA=%ld TID=%ld WinStart=%d)\n",
6549 u4StaRecIdx, u4Tid,
6550 (prEventRxAddBa->u2BAStartSeqCtrl >> 4)));
6551
6552 /* Configure the SW_RFB for the Event packet */
6553 RXM_SET_EVENT_PACKET(
6554 /* P_SW_RFB_T */ (P_SW_RFB_T)
6555 prSwRfbEventToHost,
6556 /* HIF RX Packet pointer */
6557 (PUINT_8) prEventRxAddBa,
6558 /* HIF RX port number */ HIF_RX0_INDEX
6559 );
6560
6561 rxmSendEventToHost(prSwRfbEventToHost);
6562 }
6563
6564 }
6565 #endif
6566
6567
6568 } while (FALSE);
6569
6570 }
6571
6572 /*----------------------------------------------------------------------------*/
6573 /*!
6574 * \brief
6575 *
6576 * \param[in]
6577 *
6578 * \return none
6579 */
6580 /*----------------------------------------------------------------------------*/
6581 VOID mqmHandleAddBaRsp(IN P_SW_RFB_T prSwRfb)
6582 {
6583
6584 }
6585
6586 /*----------------------------------------------------------------------------*/
6587 /*!
6588 * \brief
6589 *
6590 * \param[in]
6591 *
6592 * \return none
6593 */
6594 /*----------------------------------------------------------------------------*/
6595 VOID mqmHandleDelBa(IN P_SW_RFB_T prSwRfb)
6596 {
6597
6598 }
6599
6600 /*----------------------------------------------------------------------------*/
6601 /*!
6602 * \brief
6603 *
6604 * \param[in]
6605 *
6606 * \return none
6607 */
6608 /*----------------------------------------------------------------------------*/
6609 VOID mqmHandleBaActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
6610 {
6611 P_WLAN_ACTION_FRAME prRxFrame;
6612
6613 ASSERT(prAdapter);
6614 ASSERT(prSwRfb);
6615
6616 prRxFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader;
6617 DBGLOG(RLM, WARN, ("[Puff][%s] Action(%d)\n", __func__, prRxFrame->ucAction));
6618
6619 switch (prRxFrame->ucAction) {
6620
6621 case ACTION_ADDBA_REQ:
6622 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) ADDBA_REQ <--- peer\n", __func__));
6623 mqmHandleAddBaReq(prAdapter, prSwRfb);
6624 break;
6625
6626 case ACTION_ADDBA_RSP:
6627 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) ADDBA_RSP <--- peer\n", __func__));
6628 mqmHandleAddBaRsp(prSwRfb);
6629 break;
6630
6631 case ACTION_DELBA:
6632 DBGLOG(RLM, WARN, ("[Puff][%s] (RX_BA) DELBA <--- peer\n", __func__));
6633 mqmHandleDelBa(prSwRfb);
6634 break;
6635
6636 default:
6637 DBGLOG(RLM, WARN, ("[Puff][%s] Unknown BA Action Frame\n", __func__));
6638 break;
6639 }
6640
6641
6642
6643 }
6644
6645 #endif