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