import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / drv_wlan / mt6620 / wlan / nic / que_mgt.c
1 /*
2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 $
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 * 03 02 2012 terry.wu
19 * NULL
20 * Sync CFG80211 modification from branch 2,2.
21 *
22 * 02 23 2012 eddie.chen
23 * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule
24 * Change the enqueue policy when ACM = 1.
25 *
26 * 11 22 2011 yuche.tsai
27 * NULL
28 * Code refine, remove one #if 0 code.
29 *
30 * 11 19 2011 eddie.chen
31 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
32 * Add xlog for tx
33 *
34 * 11 18 2011 yuche.tsai
35 * NULL
36 * CONFIG P2P support RSSI query, default turned off.
37 *
38 * 11 18 2011 eddie.chen
39 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
40 * Fix xlog format to hex format
41 *
42 * 11 17 2011 tsaiyuan.hsu
43 * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3.
44 * avoid deactivating staRec when changing state from 3 to 3.
45 *
46 * 11 11 2011 tsaiyuan.hsu
47 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
48 * add debug msg for xlog.
49 *
50 * 11 11 2011 tsaiyuan.hsu
51 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
52 * add debug counters of bb and ar for xlog.
53 *
54 * 11 10 2011 eddie.chen
55 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
56 * Use short name for xlog.
57 *
58 * 11 10 2011 eddie.chen
59 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
60 * Modify the QM xlog level and remove LOG_FUNC.
61 *
62 * 11 10 2011 chinglan.wang
63 * NULL
64 * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP.
65 *
66 * 11 09 2011 chinglan.wang
67 * NULL
68 * [WiFi direct]Can't make P2P connect via PBC.
69 *
70 * 11 08 2011 eddie.chen
71 * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
72 * Add xlog function.
73 *
74 * 11 07 2011 tsaiyuan.hsu
75 * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered
76 * add debug counters and periodically dump counters for debugging.
77 *
78 * 11 01 2011 chinglan.wang
79 * NULL
80 * Modify the Wi-Fi method of the flush TX queue when disconnect the AP.
81 * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to the AP..
82 *
83 * 10 25 2011 wh.su
84 * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check un-expect
85 * let the Rx BA accept even the sta not valid.
86 *
87 * 09 28 2011 tsaiyuan.hsu
88 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
89 * enlarge window size only by 4.
90 *
91 * 09 01 2011 tsaiyuan.hsu
92 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
93 * set rx window size as twice buffer size.
94 *
95 * 08 23 2011 yuche.tsai
96 * NULL
97 * Fix multicast address list issue.
98 *
99 * 08 03 2011 tsaiyuan.hsu
100 * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX
101 * force window size at least 16.
102 *
103 * 08 02 2011 yuche.tsai
104 * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue.
105 * Fix GO send deauth frame issue.
106 *
107 * 07 26 2011 eddie.chen
108 * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter
109 * API for query the RX reorder queued packets counter.
110 *
111 * 07 07 2011 eddie.chen
112 * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS.
113 * Add setEvent when free quota is updated.
114 *
115 * 07 05 2011 eddie.chen
116 * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS.
117 * Send 1x when peer STA is in PS.
118 *
119 * 05 31 2011 eddie.chen
120 * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931
121 * Fix the QM quota in MT5931.
122 *
123 * 05 11 2011 eddie.chen
124 * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
125 * Fix dest type when GO packet copying.
126 *
127 * 05 09 2011 yuche.tsai
128 * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved)
129 * Deauthentication frame is not bound to network active status.
130 *
131 * 05 09 2011 eddie.chen
132 * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet
133 * Check free number before copying broadcast packet.
134 *
135 * 04 14 2011 eddie.chen
136 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
137 * Check the SW RFB free. Fix the compile warning..
138 *
139 * 04 12 2011 eddie.chen
140 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
141 * Fix the sta index in processing security frame
142 * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4
143 * Add debug message.
144 *
145 * 04 11 2011 yuche.tsai
146 * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue.
147 * Fix kernel panic issue when MMPDU of P2P is pending in driver.
148 *
149 * 04 08 2011 eddie.chen
150 * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
151 * Fix for sigma
152 *
153 * 03 28 2011 eddie.chen
154 * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning
155 * Fix Klockwork warning.
156 *
157 * 03 28 2011 eddie.chen
158 * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW
159 * Fix wmm parameters in beacon for BOW.
160 *
161 * 03 15 2011 eddie.chen
162 * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter
163 * Add sw debug counter for QM.
164 *
165 * 02 23 2011 eddie.chen
166 * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap
167 * Fix parsing WMM INFO and bmp delivery bitmap definition.
168 *
169 * 02 17 2011 eddie.chen
170 * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel
171 * 1) Chnage GetFrameAction decision when BSS is absent.
172 * 2) Check channel and resource in processing ProbeRequest
173 *
174 * 02 08 2011 eddie.chen
175 * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode
176 * Add event STA agint timeout
177 *
178 * 01 27 2011 tsaiyuan.hsu
179 * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support
180 * add roaming fsm
181 * 1. not support 11r, only use strength of signal to determine roaming.
182 * 2. not enable CFG_SUPPORT_ROAMING until completion of full test.
183 * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw
184 * 4. assume that change of link quality in smooth way.
185 *
186 * 01 25 2011 yuche.tsai
187 * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record.
188 * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role.
189 *
190 * 01 24 2011 eddie.chen
191 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
192 * Remove comments.
193 *
194 * 01 24 2011 eddie.chen
195 * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets
196 * Add destination decision in AP mode.
197 *
198 * 01 14 2011 wh.su
199 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!!
200 * Allow 802.1x can be send even the net is not active due the drver / fw sync issue.
201 *
202 * 01 13 2011 eddie.chen
203 * [WCXRP00000322] Add WMM IE in beacon,
204 Add per station flow control when STA is in PS
205 * Fix typo and compile error.
206 *
207 * 01 12 2011 eddie.chen
208 * [WCXRP00000322] Add WMM IE in beacon,
209 Add per station flow control when STA is in PS
210 * Fix WMM parameter condition for STA
211 *
212 * 01 12 2011 eddie.chen
213 * [WCXRP00000322] Add WMM IE in beacon,
214 Add per station flow control when STA is in PS
215 * 1) Check Bss if support QoS before adding WMMIE
216 * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control
217 *
218 * 01 12 2011 george.huang
219 * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability
220 * Update MQM for WMM IE generation method
221 *
222 * 01 11 2011 eddie.chen
223 * [WCXRP00000322] Add WMM IE in beacon,
224 Add per station flow control when STA is in PS
225
226 * Add per STA flow control when STA is in PS mode
227 *
228 * 01 03 2011 george.huang
229 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
230 * update prStaRec->fgIsUapsdSupported flag.
231 *
232 * 12 29 2010 eddie.chen
233 * [WCXRP00000322] Add WMM IE in beacon,
234 Add per station flow control when STA is in PS
235
236 * Add WMM parameter for broadcast.
237 *
238 * 12 29 2010 eddie.chen
239 * [WCXRP00000322] Add WMM IE in beacon,
240 Add per station flow control when STA is in PS
241
242 * 1) PS flow control event
243 *
244 * 2) WMM IE in beacon, assoc resp, probe resp
245 *
246 * 12 23 2010 george.huang
247 * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function
248 * 1. update WMM IE parsing, with ASSOC REQ handling
249 * 2. extend U-APSD parameter passing from driver to FW
250 *
251 * 10 14 2010 wh.su
252 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
253 * use the #14 and modify the add code for check MMPDU.
254 *
255 * 10 14 2010 wh.su
256 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
257 * only MMPDU not check the netActive flag.
258 *
259 * 10 14 2010 wh.su
260 * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out
261 * not check the netActive flag for mgmt .
262 *
263 * 10 04 2010 cp.wu
264 * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only
265 * remove ENUM_NETWORK_TYPE_T definitions
266 *
267 * 09 21 2010 kevin.huang
268 * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
269 * Eliminate Linux Compile Warning
270 *
271 * 08 30 2010 yarco.yang
272 * NULL
273 * Fixed klockwork error message
274 *
275 * 08 18 2010 yarco.yang
276 * NULL
277 * 1. Fixed HW checksum offload function not work under Linux issue.
278 * 2. Add debug message.
279 *
280 * 08 10 2010 yarco.yang
281 * NULL
282 * Code refine
283 *
284 * 08 06 2010 yarco.yang
285 * NULL
286 * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action
287 *
288 * 07 26 2010 cp.wu
289 *
290 * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet
291 * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found
292 *
293 * 07 20 2010 yarco.yang
294 *
295 * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake
296 *
297 * 07 16 2010 yarco.yang
298 *
299 * 1. Support BSS Absence/Presence Event
300 * 2. Support STA change PS mode Event
301 * 3. Support BMC forwarding for AP mode.
302 *
303 * 07 14 2010 yarco.yang
304 *
305 * 1. Remove CFG_MQM_MIGRATION
306 * 2. Add CMD_UPDATE_WMM_PARMS command
307 *
308 * 07 13 2010 yarco.yang
309 *
310 * [WPD00003849]
311 * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing
312 *
313 * 07 09 2010 yarco.yang
314 *
315 * [MT6620 and MT5931] SW Migration: Add ADDBA support
316 *
317 * 07 08 2010 cp.wu
318 *
319 * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
320 *
321 * 07 08 2010 yarco.yang
322 * [WPD00003837][MT6620]Data Path Refine
323 * .
324 *
325 * 07 06 2010 yarco.yang
326 * [WPD00003837][MT6620]Data Path Refine
327 * Use fgInUse instead of fgIsValid for De-queue judgement
328 *
329 * 07 06 2010 yarco.yang
330 * [WPD00003837][MT6620]Data Path Refine
331 * For MMPDU, STA_REC will be decided by caller module
332 *
333 * 07 06 2010 yarco.yang
334 * [WPD00003837][MT6620]Data Path Refine
335 * Add MGMT Packet type for HIF_TX_HEADER
336 *
337 * 06 29 2010 yarco.yang
338 * [WPD00003837][MT6620]Data Path Refine
339 * replace g_rQM with Adpater->rQM
340 *
341 * 06 25 2010 cp.wu
342 * [WPD00003833][MT6620 and MT5931] Driver migration
343 * add API in que_mgt to retrieve sta-rec index for security frames.
344 *
345 * 06 23 2010 yarco.yang
346 * [WPD00003837][MT6620]Data Path Refine
347 * Merge g_arStaRec[] into adapter->arStaRec[]
348 *
349 * 06 21 2010 yarco.yang
350 * [WPD00003837][MT6620]Data Path Refine
351 * Support CFG_MQM_MIGRATION flag
352 *
353 * 06 11 2010 cp.wu
354 * [WPD00003833][MT6620 and MT5931] Driver migration
355 * 1) migrate assoc.c.
356 * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness
357 * 3) add configuration options for CNM_MEM and RSN modules
358 * 4) add data path for management frames
359 * 5) eliminate rPacketInfo of MSDU_INFO_T
360 *
361 * 06 06 2010 kevin.huang
362 * [WPD00003832][MT6620 5931] Create driver base
363 * [MT6620 5931] Create driver base
364 *
365 * 03 31 2010 tehuang.liu
366 * [WPD00001943]Create WiFi test driver framework on WinXP
367 * Refined the debug msg
368 *
369 * 03 30 2010 cp.wu
370 * [WPD00001943]Create WiFi test driver framework on WinXP
371 * comment out one assertion which refer to undefined data member.
372 *
373 * 03 30 2010 tehuang.liu
374 * [WPD00001943]Create WiFi test driver framework on WinXP
375 * Enabled adaptive TC resource control
376 *
377 * 03 24 2010 jeffrey.chang
378 * [WPD00003826]Initial import for Linux port
379 * initial import for Linux port
380 *
381 * 03 17 2010 tehuang.liu
382 * [WPD00001943]Create WiFi test driver framework on WinXP
383 * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST)
384 *
385 * 03 11 2010 tehuang.liu
386 * [WPD00001943]Create WiFi test driver framework on WinXP
387 * Fixed buffer leak when processing BAR frames
388 *
389 * 03 02 2010 tehuang.liu
390 * [WPD00001943]Create WiFi test driver framework on WinXP
391 * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5
392 *
393 * 03 01 2010 tehuang.liu
394 * [WPD00001943]Create WiFi test driver framework on WinXP
395 * Fixed STA_REC index determination bug (fgIsValid shall be checked)
396 *
397 * 02 25 2010 tehuang.liu
398 * [WPD00001943]Create WiFi test driver framework on WinXP
399 * Refined function qmDetermineStaRecIndex() for BMCAST packets
400 *
401 * 02 25 2010 tehuang.liu
402 * [WPD00001943]Create WiFi test driver framework on WinXP
403 * Enabled multi-STA TX path with fairness
404 *
405 * 02 24 2010 tehuang.liu
406 * [WPD00001943]Create WiFi test driver framework on WinXP
407 * Enabled dynamically activating and deactivating STA_RECs
408 *
409 * 02 24 2010 tehuang.liu
410 * [WPD00001943]Create WiFi test driver framework on WinXP
411 * Added code for dynamic activating and deactivating STA_RECs.
412 *
413 * 01 13 2010 tehuang.liu
414 * [WPD00001943]Create WiFi test driver framework on WinXP
415 * Enabled the 802.1x path
416 *
417 * 01 13 2010 tehuang.liu
418 * [WPD00001943]Create WiFi test driver framework on WinXP
419 * Enabled the Burst_End Indication mechanism
420 ** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468
421 ** Fixed casting for qmAddRxBaEntry()
422 ** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752
423 ** remove SD1_SD3.. flag
424 ** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468
425 ** Added RX buffer reordering functions
426 ** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468
427 ** Modified Flush Queue function to let queues be reinitialized
428 ** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468
429 ** Added flushing per-Type queues code
430 ** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468
431 ** Added Debug msgs and fixed incorrect assert
432 ** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468
433 ** Bug fixing (qmDequeueTxPackets local variable initialization)
434 ** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752
435 ** correct and surpress PREfast warning
436 ** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468
437 ** Used SD1_SD3_DATAPATH_INTEGRATION
438 ** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468
439 ** Initial version
440 **
441 */
442
443 /*******************************************************************************
444 * C O M P I L E R F L A G S
445 ********************************************************************************
446 */
447
448 /*******************************************************************************
449 * E X T E R N A L R E F E R E N C E S
450 ********************************************************************************
451 */
452 #include "precomp.h"
453
454 /*******************************************************************************
455 * C O N S T A N T S
456 ********************************************************************************
457 */
458
459 /*******************************************************************************
460 * D A T A T Y P E S
461 ********************************************************************************
462 */
463
464 /*******************************************************************************
465 * P U B L I C D A T A
466 ********************************************************************************
467 */
468 OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM];
469
470 /*******************************************************************************
471 * P R I V A T E D A T A
472 ********************************************************************************
473 */
474
475
476 /*******************************************************************************
477 * M A C R O S
478 ********************************************************************************
479 */
480
481 /*******************************************************************************
482 * F U N C T I O N D E C L A R A T I O N S
483 ********************************************************************************
484 */
485 __KAL_INLINE__ VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo);
486
487 __KAL_INLINE__ VOID
488 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter,
489 OUT P_QUE_T prQue,
490 IN UINT_8 ucTC,
491 IN UINT_8 ucCurrentAvailableQuota, IN UINT_8 ucTotalQuota);
492
493 __KAL_INLINE__ VOID
494 qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter,
495 OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum);
496
497 /*******************************************************************************
498 * F U N C T I O N S
499 ********************************************************************************
500 */
501
502 /*----------------------------------------------------------------------------*/
503 /*!
504 * \brief Init Queue Managment for TX
505 *
506 * \param[in] (none)
507 *
508 * \return (none)
509 */
510 /*----------------------------------------------------------------------------*/
511 VOID qmInit(IN P_ADAPTER_T prAdapter)
512 {
513 UINT_32 u4QueArrayIdx;
514 UINT_32 i;
515
516 P_QUE_MGT_T prQM = &prAdapter->rQM;
517
518 /* DbgPrint("QM: Enter qmInit()\n"); */
519 #if CFG_SUPPORT_QOS
520 prAdapter->rWifiVar.fgSupportQoS = TRUE;
521 #else
522 prAdapter->rWifiVar.fgSupportQoS = FALSE;
523 #endif
524
525 #if CFG_SUPPORT_AMPDU_RX
526 prAdapter->rWifiVar.fgSupportAmpduRx = TRUE;
527 #else
528 prAdapter->rWifiVar.fgSupportAmpduRx = FALSE;
529 #endif
530
531 #if CFG_SUPPORT_AMPDU_TX
532 prAdapter->rWifiVar.fgSupportAmpduTx = TRUE;
533 #else
534 prAdapter->rWifiVar.fgSupportAmpduTx = FALSE;
535 #endif
536
537 #if CFG_SUPPORT_TSPEC
538 prAdapter->rWifiVar.fgSupportTspec = TRUE;
539 #else
540 prAdapter->rWifiVar.fgSupportTspec = FALSE;
541 #endif
542
543 #if CFG_SUPPORT_UAPSD
544 prAdapter->rWifiVar.fgSupportUAPSD = TRUE;
545 #else
546 prAdapter->rWifiVar.fgSupportUAPSD = FALSE;
547 #endif
548
549 #if CFG_SUPPORT_UL_PSMP
550 prAdapter->rWifiVar.fgSupportULPSMP = TRUE;
551 #else
552 prAdapter->rWifiVar.fgSupportULPSMP = FALSE;
553 #endif
554
555 /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */
556 for (u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++) {
557 QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx]));
558 }
559
560 /* 4 <3> Initialize the RX BA table and RX queues */
561 /* Initialize the RX Reordering Parameters and Queues */
562 for (u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++) {
563 prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE;
564 QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue));
565 prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF;
566 prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF;
567
568 prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE;
569
570 }
571 prQM->ucRxBaCount = 0;
572
573 kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout));
574
575 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
576 /* 4 <4> Initialize TC resource control variables */
577 for (i = 0; i < TC_NUM; i++) {
578 prQM->au4AverageQueLen[i] = 0;
579 }
580 prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC;
581 prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN;
582
583 /* ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); */
584
585 prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0;
586 prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1;
587 prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2;
588 prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3;
589 prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1) */
590 prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5;
591
592 prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE;
593 prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE;
594 prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE;
595 prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE;
596 prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1) */
597 prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE;
598
599
600 prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE;
601 prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE;
602 prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE;
603 prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE;
604 prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE;
605 prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE;
606
607 prQM->fgTcResourcePostAnnealing = FALSE;
608
609 ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64);
610 #endif
611
612 #if QM_TEST_MODE
613 prQM->u4PktCount = 0;
614
615 #if QM_TEST_FAIR_FORWARDING
616
617 prQM->u4CurrentStaRecIndexToEnqueue = 0;
618 {
619 UINT_8 aucMacAddr[MAC_ADDR_LEN];
620 P_STA_RECORD_T prStaRec;
621
622 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
623 aucMacAddr[0] = 0x11;
624 aucMacAddr[1] = 0x22;
625 aucMacAddr[2] = 0xAA;
626 aucMacAddr[3] = 0xBB;
627 aucMacAddr[4] = 0xCC;
628 aucMacAddr[5] = 0xDD;
629
630 prStaRec = &prAdapter->arStaRec[1];
631 ASSERT(prStaRec);
632
633 prStaRec->fgIsValid = TRUE;
634 prStaRec->fgIsQoS = TRUE;
635 prStaRec->fgIsInPS = FALSE;
636 prStaRec->ucPsSessionID = 0xFF;
637 prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX;
638 prStaRec->fgIsAp = TRUE;
639 COPY_MAC_ADDR((prStaRec)->aucMacAddr, aucMacAddr);
640
641 }
642
643 #endif
644
645 #endif
646
647 #if QM_FORWARDING_FAIRNESS
648 {
649 UINT_32 i;
650 for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) {
651 prQM->au4ForwardCount[i] = 0;
652 prQM->au4HeadStaRecIndex[i] = 0;
653 }
654 }
655 #endif
656
657 }
658
659 #if QM_TEST_MODE
660 VOID qmTestCases(IN P_ADAPTER_T prAdapter)
661 {
662 P_QUE_MGT_T prQM = &prAdapter->rQM;
663
664 DbgPrint("QM: ** TEST MODE **\n");
665
666 if (QM_TEST_STA_REC_DETERMINATION) {
667 if (prAdapter->arStaRec[0].fgIsValid) {
668 prAdapter->arStaRec[0].fgIsValid = FALSE;
669 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
670 } else {
671 prAdapter->arStaRec[0].fgIsValid = TRUE;
672 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
673 }
674 }
675
676 if (QM_TEST_STA_REC_DEACTIVATION) {
677 /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */
678
679 if (prAdapter->arStaRec[0].fgIsValid) {
680
681 DbgPrint("QM: (Test) Deactivate STA_REC[0]\n");
682 qmDeactivateStaRec(prAdapter, 0);
683 } else {
684
685 UINT_8 aucMacAddr[MAC_ADDR_LEN];
686
687 /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */
688 aucMacAddr[0] = 0x11;
689 aucMacAddr[1] = 0x22;
690 aucMacAddr[2] = 0xAA;
691 aucMacAddr[3] = 0xBB;
692 aucMacAddr[4] = 0xCC;
693 aucMacAddr[5] = 0xDD;
694
695 DbgPrint("QM: (Test) Activate STA_REC[0]\n");
696 qmActivateStaRec(prAdapter, /* Adapter pointer */
697 0, /* STA_REC index from FW */
698 TRUE, /* fgIsQoS */
699 NETWORK_TYPE_AIS_INDEX, /* Network type */
700 TRUE, /* fgIsAp */
701 aucMacAddr /* MAC address */
702 );
703 }
704 }
705
706 if (QM_TEST_FAIR_FORWARDING) {
707 if (prAdapter->arStaRec[1].fgIsValid) {
708 prQM->u4CurrentStaRecIndexToEnqueue++;
709 prQM->u4CurrentStaRecIndexToEnqueue %= 2;
710 DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n",
711 prQM->u4CurrentStaRecIndexToEnqueue);
712 }
713 }
714
715 }
716 #endif
717
718 /*----------------------------------------------------------------------------*/
719 /*!
720 * \brief Activate a STA_REC
721 *
722 * \param[in] prAdapter Pointer to the Adapter instance
723 * \param[in] u4StaRecIdx The index of the STA_REC
724 * \param[in] fgIsQoS Set to TRUE if this is a QoS STA
725 * \param[in] pucMacAddr The MAC address of the STA
726 *
727 * \return (none)
728 */
729 /*----------------------------------------------------------------------------*/
730 VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
731 {
732
733 /* 4 <1> Deactivate first */
734 ASSERT(prStaRec);
735
736 if (prStaRec->fgIsValid) { /* The STA_REC has been activated */
737 DBGLOG(QM, WARN,
738 ("QM: (WARNING) Activating a STA_REC which has been activated\n"));
739 DBGLOG(QM, WARN, ("QM: (WARNING) Deactivating a STA_REC before re-activating\n"));
740 qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); /* To flush TX/RX queues and del RX BA agreements */
741 }
742 /* 4 <2> Activate the STA_REC */
743 /* Init the STA_REC */
744 prStaRec->fgIsValid = TRUE;
745 prStaRec->fgIsInPS = FALSE;
746 prStaRec->ucPsSessionID = 0xFF;
747 prStaRec->fgIsAp = (IS_AP_STA(prStaRec)) ? TRUE : FALSE;
748
749 /* Done in qmInit() or qmDeactivateStaRec() */
750 #if 0
751 /* At the beginning, no RX BA agreements have been established */
752 for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) {
753 (prStaRec->aprRxReorderParamRefTbl)[i] = NULL;
754 }
755 #endif
756
757 DBGLOG(QM, INFO, ("QM: +STA[%ld]\n", prStaRec->ucIndex));
758 }
759
760 /*----------------------------------------------------------------------------*/
761 /*!
762 * \brief Deactivate a STA_REC
763 *
764 * \param[in] prAdapter Pointer to the Adapter instance
765 * \param[in] u4StaRecIdx The index of the STA_REC
766 *
767 * \return (none)
768 */
769 /*----------------------------------------------------------------------------*/
770 VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx)
771 {
772 P_STA_RECORD_T prStaRec;
773 UINT_32 i;
774 P_MSDU_INFO_T prFlushedTxPacketList = NULL;
775
776 ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD);
777
778 prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
779 ASSERT(prStaRec);
780
781 /* 4<1> Flush TX queues */
782 prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx);
783
784 if (prFlushedTxPacketList) {
785 wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList);
786 }
787 /* 4 <2> Flush RX queues and delete RX BA agreements */
788 for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) {
789 /* Delete the RX BA entry with TID = i */
790 qmDelRxBaEntry(prAdapter, (UINT_8) u4StaRecIdx, (UINT_8) i, FALSE);
791 }
792
793 /* 4 <3> Deactivate the STA_REC */
794 prStaRec->fgIsValid = FALSE;
795 prStaRec->fgIsInPS = FALSE;
796
797 DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx));
798 }
799
800
801 /*----------------------------------------------------------------------------*/
802 /*!
803 * \brief Deactivate a STA_REC
804 *
805 * \param[in] prAdapter Pointer to the Adapter instance
806 * \param[in] u4StaRecIdx The index of the network
807 *
808 * \return (none)
809 */
810 /*----------------------------------------------------------------------------*/
811
812 VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx)
813 {
814
815 P_QUE_MGT_T prQM;
816 P_QUE_T prQue;
817 QUE_T rNeedToFreeQue;
818 QUE_T rTempQue;
819 P_QUE_T prNeedToFreeQue;
820 P_QUE_T prTempQue;
821 P_MSDU_INFO_T prMsduInfo;
822
823
824 prQM = &prAdapter->rQM;
825 prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
826
827 QUEUE_INITIALIZE(&rNeedToFreeQue);
828 QUEUE_INITIALIZE(&rTempQue);
829
830 prNeedToFreeQue = &rNeedToFreeQue;
831 prTempQue = &rTempQue;
832
833 QUEUE_MOVE_ALL(prTempQue, prQue);
834
835 QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
836 while (prMsduInfo) {
837
838 if (prMsduInfo->ucNetworkType == eNetworkTypeIdx) {
839 QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T) prMsduInfo);
840 } else {
841 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo);
842 }
843
844 QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T);
845 }
846 if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) {
847 wlanProcessQueuedMsduInfo(prAdapter,
848 (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue));
849 }
850
851 }
852
853 /*----------------------------------------------------------------------------*/
854 /*!
855 * \brief Flush all TX queues
856 *
857 * \param[in] (none)
858 *
859 * \return The flushed packets (in a list of MSDU_INFOs)
860 */
861 /*----------------------------------------------------------------------------*/
862 P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter)
863 {
864 UINT_8 ucStaArrayIdx;
865 UINT_8 ucQueArrayIdx;
866
867 P_MSDU_INFO_T prMsduInfoListHead;
868 P_MSDU_INFO_T prMsduInfoListTail;
869
870 P_QUE_MGT_T prQM = &prAdapter->rQM;
871
872 DBGLOG(QM, TRACE, ("QM: Enter qmFlushTxQueues()\n"));
873
874 prMsduInfoListHead = NULL;
875 prMsduInfoListTail = NULL;
876
877 /* Concatenate all MSDU_INFOs in per-STA queues */
878 for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++) {
879
880 /* Always check each STA_REC when flushing packets no matter it is inactive or active */
881 #if 0
882 if (!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid) {
883 continue; /* Continue to check the next STA_REC */
884 }
885 #endif
886
887 for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) {
888 if (QUEUE_IS_EMPTY
889 (&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))) {
890 continue; /* Continue to check the next TX queue of the same STA */
891 }
892
893 if (!prMsduInfoListHead) {
894
895 /* The first MSDU_INFO is found */
896 prMsduInfoListHead = (P_MSDU_INFO_T)
897 QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].
898 arTxQueue[ucQueArrayIdx]);
899 prMsduInfoListTail = (P_MSDU_INFO_T)
900 QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].
901 arTxQueue[ucQueArrayIdx]);
902 } else {
903 /* Concatenate the MSDU_INFO list with the existing list */
904 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
905 QUEUE_GET_HEAD(&prAdapter->
906 arStaRec[ucStaArrayIdx].
907 arTxQueue[ucQueArrayIdx]));
908
909 prMsduInfoListTail = (P_MSDU_INFO_T)
910 QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].
911 arTxQueue[ucQueArrayIdx]);
912 }
913
914 QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].
915 arTxQueue[ucQueArrayIdx]);
916 }
917 }
918
919 /* Flush per-Type queues */
920 for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++) {
921
922 if (QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))) {
923 continue; /* Continue to check the next TX queue of the same STA */
924 }
925
926 if (!prMsduInfoListHead) {
927
928 /* The first MSDU_INFO is found */
929 prMsduInfoListHead = (P_MSDU_INFO_T)
930 QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]);
931 prMsduInfoListTail = (P_MSDU_INFO_T)
932 QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]);
933 } else {
934 /* Concatenate the MSDU_INFO list with the existing list */
935 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
936 QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]));
937
938 prMsduInfoListTail = (P_MSDU_INFO_T)
939 QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]);
940 }
941
942 QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]);
943
944 }
945
946 if (prMsduInfoListTail) {
947 /* Terminate the MSDU_INFO list with a NULL pointer */
948 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL);
949 }
950
951 return prMsduInfoListHead;
952 }
953
954
955 /*----------------------------------------------------------------------------*/
956 /*!
957 * \brief Flush TX packets for a particular STA
958 *
959 * \param[in] u4StaRecIdx STA_REC index
960 *
961 * \return The flushed packets (in a list of MSDU_INFOs)
962 */
963 /*----------------------------------------------------------------------------*/
964 P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx)
965 {
966 UINT_8 ucQueArrayIdx;
967 P_MSDU_INFO_T prMsduInfoListHead;
968 P_MSDU_INFO_T prMsduInfoListTail;
969 P_STA_RECORD_T prStaRec;
970
971 DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx));
972
973 ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD);
974
975 prMsduInfoListHead = NULL;
976 prMsduInfoListTail = NULL;
977
978 prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
979 ASSERT(prStaRec);
980
981 /* No matter whether this is an activated STA_REC, do flush */
982 #if 0
983 if (!prStaRec->fgIsValid) {
984 return NULL;
985 }
986 #endif
987
988 /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */
989 for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) {
990 if (QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))) {
991 continue;
992 }
993
994 if (!prMsduInfoListHead) {
995 /* The first MSDU_INFO is found */
996 prMsduInfoListHead = (P_MSDU_INFO_T)
997 QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]);
998 prMsduInfoListTail = (P_MSDU_INFO_T)
999 QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]);
1000 } else {
1001 /* Concatenate the MSDU_INFO list with the existing list */
1002 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
1003 QUEUE_GET_HEAD(&prStaRec->
1004 arTxQueue[ucQueArrayIdx]));
1005
1006 prMsduInfoListTail =
1007 (P_MSDU_INFO_T) QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]);
1008 }
1009
1010 QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]);
1011
1012 }
1013
1014 #if 0
1015 if (prMsduInfoListTail) {
1016 /* Terminate the MSDU_INFO list with a NULL pointer */
1017 QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail,
1018 nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx));
1019 } else {
1020 prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx);
1021 }
1022 #endif
1023
1024 return prMsduInfoListHead;
1025
1026 }
1027
1028 /*----------------------------------------------------------------------------*/
1029 /*!
1030 * \brief Flush RX packets
1031 *
1032 * \param[in] (none)
1033 *
1034 * \return The flushed packets (in a list of SW_RFBs)
1035 */
1036 /*----------------------------------------------------------------------------*/
1037 P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter)
1038 {
1039 UINT_32 i;
1040 P_SW_RFB_T prSwRfbListHead;
1041 P_SW_RFB_T prSwRfbListTail;
1042 P_QUE_MGT_T prQM = &prAdapter->rQM;
1043
1044 prSwRfbListHead = prSwRfbListTail = NULL;
1045
1046 DBGLOG(QM, TRACE, ("QM: Enter qmFlushRxQueues()\n"));
1047
1048 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
1049 if (QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) {
1050 if (!prSwRfbListHead) {
1051
1052 /* The first MSDU_INFO is found */
1053 prSwRfbListHead = (P_SW_RFB_T)
1054 QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue));
1055 prSwRfbListTail = (P_SW_RFB_T)
1056 QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue));
1057 } else {
1058 /* Concatenate the MSDU_INFO list with the existing list */
1059 QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail,
1060 QUEUE_GET_HEAD(&
1061 (prQM->arRxBaTable[i].
1062 rReOrderQue)));
1063
1064 prSwRfbListTail = (P_SW_RFB_T)
1065 QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue));
1066 }
1067
1068 QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue));
1069
1070 } else {
1071 continue;
1072 }
1073 }
1074
1075 if (prSwRfbListTail) {
1076 /* Terminate the MSDU_INFO list with a NULL pointer */
1077 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1078 }
1079 return prSwRfbListHead;
1080
1081 }
1082
1083
1084 /*----------------------------------------------------------------------------*/
1085 /*!
1086 * \brief Flush RX packets with respect to a particular STA
1087 *
1088 * \param[in] u4StaRecIdx STA_REC index
1089 * \param[in] u4Tid TID
1090 *
1091 * \return The flushed packets (in a list of SW_RFBs)
1092 */
1093 /*----------------------------------------------------------------------------*/
1094 P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx, IN UINT_32 u4Tid)
1095 {
1096 /* UINT_32 i; */
1097 P_SW_RFB_T prSwRfbListHead;
1098 P_SW_RFB_T prSwRfbListTail;
1099 P_RX_BA_ENTRY_T prReorderQueParm;
1100 P_STA_RECORD_T prStaRec;
1101
1102 DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx));
1103
1104 prSwRfbListHead = prSwRfbListTail = NULL;
1105
1106 prStaRec = &prAdapter->arStaRec[u4StaRecIdx];
1107 ASSERT(prStaRec);
1108
1109 /* No matter whether this is an activated STA_REC, do flush */
1110 #if 0
1111 if (!prStaRec->fgIsValid) {
1112 return NULL;
1113 }
1114 #endif
1115
1116 /* Obtain the RX BA Entry pointer */
1117 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]);
1118
1119 /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */
1120 if (prReorderQueParm) {
1121
1122 if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) {
1123
1124 prSwRfbListHead = (P_SW_RFB_T)
1125 QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue));
1126 prSwRfbListTail = (P_SW_RFB_T)
1127 QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue));
1128
1129
1130 QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue));
1131
1132 }
1133 }
1134
1135 if (prSwRfbListTail) {
1136 /* Terminate the MSDU_INFO list with a NULL pointer */
1137 QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL);
1138 }
1139 return prSwRfbListHead;
1140
1141
1142 }
1143
1144
1145 /*----------------------------------------------------------------------------*/
1146 /*!
1147 * \brief Enqueue TX packets
1148 *
1149 * \param[in] prMsduInfoListHead Pointer to the list of TX packets
1150 *
1151 * \return The freed packets, which are not enqueued
1152 */
1153 /*----------------------------------------------------------------------------*/
1154 P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead)
1155 {
1156 P_MSDU_INFO_T prMsduInfoReleaseList;
1157 P_MSDU_INFO_T prCurrentMsduInfo;
1158 P_MSDU_INFO_T prNextMsduInfo;
1159
1160 P_STA_RECORD_T prStaRec;
1161 P_QUE_T prTxQue;
1162 QUE_T rNotEnqueuedQue;
1163
1164
1165 UINT_8 ucPacketType;
1166 UINT_8 ucTC;
1167 P_QUE_MGT_T prQM = &prAdapter->rQM;
1168 UINT_8 aucNextUP[WMM_AC_INDEX_NUM] =
1169 { 1 /* BEtoBK */ , 1 /*na */ , 0 /*VItoBE */ , 4 /*VOtoVI */ };
1170
1171 DBGLOG(QM, LOUD, ("Enter qmEnqueueTxPackets\n"));
1172
1173 ASSERT(prMsduInfoListHead);
1174
1175 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
1176 {
1177 /* UINT_32 i; */
1178 /* 4 <0> Update TC resource control related variables */
1179 /* Keep track of the queue length */
1180 if (--prQM->u4TimeToUpdateQueLen == 0) {
1181 prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN;
1182 qmUpdateAverageTxQueLen(prAdapter);
1183 }
1184 }
1185 #endif
1186
1187 /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */
1188 prStaRec = NULL;
1189 prMsduInfoReleaseList = NULL;
1190 prCurrentMsduInfo = NULL;
1191 QUEUE_INITIALIZE(&rNotEnqueuedQue);
1192 prNextMsduInfo = prMsduInfoListHead;
1193
1194 do {
1195 P_BSS_INFO_T prBssInfo;
1196 BOOLEAN fgCheckACMAgain;
1197 ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX;
1198 prCurrentMsduInfo = prNextMsduInfo;
1199 prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo);
1200 ucTC = TC1_INDEX;
1201
1202 /* 4 <1> Lookup the STA_REC index */
1203 /* The ucStaRecIndex will be set in this function */
1204 qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo);
1205 ucPacketType = HIF_TX_PACKET_TYPE_DATA;
1206
1207 DBGLOG(QM, LOUD, ("***** ucStaRecIndex = %d *****\n",
1208 prCurrentMsduInfo->ucStaRecIndex));
1209
1210
1211 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]);
1212
1213 if (IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) {
1214
1215 switch (prCurrentMsduInfo->ucStaRecIndex) {
1216 case STA_REC_INDEX_BMCAST:
1217 prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
1218 ucTC = TC5_INDEX;
1219 #if 0
1220 if (prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX
1221 && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT) {
1222 if (LINK_IS_EMPTY
1223 (&prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].
1224 rStaRecOfClientList)) {
1225 prTxQue = &rNotEnqueuedQue;
1226 TX_INC_CNT(&prAdapter->rTxCtrl,
1227 TX_AP_BORADCAST_DROP);
1228 }
1229 }
1230 #endif
1231
1232 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23);
1233 break;
1234
1235 case STA_REC_INDEX_NOT_FOUND:
1236 ucTC = TC5_INDEX;
1237
1238 if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1239
1240 /* if the packet is the forward type. the packet should be freed */
1241 DBGLOG(QM, TRACE,
1242 ("Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"));
1243 /* prTxQue = &rNotEnqueuedQue; */
1244 }
1245 prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC];
1246 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24);
1247
1248 break;
1249
1250 default:
1251 prStaRec =
1252 QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter,
1253 prCurrentMsduInfo->ucStaRecIndex);
1254
1255 ASSERT(prStaRec);
1256 ASSERT(prStaRec->fgIsValid);
1257
1258 if (prCurrentMsduInfo->ucUserPriority < 8) {
1259 QM_DBG_CNT_INC(prQM,
1260 prCurrentMsduInfo->ucUserPriority + 15);
1261 /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */
1262 /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */
1263 }
1264
1265 eAci = WMM_AC_BE_INDEX;
1266 do {
1267 fgCheckACMAgain = FALSE;
1268 if (prStaRec->fgIsQoS) {
1269 switch (prCurrentMsduInfo->ucUserPriority) {
1270 case 1:
1271 case 2:
1272 prTxQue =
1273 &prStaRec->
1274 arTxQueue[TX_QUEUE_INDEX_AC0];
1275 ucTC = TC0_INDEX;
1276 eAci = WMM_AC_BK_INDEX;
1277 break;
1278 case 0:
1279 case 3:
1280 prTxQue =
1281 &prStaRec->
1282 arTxQueue[TX_QUEUE_INDEX_AC1];
1283 ucTC = TC1_INDEX;
1284 eAci = WMM_AC_BE_INDEX;
1285 break;
1286 case 4:
1287 case 5:
1288 prTxQue =
1289 &prStaRec->
1290 arTxQueue[TX_QUEUE_INDEX_AC2];
1291 ucTC = TC2_INDEX;
1292 eAci = WMM_AC_VI_INDEX;
1293 break;
1294 case 6:
1295 case 7:
1296 prTxQue =
1297 &prStaRec->
1298 arTxQueue[TX_QUEUE_INDEX_AC3];
1299 ucTC = TC3_INDEX;
1300 eAci = WMM_AC_VO_INDEX;
1301 break;
1302 default:
1303 prTxQue =
1304 &prStaRec->
1305 arTxQueue[TX_QUEUE_INDEX_AC1];
1306 ucTC = TC1_INDEX;
1307 eAci = WMM_AC_BE_INDEX;
1308 ASSERT(0);
1309 break;
1310 }
1311 if (prBssInfo->arACQueParms[eAci].fgIsACMSet
1312 && eAci != WMM_AC_BK_INDEX) {
1313 prCurrentMsduInfo->ucUserPriority =
1314 aucNextUP[eAci];
1315 fgCheckACMAgain = TRUE;
1316 }
1317 } else {
1318 prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1];
1319 ucTC = TC1_INDEX;
1320 }
1321 }
1322 while (fgCheckACMAgain);
1323
1324 /* LOG_FUNC ("QoS %u UP %u TC %u",prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); */
1325
1326 break; /*default */
1327 } /* switch (prCurrentMsduInfo->ucStaRecIndex) */
1328
1329 if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1330 if (prTxQue->u4NumElem > 32) {
1331 DBGLOG(QM, INFO,
1332 ("Drop the Packet for full Tx queue (forwarding) Bss %u\n",
1333 prCurrentMsduInfo->ucNetworkType));
1334 prTxQue = &rNotEnqueuedQue;
1335 TX_INC_CNT(&prAdapter->rTxCtrl, TX_FORWARD_OVERFLOW_DROP);
1336 }
1337 }
1338
1339 } else {
1340
1341 DBGLOG(QM, INFO,
1342 ("Drop the Packet for inactive Bss %u\n",
1343 prCurrentMsduInfo->ucNetworkType));
1344 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31);
1345 prTxQue = &rNotEnqueuedQue;
1346 TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP);
1347 }
1348
1349 /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */
1350
1351 /* TODO: Fill MSDU_INFO according to the network type,
1352 * EtherType, and STA status (for PS forwarding control).
1353 */
1354
1355 /* Note that the Network Type Index and STA_REC index are determined in
1356 * qmDetermineStaRecIndex(prCurrentMsduInfo).
1357 */
1358 QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(prCurrentMsduInfo, /* MSDU_INFO ptr */
1359 ucTC, /* TC tag */
1360 ucPacketType, /* Packet Type */
1361 0, /* Format ID */
1362 prCurrentMsduInfo->fgIs802_1x, /* Flag 802.1x */
1363 prCurrentMsduInfo->fgIs802_11, /* Flag 802.11 */
1364 0, /* PAL LLH */
1365 0, /* ACL SN */
1366 PS_FORWARDING_TYPE_NON_PS, /* PS Forwarding Type */
1367 0 /* PS Session ID */
1368 );
1369
1370 /* 4 <4> Enqueue the packet */
1371 QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T) prCurrentMsduInfo);
1372
1373
1374 #if QM_TEST_MODE
1375 if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) {
1376 prQM->u4PktCount = 0;
1377 qmTestCases(prAdapter);
1378 }
1379 #endif
1380
1381 DBGLOG(QM, LOUD, ("Current queue length = %u\n", prTxQue->u4NumElem));
1382 } while (prNextMsduInfo);
1383
1384 if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue)) {
1385 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL);
1386 prMsduInfoReleaseList = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rNotEnqueuedQue);
1387 }
1388
1389
1390 return prMsduInfoReleaseList;
1391 }
1392
1393 /*----------------------------------------------------------------------------*/
1394 /*!
1395 * \brief Determine the STA_REC index for a packet
1396 *
1397 * \param[in] prMsduInfo Pointer to the packet
1398 *
1399 * \return (none)
1400 */
1401 /*----------------------------------------------------------------------------*/
1402 static VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
1403 {
1404 UINT_32 i;
1405
1406 P_STA_RECORD_T prTempStaRec;
1407 /* P_QUE_MGT_T prQM = &prAdapter->rQM; */
1408
1409 prTempStaRec = NULL;
1410
1411 ASSERT(prMsduInfo);
1412
1413 /* 4 <1> DA = BMCAST */
1414 if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) {
1415 /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP.
1416 * FW shall take care of this. The host driver is not able to distinguish these cases. */
1417 prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST;
1418 DBGLOG(QM, LOUD, ("TX with DA = BMCAST\n"));
1419 return;
1420 }
1421
1422 /* 4 <2> Check if an AP STA is present */
1423 for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) {
1424 prTempStaRec = &(prAdapter->arStaRec[i]);
1425
1426 if ((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType)
1427 && (prTempStaRec->fgIsAp)
1428 && (prTempStaRec->fgIsValid)) {
1429 prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex;
1430 return;
1431 }
1432 }
1433
1434
1435
1436
1437 /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */
1438 for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) {
1439 prTempStaRec = &(prAdapter->arStaRec[i]);
1440 if (prTempStaRec->fgIsValid) {
1441 if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)) {
1442 prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex;
1443 return;
1444 }
1445 }
1446 }
1447
1448
1449 /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */
1450 prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND;
1451 DBGLOG(QM, LOUD, ("QM: TX with STA_REC_INDEX_NOT_FOUND\n"));
1452
1453
1454 #if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING)
1455 prMsduInfo->ucStaRecIndex = (UINT_8) prQM->u4CurrentStaRecIndexToEnqueue;
1456 #endif
1457 }
1458
1459 /*----------------------------------------------------------------------------*/
1460 /*!
1461 * \brief Dequeue TX packets from a STA_REC for a particular TC
1462 *
1463 * \param[out] prQue The queue to put the dequeued packets
1464 * \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX)
1465 * \param[in] ucMaxNum The maximum amount of dequeued packets
1466 *
1467 * \return (none)
1468 */
1469 /*----------------------------------------------------------------------------*/
1470 static VOID
1471 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter,
1472 OUT P_QUE_T prQue,
1473 IN UINT_8 ucTC, IN UINT_8 ucCurrentQuota, IN UINT_8 ucTotalQuota)
1474 {
1475
1476 #if QM_FORWARDING_FAIRNESS
1477 UINT_32 i; /* Loop for */
1478
1479 PUINT_32 pu4HeadStaRecIndex; /* The Head STA index */
1480 PUINT_32 pu4HeadStaRecForwardCount; /* The total forwarded packets for the head STA */
1481
1482 P_STA_RECORD_T prStaRec; /* The current focused STA */
1483 P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */
1484 P_QUE_T prCurrQueue; /* The current TX queue to dequeue */
1485 P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */
1486
1487 UINT_32 u4ForwardCount; /* To remember the total forwarded packets for a STA */
1488 UINT_32 u4MaxForwardCount; /* The maximum number of packets a STA can forward */
1489 UINT_32 u4Resource; /* The TX resource amount */
1490
1491 BOOLEAN fgChangeHeadSta; /* Whether a new head STA shall be determined at the end of the function */
1492 P_QUE_MGT_T prQM = &prAdapter->rQM;
1493
1494 PUINT_8 pucFreeQuota;
1495
1496 DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC));
1497
1498 ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX ||
1499 ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX);
1500
1501 if (!ucCurrentQuota) {
1502 DBGLOG(TX, LOUD, ("@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n",
1503 ucTC, ucCurrentQuota));
1504 return;
1505 }
1506
1507 u4Resource = ucCurrentQuota;
1508
1509 /* 4 <1> Determine the head STA */
1510 /* The head STA shall be an active STA */
1511
1512 pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]);
1513 pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]);
1514
1515 DBGLOG(QM, LOUD, ("(Fairness) TID = %u Init Head STA = %u Resource = %u\n",
1516 ucTC, *pu4HeadStaRecIndex, u4Resource));
1517
1518
1519 /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */
1520 for (i = 0; i < CFG_NUM_OF_STA_RECORD + 1; i++) {
1521 prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)];
1522 ASSERT(prStaRec);
1523
1524 /* Only Data frame (1x was not included) will be queued in */
1525 if (prStaRec->fgIsValid) {
1526
1527 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
1528
1529 ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1530
1531 /* Determine how many packets the head STA is allowed to send in a round */
1532
1533 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25);
1534 u4MaxForwardCount = ucTotalQuota;
1535 #if CFG_ENABLE_WIFI_DIRECT
1536
1537 pucFreeQuota = NULL;
1538 if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) {
1539 /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */
1540 /* u4MaxForwardCount = ucTotalQuota; */
1541 /* Per STA flow control when STA in PS mode */
1542 /* The PHASE 1: only update from ucFreeQuota (now) */
1543 /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1544 /* NOTE: other method to set u4Resource */
1545
1546 if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
1547 /* && prAdapter->rWifiVar.fgSupportQoS
1548 && prAdapter->rWifiVar.fgSupportUAPSD */) {
1549
1550 if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) {
1551 u4MaxForwardCount =
1552 prStaRec->ucFreeQuotaForDelivery;
1553 pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery;
1554 } else {
1555 u4MaxForwardCount =
1556 prStaRec->ucFreeQuotaForNonDelivery;
1557 pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1558 }
1559
1560 } else {
1561 ASSERT(prStaRec->ucFreeQuotaForDelivery == 0);
1562 u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1563 pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1564 }
1565
1566 } /* fgIsInPS */
1567 #endif /* CFG_ENABLE_WIFI_DIRECT */
1568
1569 #if CFG_ENABLE_WIFI_DIRECT
1570 if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) {
1571 if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) {
1572 u4MaxForwardCount = prBssInfo->ucBssFreeQuota;
1573 }
1574 }
1575 #endif /* CFG_ENABLE_WIFI_DIRECT */
1576
1577 /* Determine whether the head STA can continue to forward packets in this round */
1578 if ((*pu4HeadStaRecForwardCount) < u4MaxForwardCount) {
1579 break;
1580 }
1581
1582 } /* prStaRec->fgIsValid */
1583 else {
1584 /* The current Head STA has been deactivated, so search for a new head STA */
1585 prStaRec = NULL;
1586 prBssInfo = NULL;
1587 (*pu4HeadStaRecIndex)++;
1588 (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD;
1589
1590 /* Reset the forwarding count before searching (since this is for a new selected STA) */
1591 (*pu4HeadStaRecForwardCount) = 0;
1592 }
1593 } /* i < CFG_NUM_OF_STA_RECORD + 1 */
1594
1595 /* All STA_RECs are inactive, so exit */
1596 if (!prStaRec) {
1597 /* Under concurrent, it is possible that there is no candidcated STA. */
1598 /* DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); */
1599 return;
1600 }
1601
1602 DBGLOG(QM, LOUD, ("(Fairness) TID = %u Round Head STA = %lu\n", ucTC, *pu4HeadStaRecIndex));
1603
1604 /* 4 <2> Dequeue packets from the head STA */
1605
1606 prCurrQueue = &prStaRec->arTxQueue[ucTC];
1607 prDequeuedPkt = NULL;
1608 fgChangeHeadSta = FALSE;
1609
1610 while (prCurrQueue) {
1611
1612
1613 #if QM_DEBUG_COUNTER
1614
1615 if (ucTC <= TC4_INDEX) {
1616 if (QUEUE_IS_EMPTY(prCurrQueue)) {
1617 QM_DBG_CNT_INC(prQM, ucTC);
1618 /* QM_DBG_CNT_00 *//* QM_DBG_CNT_01 *//* QM_DBG_CNT_02 *//* QM_DBG_CNT_03 *//* QM_DBG_CNT_04 */
1619 }
1620 if (u4Resource == 0) {
1621 QM_DBG_CNT_INC(prQM, ucTC + 5);
1622 /* QM_DBG_CNT_05 *//* QM_DBG_CNT_06 *//* QM_DBG_CNT_07 *//* QM_DBG_CNT_08 *//* QM_DBG_CNT_09 */
1623 }
1624 if (((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) {
1625 QM_DBG_CNT_INC(prQM, ucTC + 10);
1626 /* QM_DBG_CNT_10 *//* QM_DBG_CNT_11 *//* QM_DBG_CNT_12 *//* QM_DBG_CNT_13 *//* QM_DBG_CNT_14 */
1627 }
1628 }
1629 #endif
1630
1631
1632 /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1633 if (QUEUE_IS_EMPTY(prCurrQueue)
1634 || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) {
1635 fgChangeHeadSta = TRUE;
1636 break;
1637 } else if (u4Resource == 0) {
1638 break;
1639 } else {
1640
1641 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1642 #if DBG && 0
1643 LOG_FUNC
1644 ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1645 prDequeuedPkt->ucTC, prCurrQueue->u4NumElem,
1646 prDequeuedPkt->ucNetworkType, prDequeuedPkt->ucMacHeaderLength,
1647 prDequeuedPkt->u2FrameLength, prDequeuedPkt->ucPacketType,
1648 prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11);
1649
1650 LOG_FUNC("Dest Mac: " MACSTR "\n", MAC2STR(prDequeuedPkt->aucEthDestAddr));
1651
1652 #if LINUX
1653 {
1654 struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket;
1655 dumpMemory8((PUINT_8) prSkb->data, prSkb->len);
1656 }
1657 #endif
1658
1659 #endif
1660
1661 ASSERT(prDequeuedPkt->ucTC == ucTC);
1662
1663 if (!QUEUE_IS_EMPTY(prCurrQueue)) {
1664 /* XXX: check all queues for STA */
1665 prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED;
1666 }
1667
1668 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt);
1669 u4Resource--;
1670 (*pu4HeadStaRecForwardCount)++;
1671
1672
1673 #if CFG_ENABLE_WIFI_DIRECT
1674 /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */
1675 if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) {
1676 ASSERT(pucFreeQuota);
1677 ASSERT(*pucFreeQuota > 0);
1678 if (*pucFreeQuota > 0) {
1679 *pucFreeQuota = *pucFreeQuota - 1;
1680 }
1681 }
1682 #endif /* CFG_ENABLE_WIFI_DIRECT */
1683
1684 #if CFG_ENABLE_WIFI_DIRECT
1685 if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) {
1686 if (prBssInfo->ucBssFreeQuota > 0) {
1687 prBssInfo->ucBssFreeQuota--;
1688 }
1689 }
1690 #endif /* CFG_ENABLE_WIFI_DIRECT */
1691
1692 }
1693 }
1694
1695 if (*pu4HeadStaRecForwardCount) {
1696 DBGLOG(QM, LOUD,
1697 ("TC = %u Round Head STA = %lu, u4HeadStaRecForwardCount = %lu\n", ucTC,
1698 *pu4HeadStaRecIndex, (*pu4HeadStaRecForwardCount)));
1699 }
1700 #if QM_BURST_END_INFO_ENABLED
1701 /* Let FW know which packet is the last one dequeued from the STA */
1702 if (prDequeuedPkt) {
1703 prDequeuedPkt->fgIsBurstEnd = TRUE;
1704 }
1705 #endif
1706
1707
1708 /* 4 <3> Dequeue from the other STAs if there is residual TX resource */
1709
1710 /* Check all of the STAs to continue forwarding packets (including the head STA) */
1711 for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) {
1712 /* Break in case no reasource is available */
1713 if (u4Resource == 0) {
1714 break;
1715 }
1716
1717 /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */
1718 prStaRec =
1719 &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD];
1720 ASSERT(prStaRec);
1721
1722 if (prStaRec->fgIsValid) {
1723
1724 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
1725 ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1726
1727 DBGLOG(QM, LOUD, ("(Fairness) TID = %u Sharing STA = %u Resource = %lu\n",
1728 ucTC, prStaRec->ucIndex, u4Resource));
1729
1730 prCurrQueue = &prStaRec->arTxQueue[ucTC];
1731 u4ForwardCount = 0;
1732 u4MaxForwardCount = ucTotalQuota;
1733
1734 #if CFG_ENABLE_WIFI_DIRECT
1735 pucFreeQuota = NULL;
1736 if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) {
1737 /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */
1738 /* u4MaxForwardCount = ucTotalQuota; */
1739 /* Per STA flow control when STA in PS mode */
1740 /* The PHASE 1: only update from ucFreeQuota (now) */
1741 /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */
1742 /* NOTE: other method to set u4Resource */
1743 if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
1744 /* && prAdapter->rWifiVar.fgSupportQoS
1745 && prAdapter->rWifiVar.fgSupportUAPSD */) {
1746
1747 if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) {
1748 u4MaxForwardCount =
1749 prStaRec->ucFreeQuotaForDelivery;
1750 pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery;
1751 } else {
1752 u4MaxForwardCount =
1753 prStaRec->ucFreeQuotaForNonDelivery;
1754 pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1755 }
1756
1757 } else {
1758 ASSERT(prStaRec->ucFreeQuotaForDelivery == 0);
1759 u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery;
1760 pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery;
1761 }
1762
1763 }
1764 #endif /* CFG_ENABLE_WIFI_DIRECT */
1765 #if CFG_ENABLE_WIFI_DIRECT
1766 if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) {
1767 if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) {
1768 u4MaxForwardCount = prBssInfo->ucBssFreeQuota;
1769 }
1770 }
1771 #endif /* CFG_ENABLE_WIFI_DIRECT */
1772 } /* prStaRec->fgIsValid */
1773 else {
1774 prBssInfo = NULL;
1775 /* Invalid STA, so check the next STA */
1776 continue;
1777 }
1778
1779 while (prCurrQueue) {
1780 /* Three cases to break: (1) No resource (2) No packets (3) Fairness */
1781 if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue)
1782 || (u4ForwardCount >= u4MaxForwardCount)) {
1783 break;
1784 } else {
1785
1786 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1787
1788 #if DBG && 0
1789 DBGLOG(QM, LOUD,
1790 ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
1791 prDequeuedPkt->ucTC, prCurrQueue->u4NumElem,
1792 prDequeuedPkt->ucNetworkType,
1793 prDequeuedPkt->ucMacHeaderLength,
1794 prDequeuedPkt->u2FrameLength, prDequeuedPkt->ucPacketType,
1795 prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11));
1796
1797 DBGLOG(QM, LOUD, ("Dest Mac: " MACSTR "\n",
1798 MAC2STR(prDequeuedPkt->aucEthDestAddr)));
1799
1800 #if LINUX
1801 {
1802 struct sk_buff *prSkb =
1803 (struct sk_buff *)prDequeuedPkt->prPacket;
1804 dumpMemory8((PUINT_8) prSkb->data, prSkb->len);
1805 }
1806 #endif
1807
1808 #endif
1809
1810
1811 ASSERT(prDequeuedPkt->ucTC == ucTC);
1812
1813 if (!QUEUE_IS_EMPTY(prCurrQueue)) {
1814 prDequeuedPkt->ucPsForwardingType =
1815 PS_FORWARDING_MORE_DATA_ENABLED;
1816 }
1817
1818 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt);
1819 u4Resource--;
1820 u4ForwardCount++;
1821
1822 #if CFG_ENABLE_WIFI_DIRECT
1823 /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */
1824 if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) {
1825 ASSERT(pucFreeQuota);
1826 ASSERT(*pucFreeQuota > 0);
1827 if (*pucFreeQuota > 0) {
1828 *pucFreeQuota = *pucFreeQuota - 1;
1829 }
1830 }
1831 #endif /* CFG_ENABLE_WIFI_DIRECT */
1832
1833
1834 #if CFG_ENABLE_WIFI_DIRECT
1835 ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex);
1836 if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) {
1837 if (prBssInfo->ucBssFreeQuota > 0) {
1838 prBssInfo->ucBssFreeQuota--;
1839 }
1840 }
1841 #endif /* CFG_ENABLE_WIFI_DIRECT */
1842
1843 }
1844 }
1845
1846 #if QM_BURST_END_INFO_ENABLED
1847 /* Let FW know which packet is the last one dequeued from the STA */
1848 if (u4ForwardCount) {
1849 prDequeuedPkt->fgIsBurstEnd = TRUE;
1850 }
1851 #endif
1852 }
1853
1854
1855 if (fgChangeHeadSta) {
1856 (*pu4HeadStaRecIndex)++;
1857 (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD;
1858 (*pu4HeadStaRecForwardCount) = 0;
1859 DBGLOG(QM, LOUD,
1860 ("(Fairness) TID = %u Scheduled Head STA = %lu Left Resource = %lu\n", ucTC,
1861 (*pu4HeadStaRecIndex), u4Resource));
1862 }
1863
1864
1865 /***************************************************************************************/
1866 #else
1867 UINT_8 ucStaRecIndex;
1868 P_STA_RECORD_T prStaRec;
1869 P_QUE_T prCurrQueue;
1870 UINT_8 ucPktCount;
1871 P_MSDU_INFO_T prDequeuedPkt;
1872
1873 DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC));
1874
1875 if (ucCurrentQuota == 0) {
1876 return;
1877 }
1878 /* 4 <1> Determine the queue index and the head STA */
1879
1880 /* The head STA */
1881 ucStaRecIndex = 0; /* TODO: Get the current head STA */
1882 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex);
1883 ASSERT(prStaRec);
1884
1885 if (prStaRec == NULL) {
1886 return;
1887 }
1888
1889 /* The queue to pull out packets */
1890 ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX ||
1891 ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX);
1892 prCurrQueue = &prStaRec->arTxQueue[ucTC];
1893
1894 ucPktCount = ucCurrentQuota;
1895 prDequeuedPkt = NULL;
1896
1897 /* 4 <2> Dequeue packets for the head STA */
1898 while (TRUE) {
1899 if (!(prStaRec->fgIsValid) || ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) {
1900 break;
1901
1902 } else {
1903
1904 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1905 /* DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); */
1906 ASSERT(prDequeuedPkt->ucTC == ucTC);
1907
1908 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt);
1909 ucPktCount--;
1910 }
1911 }
1912
1913 /* DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); */
1914
1915 #if QM_BURST_END_INFO_ENABLED
1916 if (prDequeuedPkt) {
1917 prDequeuedPkt->fgIsBurstEnd = TRUE;
1918 }
1919 #endif
1920
1921 /* 4 <3> Update scheduling info */
1922 /* TODO */
1923
1924 /* 4 <4> Utilize the remainaing TX opportunities for non-head STAs */
1925 /* TODO */
1926 #endif
1927 }
1928
1929
1930 /*----------------------------------------------------------------------------*/
1931 /*!
1932 * \brief Dequeue TX packets from a per-Type-based Queue for a particular TC
1933 *
1934 * \param[out] prQue The queue to put the dequeued packets
1935 * \param[in] ucTC The TC index (Shall always be TC5_INDEX)
1936 * \param[in] ucMaxNum The maximum amount of dequeued packets
1937 *
1938 * \return (none)
1939 */
1940 /*----------------------------------------------------------------------------*/
1941 static VOID
1942 qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter,
1943 OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum)
1944 {
1945 /* UINT_8 ucQueIndex; */
1946 /* UINT_8 ucStaRecIndex; */
1947 P_BSS_INFO_T prBssInfo;
1948 P_BSS_INFO_T parBssInfo;
1949 P_QUE_T prCurrQueue;
1950 UINT_8 ucPktCount;
1951 P_MSDU_INFO_T prDequeuedPkt;
1952 P_MSDU_INFO_T prBurstEndPkt;
1953 QUE_T rMergeQue;
1954 P_QUE_T prMergeQue;
1955 P_QUE_MGT_T prQM;
1956
1957 DBGLOG(QM, LOUD,
1958 ("Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum));
1959
1960 /* TC5: Broadcast/Multicast data packets */
1961 ASSERT(ucTC == TC5_INDEX);
1962
1963 if (ucMaxNum == 0) {
1964 return;
1965 }
1966
1967 prQM = &prAdapter->rQM;
1968 /* 4 <1> Determine the queue */
1969
1970 prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST];
1971 ucPktCount = ucMaxNum;
1972 prDequeuedPkt = NULL;
1973 prBurstEndPkt = NULL;
1974
1975 parBssInfo = prAdapter->rWifiVar.arBssInfo;
1976
1977 QUEUE_INITIALIZE(&rMergeQue);
1978 prMergeQue = &rMergeQue;
1979
1980 /* 4 <2> Dequeue packets */
1981 while (TRUE) {
1982 if (ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) {
1983 break;
1984 } else {
1985 QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T);
1986 ASSERT(prDequeuedPkt->ucTC == ucTC);
1987
1988 ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM);
1989
1990 prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType];
1991
1992 if (IS_BSS_ACTIVE(prBssInfo)) {
1993 if (!prBssInfo->fgIsNetAbsent) {
1994 QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt);
1995 prBurstEndPkt = prDequeuedPkt;
1996 ucPktCount--;
1997 QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26);
1998 #if DBG && 0
1999 LOG_FUNC
2000 ("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n",
2001 prDequeuedPkt->ucTC, prCurrQueue->u4NumElem,
2002 prDequeuedPkt->ucNetworkType,
2003 prDequeuedPkt->ucMacHeaderLength,
2004 prDequeuedPkt->u2FrameLength,
2005 prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x,
2006 prDequeuedPkt->fgIs802_11);
2007
2008 LOG_FUNC("Dest Mac: " MACSTR "\n",
2009 MAC2STR(prDequeuedPkt->aucEthDestAddr));
2010
2011 #if LINUX
2012 {
2013 struct sk_buff *prSkb =
2014 (struct sk_buff *)prDequeuedPkt->prPacket;
2015 dumpMemory8((PUINT_8) prSkb->data, prSkb->len);
2016 }
2017 #endif
2018
2019 #endif
2020 } else {
2021 QUEUE_INSERT_TAIL(prMergeQue,
2022 (P_QUE_ENTRY_T) prDequeuedPkt);
2023 }
2024 } else {
2025 QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL);
2026 wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt);
2027 }
2028 }
2029 }
2030
2031 if (QUEUE_IS_NOT_EMPTY(prMergeQue)) {
2032 QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue);
2033 QUEUE_MOVE_ALL(prCurrQueue, prMergeQue);
2034 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(prCurrQueue), NULL);
2035 }
2036 #if QM_BURST_END_INFO_ENABLED
2037 if (prBurstEndPkt) {
2038 prBurstEndPkt->fgIsBurstEnd = TRUE;
2039 }
2040 #endif
2041 } /* qmDequeueTxPacketsFromPerTypeQueues */
2042
2043
2044
2045
2046 /*----------------------------------------------------------------------------*/
2047 /*!
2048 * \brief Dequeue TX packets to send to HIF TX
2049 *
2050 * \param[in] prTcqStatus Info about the maximum amount of dequeued packets
2051 *
2052 * \return The list of dequeued TX packets
2053 */
2054 /*----------------------------------------------------------------------------*/
2055 P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus)
2056 {
2057
2058 INT_32 i;
2059 P_MSDU_INFO_T prReturnedPacketListHead;
2060 QUE_T rReturnedQue;
2061
2062 DBGLOG(QM, LOUD, ("Enter qmDequeueTxPackets\n"));
2063
2064 QUEUE_INITIALIZE(&rReturnedQue);
2065
2066 prReturnedPacketListHead = NULL;
2067
2068 /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */
2069 for (i = TC4_INDEX; i >= TC0_INDEX; i--) {
2070 DBGLOG(QM, LOUD, ("Dequeue packets from Per-STA queue[%u]\n", i));
2071
2072 qmDequeueTxPacketsFromPerStaQueues(prAdapter,
2073 &rReturnedQue,
2074 (UINT_8) i,
2075 prTcqStatus->aucFreeBufferCount[i],
2076 prTcqStatus->aucMaxNumOfBuffer[i]
2077 );
2078
2079 /* The aggregate number of dequeued packets */
2080 DBGLOG(QM, LOUD, ("DQA)[%u](%lu)\n", i, rReturnedQue.u4NumElem));
2081 }
2082
2083
2084 /* TC5 (BMCAST or STA-NOT-FOUND packets) */
2085 qmDequeueTxPacketsFromPerTypeQueues(prAdapter,
2086 &rReturnedQue,
2087 TC5_INDEX, prTcqStatus->aucFreeBufferCount[TC5_INDEX]
2088 );
2089
2090 DBGLOG(QM, LOUD,
2091 ("Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem));
2092
2093 if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) {
2094 prReturnedPacketListHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rReturnedQue);
2095 QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rReturnedQue), NULL);
2096 }
2097
2098 return prReturnedPacketListHead;
2099 }
2100
2101 /*----------------------------------------------------------------------------*/
2102 /*!
2103 * \brief Adjust the TC quotas according to traffic demands
2104 *
2105 * \param[out] prTcqAdjust The resulting adjustment
2106 * \param[in] prTcqStatus Info about the current TC quotas and counters
2107 *
2108 * \return (none)
2109 */
2110 /*----------------------------------------------------------------------------*/
2111 VOID
2112 qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter,
2113 OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus)
2114 {
2115 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2116 UINT_32 i;
2117 P_QUE_MGT_T prQM = &prAdapter->rQM;
2118
2119 /* Must initialize */
2120 for (i = 0; i < TC_NUM; i++) {
2121 prTcqAdjust->acVariation[i] = 0;
2122 }
2123
2124 /* 4 <1> If TC resource is not just adjusted, exit directly */
2125 if (!prQM->fgTcResourcePostAnnealing) {
2126 return;
2127 }
2128 /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */
2129 else {
2130 INT_32 i4TotalExtraQuota = 0;
2131 INT_32 ai4ExtraQuota[TC_NUM];
2132 BOOLEAN fgResourceRedistributed = TRUE;
2133
2134 /* Obtain the free-to-distribute resource */
2135 for (i = 0; i < TC_NUM; i++) {
2136 ai4ExtraQuota[i] =
2137 (INT_32) prTcqStatus->aucMaxNumOfBuffer[i] -
2138 (INT_32) prQM->au4CurrentTcResource[i];
2139
2140 if (ai4ExtraQuota[i] > 0) { /* The resource shall be reallocated to other TCs */
2141 if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]) {
2142 ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i];
2143 fgResourceRedistributed = FALSE;
2144 }
2145
2146 i4TotalExtraQuota += ai4ExtraQuota[i];
2147 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2148 }
2149 }
2150
2151 /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */
2152 for (i = 0; i < TC_NUM; i++) {
2153 if (ai4ExtraQuota[i] < 0) {
2154 if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) {
2155 ai4ExtraQuota[i] = (-i4TotalExtraQuota);
2156 fgResourceRedistributed = FALSE;
2157 }
2158
2159 i4TotalExtraQuota += ai4ExtraQuota[i];
2160 prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]);
2161 }
2162 }
2163
2164 /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */
2165 prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed);
2166
2167 #if QM_PRINT_TC_RESOURCE_CTRL
2168 DBGLOG(QM, LOUD, ("QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n",
2169 prTcqStatus->aucFreeBufferCount[0],
2170 prTcqStatus->aucFreeBufferCount[1],
2171 prTcqStatus->aucFreeBufferCount[2],
2172 prTcqStatus->aucFreeBufferCount[3],
2173 prTcqStatus->aucFreeBufferCount[4],
2174 prTcqStatus->aucFreeBufferCount[5]
2175 ));
2176 #endif
2177 }
2178
2179 #else
2180 UINT_32 i;
2181 for (i = 0; i < TC_NUM; i++) {
2182 prTcqAdjust->acVariation[i] = 0;
2183 }
2184
2185 #endif
2186 }
2187
2188 #if QM_ADAPTIVE_TC_RESOURCE_CTRL
2189 /*----------------------------------------------------------------------------*/
2190 /*!
2191 * \brief Update the average TX queue length for the TC resource control mechanism
2192 *
2193 * \param (none)
2194 *
2195 * \return (none)
2196 */
2197 /*----------------------------------------------------------------------------*/
2198 VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter)
2199 {
2200 INT_32 u4CurrQueLen, i, k;
2201 P_STA_RECORD_T prStaRec;
2202 P_QUE_MGT_T prQM = &prAdapter->rQM;
2203
2204 /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ */
2205 for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++) {
2206 u4CurrQueLen = 0;
2207
2208 for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++) {
2209 prStaRec = &prAdapter->arStaRec[k];
2210 ASSERT(prStaRec);
2211
2212 /* If the STA is activated, get the queue length */
2213 if (prStaRec->fgIsValid &&
2214 (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent)
2215 ) {
2216
2217 u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem);
2218 }
2219 }
2220
2221 if (prQM->au4AverageQueLen[i] == 0) {
2222 prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR);
2223 } else {
2224 prQM->au4AverageQueLen[i] -=
2225 (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR);
2226 prQM->au4AverageQueLen[i] += (u4CurrQueLen);
2227 }
2228
2229 }
2230
2231 /* Update the queue length for TC5 (BMCAST) */
2232 u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem;
2233
2234 if (prQM->au4AverageQueLen[TC_NUM - 1] == 0) {
2235 prQM->au4AverageQueLen[TC_NUM - 1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR);
2236 } else {
2237 prQM->au4AverageQueLen[TC_NUM - 1] -=
2238 (prQM->au4AverageQueLen[TC_NUM - 1] >> QM_QUE_LEN_MOVING_AVE_FACTOR);
2239 prQM->au4AverageQueLen[TC_NUM - 1] += (u4CurrQueLen);
2240 }
2241
2242
2243 /* 4 <2> Adjust TC resource assignment */
2244 /* Check whether it is time to adjust the TC resource assignment */
2245 if (--prQM->u4TimeToAdjustTcResource == 0) {
2246 /* The last assignment has not been completely applied */
2247 if (prQM->fgTcResourcePostAnnealing) {
2248 /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */
2249 prQM->u4TimeToAdjustTcResource = 1;
2250 }
2251
2252 /* The last assignment has been applied */
2253 else {
2254 prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC;
2255 qmReassignTcResource(prAdapter);
2256 }
2257 }
2258
2259 /* Debug */
2260 #if QM_PRINT_TC_RESOURCE_CTRL
2261 for (i = 0; i < TC_NUM; i++) {
2262 if (QM_GET_TX_QUEUE_LEN(prAdapter, i) >= 100) {
2263 DBGLOG(QM, LOUD, ("QM: QueLen [%ld %ld %ld %ld %ld %ld]\n",
2264 QM_GET_TX_QUEUE_LEN(prAdapter, 0),
2265 QM_GET_TX_QUEUE_LEN(prAdapter, 1),
2266 QM_GET_TX_QUEUE_LEN(prAdapter, 2),
2267 QM_GET_TX_QUEUE_LEN(prAdapter, 3),
2268 QM_GET_TX_QUEUE_LEN(prAdapter, 4),
2269 QM_GET_TX_QUEUE_LEN(prAdapter, 5)
2270 ));
2271 break;
2272 }
2273 }
2274 #endif
2275
2276 }
2277
2278
2279
2280 /*----------------------------------------------------------------------------*/
2281 /*!
2282 * \brief Assign TX resource for each TC according to TX queue length and current assignment
2283 *
2284 * \param (none)
2285 *
2286 * \return (none)
2287 */
2288 /*----------------------------------------------------------------------------*/
2289 VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter)
2290 {
2291 INT_32 i4TotalResourceDemand = 0;
2292 UINT_32 u4ResidualResource = 0;
2293 UINT_32 i;
2294 INT_32 ai4PerTcResourceDemand[TC_NUM];
2295 UINT_32 u4ShareCount = 0;
2296 UINT_32 u4Share = 0;
2297 P_QUE_MGT_T prQM = &prAdapter->rQM;
2298
2299 /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to
2300 * start the TC-quota adjusting procedure, which will be invoked upon every TX Done
2301 */
2302
2303 /* 4 <1> Determine the demands */
2304 /* Determine the amount of extra resource to fulfill all of the demands */
2305 for (i = 0; i < TC_NUM; i++) {
2306 /* Skip TC4, which is not adjustable */
2307 if (i == TC4_INDEX) {
2308 continue;
2309 }
2310
2311 /* Define: extra_demand = que_length + min_reserved_quota - current_quota */
2312 ai4PerTcResourceDemand[i] =
2313 ((UINT_32) (QM_GET_TX_QUEUE_LEN(prAdapter, i)) +
2314 prQM->au4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]);
2315
2316 /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */
2317 if (QM_GET_TX_QUEUE_LEN(prAdapter, i)) {
2318 ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY;
2319 }
2320
2321 i4TotalResourceDemand += ai4PerTcResourceDemand[i];
2322 }
2323
2324 /* 4 <2> Case 1: Demand <= Total Resource */
2325 if (i4TotalResourceDemand <= 0) {
2326 /* 4 <2.1> Satisfy every TC */
2327 for (i = 0; i < TC_NUM; i++) {
2328 /* Skip TC4 (not adjustable) */
2329 if (i == TC4_INDEX) {
2330 continue;
2331 }
2332
2333 prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i];
2334 }
2335
2336 /* 4 <2.2> Share the residual resource evenly */
2337 u4ShareCount = (TC_NUM - 1); /* excluding TC4 */
2338 u4ResidualResource = (UINT_32) (-i4TotalResourceDemand);
2339 u4Share = (u4ResidualResource / u4ShareCount);
2340
2341 for (i = 0; i < TC_NUM; i++) {
2342 /* Skip TC4 (not adjustable) */
2343 if (i == TC4_INDEX) {
2344 continue;
2345 }
2346
2347 prQM->au4CurrentTcResource[i] += u4Share;
2348
2349 /* Every TC is fully satisfied */
2350 ai4PerTcResourceDemand[i] = 0;
2351
2352 /* The left resource will be allocated to TC3 */
2353 u4ResidualResource -= u4Share;
2354 }
2355
2356 /* 4 <2.3> Allocate the left resource to TC3 (VO) */
2357 prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource);
2358
2359 }
2360 /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */
2361 else {
2362 u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE;
2363
2364 /* 4 <3.1> Allocated resouce amount = minimum of (guaranteed, total demand) */
2365 for (i = 0; i < TC_NUM; i++) {
2366 /* Skip TC4 (not adjustable) */
2367 if (i == TC4_INDEX) {
2368 continue;
2369 }
2370
2371 /* The demand can be fulfilled with the guaranteed resource amount */
2372 if (prQM->au4CurrentTcResource[i] + ai4PerTcResourceDemand[i] <
2373 prQM->au4GuaranteedTcResource[i]) {
2374 prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i];
2375 u4ResidualResource +=
2376 (prQM->au4GuaranteedTcResource[i] -
2377 prQM->au4CurrentTcResource[i]);
2378 ai4PerTcResourceDemand[i] = 0;
2379 }
2380
2381 /* The demand can not be fulfilled with the guaranteed resource amount */
2382 else {
2383 ai4PerTcResourceDemand[i] -=
2384 (prQM->au4GuaranteedTcResource[i] -
2385 prQM->au4CurrentTcResource[i]);
2386 prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i];
2387 u4ShareCount++;
2388 }
2389 }
2390
2391 /* 4 <3.2> Allocate the residual resource */
2392 do {
2393 /* If there is no resource left, exit directly */
2394 if (u4ResidualResource == 0) {
2395 break;
2396 }
2397
2398 /* This shall not happen */
2399 if (u4ShareCount == 0) {
2400 prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource;
2401 DBGLOG(QM, ERROR, ("QM: (Error) u4ShareCount = 0\n"));
2402 break;
2403 }
2404
2405 /* Share the residual resource evenly */
2406 u4Share = (u4ResidualResource / u4ShareCount);
2407 if (u4Share) {
2408 for (i = 0; i < TC_NUM; i++) {
2409 /* Skip TC4 (not adjustable) */
2410 if (i == TC4_INDEX) {
2411 continue;
2412 }
2413
2414 if (ai4PerTcResourceDemand[i]) {
2415 if (ai4PerTcResourceDemand[i] - u4Share) {
2416 prQM->au4CurrentTcResource[i] += u4Share;
2417 u4ResidualResource -= u4Share;
2418 ai4PerTcResourceDemand[i] -= u4Share;
2419 } else {
2420 prQM->au4CurrentTcResource[i] +=
2421 ai4PerTcResourceDemand[i];
2422 u4ResidualResource -=
2423 ai4PerTcResourceDemand[i];
2424 ai4PerTcResourceDemand[i] = 0;
2425 }
2426 }
2427 }
2428 }
2429
2430 /* By priority, allocate the left resource that is not divisible by u4Share */
2431 if (u4ResidualResource == 0) {
2432 break;
2433 }
2434
2435 if (ai4PerTcResourceDemand[TC3_INDEX]) { /* VO */
2436 prQM->au4CurrentTcResource[TC3_INDEX]++;
2437 if (--u4ResidualResource == 0) {
2438 break;
2439 }
2440 }
2441
2442 if (ai4PerTcResourceDemand[TC2_INDEX]) { /* VI */
2443 prQM->au4CurrentTcResource[TC2_INDEX]++;
2444 if (--u4ResidualResource == 0) {
2445 break;
2446 }
2447 }
2448
2449 if (ai4PerTcResourceDemand[TC5_INDEX]) { /* BMCAST */
2450 prQM->au4CurrentTcResource[TC5_INDEX]++;
2451 if (--u4ResidualResource == 0) {
2452 break;
2453 }
2454 }
2455
2456 if (ai4PerTcResourceDemand[TC1_INDEX]) { /* BE */
2457 prQM->au4CurrentTcResource[TC1_INDEX]++;
2458 if (--u4ResidualResource == 0) {
2459 break;
2460 }
2461 }
2462
2463 if (ai4PerTcResourceDemand[TC0_INDEX]) { /* BK */
2464 prQM->au4CurrentTcResource[TC0_INDEX]++;
2465 if (--u4ResidualResource == 0) {
2466 break;
2467 }
2468 }
2469
2470 /* Allocate the left resource */
2471 prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource;
2472
2473 } while (FALSE);
2474 }
2475
2476 prQM->fgTcResourcePostAnnealing = TRUE;
2477
2478 #if QM_PRINT_TC_RESOURCE_CTRL
2479 /* Debug print */
2480 DBGLOG(QM, LOUD, ("QM: TC Rsc %ld %ld %ld %ld %ld %ld\n",
2481 prQM->au4CurrentTcResource[0],
2482 prQM->au4CurrentTcResource[1],
2483 prQM->au4CurrentTcResource[2],
2484 prQM->au4CurrentTcResource[3],
2485 prQM->au4CurrentTcResource[4], prQM->au4CurrentTcResource[5]
2486 ));
2487 #endif
2488
2489 }
2490
2491 #endif
2492
2493
2494 /*----------------------------------------------------------------------------*/
2495 /* RX-Related Queue Management */
2496 /*----------------------------------------------------------------------------*/
2497 /*----------------------------------------------------------------------------*/
2498 /*!
2499 * \brief Init Queue Managment for RX
2500 *
2501 * \param[in] (none)
2502 *
2503 * \return (none)
2504 */
2505 /*----------------------------------------------------------------------------*/
2506 VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter)
2507 {
2508 /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */
2509 /* TODO */
2510 }
2511
2512 /*----------------------------------------------------------------------------*/
2513 /*!
2514 * \brief Handle RX packets (buffer reordering)
2515 *
2516 * \param[in] prSwRfbListHead The list of RX packets
2517 *
2518 * \return The list of packets which are not buffered for reordering
2519 */
2520 /*----------------------------------------------------------------------------*/
2521 P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead)
2522 {
2523
2524 #if CFG_RX_REORDERING_ENABLED
2525 /* UINT_32 i; */
2526 P_SW_RFB_T prCurrSwRfb;
2527 P_SW_RFB_T prNextSwRfb;
2528 P_HIF_RX_HEADER_T prHifRxHdr;
2529 QUE_T rReturnedQue;
2530 PUINT_8 pucEthDestAddr;
2531 BOOLEAN fgIsBMC;
2532
2533 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
2534
2535 DEBUGFUNC("qmHandleRxPackets");
2536
2537 ASSERT(prSwRfbListHead);
2538
2539 QUEUE_INITIALIZE(&rReturnedQue);
2540 prNextSwRfb = prSwRfbListHead;
2541
2542 do {
2543 prCurrSwRfb = prNextSwRfb;
2544 prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb);
2545
2546 prHifRxHdr = prCurrSwRfb->prHifRxHdr; /* TODO: (Tehuang) Use macro to obtain the pointer */
2547
2548 /* TODO: (Tehuang) Check if relaying */
2549 prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST;
2550
2551 /* Decide the Destination */
2552 #if CFG_RX_PKTS_DUMP
2553 if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) {
2554 DBGLOG(SW4, INFO, ("QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), prHifRxHdr->ucStaRecIdx, prCurrSwRfb->ucWlanIdx, HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */
2555 HIF_RX_HDR_GET_TID(prHifRxHdr),
2556 prCurrSwRfb->ucPacketType,
2557 HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)));
2558
2559 DBGLOG_MEM8(SW4, TRACE, (PUINT_8) prCurrSwRfb->pvHeader,
2560 prCurrSwRfb->u2PacketLen);
2561 }
2562 #endif
2563
2564 fgIsBMC = FALSE;
2565 if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) {
2566
2567 UINT_8 ucNetTypeIdx;
2568 P_BSS_INFO_T prBssInfo;
2569
2570 pucEthDestAddr = prCurrSwRfb->pvHeader;
2571 ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr);
2572
2573 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]);
2574 /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */
2575 /* */
2576
2577 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)
2578 && (OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) {
2579 fgIsBMC = TRUE;
2580 }
2581
2582 if (prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem
2583 > (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM)) {
2584
2585 if (IS_BSS_ACTIVE(prBssInfo)) {
2586 if (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) {
2587 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) {
2588 prCurrSwRfb->eDst =
2589 RX_PKT_DESTINATION_HOST_WITH_FORWARD;
2590 } else
2591 if (UNEQUAL_MAC_ADDR
2592 (prBssInfo->aucOwnMacAddr,
2593 pucEthDestAddr)) {
2594 prCurrSwRfb->eDst =
2595 RX_PKT_DESTINATION_FORWARD;
2596 /* TODO : need to check the dst mac is valid */
2597 /* If src mac is invalid, the packet will be freed in fw */
2598 }
2599 } /* OP_MODE_ACCESS_POINT */
2600 } else {
2601 DBGLOG(QM, TRACE,
2602 ("Mark NULL the Packet for inactive Bss %u\n",
2603 ucNetTypeIdx));
2604 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2605 QUEUE_INSERT_TAIL(&rReturnedQue,
2606 (P_QUE_ENTRY_T) prCurrSwRfb);
2607 continue;
2608 }
2609
2610 } else {
2611 /* Dont not occupy other SW RFB */
2612 DBGLOG(QM, TRACE, ("Mark NULL the Packet for less Free Sw Rfb\n"));
2613 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2614 QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
2615 continue;
2616 }
2617
2618 }
2619
2620 /* BAR frame */
2621 if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) {
2622 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2623 qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue);
2624 }
2625 /* Reordering is not required for this packet, return it without buffering */
2626 else if (!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr) || fgIsBMC) {
2627 #if 0
2628 if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) {
2629 UINT_8 ucNetTypeIdx;
2630 P_BSS_INFO_T prBssInfo;
2631
2632 pucEthDestAddr = prCurrSwRfb->pvHeader;
2633 ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr);
2634
2635 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]);
2636
2637 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)
2638 && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)) {
2639 prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD;
2640 }
2641 }
2642 #endif
2643 QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
2644 }
2645 /* Reordering is required for this packet */
2646 else {
2647 /* If this packet should dropped or indicated to the host immediately,
2648 * it should be enqueued into the rReturnedQue with specific flags. If
2649 * this packet should be buffered for reordering, it should be enqueued
2650 * into the reordering queue in the STA_REC rather than into the
2651 * rReturnedQue.
2652 */
2653 qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue);
2654
2655 }
2656 } while (prNextSwRfb);
2657
2658
2659 /* The returned list of SW_RFBs must end with a NULL pointer */
2660 if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) {
2661 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(&rReturnedQue), NULL);
2662 }
2663
2664 return (P_SW_RFB_T) QUEUE_GET_HEAD(&rReturnedQue);
2665
2666 #else
2667
2668 /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
2669 return prSwRfbListHead;
2670
2671 #endif
2672
2673 }
2674
2675 /*----------------------------------------------------------------------------*/
2676 /*!
2677 * \brief Reorder the received packet
2678 *
2679 * \param[in] prSwRfb The RX packet to process
2680 * \param[out] prReturnedQue The queue for indicating packets
2681 *
2682 * \return (none)
2683 */
2684 /*----------------------------------------------------------------------------*/
2685 VOID
2686 qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter,
2687 IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
2688 {
2689
2690
2691 P_STA_RECORD_T prStaRec;
2692 P_HIF_RX_HEADER_T prHifRxHdr;
2693 P_RX_BA_ENTRY_T prReorderQueParm;
2694
2695 UINT_32 u4SeqNo;
2696 UINT_32 u4WinStart;
2697 UINT_32 u4WinEnd;
2698 P_QUE_T prReorderQue;
2699 /* P_SW_RFB_T prReorderedSwRfb; */
2700
2701 DEBUGFUNC("qmProcessPktWithReordering");
2702
2703 ASSERT(prSwRfb);
2704 ASSERT(prReturnedQue);
2705 ASSERT(prSwRfb->prHifRxHdr);
2706
2707 prHifRxHdr = prSwRfb->prHifRxHdr;
2708 prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
2709 prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */
2710 prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr));
2711 /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
2712
2713 /* Incorrect STA_REC index */
2714 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
2715 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2716 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2717 DBGLOG(QM, WARN, ("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
2718 prSwRfb->ucStaRecIdx));
2719 /* ASSERT(0); */
2720 return;
2721 }
2722
2723 /* Check whether the STA_REC is activated */
2724 prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
2725 ASSERT(prStaRec);
2726
2727 #if 0
2728 if (!(prStaRec->fgIsValid)) {
2729 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2730 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2731 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2732 DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC\n"));
2733 /* ASSERT(0); */
2734 return;
2735 }
2736 #endif
2737
2738 /* Check whether the BA agreement exists */
2739 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
2740 if (!prReorderQueParm) {
2741 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2742 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2743 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2744 DBGLOG(QM, WARN, ("Reordering for a NULL ReorderQueParm\n"));
2745 /* ASSERT(0); */
2746 return;
2747 }
2748
2749
2750
2751 /* Start to reorder packets */
2752 u4SeqNo = (UINT_32) (prSwRfb->u2SSN);
2753 prReorderQue = &(prReorderQueParm->rReOrderQue);
2754 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
2755 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
2756
2757 /* Debug */
2758 /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2759
2760 /* Case 1: Fall within */
2761 if /* 0 - start - sn - end - 4095 */
2762 (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd))
2763 /* 0 - end - start - sn - 4095 */
2764 || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo))
2765 /* 0 - sn - end - start - 4095 */
2766 || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) {
2767
2768 qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
2769
2770 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2771 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
2772 /* Let the first received packet pass the reorder check */
2773 DBGLOG(QM, LOUD,
2774 ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart,
2775 u4WinEnd));
2776
2777 prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo;
2778 prReorderQueParm->u2WinEnd =
2779 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
2780 1) % MAX_SEQ_NO_COUNT;
2781 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
2782 }
2783 #endif
2784
2785
2786 qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue);
2787 }
2788 /* Case 2: Fall ahead */
2789 else if
2790 /* 0 - start - end - sn - (start+2048) - 4095 */
2791 (((u4WinStart < u4WinEnd)
2792 && (u4WinEnd < u4SeqNo)
2793 && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT)))
2794 /* 0 - sn - (start+2048) - start - end - 4095 */
2795 || ((u4SeqNo < u4WinStart)
2796 && (u4WinStart < u4WinEnd)
2797 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))
2798 /* 0 - end - sn - (start+2048) - start - 4095 */
2799 || ((u4WinEnd < u4SeqNo)
2800 && (u4SeqNo < u4WinStart)
2801 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) {
2802
2803
2804 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2805 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
2806 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
2807 }
2808 #endif
2809
2810 qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
2811
2812 /* Advance the window after inserting a new tail */
2813 prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo;
2814 prReorderQueParm->u2WinStart =
2815 (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) +
2816 MAX_SEQ_NO_COUNT + 1)
2817 % MAX_SEQ_NO_COUNT);
2818
2819 qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
2820
2821 }
2822 /* Case 3: Fall behind */
2823 else {
2824
2825 #if QM_RX_WIN_SSN_AUTO_ADVANCING
2826 #if QM_RX_INIT_FALL_BEHIND_PASS
2827 if (prReorderQueParm->fgIsWaitingForPktWithSsn) {
2828 /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */
2829 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2830 /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2831 return;
2832 }
2833 #endif
2834 #endif
2835
2836 /* An erroneous packet */
2837 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2838 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2839 /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */
2840 return;
2841 }
2842
2843 return;
2844
2845 }
2846
2847
2848 VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue)
2849 {
2850
2851 P_STA_RECORD_T prStaRec;
2852 P_HIF_RX_HEADER_T prHifRxHdr;
2853 P_RX_BA_ENTRY_T prReorderQueParm;
2854
2855 UINT_32 u4SSN;
2856 UINT_32 u4WinStart;
2857 UINT_32 u4WinEnd;
2858 P_QUE_T prReorderQue;
2859 /* P_SW_RFB_T prReorderedSwRfb; */
2860
2861 ASSERT(prSwRfb);
2862 ASSERT(prReturnedQue);
2863 ASSERT(prSwRfb->prHifRxHdr);
2864
2865 prHifRxHdr = prSwRfb->prHifRxHdr;
2866 prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
2867 prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */
2868 prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr));
2869
2870 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2871 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2872
2873 /* Incorrect STA_REC index */
2874 if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
2875 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
2876 prSwRfb->ucStaRecIdx));
2877 /* ASSERT(0); */
2878 return;
2879 }
2880
2881 /* Check whether the STA_REC is activated */
2882 prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
2883 ASSERT(prStaRec);
2884
2885 #if 0
2886 if (!(prStaRec->fgIsValid)) {
2887 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2888 DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n");
2889 /* ASSERT(0); */
2890 return;
2891 }
2892 #endif
2893
2894 /* Check whether the BA agreement exists */
2895 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
2896 if (!prReorderQueParm) {
2897 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
2898 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm\n"));
2899 /* ASSERT(0); */
2900 return;
2901 }
2902
2903
2904 u4SSN = (UINT_32) (prSwRfb->u2SSN);
2905 prReorderQue = &(prReorderQueParm->rReOrderQue);
2906 u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart);
2907 u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd);
2908
2909 if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) {
2910 prReorderQueParm->u2WinStart = (UINT_16) u4SSN;
2911 prReorderQueParm->u2WinEnd =
2912 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
2913 1) % MAX_SEQ_NO_COUNT;
2914 DBGLOG(QM, TRACE,
2915 ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, u4SSN,
2916 prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
2917 qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
2918 } else {
2919 DBGLOG(QM, TRACE,
2920 ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SSN, u4WinStart,
2921 u4WinEnd));
2922 }
2923 }
2924
2925
2926
2927 VOID
2928 qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb,
2929 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
2930 {
2931 P_SW_RFB_T prExaminedQueuedSwRfb;
2932 P_QUE_T prReorderQue;
2933 ASSERT(prSwRfb);
2934 ASSERT(prReorderQueParm);
2935 ASSERT(prReturnedQue);
2936
2937 prReorderQue = &(prReorderQueParm->rReOrderQue);
2938 prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
2939
2940 /* There are no packets queued in the Reorder Queue */
2941 if (prExaminedQueuedSwRfb == NULL) {
2942 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
2943 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
2944 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
2945 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
2946 prReorderQue->u4NumElem++;
2947 }
2948
2949 /* Determine the insert position */
2950 else {
2951 do {
2952 /* Case 1: Terminate. A duplicate packet */
2953 if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) {
2954 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2955 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb);
2956 return;
2957 }
2958
2959 /* Case 2: Terminate. The insert point is found */
2960 else if (qmCompareSnIsLessThan((prSwRfb->u2SSN),
2961 (prExaminedQueuedSwRfb->u2SSN))) {
2962 break;
2963 }
2964
2965 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
2966 else {
2967 prExaminedQueuedSwRfb =
2968 (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext);
2969 }
2970 } while (prExaminedQueuedSwRfb);
2971
2972 /* Update the Reorder Queue Parameters according to the found insert position */
2973 if (prExaminedQueuedSwRfb == NULL) {
2974 /* The received packet shall be placed at the tail */
2975 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
2976 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
2977 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
2978 prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb);
2979 } else {
2980 ((P_QUE_ENTRY_T) prSwRfb)->prPrev =
2981 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev;
2982 ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb;
2983 if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) {
2984 /* The received packet will become the head */
2985 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
2986 } else {
2987 (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext =
2988 (P_QUE_ENTRY_T) prSwRfb;
2989 }
2990 ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb;
2991 }
2992
2993 prReorderQue->u4NumElem++;
2994
2995 }
2996
2997 }
2998
2999
3000 VOID
3001 qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb,
3002 IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3003 {
3004 P_QUE_T prReorderQue;
3005 ASSERT(prSwRfb);
3006 ASSERT(prReorderQueParm);
3007 ASSERT(prReturnedQue);
3008
3009 prReorderQue = &(prReorderQueParm->rReOrderQue);
3010
3011 /* There are no packets queued in the Reorder Queue */
3012 if (QUEUE_IS_EMPTY(prReorderQue)) {
3013 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL;
3014 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3015 prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb;
3016 } else {
3017 ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail;
3018 ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL;
3019 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb);
3020 }
3021 prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb;
3022 prReorderQue->u4NumElem++;
3023
3024 }
3025
3026
3027 VOID qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3028 {
3029 P_SW_RFB_T prReorderedSwRfb;
3030 P_QUE_T prReorderQue;
3031 BOOLEAN fgDequeuHead, fgMissing;
3032 OS_SYSTIME rCurrentTime, *prMissTimeout;
3033
3034 prReorderQue = &(prReorderQueParm->rReOrderQue);
3035
3036 fgMissing = FALSE;
3037 rCurrentTime = 0;
3038 prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]);
3039 if ((*prMissTimeout)) {
3040 fgMissing = TRUE;
3041 GET_CURRENT_SYSTIME(&rCurrentTime);
3042 }
3043
3044 /* Check whether any packet can be indicated to the higher layer */
3045 while (TRUE) {
3046 if (QUEUE_IS_EMPTY(prReorderQue)) {
3047 break;
3048 }
3049
3050 /* Always examine the head packet */
3051 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3052 fgDequeuHead = FALSE;
3053
3054 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3055 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3056
3057 fgDequeuHead = TRUE;
3058 prReorderQueParm->u2WinStart =
3059 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3060 }
3061 /* SN > WinStart, break to update WinEnd */
3062 else {
3063 if ((fgMissing == TRUE) &&
3064 CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout),
3065 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3066 DBGLOG(QM, TRACE,
3067 ("QM:RX BA Timout Next Tid %d SSN %d\n",
3068 prReorderQueParm->ucTid, prReorderedSwRfb->u2SSN));
3069 fgDequeuHead = TRUE;
3070 prReorderQueParm->u2WinStart =
3071 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3072
3073 fgMissing = FALSE;
3074 } else
3075 break;
3076 }
3077
3078
3079 /* Dequeue the head packet */
3080 if (fgDequeuHead) {
3081
3082 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3083 prReorderQue->prHead = NULL;
3084 prReorderQue->prTail = NULL;
3085 } else {
3086 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3087 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3088 }
3089 prReorderQue->u4NumElem--;
3090 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3091 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3092 }
3093 }
3094
3095 if (QUEUE_IS_EMPTY(prReorderQue)) {
3096 *prMissTimeout = 0;
3097 } else {
3098 if (fgMissing == FALSE) {
3099 GET_CURRENT_SYSTIME(prMissTimeout);
3100 }
3101 }
3102
3103 /* After WinStart has been determined, update the WinEnd */
3104 prReorderQueParm->u2WinEnd =
3105 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3106 1) % MAX_SEQ_NO_COUNT);
3107
3108 }
3109
3110 VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue)
3111 {
3112 P_SW_RFB_T prReorderedSwRfb;
3113 P_QUE_T prReorderQue;
3114 BOOLEAN fgDequeuHead;
3115
3116 prReorderQue = &(prReorderQueParm->rReOrderQue);
3117
3118 /* Check whether any packet can be indicated to the higher layer */
3119 while (TRUE) {
3120 if (QUEUE_IS_EMPTY(prReorderQue)) {
3121 break;
3122 }
3123
3124 /* Always examine the head packet */
3125 prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue);
3126 fgDequeuHead = FALSE;
3127
3128 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3129 if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) {
3130
3131 fgDequeuHead = TRUE;
3132 prReorderQueParm->u2WinStart =
3133 (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT);
3134 }
3135
3136 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3137 else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN),
3138 (UINT_32) (prReorderQueParm->u2WinStart))) {
3139
3140 fgDequeuHead = TRUE;
3141
3142 }
3143
3144 /* SN > WinStart, break to update WinEnd */
3145 else {
3146 break;
3147 }
3148
3149
3150 /* Dequeue the head packet */
3151 if (fgDequeuHead) {
3152
3153 if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) {
3154 prReorderQue->prHead = NULL;
3155 prReorderQue->prTail = NULL;
3156 } else {
3157 prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext;
3158 (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL;
3159 }
3160 prReorderQue->u4NumElem--;
3161 /* DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */
3162 QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb);
3163 }
3164 }
3165
3166 /* After WinStart has been determined, update the WinEnd */
3167 prReorderQueParm->u2WinEnd =
3168 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -
3169 1) % MAX_SEQ_NO_COUNT);
3170
3171 }
3172
3173 BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater)
3174 {
3175 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
3176 if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) { /* Shall be <= */
3177 return FALSE;
3178 }
3179
3180 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
3181 else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) {
3182 return TRUE;
3183 }
3184
3185 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
3186 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
3187 else {
3188 return (u4SnLess < u4SnGreater);
3189 }
3190 }
3191
3192
3193 /*----------------------------------------------------------------------------*/
3194 /*!
3195 * \brief Handle Mailbox RX messages
3196 *
3197 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
3198 *
3199 * \return (none)
3200 */
3201 /*----------------------------------------------------------------------------*/
3202 VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg)
3203 {
3204 /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */
3205 /* TODO */
3206 }
3207
3208
3209 /*----------------------------------------------------------------------------*/
3210 /*!
3211 * \brief Handle ADD RX BA Event from the FW
3212 *
3213 * \param[in] prAdapter Adapter pointer
3214 * \param[in] prEvent The event packet from the FW
3215 *
3216 * \return (none)
3217 */
3218 /*----------------------------------------------------------------------------*/
3219 VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
3220 {
3221 P_EVENT_RX_ADDBA_T prEventRxAddBa;
3222 P_STA_RECORD_T prStaRec;
3223 UINT_32 u4Tid;
3224 UINT_32 u4WinSize;
3225
3226 DBGLOG(QM, INFO, ("QM:Event +RxBa\n"));
3227
3228 prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent;
3229 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx);
3230
3231 if (!prStaRec) {
3232 /* Invalid STA_REC index, discard the event packet */
3233 /* ASSERT(0); */
3234 DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
3235 return;
3236 }
3237 #if 0
3238 if (!(prStaRec->fgIsValid)) {
3239 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3240 DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
3241 /* ASSERT(0); */
3242 /* return; */
3243 }
3244 #endif
3245
3246 u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK)
3247 >> BA_PARAM_SET_TID_MASK_OFFSET);
3248
3249 u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK)
3250 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
3251
3252 if (!qmAddRxBaEntry(prAdapter,
3253 prStaRec->ucIndex,
3254 (UINT_8) u4Tid,
3255 (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN),
3256 (UINT_16) u4WinSize)) {
3257
3258 /* FW shall ensure the availabiilty of the free-to-use BA entry */
3259 DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n"));
3260 ASSERT(0);
3261 }
3262
3263 }
3264
3265 /*----------------------------------------------------------------------------*/
3266 /*!
3267 * \brief Handle DEL RX BA Event from the FW
3268 *
3269 * \param[in] prAdapter Adapter pointer
3270 * \param[in] prEvent The event packet from the FW
3271 *
3272 * \return (none)
3273 */
3274 /*----------------------------------------------------------------------------*/
3275 VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
3276 {
3277 P_EVENT_RX_DELBA_T prEventRxDelBa;
3278 P_STA_RECORD_T prStaRec;
3279
3280 /* DbgPrint("QM:Event -RxBa\n"); */
3281
3282 prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent;
3283 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx);
3284
3285 if (!prStaRec) {
3286 /* Invalid STA_REC index, discard the event packet */
3287 /* ASSERT(0); */
3288 return;
3289 }
3290 #if 0
3291 if (!(prStaRec->fgIsValid)) {
3292 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3293 /* ASSERT(0); */
3294 return;
3295 }
3296 #endif
3297
3298 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE);
3299
3300 }
3301
3302 P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid)
3303 {
3304 int i;
3305 P_QUE_MGT_T prQM = &prAdapter->rQM;
3306
3307 /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */
3308
3309 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
3310 if (prQM->arRxBaTable[i].fgIsValid) {
3311 if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) &&
3312 (prQM->arRxBaTable[i].ucTid == ucTid)) {
3313 return &prQM->arRxBaTable[i];
3314 }
3315 }
3316 }
3317 return NULL;
3318 }
3319
3320 BOOL
3321 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter,
3322 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize)
3323 {
3324 int i;
3325 P_RX_BA_ENTRY_T prRxBaEntry = NULL;
3326 P_STA_RECORD_T prStaRec;
3327 P_QUE_MGT_T prQM = &prAdapter->rQM;
3328
3329 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3330
3331 if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) {
3332 /* Invalid STA_REC index, discard the event packet */
3333 DBGLOG(QM, WARN,
3334 ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n",
3335 ucStaRecIdx));
3336 return FALSE;
3337 }
3338
3339 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3340 ASSERT(prStaRec);
3341
3342 /* if(!(prStaRec->fgIsValid)){ */
3343 /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */
3344 /* return FALSE; */
3345 /* } */
3346
3347 /* 4 <1> Delete before adding */
3348 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3349 if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) {
3350 qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */
3351 }
3352 /* 4 <2> Add a new BA entry */
3353 /* No available entry to store the BA agreement info. Retrun FALSE. */
3354 if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) {
3355 DBGLOG(QM, ERROR,
3356 ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3357 return FALSE;
3358 } else {
3359 /* Find the free-to-use BA entry */
3360 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
3361 if (!prQM->arRxBaTable[i].fgIsValid) {
3362 prRxBaEntry = &(prQM->arRxBaTable[i]);
3363 prQM->ucRxBaCount++;
3364 DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount));
3365 break;
3366 }
3367 }
3368
3369 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
3370 u2WinSize += CFG_RX_BA_INC_SIZE;
3371 if (prRxBaEntry) {
3372 prRxBaEntry->ucStaRecIdx = ucStaRecIdx;
3373 prRxBaEntry->ucTid = ucTid;
3374 prRxBaEntry->u2WinStart = u2WinStart;
3375 prRxBaEntry->u2WinSize = u2WinSize;
3376 prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT);
3377 prRxBaEntry->fgIsValid = TRUE;
3378 prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE;
3379
3380 g_arMissTimeout[ucStaRecIdx][ucTid] = 0;
3381
3382 DBGLOG(QM, INFO,
3383 ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
3384 ucStaRecIdx, ucTid, prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd,
3385 prRxBaEntry->u2WinSize));
3386
3387 /* Update the BA entry reference table for per-packet lookup */
3388 prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry;
3389 } else {
3390 /* This shall not happen because FW should keep track of the usage of RX BA entries */
3391 DBGLOG(QM, ERROR,
3392 ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3393 return FALSE;
3394 }
3395 }
3396
3397 return TRUE;
3398 }
3399
3400 VOID
3401 qmDelRxBaEntry(IN P_ADAPTER_T prAdapter,
3402 IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost)
3403 {
3404 P_RX_BA_ENTRY_T prRxBaEntry;
3405 P_STA_RECORD_T prStaRec;
3406 P_SW_RFB_T prFlushedPacketList = NULL;
3407 P_QUE_MGT_T prQM = &prAdapter->rQM;
3408
3409 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3410
3411 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3412 ASSERT(prStaRec);
3413
3414 #if 0
3415 if (!(prStaRec->fgIsValid)) {
3416 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n");
3417 return;
3418 }
3419 #endif
3420
3421 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3422 prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid];
3423
3424 if (prRxBaEntry) {
3425
3426 prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid);
3427
3428 if (prFlushedPacketList) {
3429
3430 if (fgFlushToHost) {
3431 wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList);
3432 } else {
3433
3434 P_SW_RFB_T prSwRfb;
3435 P_SW_RFB_T prNextSwRfb;
3436 prSwRfb = prFlushedPacketList;
3437
3438 do {
3439 prNextSwRfb =
3440 (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)
3441 prSwRfb);
3442 nicRxReturnRFB(prAdapter, prSwRfb);
3443 prSwRfb = prNextSwRfb;
3444 } while (prSwRfb);
3445
3446 }
3447
3448
3449 }
3450 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
3451 /* Update RX BA entry state. Note that RX queue flush is not done here */
3452 prRxBaEntry->fgIsValid = FALSE;
3453 prQM->ucRxBaCount--;
3454
3455 /* Debug */
3456 #if 0
3457 DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount);
3458 #endif
3459
3460 /* Update STA RX BA table */
3461 prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL;
3462 #endif
3463
3464 DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid));
3465
3466 }
3467
3468
3469 /* Debug */
3470 #if CFG_HIF_RX_STARVATION_WARNING
3471 {
3472 P_RX_CTRL_T prRxCtrl;
3473 prRxCtrl = &prAdapter->rRxCtrl;
3474 DBGLOG(QM, TRACE,
3475 ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt,
3476 prRxCtrl->u4DequeuedCnt));
3477 }
3478 #endif
3479 }
3480
3481
3482 /*----------------------------------------------------------------------------*/
3483 /*!
3484 * \brief To process WMM related IEs in ASSOC_RSP
3485 *
3486 * \param[in] prAdapter Adapter pointer
3487 * \param[in] prSwRfb The received frame
3488 * \param[in] pucIE The pointer to the first IE in the frame
3489 * \param[in] u2IELength The total length of IEs in the frame
3490 *
3491 * \return none
3492 */
3493 /*----------------------------------------------------------------------------*/
3494 VOID
3495 mqmProcessAssocReq(IN P_ADAPTER_T prAdapter,
3496 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
3497 {
3498 P_STA_RECORD_T prStaRec;
3499 UINT_16 u2Offset;
3500 PUINT_8 pucIEStart;
3501 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3502 P_IE_WMM_INFO_T prIeWmmInfo;
3503
3504 DEBUGFUNC("mqmProcessAssocReq");
3505
3506 ASSERT(prSwRfb);
3507 ASSERT(pucIE);
3508
3509 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3510 ASSERT(prStaRec);
3511
3512 if (prStaRec == NULL) {
3513 return;
3514 }
3515
3516 prStaRec->fgIsQoS = FALSE;
3517 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
3518
3519 pucIEStart = pucIE;
3520
3521 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
3522 if (!prAdapter->rWifiVar.fgSupportQoS) {
3523 return;
3524 }
3525
3526
3527 /* Determine whether QoS is enabled with the association */
3528 else {
3529 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3530 switch (IE_ID(pucIE)) {
3531 case ELEM_ID_WMM:
3532
3533 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3534 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
3535
3536 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
3537 case VENDOR_OUI_SUBTYPE_WMM_INFO:
3538 {
3539
3540 UINT_8 ucQosInfo;
3541 UINT_8 ucQosInfoAC;
3542 UINT_8 ucBmpAC;
3543 if (IE_LEN(pucIE) != 7) {
3544 break; /* WMM Info IE with a wrong length */
3545 }
3546 prStaRec->fgIsQoS = TRUE;
3547 prStaRec->fgIsWmmSupported = TRUE;
3548
3549 prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE;
3550 ucQosInfo = prIeWmmInfo->ucQosInfo;
3551 ucQosInfoAC = ucQosInfo & BITS(0, 3);
3552
3553 prStaRec->fgIsUapsdSupported =
3554 ((ucQosInfoAC) ? TRUE : FALSE) &
3555 prAdapter->rWifiVar.fgSupportUAPSD;
3556
3557 ucBmpAC = 0;
3558
3559 if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) {
3560 ucBmpAC |= BIT(ACI_VO);
3561 }
3562 if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) {
3563 ucBmpAC |= BIT(ACI_VI);
3564 }
3565 if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) {
3566 ucBmpAC |= BIT(ACI_BE);
3567 }
3568 if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) {
3569 ucBmpAC |= BIT(ACI_BK);
3570 }
3571
3572 prStaRec->ucBmpTriggerAC =
3573 prStaRec->ucBmpDeliveryAC = ucBmpAC;
3574
3575 prStaRec->ucUapsdSp =
3576 (ucQosInfo &
3577 WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5;
3578
3579 }
3580 break;
3581
3582 default:
3583 /* Other WMM QoS IEs. Ignore any */
3584 break;
3585 }
3586 }
3587 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3588
3589 break;
3590
3591 case ELEM_ID_HT_CAP:
3592 /* Some client won't put the WMM IE if client is 802.11n */
3593 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
3594 prStaRec->fgIsQoS = TRUE;
3595 }
3596 break;
3597 default:
3598 break;
3599 }
3600 }
3601
3602 DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
3603
3604 }
3605 }
3606
3607
3608 /*----------------------------------------------------------------------------*/
3609 /*!
3610 * \brief To process WMM related IEs in ASSOC_RSP
3611 *
3612 * \param[in] prAdapter Adapter pointer
3613 * \param[in] prSwRfb The received frame
3614 * \param[in] pucIE The pointer to the first IE in the frame
3615 * \param[in] u2IELength The total length of IEs in the frame
3616 *
3617 * \return none
3618 */
3619 /*----------------------------------------------------------------------------*/
3620 VOID
3621 mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter,
3622 IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength)
3623 {
3624 P_STA_RECORD_T prStaRec;
3625 UINT_16 u2Offset;
3626 PUINT_8 pucIEStart;
3627 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3628
3629 DEBUGFUNC("mqmProcessAssocRsp");
3630
3631 ASSERT(prSwRfb);
3632 ASSERT(pucIE);
3633
3634 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3635 ASSERT(prStaRec);
3636
3637 if (prStaRec == NULL) {
3638 return;
3639 }
3640
3641 prStaRec->fgIsQoS = FALSE;
3642
3643 pucIEStart = pucIE;
3644
3645 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
3646 prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS));
3647
3648 /* If the device does not support QoS or if WMM is not supported by the peer, exit. */
3649 /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */
3650 if ((!prAdapter->rWifiVar.fgSupportQoS)) {
3651 return;
3652 }
3653
3654 /* Determine whether QoS is enabled with the association */
3655 else {
3656 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3657 switch (IE_ID(pucIE)) {
3658 case ELEM_ID_WMM:
3659 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3660 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
3661
3662 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
3663 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
3664 if (IE_LEN(pucIE) != 24) {
3665 break; /* WMM Info IE with a wrong length */
3666 }
3667 prStaRec->fgIsQoS = TRUE;
3668 break;
3669
3670 case VENDOR_OUI_SUBTYPE_WMM_INFO:
3671 if (IE_LEN(pucIE) != 7) {
3672 break; /* WMM Info IE with a wrong length */
3673 }
3674 prStaRec->fgIsQoS = TRUE;
3675 break;
3676
3677 default:
3678 /* Other WMM QoS IEs. Ignore any */
3679 break;
3680 }
3681 }
3682 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3683 break;
3684
3685 case ELEM_ID_HT_CAP:
3686 /* Some AP won't put the WMM IE if client is 802.11n */
3687 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
3688 prStaRec->fgIsQoS = TRUE;
3689 }
3690 break;
3691 default:
3692 break;
3693 }
3694 }
3695
3696 /* Parse AC parameters and write to HW CRs */
3697 if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) {
3698 mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE);
3699 }
3700
3701 DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
3702 if (prStaRec->fgIsWmmSupported) {
3703 nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex);
3704 }
3705 }
3706 }
3707
3708
3709 /*----------------------------------------------------------------------------*/
3710 /*!
3711 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
3712 *
3713 * \param[in] prAdapter Adapter pointer
3714 * \param[in] prSwRfb The received frame
3715 * \param[in] pucIE The pointer to the first IE in the frame
3716 * \param[in] u2IELength The total length of IEs in the frame
3717 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
3718 *
3719 * \return none
3720 */
3721 /*----------------------------------------------------------------------------*/
3722 VOID
3723 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter,
3724 IN P_SW_RFB_T prSwRfb,
3725 IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride)
3726 {
3727 P_STA_RECORD_T prStaRec;
3728 UINT_16 u2Offset;
3729 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3730 P_BSS_INFO_T prBssInfo;
3731
3732 DEBUGFUNC("mqmParseEdcaParameters");
3733
3734 ASSERT(prSwRfb);
3735 ASSERT(pucIE);
3736
3737 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3738 ASSERT(prStaRec);
3739
3740 if (prStaRec == NULL) {
3741 return;
3742 }
3743
3744 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
3745 prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS));
3746
3747 if ((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)
3748 || (!prStaRec->fgIsQoS)) {
3749 return;
3750 }
3751
3752 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
3753
3754 /* Goal: Obtain the EDCA parameters */
3755 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3756 switch (IE_ID(pucIE)) {
3757 case ELEM_ID_WMM:
3758
3759 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3760 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
3761
3762 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
3763 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
3764 if (IE_LEN(pucIE) != 24) {
3765 break; /* WMM Param IE with a wrong length */
3766 } else {
3767 P_AC_QUE_PARMS_T prAcQueParams;
3768 P_IE_WMM_PARAM_T prIeWmmParam;
3769 ENUM_WMM_ACI_T eAci;
3770 PUINT_8 pucWmmParamSetCount;
3771 /* int i; */
3772
3773 pucWmmParamSetCount =
3774 &(prBssInfo->ucWmmParamSetCount);
3775
3776 prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE;
3777
3778 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
3779 if (!fgForceOverride) {
3780 if (*pucWmmParamSetCount ==
3781 (prIeWmmParam->
3782 ucQosInfo &
3783 WMM_QOS_INFO_PARAM_SET_CNT)) {
3784 break; /* Ignore the IE without updating HW CRs */
3785 }
3786 }
3787
3788 /* Update Parameter Set Count */
3789 *pucWmmParamSetCount =
3790 (prIeWmmParam->
3791 ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT);
3792
3793 /* Update EDCA parameters */
3794 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
3795
3796 prAcQueParams =
3797 &prBssInfo->arACQueParms[eAci];
3798 mqmFillAcQueParam(prIeWmmParam, eAci,
3799 prAcQueParams);
3800
3801 prAcQueParams->fgIsACMSet =
3802 (prAcQueParams->
3803 u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE :
3804 FALSE;
3805 prAcQueParams->u2Aifsn &=
3806 WMM_ACIAIFSN_AIFSN;
3807
3808 DBGLOG(QM, LOUD,
3809 ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
3810 eAci, prAcQueParams->fgIsACMSet,
3811 prAcQueParams->u2Aifsn,
3812 prAcQueParams->u2CWmin,
3813 prAcQueParams->u2CWmax,
3814 prAcQueParams->u2TxopLimit));
3815 }
3816 }
3817 break;
3818
3819 default:
3820 /* Other WMM QoS IEs. Ignore */
3821 break;
3822 }
3823
3824 }
3825 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
3826 break;
3827 default:
3828 break;
3829 }
3830 }
3831 }
3832
3833
3834 /*----------------------------------------------------------------------------*/
3835 /*!
3836 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
3837 *
3838 * \param[in] prAdapter Adapter pointer
3839 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
3840 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
3841 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
3842 *
3843 * \return none
3844 */
3845 /*----------------------------------------------------------------------------*/
3846 VOID
3847 mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam,
3848 IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams)
3849 {
3850 prAcQueParams->u2Aifsn = *((PUINT_8) (&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4));
3851
3852 prAcQueParams->u2CWmax =
3853 BIT(((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK)
3854 >> WMM_ECW_WMAX_OFFSET) - 1;
3855
3856 prAcQueParams->u2CWmin =
3857 BIT((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK) -
3858 1;
3859
3860 WLAN_GET_FIELD_16(((PUINT_8) (&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)),
3861 &(prAcQueParams->u2TxopLimit));
3862
3863 prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME;
3864
3865
3866 }
3867
3868
3869 /*----------------------------------------------------------------------------*/
3870 /*!
3871 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
3872 *
3873 * \param[in] prAdapter Adapter pointer
3874 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
3875 * \param[out] prStaRec The obtained info is stored in the STA_REC
3876 *
3877 * \return none
3878 */
3879 /*----------------------------------------------------------------------------*/
3880 VOID
3881 mqmProcessScanResult(IN P_ADAPTER_T prAdapter,
3882 IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec)
3883 {
3884 PUINT_8 pucIE;
3885 UINT_16 u2IELength;
3886 UINT_16 u2Offset;
3887 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3888
3889 DEBUGFUNC("mqmProcessScanResult");
3890
3891 ASSERT(prScanResult);
3892 ASSERT(prStaRec);
3893
3894 /* Reset the flag before parsing */
3895 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
3896
3897 if (!prAdapter->rWifiVar.fgSupportQoS) {
3898 return;
3899 }
3900
3901 u2IELength = prScanResult->u2IELength;
3902 pucIE = prScanResult->aucIEBuf;
3903
3904 /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */
3905 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3906 switch (IE_ID(pucIE)) {
3907 case ELEM_ID_WMM:
3908 if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3909 (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) {
3910
3911 switch (WMM_IE_OUI_SUBTYPE(pucIE)) {
3912 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
3913 if (IE_LEN(pucIE) != 24) {
3914 break; /* WMM Param IE with a wrong length */
3915 } else {
3916 prStaRec->fgIsWmmSupported = TRUE;
3917 prStaRec->fgIsUapsdSupported =
3918 (((((P_IE_WMM_PARAM_T) pucIE)->
3919 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
3920 FALSE);
3921 }
3922 break;
3923
3924 case VENDOR_OUI_SUBTYPE_WMM_INFO:
3925 if (IE_LEN(pucIE) != 7) {
3926 break; /* WMM Info IE with a wrong length */
3927 } else {
3928 prStaRec->fgIsWmmSupported = TRUE;
3929 prStaRec->fgIsUapsdSupported =
3930 (((((P_IE_WMM_INFO_T) pucIE)->
3931 ucQosInfo) & WMM_QOS_INFO_UAPSD) ? TRUE :
3932 FALSE);
3933 }
3934 break;
3935
3936 default:
3937 /* A WMM QoS IE that doesn't matter. Ignore it. */
3938 break;
3939 }
3940 }
3941 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
3942
3943 break;
3944
3945 default:
3946 /* A WMM IE that doesn't matter. Ignore it. */
3947 break;
3948 }
3949 }
3950 DBGLOG(QM, LOUD, ("MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n",
3951 prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported));
3952
3953 }
3954
3955 UINT_8
3956 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter,
3957 IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType)
3958 {
3959 UINT_32 i;
3960 P_STA_RECORD_T prTempStaRec;
3961
3962 prTempStaRec = NULL;
3963
3964 ASSERT(prAdapter);
3965
3966 /* 4 <1> DA = BMCAST */
3967 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) {
3968 return STA_REC_INDEX_BMCAST;
3969 }
3970
3971 /* 4 <2> Check if an AP STA is present */
3972 for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) {
3973 prTempStaRec = &(prAdapter->arStaRec[i]);
3974 if ((prTempStaRec->ucNetTypeIndex == eNetworkType)
3975 && (prTempStaRec->fgIsAp)
3976 && (prTempStaRec->fgIsValid)) {
3977 return prTempStaRec->ucIndex;
3978 }
3979 }
3980
3981 /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */
3982 for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) {
3983 prTempStaRec = &(prAdapter->arStaRec[i]);
3984 if (prTempStaRec->fgIsValid) {
3985 if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)) {
3986 return prTempStaRec->ucIndex;
3987 }
3988 }
3989 }
3990
3991
3992 /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */
3993 return STA_REC_INDEX_NOT_FOUND;
3994 }
3995
3996
3997 /*----------------------------------------------------------------------------*/
3998 /*!
3999 * @brief Generate the WMM Info IE
4000 *
4001 * \param[in] prAdapter Adapter pointer
4002 * @param prMsduInfo The TX MMPDU
4003 *
4004 * @return (none)
4005 */
4006 /*----------------------------------------------------------------------------*/
4007 VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
4008 {
4009 P_IE_WMM_INFO_T prIeWmmInfo;
4010 UINT_32 ucUapsd[] = {
4011 WMM_QOS_INFO_BE_UAPSD,
4012 WMM_QOS_INFO_BK_UAPSD,
4013 WMM_QOS_INFO_VI_UAPSD,
4014 WMM_QOS_INFO_VO_UAPSD
4015 };
4016 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4017
4018 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo;
4019 P_BSS_INFO_T prBssInfo;
4020 P_STA_RECORD_T prStaRec;
4021
4022 DEBUGFUNC("mqmGenerateWmmInfoIE");
4023
4024 ASSERT(prMsduInfo);
4025
4026 /* In case QoS is not turned off, exit directly */
4027 if (!prAdapter->rWifiVar.fgSupportQoS) {
4028 return;
4029 }
4030
4031 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4032 ASSERT(prStaRec);
4033
4034 if (prStaRec == NULL) {
4035 return;
4036 }
4037
4038 if (!prStaRec->fgIsWmmSupported) {
4039 return;
4040 }
4041
4042 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
4043
4044 prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
4045
4046 prIeWmmInfo = (P_IE_WMM_INFO_T)
4047 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4048
4049 prIeWmmInfo->ucId = ELEM_ID_WMM;
4050 prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4051
4052 /* WMM-2.2.1 WMM Information Element Field Values */
4053 prIeWmmInfo->aucOui[0] = aucWfaOui[0];
4054 prIeWmmInfo->aucOui[1] = aucWfaOui[1];
4055 prIeWmmInfo->aucOui[2] = aucWfaOui[2];
4056 prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
4057 prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
4058
4059 prIeWmmInfo->ucVersion = VERSION_WMM;
4060 prIeWmmInfo->ucQosInfo = 0;
4061
4062 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4063 /* if(prAdapter->rWifiVar.fgSupportUAPSD){ */
4064 if (prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported) {
4065
4066 UINT_8 ucQosInfo = 0;
4067 UINT_8 i;
4068
4069
4070 /* Static U-APSD setting */
4071 for (i = ACI_BE; i <= ACI_VO; i++) {
4072 if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->
4073 ucBmpTriggerAC & BIT(i)) {
4074 ucQosInfo |= (UINT_8) ucUapsd[i];
4075 }
4076 }
4077
4078
4079 if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) {
4080 switch (prPmProfSetupInfo->ucUapsdSp) {
4081 case WMM_MAX_SP_LENGTH_ALL:
4082 ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
4083 break;
4084
4085 case WMM_MAX_SP_LENGTH_2:
4086 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4087 break;
4088
4089 case WMM_MAX_SP_LENGTH_4:
4090 ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
4091 break;
4092
4093 case WMM_MAX_SP_LENGTH_6:
4094 ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
4095 break;
4096
4097 default:
4098 DBGLOG(QM, INFO, ("MQM: Incorrect SP length\n"));
4099 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4100 break;
4101 }
4102 }
4103 prIeWmmInfo->ucQosInfo = ucQosInfo;
4104
4105 }
4106
4107 /* Increment the total IE length for the Element ID and Length fields. */
4108 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo);
4109
4110 }
4111
4112
4113 #if 0
4114 /*----------------------------------------------------------------------------*/
4115 /*!
4116 * @brief log2 calculation for CW
4117 *
4118 * @param[in] val value
4119 *
4120 * @return log2(val)
4121 */
4122 /*----------------------------------------------------------------------------*/
4123
4124 UINT_32 cwlog2(UINT_32 val)
4125 {
4126
4127 UINT_32 n;
4128 n = 0;
4129
4130 while (val >= 512) {
4131 n += 9;
4132 val = val >> 9;
4133 }
4134 while (val >= 16) {
4135 n += 4;
4136 val >>= 4;
4137 }
4138 while (val >= 2) {
4139 n += 1;
4140 val >>= 1;
4141 }
4142 return n;
4143 }
4144 #endif
4145
4146
4147 /*----------------------------------------------------------------------------*/
4148 /*!
4149 * @brief Generate the WMM Param IE
4150 *
4151 * \param[in] prAdapter Adapter pointer
4152 * @param prMsduInfo The TX MMPDU
4153 *
4154 * @return (none)
4155 */
4156 /*----------------------------------------------------------------------------*/
4157 VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
4158 {
4159 P_IE_WMM_PARAM_T prIeWmmParam;
4160
4161 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4162
4163 UINT_8 aucACI[] = {
4164 WMM_ACI_AC_BE,
4165 WMM_ACI_AC_BK,
4166 WMM_ACI_AC_VI,
4167 WMM_ACI_AC_VO
4168 };
4169
4170 P_BSS_INFO_T prBssInfo;
4171 P_STA_RECORD_T prStaRec;
4172 ENUM_WMM_ACI_T eAci;
4173
4174 DEBUGFUNC("mqmGenerateWmmParamIE");
4175 DBGLOG(QM, LOUD, ("\n"));
4176
4177 ASSERT(prMsduInfo);
4178
4179 /* In case QoS is not turned off, exit directly */
4180 if (!prAdapter->rWifiVar.fgSupportQoS) {
4181 return;
4182 }
4183
4184 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4185
4186 if (prStaRec) {
4187 if (!prStaRec->fgIsQoS) {
4188 return;
4189 }
4190 }
4191
4192 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]);
4193
4194 if (!prBssInfo->fgIsQBSS) {
4195 return;
4196 }
4197 #if 0 /* 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. */
4198 if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT &&
4199 prBssInfo->eCurrentOPMode != OP_MODE_BOW) {
4200 return;
4201 }
4202 #endif
4203
4204 prIeWmmParam = (P_IE_WMM_PARAM_T)
4205 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4206
4207 prIeWmmParam->ucId = ELEM_ID_WMM;
4208 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
4209
4210 /* WMM-2.2.1 WMM Information Element Field Values */
4211 prIeWmmParam->aucOui[0] = aucWfaOui[0];
4212 prIeWmmParam->aucOui[1] = aucWfaOui[1];
4213 prIeWmmParam->aucOui[2] = aucWfaOui[2];
4214 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
4215 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
4216
4217 prIeWmmParam->ucVersion = VERSION_WMM;
4218 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
4219
4220 /* UAPSD intial queue configurations (delivery and trigger enabled) */
4221 if (prAdapter->rWifiVar.fgSupportUAPSD) {
4222
4223 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
4224
4225 }
4226
4227 /* EDCA parameter */
4228
4229 for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) {
4230
4231 /* DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */
4232 /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */
4233 /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */
4234 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */
4235 /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */
4236 /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */
4237
4238 *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci]
4239 |
4240 (prBssInfo->
4241 arACQueParmsForBcast
4242 [eAci].
4243 fgIsACMSet
4244 ?
4245 WMM_ACIAIFSN_ACM
4246 : 0)
4247 |
4248 (prBssInfo->
4249 arACQueParmsForBcast
4250 [eAci].
4251 u2Aifsn &
4252 (WMM_ACIAIFSN_AIFSN)));
4253 #if 1
4254 *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0
4255 |
4256 (((prBssInfo->
4257 aucCWminLog2ForBcast
4258 [eAci])) &
4259 WMM_ECW_WMIN_MASK)
4260 |
4261 ((((prBssInfo->
4262 aucCWmaxLog2ForBcast
4263 [eAci])) <<
4264 WMM_ECW_WMAX_OFFSET)
4265 &
4266 WMM_ECW_WMAX_MASK)
4267 );
4268 #else
4269 *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0
4270 |
4271 (cwlog2
4272 ((prBssInfo->
4273 arACQueParmsForBcast
4274 [eAci].
4275 u2CWmin +
4276 1)) &
4277 WMM_ECW_WMIN_MASK)
4278 |
4279 ((cwlog2
4280 ((prBssInfo->
4281 arACQueParmsForBcast
4282 [eAci].
4283 u2CWmax +
4284 1)) <<
4285 WMM_ECW_WMAX_OFFSET)
4286 &
4287 WMM_ECW_WMAX_MASK)
4288 );
4289 #endif
4290
4291 WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2)
4292 , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
4293
4294 }
4295
4296 /* Increment the total IE length for the Element ID and Length fields. */
4297 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam);
4298
4299 }
4300
4301
4302
4303
4304 ENUM_FRAME_ACTION_T
4305 qmGetFrameAction(IN P_ADAPTER_T prAdapter,
4306 IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType,
4307 IN UINT_8 ucStaRecIdx,
4308 IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType)
4309 {
4310 P_BSS_INFO_T prBssInfo;
4311 P_STA_RECORD_T prStaRec;
4312 P_WLAN_MAC_HEADER_T prWlanFrame;
4313 UINT_16 u2TxFrameCtrl;
4314
4315 DEBUGFUNC("qmGetFrameAction");
4316
4317 #if (NIC_TX_BUFF_COUNT_TC4 > 2)
4318 #define QM_MGMT_QUUEUD_THRESHOLD 2
4319 #else
4320 #define QM_MGMT_QUUEUD_THRESHOLD 1
4321 #endif
4322
4323 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4));
4324 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0);
4325
4326 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]);
4327 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx);
4328
4329 /* XXX Check BOW P2P AIS time ot set active */
4330 if (!IS_BSS_ACTIVE(prBssInfo)) {
4331 if (eFrameType == FRAME_TYPE_MMPDU) {
4332 prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4333 u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */
4334 if ((u2TxFrameCtrl == MAC_FRAME_DEAUTH)
4335 && (prMsduInfo->pfTxDoneHandler == NULL)) {
4336 return FRAME_ACTION_TX_PKT;
4337 }
4338
4339 }
4340
4341 DBGLOG(QM, INFO,
4342 ("Drop packets Action (Inactive %u).\n", prBssInfo->ucNetTypeIndex));
4343 TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP);
4344 return FRAME_ACTION_DROP_PKT;
4345 }
4346
4347 /* TODO Handle disconnect issue */
4348
4349 /* P2P probe Request frame */
4350 do {
4351 if (eFrameType == FRAME_TYPE_MMPDU) {
4352 ASSERT(prMsduInfo != NULL);
4353 prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4354 u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */
4355
4356 if (u2TxFrameCtrl == MAC_FRAME_BEACON) {
4357 if (prBssInfo->fgIsNetAbsent) {
4358 return FRAME_ACTION_DROP_PKT;
4359 }
4360 } else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) {
4361 if (prBssInfo->fgIsNetAbsent) {
4362 break;
4363 }
4364 } else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) {
4365 if (prBssInfo->fgIsNetAbsent) {
4366 break;
4367 }
4368 DBGLOG(P2P, LOUD, ("Sending DEAUTH Frame\n"));
4369 return FRAME_ACTION_TX_PKT;
4370 }
4371 /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */
4372 else if (u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ
4373 || u2TxFrameCtrl == MAC_FRAME_AUTH
4374 || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ
4375 || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ
4376 || u2TxFrameCtrl == MAC_FRAME_ACTION) {
4377
4378 if (prStaRec) {
4379 if (prStaRec->fgIsInPS) {
4380 if (nicTxGetResource(prAdapter, TC4_INDEX) >=
4381 QM_MGMT_QUUEUD_THRESHOLD) {
4382 return FRAME_ACTION_TX_PKT;
4383 } else {
4384 return FRAME_ACTION_QUEUE_PKT;
4385 }
4386 }
4387 }
4388 return FRAME_ACTION_TX_PKT;
4389 }
4390
4391 if (!prStaRec) {
4392 return FRAME_ACTION_TX_PKT;
4393 } else {
4394 if (!prStaRec->fgIsInUse) {
4395 return FRAME_ACTION_DROP_PKT;
4396 }
4397 }
4398
4399 } /* FRAME_TYPE_MMPDU */
4400 else if ((eFrameType == FRAME_TYPE_802_1X)) {
4401
4402 if (!prStaRec) {
4403 return FRAME_ACTION_TX_PKT;
4404 } else {
4405 if (!prStaRec->fgIsInUse) {
4406 return FRAME_ACTION_DROP_PKT;
4407 }
4408 if (prStaRec->fgIsInPS) {
4409 if (nicTxGetResource(prAdapter, TC4_INDEX) >=
4410 QM_MGMT_QUUEUD_THRESHOLD) {
4411 return FRAME_ACTION_TX_PKT;
4412 } else {
4413 return FRAME_ACTION_QUEUE_PKT;
4414 }
4415 }
4416 }
4417
4418 } /* FRAME_TYPE_802_1X */
4419 else if ((!IS_BSS_ACTIVE(prBssInfo))
4420 || (!prStaRec)
4421 || (!prStaRec->fgIsInUse)) {
4422 return FRAME_ACTION_DROP_PKT;
4423 }
4424 } while (0);
4425
4426 if (prBssInfo->fgIsNetAbsent) {
4427 DBGLOG(QM, LOUD, ("Queue packets (Absent %u).\n", prBssInfo->ucNetTypeIndex));
4428 return FRAME_ACTION_QUEUE_PKT;
4429 }
4430
4431 if (prStaRec && prStaRec->fgIsInPS) {
4432 DBGLOG(QM, LOUD, ("Queue packets (PS %u).\n", prStaRec->fgIsInPS));
4433 return FRAME_ACTION_QUEUE_PKT;
4434 } else {
4435 switch (eFrameType) {
4436 case FRAME_TYPE_802_1X:
4437 if (!prStaRec->fgIsValid) {
4438 return FRAME_ACTION_QUEUE_PKT;
4439 }
4440 break;
4441
4442 case FRAME_TYPE_MMPDU:
4443 break;
4444
4445 default:
4446 ASSERT(0);
4447 }
4448 }
4449
4450 return FRAME_ACTION_TX_PKT;
4451 }
4452
4453
4454 /*----------------------------------------------------------------------------*/
4455 /*!
4456 * \brief Handle BSS change operation Event from the FW
4457 *
4458 * \param[in] prAdapter Adapter pointer
4459 * \param[in] prEvent The event packet from the FW
4460 *
4461 * \return (none)
4462 */
4463 /*----------------------------------------------------------------------------*/
4464 VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4465 {
4466 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus;
4467 P_BSS_INFO_T prBssInfo;
4468 BOOLEAN fgIsNetAbsentOld;
4469
4470 prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent;
4471 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]);
4472 fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent;
4473 prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent;
4474 prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota;
4475
4476 /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */
4477 /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */
4478
4479 DBGLOG(QM, TRACE, ("NAF=%d,%d,%d\n",
4480 prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent,
4481 prBssInfo->ucBssFreeQuota));
4482
4483 if (!prBssInfo->fgIsNetAbsent) {
4484 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27);
4485 } else {
4486 QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28);
4487 }
4488 /* From Absent to Present */
4489 if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) {
4490 kalSetEvent(prAdapter->prGlueInfo);
4491 }
4492 }
4493
4494
4495 /*----------------------------------------------------------------------------*/
4496 /*!
4497 * \brief Handle STA change PS mode Event from the FW
4498 *
4499 * \param[in] prAdapter Adapter pointer
4500 * \param[in] prEvent The event packet from the FW
4501 *
4502 * \return (none)
4503 */
4504 /*----------------------------------------------------------------------------*/
4505 VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4506 {
4507 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode;
4508 P_STA_RECORD_T prStaRec;
4509 BOOLEAN fgIsInPSOld;
4510
4511 /* DbgPrint("QM:Event -RxBa\n"); */
4512
4513 prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent;
4514 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx);
4515 ASSERT(prStaRec);
4516
4517 if (prStaRec) {
4518
4519 fgIsInPSOld = prStaRec->fgIsInPS;
4520 prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs;
4521
4522 qmUpdateFreeQuota(prAdapter,
4523 prStaRec,
4524 prEventStaChangePsMode->ucUpdateMode,
4525 prEventStaChangePsMode->ucFreeQuota);
4526
4527 /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */
4528 /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */
4529
4530
4531 DBGLOG(QM, TRACE, ("PS=%d,%d\n",
4532 prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
4533
4534 /* From PS to Awake */
4535 if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) {
4536 kalSetEvent(prAdapter->prGlueInfo);
4537 }
4538 }
4539 }
4540
4541 /*----------------------------------------------------------------------------*/
4542 /*!
4543 * \brief Update STA free quota Event from FW
4544 *
4545 * \param[in] prAdapter Adapter pointer
4546 * \param[in] prEvent The event packet from the FW
4547 *
4548 * \return (none)
4549 */
4550 /*----------------------------------------------------------------------------*/
4551 VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
4552 {
4553 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota;
4554 P_STA_RECORD_T prStaRec;
4555
4556
4557 prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent;
4558 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx);
4559 ASSERT(prStaRec);
4560
4561 if (prStaRec) {
4562 if (prStaRec->fgIsInPS) {
4563 qmUpdateFreeQuota(prAdapter,
4564 prStaRec,
4565 prEventStaUpdateFreeQuota->ucUpdateMode,
4566 prEventStaUpdateFreeQuota->ucFreeQuota);
4567
4568 kalSetEvent(prAdapter->prGlueInfo);
4569 }
4570 #if 0
4571 DBGLOG(QM, TRACE,
4572 ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
4573 prEventStaUpdateFreeQuota->ucStaRecIdx,
4574 prEventStaUpdateFreeQuota->ucUpdateMode,
4575 prEventStaUpdateFreeQuota->ucFreeQuota));
4576 #endif
4577
4578 DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n",
4579 prEventStaUpdateFreeQuota->ucStaRecIdx,
4580 prEventStaUpdateFreeQuota->ucUpdateMode,
4581 prEventStaUpdateFreeQuota->ucFreeQuota));
4582
4583
4584 }
4585
4586 }
4587
4588
4589 /*----------------------------------------------------------------------------*/
4590 /*!
4591 * \brief Update STA free quota
4592 *
4593 * \param[in] prStaRec the STA
4594 * \param[in] ucUpdateMode the method to update free quota
4595 * \param[in] ucFreeQuota the value for update
4596 *
4597 * \return (none)
4598 */
4599 /*----------------------------------------------------------------------------*/
4600 VOID
4601 qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter,
4602 IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota)
4603 {
4604
4605 UINT_8 ucFreeQuotaForNonDelivery;
4606 UINT_8 ucFreeQuotaForDelivery;
4607
4608 ASSERT(prStaRec);
4609 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
4610 prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota));
4611
4612 if (!prStaRec->fgIsInPS)
4613 return;
4614
4615 switch (ucUpdateMode) {
4616 case FREE_QUOTA_UPDATE_MODE_INIT:
4617 case FREE_QUOTA_UPDATE_MODE_OVERWRITE:
4618 prStaRec->ucFreeQuota = ucFreeQuota;
4619 break;
4620 case FREE_QUOTA_UPDATE_MODE_INCREASE:
4621 prStaRec->ucFreeQuota += ucFreeQuota;
4622 break;
4623 case FREE_QUOTA_UPDATE_MODE_DECREASE:
4624 prStaRec->ucFreeQuota -= ucFreeQuota;
4625 break;
4626 default:
4627 ASSERT(0);
4628 }
4629
4630 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota));
4631
4632 ucFreeQuota = prStaRec->ucFreeQuota;
4633
4634 ucFreeQuotaForNonDelivery = 0;
4635 ucFreeQuotaForDelivery = 0;
4636
4637 if (ucFreeQuota > 0) {
4638 if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
4639 /* && prAdapter->rWifiVar.fgSupportQoS
4640 && prAdapter->rWifiVar.fgSupportUAPSD */) {
4641 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
4642
4643 if (prStaRec->ucFreeQuotaForNonDelivery > 0
4644 && prStaRec->ucFreeQuotaForDelivery > 0) {
4645 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
4646 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
4647 } else if (prStaRec->ucFreeQuotaForNonDelivery == 0
4648 && prStaRec->ucFreeQuotaForDelivery == 0) {
4649 ucFreeQuotaForNonDelivery = ucFreeQuota >> 1;
4650 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
4651 } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) {
4652 /* NonDelivery is not busy */
4653 if (ucFreeQuota >= 3) {
4654 ucFreeQuotaForNonDelivery = 2;
4655 ucFreeQuotaForDelivery =
4656 ucFreeQuota - ucFreeQuotaForNonDelivery;
4657 } else {
4658 ucFreeQuotaForDelivery = ucFreeQuota;
4659 ucFreeQuotaForNonDelivery = 0;
4660 }
4661 } else if (prStaRec->ucFreeQuotaForDelivery > 0) {
4662 /* Delivery is not busy */
4663 if (ucFreeQuota >= 3) {
4664 ucFreeQuotaForDelivery = 2;
4665 ucFreeQuotaForNonDelivery =
4666 ucFreeQuota - ucFreeQuotaForDelivery;
4667 } else {
4668 ucFreeQuotaForNonDelivery = ucFreeQuota;
4669 ucFreeQuotaForDelivery = 0;
4670 }
4671 }
4672
4673 } else {
4674 /* !prStaRec->fgIsUapsdSupported */
4675 ucFreeQuotaForNonDelivery = ucFreeQuota;
4676 ucFreeQuotaForDelivery = 0;
4677 }
4678 }
4679 /* ucFreeQuota > 0 */
4680 prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery;
4681 prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery;
4682
4683 DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
4684 prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery));
4685
4686 }
4687
4688 /*----------------------------------------------------------------------------*/
4689 /*!
4690 * \brief Return the reorder queued RX packets
4691 *
4692 * \param[in] (none)
4693 *
4694 * \return The number of queued RX packets
4695 */
4696 /*----------------------------------------------------------------------------*/
4697 UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter)
4698 {
4699 UINT_32 i, u4Total;
4700 P_QUE_MGT_T prQM = &prAdapter->rQM;
4701 u4Total = 0;
4702 /* XXX The summation may impact the performance */
4703 for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) {
4704 u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem;
4705 #if DBG && 0
4706 if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) {
4707 ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0);
4708 }
4709 #endif
4710 }
4711 ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2));
4712 return u4Total;
4713 }