import PULS_20160108
[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
2979 /* BAR frame */
2980 if(HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)){
2981 prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
2982 qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue);
2983 }
2984 /* Reordering is not required for this packet, return it without buffering */
2985 else if(!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr) || fgIsBMC){
2986 #if 0
2987 if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){
2988 UINT_8 ucNetTypeIdx;
2989 P_BSS_INFO_T prBssInfo;
2990
2991 pucEthDestAddr = prCurrSwRfb->pvHeader;
2992 ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr);
2993
2994 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]);
2995
2996 if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)){
2997 prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD;
2998 }
2999 }
3000 #endif
3001 QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb);
3002 }
3003 /* Reordering is required for this packet */
3004 else{
3005 /* If this packet should dropped or indicated to the host immediately,
3006 * it should be enqueued into the rReturnedQue with specific flags. If
3007 * this packet should be buffered for reordering, it should be enqueued
3008 * into the reordering queue in the STA_REC rather than into the
3009 * rReturnedQue.
3010 */
3011 qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue);
3012
3013 }
3014 }while(prNextSwRfb);
3015
3016
3017 /* RX_PKT_DESTINATION_HOST_WITH_FORWARD or RX_PKT_DESTINATION_FORWARD */
3018 /* The returned list of SW_RFBs must end with a NULL pointer */
3019 if(QUEUE_IS_NOT_EMPTY(&rReturnedQue)){
3020 QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T)QUEUE_GET_TAIL(&rReturnedQue), NULL);
3021 }
3022
3023 return (P_SW_RFB_T)QUEUE_GET_HEAD(&rReturnedQue);
3024
3025 #else
3026
3027 //DbgPrint("QM: Enter qmHandleRxPackets()\n");
3028 return prSwRfbListHead;
3029
3030 #endif
3031
3032 }
3033
3034 /*----------------------------------------------------------------------------*/
3035 /*!
3036 * \brief Reorder the received packet
3037 *
3038 * \param[in] prSwRfb The RX packet to process
3039 * \param[out] prReturnedQue The queue for indicating packets
3040 *
3041 * \return (none)
3042 */
3043 /*----------------------------------------------------------------------------*/
3044 VOID
3045 qmProcessPktWithReordering(
3046 IN P_ADAPTER_T prAdapter,
3047 IN P_SW_RFB_T prSwRfb,
3048 OUT P_QUE_T prReturnedQue
3049 )
3050 {
3051
3052
3053 P_STA_RECORD_T prStaRec;
3054 P_HIF_RX_HEADER_T prHifRxHdr;
3055 P_RX_BA_ENTRY_T prReorderQueParm;
3056
3057 UINT_32 u4SeqNo;
3058 UINT_32 u4WinStart;
3059 UINT_32 u4WinEnd;
3060 P_QUE_T prReorderQue;
3061 //P_SW_RFB_T prReorderedSwRfb;
3062
3063 DEBUGFUNC("qmProcessPktWithReordering");
3064
3065 ASSERT(prSwRfb);
3066 ASSERT(prReturnedQue);
3067 ASSERT(prSwRfb->prHifRxHdr);
3068
3069 prHifRxHdr = prSwRfb->prHifRxHdr;
3070 prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
3071 prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */
3072 prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr));
3073 //prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
3074
3075 /* Incorrect STA_REC index */
3076 if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
3077 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3078 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3079 DBGLOG(QM, WARN,("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n",
3080 prSwRfb->ucStaRecIdx));
3081 //ASSERT(0);
3082 return;
3083 }
3084
3085 /* Check whether the STA_REC is activated */
3086 prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
3087 ASSERT(prStaRec);
3088
3089 #if 0
3090 if(!(prStaRec->fgIsValid)){
3091 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3092 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3093 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3094 DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC \n"));
3095 //ASSERT(0);
3096 return;
3097 }
3098 #endif
3099
3100 /* Check whether the BA agreement exists */
3101 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3102 if(!prReorderQueParm){
3103 /* TODO: (Tehuang) Handle the Host-FW sync issue.*/
3104 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3105 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3106 DBGLOG(QM, WARN,("Reordering for a NULL ReorderQueParm \n"));
3107 //ASSERT(0);
3108 return;
3109 }
3110
3111
3112
3113 /* Start to reorder packets */
3114 u4SeqNo = (UINT_32)(prSwRfb->u2SSN);
3115 prReorderQue = &(prReorderQueParm->rReOrderQue);
3116 u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart);
3117 u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd);
3118
3119 /* Debug */
3120 //DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
3121
3122 /* Case 1: Fall within */
3123 if /* 0 - start - sn - end - 4095 */
3124 (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd))
3125 /* 0 - end - start - sn - 4095 */
3126 || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo))
3127 /* 0 - sn - end - start - 4095 */
3128 || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))){
3129
3130 qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3131
3132 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3133 if(prReorderQueParm->fgIsWaitingForPktWithSsn){
3134 /* Let the first received packet pass the reorder check */
3135 DBGLOG(QM, LOUD, ("QM:(A)[%d](%u){%u,%u}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd));
3136
3137 prReorderQueParm->u2WinStart = (UINT_16)u4SeqNo;
3138 prReorderQueParm->u2WinEnd =
3139 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT;
3140 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3141 }
3142 #endif
3143
3144 if (qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue) == FALSE)
3145 STATS_RX_REORDER_HOLE_INC(prStaRec); /* record hole count */
3146 }
3147 /* Case 2: Fall ahead */
3148 else if
3149 /* 0 - start - end - sn - (start+2048) - 4095 */
3150 (((u4WinStart < u4WinEnd)
3151 && (u4WinEnd < u4SeqNo)
3152 && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT)))
3153 /* 0 - sn - (start+2048) - start - end - 4095 */
3154 || ((u4SeqNo < u4WinStart)
3155 && (u4WinStart < u4WinEnd)
3156 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))
3157 /* 0 - end - sn - (start+2048) - start - 4095 */
3158 || ((u4WinEnd < u4SeqNo)
3159 && (u4SeqNo < u4WinStart)
3160 && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))){
3161
3162
3163 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3164 if(prReorderQueParm->fgIsWaitingForPktWithSsn){
3165 prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE;
3166 }
3167 #endif
3168
3169 qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue);
3170
3171 /* Advance the window after inserting a new tail */
3172 prReorderQueParm->u2WinEnd = (UINT_16)u4SeqNo;
3173 prReorderQueParm->u2WinStart =
3174 (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1)
3175 % MAX_SEQ_NO_COUNT);
3176
3177 qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
3178
3179 STATS_RX_REORDER_FALL_AHEAD_INC(prStaRec);
3180
3181 }
3182 /* Case 3: Fall behind */
3183 else{
3184
3185 #if QM_RX_WIN_SSN_AUTO_ADVANCING
3186 #if QM_RX_INIT_FALL_BEHIND_PASS
3187 if(prReorderQueParm->fgIsWaitingForPktWithSsn){
3188 //?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST;
3189 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3190 //DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
3191 return;
3192 }
3193 #endif
3194 #endif
3195
3196 STATS_RX_REORDER_FALL_BEHIND_INC(prStaRec);
3197 /* An erroneous packet */
3198 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3199 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3200 //DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd);
3201 return;
3202 }
3203
3204 return;
3205
3206 }
3207
3208
3209 VOID
3210 qmProcessBarFrame(
3211 IN P_ADAPTER_T prAdapter,
3212 IN P_SW_RFB_T prSwRfb,
3213 OUT P_QUE_T prReturnedQue
3214 )
3215 {
3216
3217 P_STA_RECORD_T prStaRec;
3218 P_HIF_RX_HEADER_T prHifRxHdr;
3219 P_RX_BA_ENTRY_T prReorderQueParm;
3220
3221 UINT_32 u4SSN;
3222 UINT_32 u4WinStart;
3223 UINT_32 u4WinEnd;
3224 P_QUE_T prReorderQue;
3225 //P_SW_RFB_T prReorderedSwRfb;
3226
3227 ASSERT(prSwRfb);
3228 ASSERT(prReturnedQue);
3229 ASSERT(prSwRfb->prHifRxHdr);
3230
3231 prHifRxHdr = prSwRfb->prHifRxHdr;
3232 prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx;
3233 prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */
3234 prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr));
3235
3236 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3237 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3238
3239 /* Incorrect STA_REC index */
3240 if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
3241 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n",
3242 prSwRfb->ucStaRecIdx));
3243 //ASSERT(0);
3244 return;
3245 }
3246
3247 /* Check whether the STA_REC is activated */
3248 prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]);
3249 ASSERT(prStaRec);
3250
3251 #if 0
3252 if(!(prStaRec->fgIsValid)){
3253 /* TODO: (Tehuang) Handle the Host-FW sync issue. */
3254 DbgPrint("QM: (Warning) BAR for an invalid STA_REC \n");
3255 //ASSERT(0);
3256 return;
3257 }
3258 #endif
3259
3260 /* Check whether the BA agreement exists */
3261 prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]);
3262 if(!prReorderQueParm){
3263 /* TODO: (Tehuang) Handle the Host-FW sync issue.*/
3264 DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm \n"));
3265 //ASSERT(0);
3266 return;
3267 }
3268
3269
3270 u4SSN = (UINT_32)(prSwRfb->u2SSN);
3271 prReorderQue = &(prReorderQueParm->rReOrderQue);
3272 u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart);
3273 u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd);
3274
3275 if(qmCompareSnIsLessThan(u4WinStart,u4SSN)){
3276 prReorderQueParm->u2WinStart = (UINT_16)u4SSN;
3277 prReorderQueParm->u2WinEnd =
3278 ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT;
3279 DBGLOG(QM, TRACE, ("QM:(BAR)[%d](%u){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd));
3280 qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue);
3281 }
3282 else{
3283 DBGLOG(QM, TRACE, ("QM:(BAR)(%d)(%u){%u,%u}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd));
3284 }
3285 }
3286
3287
3288
3289 VOID
3290 qmInsertFallWithinReorderPkt(
3291 IN P_SW_RFB_T prSwRfb,
3292 IN P_RX_BA_ENTRY_T prReorderQueParm,
3293 OUT P_QUE_T prReturnedQue
3294 )
3295 {
3296 P_SW_RFB_T prExaminedQueuedSwRfb;
3297 P_QUE_T prReorderQue;
3298 ASSERT(prSwRfb);
3299 ASSERT(prReorderQueParm);
3300 ASSERT(prReturnedQue);
3301
3302 prReorderQue = &(prReorderQueParm->rReOrderQue);
3303 prExaminedQueuedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3304
3305 /* There are no packets queued in the Reorder Queue */
3306 if(prExaminedQueuedSwRfb == NULL){
3307 ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL;
3308 ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3309 prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3310 prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb;
3311 prReorderQue->u4NumElem ++;
3312 }
3313
3314 /* Determine the insert position */
3315 else{
3316 do{
3317 /* Case 1: Terminate. A duplicate packet */
3318 if(((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))){
3319 prSwRfb->eDst = RX_PKT_DESTINATION_NULL;
3320 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb);
3321 return;
3322 }
3323
3324 /* Case 2: Terminate. The insert point is found */
3325 else if(qmCompareSnIsLessThan(
3326 (prSwRfb->u2SSN),(prExaminedQueuedSwRfb->u2SSN))){
3327 break;
3328 }
3329
3330 /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */
3331 else{
3332 prExaminedQueuedSwRfb =
3333 (P_SW_RFB_T)(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prNext);
3334 }
3335 }while(prExaminedQueuedSwRfb);
3336
3337 /* Update the Reorder Queue Parameters according to the found insert position */
3338 if(prExaminedQueuedSwRfb == NULL){
3339 /* The received packet shall be placed at the tail */
3340 ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail;
3341 ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3342 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb);
3343 prReorderQue->prTail = (P_QUE_ENTRY_T)(prSwRfb);
3344 }
3345 else{
3346 ((P_QUE_ENTRY_T)prSwRfb)->prPrev = ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev;
3347 ((P_QUE_ENTRY_T)prSwRfb)->prNext = (P_QUE_ENTRY_T)prExaminedQueuedSwRfb;
3348 if(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb) == (prReorderQue->prHead)){
3349 /* The received packet will become the head */
3350 prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3351 }
3352 else{
3353 (((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T)prSwRfb;
3354 }
3355 ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T)prSwRfb;
3356 }
3357
3358 prReorderQue->u4NumElem ++;
3359
3360 }
3361
3362 }
3363
3364
3365 VOID
3366 qmInsertFallAheadReorderPkt(
3367 IN P_SW_RFB_T prSwRfb,
3368 IN P_RX_BA_ENTRY_T prReorderQueParm,
3369 OUT P_QUE_T prReturnedQue
3370 )
3371 {
3372 P_QUE_T prReorderQue;
3373 ASSERT(prSwRfb);
3374 ASSERT(prReorderQueParm);
3375 ASSERT(prReturnedQue);
3376
3377 prReorderQue = &(prReorderQueParm->rReOrderQue);
3378
3379 /* There are no packets queued in the Reorder Queue */
3380 if(QUEUE_IS_EMPTY(prReorderQue)){
3381 ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL;
3382 ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3383 prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb;
3384 }
3385 else{
3386 ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail;
3387 ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL;
3388 (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb);
3389 }
3390 prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb;
3391 prReorderQue->u4NumElem ++;
3392
3393 }
3394
3395
3396 BOOLEAN
3397 qmPopOutDueToFallWithin(
3398 IN P_RX_BA_ENTRY_T prReorderQueParm,
3399 OUT P_QUE_T prReturnedQue
3400 )
3401 {
3402 P_SW_RFB_T prReorderedSwRfb;
3403 P_QUE_T prReorderQue;
3404 BOOLEAN fgDequeuHead, fgMissing;
3405 OS_SYSTIME rCurrentTime, *prMissTimeout;
3406
3407 prReorderQue = &(prReorderQueParm->rReOrderQue);
3408
3409 fgMissing = FALSE;
3410 rCurrentTime = 0;
3411 prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]);
3412 if ((*prMissTimeout)){
3413 fgMissing = TRUE;
3414 GET_CURRENT_SYSTIME(&rCurrentTime);
3415 }
3416
3417 /* Check whether any packet can be indicated to the higher layer */
3418 while(TRUE){
3419 if(QUEUE_IS_EMPTY(prReorderQue)){
3420 break;
3421 }
3422
3423 /* Always examine the head packet */
3424 prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3425 fgDequeuHead = FALSE;
3426
3427 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3428 if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){
3429
3430 fgDequeuHead = TRUE;
3431 prReorderQueParm->u2WinStart =
3432 (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT);
3433 }
3434 /* SN > WinStart, break to update WinEnd */
3435 else{
3436 if ((fgMissing == TRUE) &&
3437 CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout),
3438 MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) {
3439 DBGLOG(QM, TRACE, ("QM:RX BA Timout Next Tid %d SSN %d\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2SSN));
3440 fgDequeuHead = TRUE;
3441 prReorderQueParm->u2WinStart =
3442 (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT);
3443
3444 fgMissing = FALSE;
3445 }
3446 else break;
3447 }
3448
3449
3450 /* Dequeue the head packet */
3451 if(fgDequeuHead){
3452
3453 if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){
3454 prReorderQue->prHead = NULL;
3455 prReorderQue->prTail = NULL;
3456 }
3457 else{
3458 prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext;
3459 (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL;
3460 }
3461 prReorderQue->u4NumElem --;
3462 //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN);
3463 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb);
3464 }
3465 }
3466
3467 if (QUEUE_IS_EMPTY(prReorderQue)){
3468 *prMissTimeout = 0;
3469 }
3470 else {
3471 if (fgMissing == FALSE) {
3472 GET_CURRENT_SYSTIME(prMissTimeout);
3473 }
3474 }
3475
3476 /* After WinStart has been determined, update the WinEnd */
3477 prReorderQueParm->u2WinEnd =
3478 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1 )% MAX_SEQ_NO_COUNT);
3479 return QUEUE_IS_EMPTY(prReorderQue);
3480 }
3481
3482 VOID
3483 qmPopOutDueToFallAhead(
3484 IN P_RX_BA_ENTRY_T prReorderQueParm,
3485 OUT P_QUE_T prReturnedQue
3486 )
3487 {
3488 P_SW_RFB_T prReorderedSwRfb;
3489 P_QUE_T prReorderQue;
3490 BOOLEAN fgDequeuHead;
3491
3492 prReorderQue = &(prReorderQueParm->rReOrderQue);
3493
3494 /* Check whether any packet can be indicated to the higher layer */
3495 while(TRUE){
3496 if(QUEUE_IS_EMPTY(prReorderQue)){
3497 break;
3498 }
3499
3500 /* Always examine the head packet */
3501 prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue);
3502 fgDequeuHead = FALSE;
3503
3504 /* SN == WinStart, so the head packet shall be indicated (advance the window) */
3505 if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){
3506
3507 fgDequeuHead = TRUE;
3508 prReorderQueParm->u2WinStart =
3509 (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT);
3510 }
3511
3512 /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */
3513 else if(qmCompareSnIsLessThan(
3514 (UINT_32)(prReorderedSwRfb->u2SSN),
3515 (UINT_32)(prReorderQueParm->u2WinStart))){
3516
3517 fgDequeuHead = TRUE;
3518
3519 }
3520
3521 /* SN > WinStart, break to update WinEnd */
3522 else{
3523 break;
3524 }
3525
3526
3527 /* Dequeue the head packet */
3528 if(fgDequeuHead){
3529
3530 if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){
3531 prReorderQue->prHead = NULL;
3532 prReorderQue->prTail = NULL;
3533 }
3534 else{
3535 prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext;
3536 (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL;
3537 }
3538 prReorderQue->u4NumElem --;
3539 //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN);
3540 QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb);
3541 }
3542 }
3543
3544 /* After WinStart has been determined, update the WinEnd */
3545 prReorderQueParm->u2WinEnd =
3546 (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1)% MAX_SEQ_NO_COUNT);
3547
3548 }
3549
3550 BOOLEAN
3551 qmCompareSnIsLessThan(
3552 IN UINT_32 u4SnLess,
3553 IN UINT_32 u4SnGreater
3554 )
3555 {
3556 /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */
3557 if((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater){ /* Shall be <= */
3558 return FALSE;
3559 }
3560
3561 /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */
3562 else if((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess){
3563 return TRUE;
3564 }
3565
3566 /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */
3567 /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */
3568 else{
3569 return (u4SnLess < u4SnGreater);
3570 }
3571 }
3572
3573
3574 /*----------------------------------------------------------------------------*/
3575 /*!
3576 * \brief Handle Mailbox RX messages
3577 *
3578 * \param[in] prMailboxRxMsg The received Mailbox message from the FW
3579 *
3580 * \return (none)
3581 */
3582 /*----------------------------------------------------------------------------*/
3583 VOID
3584 qmHandleMailboxRxMessage(
3585 IN MAILBOX_MSG_T prMailboxRxMsg
3586 )
3587 {
3588 //DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n");
3589 /* TODO */
3590 }
3591
3592
3593 /*----------------------------------------------------------------------------*/
3594 /*!
3595 * \brief Handle ADD RX BA Event from the FW
3596 *
3597 * \param[in] prAdapter Adapter pointer
3598 * \param[in] prEvent The event packet from the FW
3599 *
3600 * \return (none)
3601 */
3602 /*----------------------------------------------------------------------------*/
3603 VOID
3604 qmHandleEventRxAddBa(
3605 IN P_ADAPTER_T prAdapter,
3606 IN P_WIFI_EVENT_T prEvent
3607 )
3608 {
3609 P_EVENT_RX_ADDBA_T prEventRxAddBa;
3610 P_STA_RECORD_T prStaRec;
3611 UINT_32 u4Tid;
3612 UINT_32 u4WinSize;
3613
3614 DBGLOG(QM, INFO, ("QM:Event +RxBa\n"));
3615
3616 prEventRxAddBa = (P_EVENT_RX_ADDBA_T)prEvent;
3617 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx);
3618
3619 if(!prStaRec){
3620 /* Invalid STA_REC index, discard the event packet */
3621 //ASSERT(0);
3622 DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"));
3623 return;
3624 }
3625
3626 #if 0
3627 if(!(prStaRec->fgIsValid)){
3628 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3629 DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"));
3630 //ASSERT(0);
3631 //return;
3632 }
3633 #endif
3634
3635 u4Tid = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_TID_MASK)
3636 >> BA_PARAM_SET_TID_MASK_OFFSET);
3637
3638 u4WinSize = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_BUFFER_SIZE_MASK)
3639 >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET);
3640
3641 if(!qmAddRxBaEntry(
3642 prAdapter,
3643 prStaRec->ucIndex,
3644 (UINT_8)u4Tid,
3645 (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN),
3646 (UINT_16)u4WinSize)){
3647
3648 /* FW shall ensure the availabiilty of the free-to-use BA entry */
3649 DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n"));
3650 ASSERT(0);
3651 }
3652
3653 }
3654
3655 /*----------------------------------------------------------------------------*/
3656 /*!
3657 * \brief Handle DEL RX BA Event from the FW
3658 *
3659 * \param[in] prAdapter Adapter pointer
3660 * \param[in] prEvent The event packet from the FW
3661 *
3662 * \return (none)
3663 */
3664 /*----------------------------------------------------------------------------*/
3665 VOID
3666 qmHandleEventRxDelBa(
3667 IN P_ADAPTER_T prAdapter,
3668 IN P_WIFI_EVENT_T prEvent
3669 )
3670 {
3671 P_EVENT_RX_DELBA_T prEventRxDelBa;
3672 P_STA_RECORD_T prStaRec;
3673
3674 //DbgPrint("QM:Event -RxBa\n");
3675
3676 prEventRxDelBa = (P_EVENT_RX_DELBA_T)prEvent;
3677 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx);
3678
3679 if(!prStaRec){
3680 /* Invalid STA_REC index, discard the event packet */
3681 //ASSERT(0);
3682 return;
3683 }
3684
3685 #if 0
3686 if(!(prStaRec->fgIsValid)){
3687 /* TODO: (Tehuang) Handle the Host-FW synchronization issue */
3688 //ASSERT(0);
3689 return;
3690 }
3691 #endif
3692
3693 qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE);
3694
3695 }
3696
3697 P_RX_BA_ENTRY_T
3698 qmLookupRxBaEntry(
3699 IN P_ADAPTER_T prAdapter,
3700 UINT_8 ucStaRecIdx,
3701 UINT_8 ucTid
3702 )
3703 {
3704 int i;
3705 P_QUE_MGT_T prQM = &prAdapter->rQM;
3706
3707 //DbgPrint("QM: Enter qmLookupRxBaEntry()\n");
3708
3709 for(i=0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
3710 if(prQM->arRxBaTable[i].fgIsValid){
3711 if((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) &&
3712 (prQM->arRxBaTable[i].ucTid == ucTid)){
3713 return &prQM->arRxBaTable[i];
3714 }
3715 }
3716 }
3717 return NULL;
3718 }
3719
3720 BOOLEAN
3721 qmAddRxBaEntry(
3722 IN P_ADAPTER_T prAdapter,
3723 IN UINT_8 ucStaRecIdx,
3724 IN UINT_8 ucTid,
3725 IN UINT_16 u2WinStart,
3726 IN UINT_16 u2WinSize
3727 )
3728 {
3729 int i;
3730 P_RX_BA_ENTRY_T prRxBaEntry = NULL;
3731 P_STA_RECORD_T prStaRec;
3732 P_QUE_MGT_T prQM = &prAdapter->rQM;
3733
3734 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3735
3736 if(ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){
3737 /* Invalid STA_REC index, discard the event packet */
3738 DBGLOG(QM, WARN, ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx));
3739 return FALSE;
3740 }
3741
3742 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3743 ASSERT(prStaRec);
3744
3745 //if(!(prStaRec->fgIsValid)){
3746 // DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA \n");
3747 // return FALSE;
3748 //}
3749
3750 //4 <1> Delete before adding
3751 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3752 if(qmLookupRxBaEntry(prAdapter, ucStaRecIdx,ucTid)){
3753 qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */
3754 }
3755
3756 //4 <2> Add a new BA entry
3757 /* No available entry to store the BA agreement info. Retrun FALSE. */
3758 if(prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS){
3759 DBGLOG(QM, ERROR, ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3760 return FALSE;
3761 }
3762 else{
3763 /* Find the free-to-use BA entry */
3764 for(i=0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
3765 if(!prQM->arRxBaTable[i].fgIsValid){
3766 prRxBaEntry = &(prQM->arRxBaTable[i]);
3767 prQM->ucRxBaCount++;
3768 DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount));
3769 break;
3770 }
3771 }
3772
3773 /* If a free-to-use entry is found, configure it and associate it with the STA_REC */
3774 u2WinSize += CFG_RX_BA_INC_SIZE;
3775 if(prRxBaEntry){
3776 prRxBaEntry->ucStaRecIdx = ucStaRecIdx;
3777 prRxBaEntry->ucTid = ucTid;
3778 prRxBaEntry->u2WinStart = u2WinStart;
3779 prRxBaEntry->u2WinSize= u2WinSize;
3780 prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT);
3781 prRxBaEntry->fgIsValid = TRUE;
3782 prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE;
3783
3784 g_arMissTimeout[ucStaRecIdx][ucTid] = 0;
3785
3786 DBGLOG(QM, INFO, ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n",
3787 ucStaRecIdx, ucTid,
3788 prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize));
3789
3790 /* Update the BA entry reference table for per-packet lookup */
3791 prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry;
3792 }
3793 else{
3794 /* This shall not happen because FW should keep track of the usage of RX BA entries */
3795 DBGLOG(QM, ERROR, ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount));
3796 return FALSE;
3797 }
3798 }
3799
3800 return TRUE;
3801 }
3802 VOID
3803 qmDelRxBaEntry(
3804 IN P_ADAPTER_T prAdapter,
3805 IN UINT_8 ucStaRecIdx,
3806 IN UINT_8 ucTid,
3807 IN BOOLEAN fgFlushToHost
3808 )
3809 {
3810 P_RX_BA_ENTRY_T prRxBaEntry;
3811 P_STA_RECORD_T prStaRec;
3812 P_SW_RFB_T prFlushedPacketList = NULL;
3813 P_QUE_MGT_T prQM = &prAdapter->rQM;
3814
3815 ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD);
3816
3817 prStaRec = &prAdapter->arStaRec[ucStaRecIdx];
3818 ASSERT(prStaRec);
3819
3820 #if 0
3821 if(!(prStaRec->fgIsValid)){
3822 DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA \n");
3823 return;
3824 }
3825 #endif
3826
3827 /* Remove the BA entry for the same (STA, TID) tuple if it exists */
3828 prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid];
3829
3830 if(prRxBaEntry){
3831
3832 prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid);
3833
3834 if(prFlushedPacketList){
3835
3836 if(fgFlushToHost) {
3837 wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList);
3838 }
3839 else {
3840
3841 P_SW_RFB_T prSwRfb;
3842 P_SW_RFB_T prNextSwRfb;
3843 prSwRfb = prFlushedPacketList;
3844
3845 do {
3846 prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prSwRfb);
3847 nicRxReturnRFB(prAdapter, prSwRfb);
3848 prSwRfb = prNextSwRfb;
3849 } while(prSwRfb);
3850
3851 }
3852
3853
3854 }
3855 #if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0))
3856 /* Update RX BA entry state. Note that RX queue flush is not done here */
3857 prRxBaEntry->fgIsValid = FALSE;
3858 prQM->ucRxBaCount--;
3859
3860 /* Debug */
3861 #if 0
3862 DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount);
3863 #endif
3864
3865 /* Update STA RX BA table */
3866 prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL;
3867 #endif
3868
3869 DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid));
3870
3871 }
3872
3873
3874 /* Debug */
3875 #if CFG_HIF_RX_STARVATION_WARNING
3876 {
3877 P_RX_CTRL_T prRxCtrl;
3878 prRxCtrl = &prAdapter->rRxCtrl;
3879 DBGLOG(QM, TRACE, ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, prRxCtrl->u4DequeuedCnt));
3880 }
3881 #endif
3882 }
3883
3884
3885 /*----------------------------------------------------------------------------*/
3886 /*!
3887 * \brief To process WMM related IEs in ASSOC_RSP
3888 *
3889 * \param[in] prAdapter Adapter pointer
3890 * \param[in] prSwRfb The received frame
3891 * \param[in] pucIE The pointer to the first IE in the frame
3892 * \param[in] u2IELength The total length of IEs in the frame
3893 *
3894 * \return none
3895 */
3896 /*----------------------------------------------------------------------------*/
3897 VOID
3898 mqmProcessAssocReq (
3899 IN P_ADAPTER_T prAdapter,
3900 IN P_SW_RFB_T prSwRfb,
3901 IN PUINT_8 pucIE,
3902 IN UINT_16 u2IELength
3903 )
3904 {
3905 P_STA_RECORD_T prStaRec;
3906 UINT_16 u2Offset;
3907 PUINT_8 pucIEStart;
3908 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
3909 P_IE_WMM_INFO_T prIeWmmInfo;
3910
3911 DEBUGFUNC("mqmProcessAssocReq");
3912
3913 ASSERT(prSwRfb);
3914 ASSERT(pucIE);
3915
3916 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
3917 ASSERT(prStaRec);
3918
3919 if(prStaRec == NULL) {
3920 return;
3921 }
3922
3923 prStaRec->fgIsQoS = FALSE;
3924 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
3925
3926 pucIEStart = pucIE;
3927
3928 /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/
3929 if (!prAdapter->rWifiVar.fgSupportQoS) {
3930 return;
3931 }
3932
3933
3934 /* Determine whether QoS is enabled with the association */
3935 else{
3936 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
3937 switch (IE_ID(pucIE)) {
3938 case ELEM_ID_WMM:
3939
3940 if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
3941 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
3942
3943 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
3944 case VENDOR_OUI_SUBTYPE_WMM_INFO:
3945 {
3946
3947 UINT_8 ucQosInfo;
3948 UINT_8 ucQosInfoAC;
3949 UINT_8 ucBmpAC;
3950 if(IE_LEN(pucIE) != 7){
3951 break; /* WMM Info IE with a wrong length */
3952 }
3953 prStaRec->fgIsQoS = TRUE;
3954 prStaRec->fgIsWmmSupported = TRUE;
3955
3956 prIeWmmInfo = (P_IE_WMM_INFO_T)pucIE;
3957 ucQosInfo = prIeWmmInfo->ucQosInfo;
3958 ucQosInfoAC = ucQosInfo & BITS(0, 3);
3959
3960 prStaRec->fgIsUapsdSupported = ((ucQosInfoAC)? TRUE: FALSE) &
3961 prAdapter->rWifiVar.fgSupportUAPSD;
3962
3963 ucBmpAC = 0;
3964
3965 if( ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) {
3966 ucBmpAC |= BIT(ACI_VO);
3967 }
3968 if( ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) {
3969 ucBmpAC |= BIT(ACI_VI);
3970 }
3971 if( ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) {
3972 ucBmpAC |= BIT(ACI_BE);
3973 }
3974 if( ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) {
3975 ucBmpAC |= BIT(ACI_BK);
3976 }
3977
3978 prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC;
3979
3980 prStaRec->ucUapsdSp = (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5;
3981
3982 }
3983 break;
3984
3985 default:
3986 /* Other WMM QoS IEs. Ignore any */
3987 break;
3988 }
3989 }
3990 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
3991
3992 break;
3993
3994 case ELEM_ID_HT_CAP:
3995 /* Some client won't put the WMM IE if client is 802.11n */
3996 if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
3997 prStaRec->fgIsQoS = TRUE;
3998 }
3999 break;
4000 default:
4001 break;
4002 }
4003 }
4004
4005 DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4006
4007 }
4008 }
4009
4010
4011 /*----------------------------------------------------------------------------*/
4012 /*!
4013 * \brief To process WMM related IEs in ASSOC_RSP
4014 *
4015 * \param[in] prAdapter Adapter pointer
4016 * \param[in] prSwRfb The received frame
4017 * \param[in] pucIE The pointer to the first IE in the frame
4018 * \param[in] u2IELength The total length of IEs in the frame
4019 *
4020 * \return none
4021 */
4022 /*----------------------------------------------------------------------------*/
4023 VOID
4024 mqmProcessAssocRsp (
4025 IN P_ADAPTER_T prAdapter,
4026 IN P_SW_RFB_T prSwRfb,
4027 IN PUINT_8 pucIE,
4028 IN UINT_16 u2IELength
4029 )
4030 {
4031 P_STA_RECORD_T prStaRec;
4032 UINT_16 u2Offset;
4033 PUINT_8 pucIEStart;
4034 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4035
4036 DEBUGFUNC("mqmProcessAssocRsp");
4037
4038 ASSERT(prSwRfb);
4039 ASSERT(pucIE);
4040
4041 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4042 ASSERT(prStaRec);
4043
4044 if(prStaRec == NULL) {
4045 return;
4046 }
4047
4048 prStaRec->fgIsQoS = FALSE;
4049
4050 pucIEStart = pucIE;
4051
4052 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n",
4053 prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS));
4054
4055 /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/
4056 //if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported))
4057 if((!prAdapter->rWifiVar.fgSupportQoS))
4058 {
4059 return;
4060 }
4061
4062 /* Determine whether QoS is enabled with the association */
4063 else{
4064 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4065 switch (IE_ID(pucIE)) {
4066 case ELEM_ID_WMM:
4067 if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4068 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
4069
4070 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
4071 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4072 if(IE_LEN(pucIE) != 24){
4073 break; /* WMM Info IE with a wrong length */
4074 }
4075 prStaRec->fgIsQoS = TRUE;
4076 break;
4077
4078 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4079 if(IE_LEN(pucIE) != 7){
4080 break; /* WMM Info IE with a wrong length */
4081 }
4082 prStaRec->fgIsQoS = TRUE;
4083 break;
4084
4085 default:
4086 /* Other WMM QoS IEs. Ignore any */
4087 break;
4088 }
4089 }
4090 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */
4091 break;
4092
4093 case ELEM_ID_HT_CAP:
4094 /* Some AP won't put the WMM IE if client is 802.11n */
4095 if ( IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) {
4096 prStaRec->fgIsQoS = TRUE;
4097 }
4098 break;
4099 default:
4100 break;
4101 }
4102 }
4103
4104 /* Parse AC parameters and write to HW CRs */
4105 if((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)){
4106 mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE);
4107 }
4108
4109 DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS));
4110 if(prStaRec->fgIsWmmSupported) {
4111 nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex);
4112 }
4113 }
4114 }
4115
4116
4117 /*----------------------------------------------------------------------------*/
4118 /*!
4119 * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp)
4120 *
4121 * \param[in] prAdapter Adapter pointer
4122 * \param[in] prSwRfb The received frame
4123 * \param[in] pucIE The pointer to the first IE in the frame
4124 * \param[in] u2IELength The total length of IEs in the frame
4125 * \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs.
4126 *
4127 * \return none
4128 */
4129 /*----------------------------------------------------------------------------*/
4130 VOID
4131 mqmParseEdcaParameters (
4132 IN P_ADAPTER_T prAdapter,
4133 IN P_SW_RFB_T prSwRfb,
4134 IN PUINT_8 pucIE,
4135 IN UINT_16 u2IELength,
4136 IN BOOLEAN fgForceOverride
4137 )
4138 {
4139 P_STA_RECORD_T prStaRec;
4140 UINT_16 u2Offset;
4141 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4142 P_BSS_INFO_T prBssInfo;
4143
4144 DEBUGFUNC("mqmParseEdcaParameters");
4145
4146 ASSERT(prSwRfb);
4147 ASSERT(pucIE);
4148
4149 prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
4150 ASSERT(prStaRec);
4151
4152 if(prStaRec == NULL) {
4153 return;
4154 }
4155
4156 DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n",
4157 prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS));
4158
4159 if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)){
4160 return;
4161 }
4162
4163 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
4164
4165 /* Goal: Obtain the EDCA parameters */
4166 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4167 switch (IE_ID(pucIE)) {
4168 case ELEM_ID_WMM:
4169
4170 if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4171 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
4172
4173 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
4174 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4175 if(IE_LEN(pucIE) != 24){
4176 break; /* WMM Param IE with a wrong length */
4177 }
4178 else{
4179 P_AC_QUE_PARMS_T prAcQueParams;
4180 P_IE_WMM_PARAM_T prIeWmmParam;
4181 ENUM_WMM_ACI_T eAci;
4182 PUINT_8 pucWmmParamSetCount;
4183 //int i;
4184
4185 pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount);
4186
4187 prIeWmmParam = (P_IE_WMM_PARAM_T)pucIE;
4188
4189 /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */
4190 if(!fgForceOverride){
4191 if(*pucWmmParamSetCount == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)){
4192 break; /* Ignore the IE without updating HW CRs */
4193 }
4194 }
4195
4196 /* Update Parameter Set Count */
4197 *pucWmmParamSetCount = (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT);
4198
4199 /* Update EDCA parameters */
4200 for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){
4201
4202 prAcQueParams = &prBssInfo->arACQueParms[eAci];
4203 mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams);
4204
4205 prAcQueParams->fgIsACMSet =
4206 (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE;
4207 prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN;
4208
4209 DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
4210 eAci, prAcQueParams->fgIsACMSet,
4211 prAcQueParams->u2Aifsn, prAcQueParams->u2CWmin,
4212 prAcQueParams->u2CWmax, prAcQueParams->u2TxopLimit));
4213 }
4214 }
4215 break;
4216
4217 default:
4218 /* Other WMM QoS IEs. Ignore */
4219 break;
4220 }
4221
4222 }
4223 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4224 break;
4225 default:
4226 break;
4227 }
4228 }
4229 }
4230
4231
4232 /*----------------------------------------------------------------------------*/
4233 /*!
4234 * \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE
4235 *
4236 * \param[in] prAdapter Adapter pointer
4237 * \param[in] prIeWmmParam The pointer to the WMM Parameter IE
4238 * \param[in] u4AcOffset The offset specifying the AC queue for parsing
4239 * \param[in] prHwAcParams The parameter structure used to configure the HW CRs
4240 *
4241 * \return none
4242 */
4243 /*----------------------------------------------------------------------------*/
4244 VOID
4245 mqmFillAcQueParam(
4246 IN P_IE_WMM_PARAM_T prIeWmmParam,
4247 IN UINT_32 u4AcOffset,
4248 OUT P_AC_QUE_PARMS_T prAcQueParams
4249 )
4250 {
4251 prAcQueParams->u2Aifsn = *((PUINT_8)(&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4));
4252
4253 prAcQueParams->u2CWmax =
4254 BIT(((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK)
4255 >> WMM_ECW_WMAX_OFFSET)-1;
4256
4257 prAcQueParams->u2CWmin =
4258 BIT((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK)-1;
4259
4260 WLAN_GET_FIELD_16(((PUINT_8)(&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)),&(prAcQueParams->u2TxopLimit));
4261
4262 prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME;
4263
4264
4265 }
4266
4267
4268 /*----------------------------------------------------------------------------*/
4269 /*!
4270 * \brief To parse WMM/11n related IEs in scan results (only for AP peers)
4271 *
4272 * \param[in] prAdapter Adapter pointer
4273 * \param[in] prScanResult The scan result which shall be parsed to obtain needed info
4274 * \param[out] prStaRec The obtained info is stored in the STA_REC
4275 *
4276 * \return none
4277 */
4278 /*----------------------------------------------------------------------------*/
4279 #if (CFG_SUPPORT_TDLS == 1) /* for test purpose */
4280 BOOLEAN flgTdlsTestExtCapElm = FALSE;
4281 UINT8 aucTdlsTestExtCapElm[7];
4282 #endif /* CFG_SUPPORT_TDLS */
4283 VOID
4284 mqmProcessScanResult(
4285 IN P_ADAPTER_T prAdapter,
4286 IN P_BSS_DESC_T prScanResult,
4287 OUT P_STA_RECORD_T prStaRec
4288 )
4289 {
4290 PUINT_8 pucIE;
4291 UINT_16 u2IELength;
4292 UINT_16 u2Offset;
4293 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4294
4295 DEBUGFUNC("mqmProcessScanResult");
4296
4297 ASSERT(prScanResult);
4298 ASSERT(prStaRec);
4299
4300 /* Reset the flag before parsing */
4301 prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE;
4302
4303 if (!prAdapter->rWifiVar.fgSupportQoS){
4304 return;
4305 }
4306
4307 u2IELength = prScanResult->u2IELength;
4308 pucIE = prScanResult->aucIEBuf;
4309
4310 #if (CFG_SUPPORT_TDLS == 1)
4311 /* TDLS test purpose */
4312 if (flgTdlsTestExtCapElm == TRUE)
4313 TdlsexBssExtCapParse(prStaRec, aucTdlsTestExtCapElm);
4314 #endif /* CFG_SUPPORT_TDLS */
4315
4316 /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */
4317 IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
4318 switch (IE_ID(pucIE)) {
4319 case ELEM_ID_EXTENDED_CAP:
4320 #if (CFG_SUPPORT_TDLS == 1)
4321 TdlsexBssExtCapParse(prStaRec, pucIE);
4322 #endif /* CFG_SUPPORT_TDLS */
4323 break;
4324
4325 case ELEM_ID_WMM:
4326 if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) &&
4327 (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){
4328
4329 switch(WMM_IE_OUI_SUBTYPE(pucIE)){
4330 case VENDOR_OUI_SUBTYPE_WMM_PARAM:
4331 if(IE_LEN(pucIE) != 24){
4332 break; /* WMM Param IE with a wrong length */
4333 }
4334 else{
4335 prStaRec->fgIsWmmSupported = TRUE;
4336 prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_PARAM_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE);
4337 }
4338 break;
4339
4340 case VENDOR_OUI_SUBTYPE_WMM_INFO:
4341 if(IE_LEN(pucIE) != 7){
4342 break; /* WMM Info IE with a wrong length */
4343 }
4344 else{
4345 prStaRec->fgIsWmmSupported = TRUE;
4346 prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_INFO_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE);
4347 }
4348 break;
4349
4350 default:
4351 /* A WMM QoS IE that doesn't matter. Ignore it. */
4352 break;
4353 }
4354 }
4355 /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */
4356
4357 break;
4358
4359 default:
4360 /* A WMM IE that doesn't matter. Ignore it. */
4361 break;
4362 }
4363 }
4364 DBGLOG(QM, LOUD, ("MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n",
4365 prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported));
4366
4367 }
4368
4369 UINT_8
4370 qmGetStaRecIdx(
4371 IN P_ADAPTER_T prAdapter,
4372 IN PUINT_8 pucEthDestAddr,
4373 IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType
4374 )
4375 {
4376 UINT_32 i;
4377 P_STA_RECORD_T prTempStaRec;
4378
4379 prTempStaRec = NULL;
4380
4381 ASSERT(prAdapter);
4382
4383 //4 <1> DA = BMCAST
4384 if(IS_BMCAST_MAC_ADDR(pucEthDestAddr)){
4385 return STA_REC_INDEX_BMCAST;
4386 }
4387
4388
4389 //4 <2> Check if an AP STA is present
4390 for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
4391 prTempStaRec = &(prAdapter->arStaRec[i]);
4392 if((prTempStaRec->ucNetTypeIndex == eNetworkType)
4393 && (prTempStaRec->fgIsAp)
4394 && (prTempStaRec->fgIsValid)){
4395 return prTempStaRec->ucIndex;
4396 }
4397 }
4398
4399 //4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client)
4400 for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){
4401 prTempStaRec = &(prAdapter->arStaRec[i]);
4402 if(prTempStaRec->fgIsValid){
4403 if(EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)){
4404 return prTempStaRec->ucIndex;
4405 }
4406 }
4407 }
4408
4409
4410 //4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW
4411 return STA_REC_INDEX_NOT_FOUND;
4412 }
4413
4414
4415 UINT_32
4416 mqmGenerateWmmInfoIEByParam (
4417 BOOLEAN fgSupportUAPSD,
4418 UINT_8 ucBmpDeliveryAC,
4419 UINT_8 ucBmpTriggerAC,
4420 UINT_8 ucUapsdSp,
4421 UINT_8 *pOutBuf
4422 )
4423 {
4424 P_IE_WMM_INFO_T prIeWmmInfo;
4425 UINT_32 ucUapsd[] = {
4426 WMM_QOS_INFO_BE_UAPSD,
4427 WMM_QOS_INFO_BK_UAPSD,
4428 WMM_QOS_INFO_VI_UAPSD,
4429 WMM_QOS_INFO_VO_UAPSD
4430 };
4431 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4432
4433 ASSERT(pOutBuf);
4434
4435 prIeWmmInfo = (P_IE_WMM_INFO_T)pOutBuf;
4436
4437 prIeWmmInfo->ucId = ELEM_ID_WMM;
4438 prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4439
4440 /* WMM-2.2.1 WMM Information Element Field Values */
4441 prIeWmmInfo->aucOui[0] = aucWfaOui[0];
4442 prIeWmmInfo->aucOui[1] = aucWfaOui[1];
4443 prIeWmmInfo->aucOui[2] = aucWfaOui[2];
4444 prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
4445 prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
4446
4447 prIeWmmInfo->ucVersion = VERSION_WMM;
4448 prIeWmmInfo->ucQosInfo = 0;
4449
4450 /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4451 if(fgSupportUAPSD){
4452
4453 UINT_8 ucQosInfo = 0;
4454 UINT_8 i;
4455
4456
4457 /* Static U-APSD setting */
4458 for(i = ACI_BE; i <= ACI_VO; i++){
4459 if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)){
4460 ucQosInfo |= (UINT_8)ucUapsd[i];
4461 }
4462 }
4463
4464
4465 if (ucBmpDeliveryAC & ucBmpTriggerAC) {
4466 switch (ucUapsdSp) {
4467 case WMM_MAX_SP_LENGTH_ALL:
4468 ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
4469 break;
4470
4471 case WMM_MAX_SP_LENGTH_2:
4472 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4473 break;
4474
4475 case WMM_MAX_SP_LENGTH_4:
4476 ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
4477 break;
4478
4479 case WMM_MAX_SP_LENGTH_6:
4480 ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
4481 break;
4482
4483 default:
4484 DBGLOG(QM, INFO, ("MQM: Incorrect SP length \n"));
4485 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4486 break;
4487 }
4488 }
4489 prIeWmmInfo->ucQosInfo = ucQosInfo;
4490
4491 }
4492
4493 /* Increment the total IE length for the Element ID and Length fields. */
4494 return IE_SIZE(prIeWmmInfo);
4495 }
4496
4497
4498 /*----------------------------------------------------------------------------*/
4499 /*!
4500 * @brief Generate the WMM Info IE
4501 *
4502 * \param[in] prAdapter Adapter pointer
4503 * @param prMsduInfo The TX MMPDU
4504 *
4505 * @return (none)
4506 */
4507 /*----------------------------------------------------------------------------*/
4508 VOID
4509 mqmGenerateWmmInfoIE (
4510 IN P_ADAPTER_T prAdapter,
4511 IN P_MSDU_INFO_T prMsduInfo
4512 )
4513 {
4514 P_IE_WMM_INFO_T prIeWmmInfo;
4515 P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo;
4516 P_BSS_INFO_T prBssInfo;
4517 P_STA_RECORD_T prStaRec;
4518
4519 DEBUGFUNC("mqmGenerateWmmInfoIE");
4520
4521 ASSERT(prMsduInfo);
4522
4523 /* In case QoS is not turned off, exit directly */
4524 if(!prAdapter->rWifiVar.fgSupportQoS){
4525 return;
4526 }
4527
4528 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4529 ASSERT(prStaRec);
4530
4531 if(prStaRec == NULL) {
4532 return;
4533 }
4534
4535 if(!prStaRec->fgIsWmmSupported) {
4536 return;
4537 }
4538
4539 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]);
4540
4541 prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo;
4542
4543 prIeWmmInfo = (P_IE_WMM_INFO_T)
4544 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4545
4546 #if 0
4547 prIeWmmInfo->ucId = ELEM_ID_WMM;
4548 prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO;
4549
4550 /* WMM-2.2.1 WMM Information Element Field Values */
4551 prIeWmmInfo->aucOui[0] = aucWfaOui[0];
4552 prIeWmmInfo->aucOui[1] = aucWfaOui[1];
4553 prIeWmmInfo->aucOui[2] = aucWfaOui[2];
4554 prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM;
4555 prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO;
4556
4557 prIeWmmInfo->ucVersion = VERSION_WMM;
4558 prIeWmmInfo->ucQosInfo = 0;
4559
4560 /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4561 // if(prAdapter->rWifiVar.fgSupportUAPSD){
4562 if(prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported){
4563
4564 UINT_8 ucQosInfo = 0;
4565 UINT_8 i;
4566
4567
4568 /* Static U-APSD setting */
4569 for(i = ACI_BE; i <= ACI_VO; i++){
4570 if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)){
4571 ucQosInfo |= (UINT_8)ucUapsd[i];
4572 }
4573 }
4574
4575
4576 if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) {
4577 switch (prPmProfSetupInfo->ucUapsdSp) {
4578 case WMM_MAX_SP_LENGTH_ALL:
4579 ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL;
4580 break;
4581
4582 case WMM_MAX_SP_LENGTH_2:
4583 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4584 break;
4585
4586 case WMM_MAX_SP_LENGTH_4:
4587 ucQosInfo |= WMM_QOS_INFO_MAX_SP_4;
4588 break;
4589
4590 case WMM_MAX_SP_LENGTH_6:
4591 ucQosInfo |= WMM_QOS_INFO_MAX_SP_6;
4592 break;
4593
4594 default:
4595 DBGLOG(QM, INFO, ("MQM: Incorrect SP length \n"));
4596 ucQosInfo |= WMM_QOS_INFO_MAX_SP_2;
4597 break;
4598 }
4599 }
4600 prIeWmmInfo->ucQosInfo = ucQosInfo;
4601
4602 }
4603
4604 /* Increment the total IE length for the Element ID and Length fields. */
4605 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo);
4606 #else
4607
4608 prMsduInfo->u2FrameLength += mqmGenerateWmmInfoIEByParam(\
4609 (prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported),
4610 prPmProfSetupInfo->ucBmpDeliveryAC,
4611 prPmProfSetupInfo->ucBmpTriggerAC,
4612 prPmProfSetupInfo->ucUapsdSp,
4613 (UINT_8 *)prIeWmmInfo);
4614 #endif
4615 }
4616
4617
4618 #if 0
4619 /*----------------------------------------------------------------------------*/
4620 /*!
4621 * @brief log2 calculation for CW
4622 *
4623 * @param[in] val value
4624 *
4625 * @return log2(val)
4626 */
4627 /*----------------------------------------------------------------------------*/
4628
4629 UINT_32 cwlog2(UINT_32 val) {
4630
4631 UINT_32 n;
4632 n=0;
4633
4634 while (val >= 512) { n+= 9; val = val >> 9; }
4635 while (val >= 16) { n+= 4; val >>= 4; }
4636 while (val >= 2) { n+= 1; val >>= 1; }
4637 return n;
4638 }
4639 #endif
4640
4641
4642 UINT_32
4643 mqmGenerateWmmParamIEByParam (
4644 P_ADAPTER_T prAdapter,
4645 P_BSS_INFO_T prBssInfo,
4646 UINT_8 *pOutBuf
4647 )
4648 {
4649 P_IE_WMM_PARAM_T prIeWmmParam;
4650 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4651
4652 UINT_8 aucACI[] = {
4653 WMM_ACI_AC_BE,
4654 WMM_ACI_AC_BK,
4655 WMM_ACI_AC_VI,
4656 WMM_ACI_AC_VO
4657 };
4658 ENUM_WMM_ACI_T eAci;
4659
4660
4661 ASSERT(pOutBuf);
4662
4663 prIeWmmParam = (P_IE_WMM_PARAM_T)pOutBuf;
4664
4665 prIeWmmParam->ucId = ELEM_ID_WMM;
4666 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
4667
4668 /* WMM-2.2.1 WMM Information Element Field Values */
4669 prIeWmmParam->aucOui[0] = aucWfaOui[0];
4670 prIeWmmParam->aucOui[1] = aucWfaOui[1];
4671 prIeWmmParam->aucOui[2] = aucWfaOui[2];
4672 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
4673 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
4674
4675 prIeWmmParam->ucVersion = VERSION_WMM;
4676 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
4677
4678 /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4679 if (prAdapter->rWifiVar.fgSupportUAPSD) {
4680 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
4681 }
4682
4683 /* EDCA parameter */
4684
4685 for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){
4686
4687 //DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
4688 // eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ,
4689 // prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn,
4690 // prBssInfo->arACQueParmsForBcast[eAci].u2CWmin,
4691 // prBssInfo->arACQueParmsForBcast[eAci].u2CWmax,
4692 // prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit));
4693
4694 *( ((PUINT_8)(&prIeWmmParam->ucAciAifsn_BE)) + (eAci <<2) ) = (UINT_8) (aucACI[eAci]
4695 | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM:0 )
4696 | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN)));
4697 #if 1
4698 *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4699 | (((prBssInfo->aucCWminLog2ForBcast[eAci] )) & WMM_ECW_WMIN_MASK)
4700 | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci] )) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4701 );
4702 #else
4703 *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4704 | (cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmin + 1)) & WMM_ECW_WMIN_MASK)
4705 | ((cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmax + 1)) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4706 );
4707 #endif
4708
4709 WLAN_SET_FIELD_16( ((PUINT_8)(prIeWmmParam->aucTxopLimit_BE)) + (eAci<<2)
4710 , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
4711
4712 }
4713
4714 /* Increment the total IE length for the Element ID and Length fields. */
4715 return IE_SIZE(prIeWmmParam);
4716 }
4717
4718
4719 /*----------------------------------------------------------------------------*/
4720 /*!
4721 * @brief Generate the WMM Param IE
4722 *
4723 * \param[in] prAdapter Adapter pointer
4724 * @param prMsduInfo The TX MMPDU
4725 *
4726 * @return (none)
4727 */
4728 /*----------------------------------------------------------------------------*/
4729 VOID
4730 mqmGenerateWmmParamIE (
4731 IN P_ADAPTER_T prAdapter,
4732 IN P_MSDU_INFO_T prMsduInfo
4733 )
4734 {
4735 P_IE_WMM_PARAM_T prIeWmmParam;
4736
4737 #if 0
4738 UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
4739
4740 UINT_8 aucACI[] = {
4741 WMM_ACI_AC_BE,
4742 WMM_ACI_AC_BK,
4743 WMM_ACI_AC_VI,
4744 WMM_ACI_AC_VO
4745 };
4746 ENUM_WMM_ACI_T eAci;
4747 #endif
4748
4749 P_BSS_INFO_T prBssInfo;
4750 P_STA_RECORD_T prStaRec;
4751
4752 DEBUGFUNC("mqmGenerateWmmParamIE");
4753 DBGLOG(QM, LOUD,("\n"));
4754
4755 ASSERT(prMsduInfo);
4756
4757 /* In case QoS is not turned off, exit directly */
4758 if(!prAdapter->rWifiVar.fgSupportQoS){
4759 return;
4760 }
4761
4762 prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
4763
4764 if(prStaRec) {
4765 if(!prStaRec->fgIsQoS) {
4766 return;
4767 }
4768 }
4769
4770 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]);
4771
4772 if(!prBssInfo->fgIsQBSS) { return; }
4773
4774 #if 0 // 20120220 frog: update beacon content & change OP mode is a separate event for P2P network.
4775 if( prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT &&
4776 prBssInfo->eCurrentOPMode != OP_MODE_BOW)
4777 {
4778 return;
4779 }
4780 #endif
4781
4782 prIeWmmParam = (P_IE_WMM_PARAM_T)
4783 ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength);
4784
4785 #if 0
4786 prIeWmmParam->ucId = ELEM_ID_WMM;
4787 prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM;
4788
4789 /* WMM-2.2.1 WMM Information Element Field Values */
4790 prIeWmmParam->aucOui[0] = aucWfaOui[0];
4791 prIeWmmParam->aucOui[1] = aucWfaOui[1];
4792 prIeWmmParam->aucOui[2] = aucWfaOui[2];
4793 prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM;
4794 prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM;
4795
4796 prIeWmmParam->ucVersion = VERSION_WMM;
4797 prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT);
4798
4799 /* UAPSD intial queue configurations (delivery and trigger enabled)*/
4800 if(prAdapter->rWifiVar.fgSupportUAPSD){
4801
4802 prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD;
4803
4804 }
4805
4806 /* EDCA parameter */
4807
4808 for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){
4809
4810 //DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n",
4811 // eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ,
4812 // prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn,
4813 // prBssInfo->arACQueParmsForBcast[eAci].u2CWmin,
4814 // prBssInfo->arACQueParmsForBcast[eAci].u2CWmax,
4815 // prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit));
4816
4817 *( ((PUINT_8)(&prIeWmmParam->ucAciAifsn_BE)) + (eAci <<2) ) = (UINT_8) (aucACI[eAci]
4818 | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM:0 )
4819 | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN)));
4820 #if 1
4821 *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4822 | (((prBssInfo->aucCWminLog2ForBcast[eAci] )) & WMM_ECW_WMIN_MASK)
4823 | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci] )) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4824 );
4825 #else
4826 *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0
4827 | (cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmin + 1)) & WMM_ECW_WMIN_MASK)
4828 | ((cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmax + 1)) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK)
4829 );
4830 #endif
4831
4832 WLAN_SET_FIELD_16( ((PUINT_8)(prIeWmmParam->aucTxopLimit_BE)) + (eAci<<2)
4833 , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit);
4834
4835 }
4836
4837 /* Increment the total IE length for the Element ID and Length fields. */
4838 prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam);
4839 #else
4840
4841 prMsduInfo->u2FrameLength += mqmGenerateWmmParamIEByParam(\
4842 prAdapter, prBssInfo, (UINT_8 *)prIeWmmParam);
4843 #endif
4844 }
4845
4846
4847
4848
4849 ENUM_FRAME_ACTION_T
4850 qmGetFrameAction(
4851 IN P_ADAPTER_T prAdapter,
4852 IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType,
4853 IN UINT_8 ucStaRecIdx,
4854 IN P_MSDU_INFO_T prMsduInfo,
4855 IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType
4856 )
4857 {
4858 P_BSS_INFO_T prBssInfo;
4859 P_STA_RECORD_T prStaRec;
4860 P_WLAN_MAC_HEADER_T prWlanFrame;
4861 UINT_16 u2TxFrameCtrl;
4862
4863 DEBUGFUNC("qmGetFrameAction");
4864
4865 #if (NIC_TX_BUFF_COUNT_TC4 > 2)
4866 #define QM_MGMT_QUUEUD_THRESHOLD 2
4867 #else
4868 #define QM_MGMT_QUUEUD_THRESHOLD 1
4869 #endif
4870
4871 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4));
4872 DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0);
4873
4874 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]);
4875 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx);
4876
4877 /* XXX Check BOW P2P AIS time ot set active */
4878 if (!IS_BSS_ACTIVE(prBssInfo)) {
4879 if (eFrameType == FRAME_TYPE_MMPDU) {
4880 prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4881 u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM
4882 if (((u2TxFrameCtrl == MAC_FRAME_DEAUTH) && (prMsduInfo->pfTxDoneHandler == NULL)) ||
4883 (u2TxFrameCtrl == MAC_FRAME_ACTION)) { /* whsu */
4884 return FRAME_ACTION_TX_PKT;
4885 }
4886 }
4887
4888 DBGLOG(QM, INFO, ("Drop packets Action (Inactive %u).\n",prBssInfo->ucNetTypeIndex));
4889 TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP);
4890 return FRAME_ACTION_DROP_PKT;
4891 }
4892
4893 /* TODO Handle disconnect issue */
4894
4895 /* P2P probe Request frame */
4896 do {
4897 if(eFrameType == FRAME_TYPE_MMPDU) {
4898 ASSERT(prMsduInfo!=NULL);
4899 prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket;
4900 u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM
4901
4902 if (u2TxFrameCtrl == MAC_FRAME_BEACON ) {
4903 if( prBssInfo->fgIsNetAbsent) {
4904 return FRAME_ACTION_DROP_PKT;
4905 }
4906 }
4907 else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) {
4908 if( prBssInfo->fgIsNetAbsent) {
4909 return FRAME_ACTION_DROP_PKT;
4910 }
4911 }
4912 else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) {
4913 if( prBssInfo->fgIsNetAbsent) {
4914 break;
4915 }
4916 DBGLOG(P2P, LOUD, ("Sending DEAUTH Frame\n"));
4917 return FRAME_ACTION_TX_PKT;
4918 }
4919 /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */
4920 else if(u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ
4921 || u2TxFrameCtrl == MAC_FRAME_AUTH
4922 || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ
4923 || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ
4924 || u2TxFrameCtrl == MAC_FRAME_ACTION) {
4925
4926 if(prStaRec){
4927 if(prStaRec->fgIsInPS) {
4928 if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) {
4929 return FRAME_ACTION_TX_PKT;
4930 }
4931 else {
4932 return FRAME_ACTION_QUEUE_PKT;
4933 }
4934 }
4935 }
4936 return FRAME_ACTION_TX_PKT;
4937 }
4938
4939 if (!prStaRec){
4940 return FRAME_ACTION_TX_PKT;
4941 }
4942 else {
4943 if (!prStaRec->fgIsInUse) {
4944 return FRAME_ACTION_DROP_PKT;
4945 }
4946 }
4947
4948 } /* FRAME_TYPE_MMPDU */
4949 else if ((eFrameType == FRAME_TYPE_802_1X)){
4950
4951 if (!prStaRec){
4952 return FRAME_ACTION_TX_PKT;
4953 }
4954 else {
4955 if (!prStaRec->fgIsInUse) {
4956 return FRAME_ACTION_DROP_PKT;
4957 }
4958 if(prStaRec->fgIsInPS) {
4959 if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) {
4960 return FRAME_ACTION_TX_PKT;
4961 }
4962 else {
4963 return FRAME_ACTION_QUEUE_PKT;
4964 }
4965 }
4966 }
4967
4968 } /* FRAME_TYPE_802_1X */
4969 else if ((!IS_BSS_ACTIVE(prBssInfo))
4970 || (!prStaRec)
4971 || (!prStaRec->fgIsInUse)){
4972 return FRAME_ACTION_DROP_PKT;
4973 }
4974 }while(0);
4975
4976 if (prBssInfo->fgIsNetAbsent){
4977 DBGLOG(QM, LOUD, ("Queue packets (Absent %u).\n",prBssInfo->ucNetTypeIndex));
4978 return FRAME_ACTION_QUEUE_PKT;
4979 }
4980
4981 if (prStaRec && prStaRec->fgIsInPS){
4982 DBGLOG(QM, LOUD, ("Queue packets (PS %u).\n",prStaRec->fgIsInPS));
4983 return FRAME_ACTION_QUEUE_PKT;
4984 }
4985 else {
4986 switch (eFrameType){
4987 case FRAME_TYPE_802_1X:
4988 if (!prStaRec->fgIsValid){
4989 return FRAME_ACTION_QUEUE_PKT;
4990 }
4991 break;
4992
4993 case FRAME_TYPE_MMPDU:
4994 break;
4995
4996 default:
4997 ASSERT(0);
4998 }
4999 }
5000
5001 return FRAME_ACTION_TX_PKT;
5002 }
5003
5004
5005 /*----------------------------------------------------------------------------*/
5006 /*!
5007 * \brief Handle BSS change operation Event from the FW
5008 *
5009 * \param[in] prAdapter Adapter pointer
5010 * \param[in] prEvent The event packet from the FW
5011 *
5012 * \return (none)
5013 */
5014 /*----------------------------------------------------------------------------*/
5015 VOID
5016 qmHandleEventBssAbsencePresence(
5017 IN P_ADAPTER_T prAdapter,
5018 IN P_WIFI_EVENT_T prEvent
5019 )
5020 {
5021 P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus;
5022 P_BSS_INFO_T prBssInfo;
5023 BOOLEAN fgIsNetAbsentOld;
5024
5025 prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T)prEvent;
5026 prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]);
5027 fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent;
5028 prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent;
5029 prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota;
5030
5031 //DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n",
5032 // prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota));
5033
5034 DBGLOG(QM, TRACE, ("NAF=%d,%d,%d\n",
5035 prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota));
5036
5037 if(!prBssInfo->fgIsNetAbsent) {
5038 QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_27);
5039 }
5040 else {
5041 QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_28);
5042 }
5043 /* From Absent to Present */
5044 if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)){
5045 kalSetEvent(prAdapter->prGlueInfo);
5046 }
5047 }
5048
5049
5050 /*----------------------------------------------------------------------------*/
5051 /*!
5052 * \brief Handle STA change PS mode Event from the FW
5053 *
5054 * \param[in] prAdapter Adapter pointer
5055 * \param[in] prEvent The event packet from the FW
5056 *
5057 * \return (none)
5058 */
5059 /*----------------------------------------------------------------------------*/
5060 VOID
5061 qmHandleEventStaChangePsMode(
5062 IN P_ADAPTER_T prAdapter,
5063 IN P_WIFI_EVENT_T prEvent
5064 )
5065 {
5066 P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode;
5067 P_STA_RECORD_T prStaRec;
5068 BOOLEAN fgIsInPSOld;
5069
5070 //DbgPrint("QM:Event -RxBa\n");
5071
5072 prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T)prEvent;
5073 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx);
5074 ASSERT(prStaRec);
5075
5076 if(prStaRec) {
5077
5078 fgIsInPSOld = prStaRec->fgIsInPS;
5079 prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs;
5080
5081 qmUpdateFreeQuota(
5082 prAdapter,
5083 prStaRec,
5084 prEventStaChangePsMode->ucUpdateMode,
5085 prEventStaChangePsMode->ucFreeQuota,
5086 0);
5087
5088 //DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n",
5089 // prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
5090
5091
5092 DBGLOG(QM, TRACE, ("PS=%d,%d\n",
5093 prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS));
5094
5095 /* From PS to Awake */
5096 if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)){
5097 kalSetEvent(prAdapter->prGlueInfo);
5098 }
5099 }
5100 }
5101
5102 /*----------------------------------------------------------------------------*/
5103 /*!
5104 * \brief Update STA free quota Event from FW
5105 *
5106 * \param[in] prAdapter Adapter pointer
5107 * \param[in] prEvent The event packet from the FW
5108 *
5109 * \return (none)
5110 */
5111 /*----------------------------------------------------------------------------*/
5112 VOID
5113 qmHandleEventStaUpdateFreeQuota(
5114 IN P_ADAPTER_T prAdapter,
5115 IN P_WIFI_EVENT_T prEvent
5116 )
5117 {
5118 P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota;
5119 P_STA_RECORD_T prStaRec;
5120
5121
5122 prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T)prEvent;
5123 prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx);
5124 ASSERT(prStaRec);
5125
5126 if(prStaRec) {
5127 if(prStaRec->fgIsInPS) {
5128 qmUpdateFreeQuota(
5129 prAdapter,
5130 prStaRec,
5131 prEventStaUpdateFreeQuota->ucUpdateMode,
5132 prEventStaUpdateFreeQuota->ucFreeQuota,
5133 prEventStaUpdateFreeQuota->aucReserved[0]);
5134
5135 kalSetEvent(prAdapter->prGlueInfo);
5136 }
5137 #if 0
5138 DBGLOG(QM, TRACE, ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n",
5139 prEventStaUpdateFreeQuota->ucStaRecIdx,
5140 prEventStaUpdateFreeQuota->ucUpdateMode,
5141 prEventStaUpdateFreeQuota->ucFreeQuota));
5142 #endif
5143
5144 DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n",
5145 prEventStaUpdateFreeQuota->ucStaRecIdx,
5146 prEventStaUpdateFreeQuota->ucUpdateMode,
5147 prEventStaUpdateFreeQuota->ucFreeQuota));
5148
5149
5150 }
5151
5152 }
5153
5154
5155 /*----------------------------------------------------------------------------*/
5156 /*!
5157 * \brief Update STA free quota
5158 *
5159 * \param[in] prStaRec the STA
5160 * \param[in] ucUpdateMode the method to update free quota
5161 * \param[in] ucFreeQuota the value for update
5162 *
5163 * \return (none)
5164 */
5165 /*----------------------------------------------------------------------------*/
5166 VOID
5167 qmUpdateFreeQuota(
5168 IN P_ADAPTER_T prAdapter,
5169 IN P_STA_RECORD_T prStaRec,
5170 IN UINT_8 ucUpdateMode,
5171 IN UINT_8 ucFreeQuota,
5172 IN UINT_8 ucNumOfTxDone
5173 )
5174 {
5175
5176 UINT_8 ucFreeQuotaForNonDelivery;
5177 UINT_8 ucFreeQuotaForDelivery;
5178 BOOLEAN flgIsUpdateForcedToDelivery;
5179
5180 ASSERT(prStaRec);
5181 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n",
5182 prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota ));
5183
5184 if(!prStaRec->fgIsInPS)return;
5185
5186 flgIsUpdateForcedToDelivery = FALSE;
5187
5188 if (ucNumOfTxDone > 0)
5189 {
5190 /*
5191 update free quota by
5192 num of tx done + resident free quota (delivery + non-delivery)
5193 */
5194 UINT_8 ucAvailQuota;
5195 ucAvailQuota = ucNumOfTxDone + prStaRec->ucFreeQuotaForDelivery +\
5196 prStaRec->ucFreeQuotaForNonDelivery;
5197 if (ucAvailQuota > ucFreeQuota) /* sanity check */
5198 ucAvailQuota = ucFreeQuota;
5199
5200 /* update current free quota */
5201 ucFreeQuota = ucAvailQuota;
5202
5203 /* check if the update is from last packet */
5204 if (ucFreeQuota == (prStaRec->ucFreeQuota+1))
5205 {
5206 /* just add the extra quota to delivery queue */
5207
5208 /*
5209 EX:
5210 1. TDLS peer enters power save
5211 2. When the last 2 VI packets are tx done, we will receive 2 update events
5212 3. 1st update event: ucFreeQuota = 9
5213 4. We will correct new quota for delivey and non-delivery to 7:2
5214 5. 2rd update event: ucFreeQuota = 10
5215 6. We will re-correct new quota for delivery and non-delivery to 5:5
5216
5217 But non-delivery queue is not busy.
5218 So in the case, we will have wrong decision, i.e. higher queue always quota 5
5219
5220 Solution: skip the 2rd update event and just add the extra quota to delivery.
5221 */
5222
5223 flgIsUpdateForcedToDelivery = TRUE;
5224 }
5225 }
5226
5227 switch (ucUpdateMode) {
5228 case FREE_QUOTA_UPDATE_MODE_INIT:
5229 case FREE_QUOTA_UPDATE_MODE_OVERWRITE:
5230 prStaRec->ucFreeQuota = ucFreeQuota;
5231 break;
5232 case FREE_QUOTA_UPDATE_MODE_INCREASE:
5233 prStaRec->ucFreeQuota += ucFreeQuota;
5234 break;
5235 case FREE_QUOTA_UPDATE_MODE_DECREASE:
5236 prStaRec->ucFreeQuota -= ucFreeQuota;
5237 break;
5238 default:
5239 ASSERT(0);
5240 }
5241
5242 DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n",
5243 prStaRec->ucFreeQuota ));
5244
5245 ucFreeQuota = prStaRec->ucFreeQuota;
5246
5247 ucFreeQuotaForNonDelivery = 0;
5248 ucFreeQuotaForDelivery = 0;
5249
5250 if(ucFreeQuota > 0) {
5251 if( prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported
5252 /* && prAdapter->rWifiVar.fgSupportQoS
5253 && prAdapter->rWifiVar.fgSupportUAPSD*/) {
5254 /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */
5255
5256 if (flgIsUpdateForcedToDelivery == FALSE)
5257 {
5258 if(prStaRec->ucFreeQuotaForNonDelivery > 0 && prStaRec->ucFreeQuotaForDelivery > 0) {
5259 ucFreeQuotaForNonDelivery = ucFreeQuota>>1;
5260 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5261 }
5262 else if(prStaRec->ucFreeQuotaForNonDelivery == 0 && prStaRec->ucFreeQuotaForDelivery == 0) {
5263 ucFreeQuotaForNonDelivery = ucFreeQuota>>1;
5264 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5265 }
5266 else if(prStaRec->ucFreeQuotaForNonDelivery > 0) {
5267 /* NonDelivery is not busy */
5268 if(ucFreeQuota >= 3 ) {
5269 ucFreeQuotaForNonDelivery = 2;
5270 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery ;
5271 }
5272 else {
5273 ucFreeQuotaForDelivery = ucFreeQuota;
5274 ucFreeQuotaForNonDelivery = 0;
5275 }
5276 }
5277 else if(prStaRec->ucFreeQuotaForDelivery > 0) {
5278 /* Delivery is not busy */
5279 if(ucFreeQuota >= 3 ) {
5280 ucFreeQuotaForDelivery = 2;
5281 ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery;
5282 }
5283 else {
5284 ucFreeQuotaForNonDelivery = ucFreeQuota;
5285 ucFreeQuotaForDelivery = 0;
5286 }
5287 }
5288 }
5289 else
5290 {
5291 ucFreeQuotaForNonDelivery = 2;
5292 ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery;
5293 }
5294 }
5295 else {
5296 /* no use ? */
5297 /* !prStaRec->fgIsUapsdSupported */
5298 ucFreeQuotaForNonDelivery = ucFreeQuota;
5299 ucFreeQuotaForDelivery = 0;
5300 }
5301 } /* ucFreeQuota > 0 */
5302
5303 prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery;
5304 prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery;
5305
5306 #if (CFG_SUPPORT_TDLS_DBG == 1)
5307 if (IS_TDLS_STA(prStaRec))
5308 printk("<tx> quota %d %d %d\n",
5309 ucFreeQuota, ucFreeQuotaForDelivery, ucFreeQuotaForNonDelivery);
5310 #endif
5311
5312 DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n",
5313 prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery ));
5314
5315 }
5316
5317 /*----------------------------------------------------------------------------*/
5318 /*!
5319 * \brief Return the reorder queued RX packets
5320 *
5321 * \param[in] (none)
5322 *
5323 * \return The number of queued RX packets
5324 */
5325 /*----------------------------------------------------------------------------*/
5326 UINT_32
5327 qmGetRxReorderQueuedBufferCount(
5328 IN P_ADAPTER_T prAdapter
5329 )
5330 {
5331 UINT_32 i, u4Total;
5332 P_QUE_MGT_T prQM = &prAdapter->rQM;
5333 u4Total = 0;
5334 /* XXX The summation may impact the performance */
5335 for(i =0; i<CFG_NUM_OF_RX_BA_AGREEMENTS; i++){
5336 u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem;
5337 #if DBG && 0
5338 if(QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))){
5339 ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0);
5340 }
5341 #endif
5342 }
5343 ASSERT(u4Total <=( CFG_NUM_OF_QM_RX_PKT_NUM*2));
5344 return u4Total;
5345 }
5346
5347