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