55f9027eaecc00d4c1094292d3b3be93d4350b92
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / combo_mt66xx / mt6628 / wlan / nic / nic_tx.c
1 /*
2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_tx.c#1 $
3 */
4
5 /*! \file   nic_tx.c
6     \brief  Functions that provide TX operation in NIC Layer.
7
8     This file provides TX functions which are responsible for both Hardware and
9     Software Resource Management and keep their Synchronization.
10 */
11
12
13
14 /*
15 ** $Log: nic_tx.c $
16  *
17  * 06 13 2012 yuche.tsai
18  * NULL
19  * Update maintrunk driver.
20  * Add support for driver compose assoc request frame.
21  *
22  * 11 18 2011 eddie.chen
23  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
24  * Add log counter for tx
25  *
26  * 11 09 2011 eddie.chen
27  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
28  * Add xlog for beacon timeout and sta aging timeout.
29  *
30  * 11 08 2011 eddie.chen
31  * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog)
32  * Add xlog function.
33  *
34  * 05 17 2011 cp.wu
35  * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss disconnection
36  * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state.
37  *
38  * 04 12 2011 eddie.chen
39  * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma
40  * Fix the sta index in processing security frame
41  * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4
42  * Add debug message.
43  *
44  * 04 12 2011 cp.wu
45  * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path
46  * remove unused variables.
47  *
48  * 04 12 2011 cp.wu
49  * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path
50  * 1. add nicTxGetResource() API for QM to make decisions.
51  * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case.
52  *
53  * 03 17 2011 cp.wu
54  * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period
55  * use pre-allocated buffer for storing enhanced interrupt response as well
56  *
57  * 03 15 2011 cp.wu
58  * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption
59  * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK
60  * 2. Use common coalescing buffer for both TX/RX directions
61  * 
62  *
63  * 02 16 2011 cp.wu
64  * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking availble count and modify behavior
65  * 1. add new API: nicTxGetFreeCmdCount()
66  * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly
67  *
68  * 01 24 2011 cp.wu
69  * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving
70  * 1. add an extra counter for tracking pending forward frames.
71  * 2. notify TX service thread as well when there is pending forward frame
72  * 3. correct build errors leaded by introduction of Wi-Fi direct separation module
73  *
74  * 01 12 2011 cp.wu
75  * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation needs such information
76  * fill mac header length information for 802.1x frames.
77  *
78  * 12 31 2010 cp.wu
79  * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling
80  * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded
81  *
82  * 11 01 2010 yarco.yang
83  * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform
84  * Add GPIO debug function
85  *
86  * 10 18 2010 cp.wu
87  * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore
88  * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion
89  * 2. shorten polling count for shorter response time
90  * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well
91  *
92  * 10 06 2010 cp.wu
93  * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning
94  * code reorganization to improve isolation between GLUE and CORE layers.
95  *
96  * 09 29 2010 wh.su
97  * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue
98  * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue.
99  *
100  * 09 27 2010 wh.su
101  * NULL
102  * since the u2TxByteCount_UserPriority will or another setting, keep the overall buffer for avoid error
103  *
104  * 09 24 2010 wh.su
105  * NULL
106  * [WCXRP000000058][MT6620 Wi-Fi][Driver] Fail to handshake with WAPI AP due the 802.1x frame send to fw with extra bytes padding.
107  *
108  * 09 01 2010 cp.wu
109  * NULL
110  * HIFSYS Clock Source Workaround
111  *
112  * 08 30 2010 cp.wu
113  * NULL
114  * API added: nicTxPendingPackets(), for simplifying porting layer
115  *
116  * 08 30 2010 cp.wu
117  * NULL
118  * eliminate klockwork errors
119  *
120  * 08 20 2010 wh.su
121  * NULL
122  * adding the eapol callback setting.
123  *
124  * 08 18 2010 yarco.yang
125  * NULL
126  * 1. Fixed HW checksum offload function not work under Linux issue.
127  * 2. Add debug message.
128  *
129  * 08 05 2010 yuche.tsai
130  * NULL
131  * .
132  *
133  * 08 03 2010 cp.wu
134  * NULL
135  * surpress compilation warning.
136  *
137  * 08 02 2010 jeffrey.chang
138  * NULL
139  * 1) modify tx service thread to avoid busy looping
140  * 2) add spin lock declartion for linux build
141  *
142  * 07 29 2010 cp.wu
143  * NULL
144  * simplify post-handling after TX_DONE interrupt is handled.
145  *
146  * 07 19 2010 jeffrey.chang
147  *
148  * Linux port modification
149  *
150  * 07 13 2010 cp.wu
151  *
152  * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets
153  * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending
154  * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation
155  *
156  * 07 08 2010 cp.wu
157  *
158  * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
159  *
160  * 06 29 2010 yarco.yang
161  * [WPD00003837][MT6620]Data Path Refine
162  * replace g_rQM with Adpater->rQM
163  *
164  * 06 25 2010 cp.wu
165  * [WPD00003833][MT6620 and MT5931] Driver migration
166  * add API in que_mgt to retrieve sta-rec index for security frames.
167  *
168  * 06 24 2010 cp.wu
169  * [WPD00003833][MT6620 and MT5931] Driver migration
170  * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path.
171  *
172  * 06 23 2010 yarco.yang
173  * [WPD00003837][MT6620]Data Path Refine
174  * Merge g_arStaRec[] into adapter->arStaRec[]
175  *
176  * 06 22 2010 cp.wu
177  * [WPD00003833][MT6620 and MT5931] Driver migration
178  * 1) add command warpper for STA-REC/BSS-INFO sync.
179  * 2) enhance command packet sending procedure for non-oid part
180  * 3) add command packet definitions for STA-REC/BSS-INFO sync.
181  *
182  * 06 21 2010 cp.wu
183  * [WPD00003833][MT6620 and MT5931] Driver migration
184  * add checking for TX descriptor poll.
185  *
186  * 06 21 2010 cp.wu
187  * [WPD00003833][MT6620 and MT5931] Driver migration
188  * TX descriptors are now allocated once for reducing allocation overhead
189  *
190  * 06 18 2010 cm.chang
191  * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver
192  * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf
193  *
194  * 06 15 2010 cp.wu
195  * [WPD00003833][MT6620 and MT5931] Driver migration
196  * change zero-padding for TX port access to HAL.
197  *
198  * 06 15 2010 cp.wu
199  * [WPD00003833][MT6620 and MT5931] Driver migration
200  * .
201  *
202  * 06 15 2010 cp.wu
203  * [WPD00003833][MT6620 and MT5931] Driver migration
204  * .
205  *
206  * 06 14 2010 cp.wu
207  * [WPD00003833][MT6620 and MT5931] Driver migration
208  * fill extra information for revised HIF_TX_HEADER.
209  *
210  * 06 11 2010 cp.wu
211  * [WPD00003833][MT6620 and MT5931] Driver migration
212  * 1) migrate assoc.c.
213  * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness
214  * 3) add configuration options for CNM_MEM and RSN modules
215  * 4) add data path for management frames
216  * 5) eliminate rPacketInfo of MSDU_INFO_T
217  *
218  * 06 10 2010 cp.wu
219  * [WPD00003833][MT6620 and MT5931] Driver migration
220  * change to enqueue TX frame infinitely.
221  *
222  * 06 09 2010 cp.wu
223  * [WPD00003833][MT6620 and MT5931] Driver migration
224  * add TX_PACKET_MGMT to indicate the frame is coming from management modules
225  *
226  * 06 06 2010 kevin.huang
227  * [WPD00003832][MT6620 5931] Create driver base
228  * [MT6620 5931] Create driver base
229  *
230  * 05 10 2010 cp.wu
231  * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support
232  * fill network type field while doing frame identification.
233  *
234  * 04 23 2010 cp.wu
235  * [WPD00001943]Create WiFi test driver framework on WinXP
236  * surpress compiler warning
237  *
238  * 04 06 2010 jeffrey.chang
239  * [WPD00003826]Initial import for Linux port
240  * Tag the packet for QoS on Tx path
241  *
242  * 03 30 2010 cp.wu
243  * [WPD00001943]Create WiFi test driver framework on WinXP
244  * remove driver-land statistics.
245  *
246  * 03 29 2010 jeffrey.chang
247  * [WPD00003826]Initial import for Linux port
248  * improve none-glue code portability
249  *
250  * 03 24 2010 jeffrey.chang
251  * [WPD00003826]Initial import for Linux port
252  * initial import for Linux port
253  *
254  * 03 24 2010 cp.wu
255  * [WPD00001943]Create WiFi test driver framework on WinXP
256  * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK
257  *  *  *  *  *
258  *
259 * 03 10 2010 cp.wu
260  * [WPD00001943]Create WiFi test driver framework on WinXP
261  * code clean: removing unused variables and structure definitions
262  *
263  * 03 08 2010 cp.wu
264  * [WPD00001943]Create WiFi test driver framework on WinXP
265  * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread.
266  *  *  *  * 2) change own-back acquiring procedure to wait for up to 16.67 seconds
267  *
268  * 03 02 2010 cp.wu
269  * [WPD00001943]Create WiFi test driver framework on WinXP
270  * add mutex to avoid multiple access to qmTxQueue simultaneously.
271  *
272  * 02 26 2010 cp.wu
273  * [WPD00001943]Create WiFi test driver framework on WinXP
274  * avoid refering to NDIS-specific data structure directly from non-glue layer.
275  *
276  * 02 24 2010 cp.wu
277  * [WPD00001943]Create WiFi test driver framework on WinXP
278  * add Ethernet destination address information in packet info for TX
279  *
280  * 02 10 2010 cp.wu
281  * [WPD00001943]Create WiFi test driver framework on WinXP
282  * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c]
283  *  *  *  *  *  * 2) firmware image length is now retrieved via NdisFileOpen
284  *  *  *  *  *  * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore
285  *  *  *  *  *  * 4) nicRxWaitResponse() revised
286  *  *  *  *  *  * 5) another set of TQ counter default value is added for fw-download state
287  *  *  *  *  *  * 6) Wi-Fi load address is now retrieved from registry too
288  *
289  * 02 09 2010 cp.wu
290  * [WPD00001943]Create WiFi test driver framework on WinXP
291  * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address
292  *  *  *  *  *  *  *  *  * 2. follow MSDN defined behavior when associates to another AP
293  *  *  *  *  *  *  *  *  * 3. for firmware download, packet size could be up to 2048 bytes
294  *
295  * 02 08 2010 cp.wu
296  * [WPD00001943]Create WiFi test driver framework on WinXP
297  * prepare for implementing fw download logic
298  *
299  * 01 27 2010 cp.wu
300  * [WPD00001943]Create WiFi test driver framework on WinXP
301  * 1. eliminate improper variable in rHifInfo
302  *  *  *  *  *  *  *  *  * 2. block TX/ordinary OID when RF test mode is engaged
303  *  *  *  *  *  *  *  *  * 3. wait until firmware finish operation when entering into and leaving from RF test mode
304  *  *  *  *  *  *  *  *  * 4. correct some HAL implementation
305  *
306  * 01 13 2010 tehuang.liu
307  * [WPD00001943]Create WiFi test driver framework on WinXP
308  * Enabled the Burst_End Indication mechanism
309  *
310  * 01 13 2010 cp.wu
311  * [WPD00001943]Create WiFi test driver framework on WinXP
312  * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo
313  *
314  * 12 30 2009 cp.wu
315  * [WPD00001943]Create WiFi test driver framework on WinXP
316  * 1) According to CMD/EVENT documentation v0.8,
317  *  *  *  *  *  *  *  *  *  * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used,
318  *  *  *  *  *  *  *  *  *  * and result is retrieved by get ATInfo instead
319  *  *  *  *  *  *  *  *  *  * 2) add 4 counter for recording aggregation statistics
320 **  \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-10 16:52:15 GMT mtk02752
321 **  remove unused API
322 **  \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-12-07 22:44:24 GMT mtk02752
323 **  correct assertion criterion
324 **  \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-12-07 21:15:52 GMT mtk02752
325 **  correct trivial mistake
326 **  \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-12-04 15:47:21 GMT mtk02752
327 **  + always append a dword of zero on TX path to avoid TX aggregation to triggered on uninitialized data
328 **  + add more assertion for packet size check
329 **  \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-12-04 14:51:55 GMT mtk02752
330 **  nicTxMsduInfo(): save ptr for next entry before attaching to qDataPort
331 **  \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-12-04 11:54:54 GMT mtk02752
332 **  add 2 assertion for size check
333 **  \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-12-03 16:20:35 GMT mtk01461
334 **  Add debug message
335 **  \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-30 10:57:10 GMT mtk02752
336 **  1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T
337 **  \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-30 09:20:43 GMT mtk02752
338 **  use TC4 instead of TC5 for command packet
339 **  \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-27 11:08:11 GMT mtk02752
340 **  add flush for reset
341 **  \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-26 20:31:22 GMT mtk02752
342 **  fill prMsduInfo->ucUserPriority
343 **  \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-25 21:04:33 GMT mtk02752
344 **  fill u2SeqNo
345 **  \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-24 20:52:12 GMT mtk02752
346 **  integration with SD1's data path API
347 **  \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-24 19:54:25 GMT mtk02752
348 **  nicTxRetransmitOfOsSendQue & nicTxData but changed to use nicTxMsduInfoList
349 **  \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 17:53:18 GMT mtk02752
350 **  add nicTxCmd() for SD1_SD3_DATAPATH_INTEGRATION, which will append only HIF_TX_HEADER. seqNum, WIFI_CMD_T will be created inside oid handler
351 **  \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-20 15:10:24 GMT mtk02752
352 **  use TxAccquireResource instead of accessing TCQ directly.
353 **  \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-17 22:40:57 GMT mtk01084
354 **  \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-17 17:35:40 GMT mtk02752
355 **  add nicTxMsduInfoList () implementation
356 **  \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-17 11:07:10 GMT mtk02752
357 **  add nicTxAdjustTcq() implementation
358 **  \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-16 22:28:38 GMT mtk02752
359 **  move aucFreeBufferCount/aucMaxNumOfBuffer into another structure
360 **  \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-16 21:45:32 GMT mtk02752
361 **  add SD1_SD3_DATAPATH_INTEGRATION data path handling
362 **  \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-13 13:29:56 GMT mtk01084
363 **  modify TX hdr format, fix tx retransmission issue
364 **  \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 10:36:21 GMT mtk01084
365 **  \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-04 14:11:11 GMT mtk01084
366 **  modify TX SW data structure
367 **  \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-10-29 19:56:17 GMT mtk01084
368 **  modify HAL part
369 **  \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-13 21:59:23 GMT mtk01084
370 **  update for new HW design
371 **  \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-02 14:00:18 GMT mtk01725
372 **  \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-05-20 12:26:06 GMT mtk01461
373 **  Assign SeqNum to CMD Packet
374 **  \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-05-19 10:54:04 GMT mtk01461
375 **  Add debug message
376 **  \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-05-12 09:41:55 GMT mtk01461
377 **  Fix Query Command need resp issue
378 **  \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-29 15:44:38 GMT mtk01461
379 **  Move OS dependent code to kalQueryTxOOBData()
380 **  \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-28 10:40:03 GMT mtk01461
381 **  Add nicTxReleaseResource() for SDIO_STATUS_ENHANCE, and also fix the TX aggregation issue for 1x packet to TX1 port
382 **  \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-21 09:50:47 GMT mtk01461
383 **  Update nicTxCmd() for moving wait RESP function call to wlanSendCommand()
384 **  \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-17 19:56:32 GMT mtk01461
385 **  Move the CMD_INFO_T related function to cmd_buf.c
386 **  \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-17 18:14:40 GMT mtk01426
387 **  Update OOB query for TX packet
388 **  \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:51:32 GMT mtk01426
389 **  Support PKGUIO
390 **  \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-02 17:26:40 GMT mtk01461
391 **  Add virtual OOB for HIF LOOPBACK SW PRETEST
392 **  \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:54:43 GMT mtk01461
393 **  Add function for SDIO_TX_ENHANCE
394 **  \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:53:47 GMT mtk01461
395 **  Add code for retransmit of rOsSendQueue, mpSendPacket(), and add code for TX Checksum offload, Loopback Test.
396 **  \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:33:51 GMT mtk01461
397 **  Add code for TX Data & Cmd Packet
398 **  \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:40 GMT mtk01461
399 **  Fix LINT warning
400 **  \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:30 GMT mtk01461
401 **  Update TX PATH API
402 **  \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:04 GMT mtk01426
403 **  Init for develop
404 **
405 */
406
407 /*******************************************************************************
408 *                         C O M P I L E R   F L A G S
409 ********************************************************************************
410 */
411
412 /*******************************************************************************
413 *                    E X T E R N A L   R E F E R E N C E S
414 ********************************************************************************
415 */
416 #include "precomp.h"
417
418 /*******************************************************************************
419 *                              C O N S T A N T S
420 ********************************************************************************
421 */
422
423 /*******************************************************************************
424 *                             D A T A   T Y P E S
425 ********************************************************************************
426 */
427
428 /*******************************************************************************
429 *                            P U B L I C   D A T A
430 ********************************************************************************
431 */
432
433 /*******************************************************************************
434 *                           P R I V A T E   D A T A
435 ********************************************************************************
436 */
437
438 /*******************************************************************************
439 *                                 M A C R O S
440 ********************************************************************************
441 */
442
443 /*******************************************************************************
444 *                  F U N C T I O N   D E C L A R A T I O N S
445 ********************************************************************************
446 */
447
448 /*******************************************************************************
449 *                              F U N C T I O N S
450 ********************************************************************************
451 */
452 /*----------------------------------------------------------------------------*/
453 /*!
454 * @brief This function will initial all variables in regard to SW TX Queues and
455 *        all free lists of MSDU_INFO_T and SW_TFCB_T.
456 *
457 * @param prAdapter  Pointer to the Adapter structure.
458 *
459 * @return (none)
460 */
461 /*----------------------------------------------------------------------------*/
462 VOID
463 nicTxInitialize (
464     IN P_ADAPTER_T  prAdapter
465     )
466 {
467     P_TX_CTRL_T prTxCtrl;
468     PUINT_8 pucMemHandle;
469     P_MSDU_INFO_T prMsduInfo;
470     UINT_32 i;
471     KAL_SPIN_LOCK_DECLARATION();
472
473     DEBUGFUNC("nicTxInitialize");
474
475     ASSERT(prAdapter);
476     prTxCtrl = &prAdapter->rTxCtrl;
477
478     //4 <1> Initialization of Traffic Class Queue Parameters
479     nicTxResetResource(prAdapter);
480
481 #if CFG_SDIO_TX_AGG
482     prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached;
483 #endif /* CFG_SDIO_TX_AGG */
484
485     // allocate MSDU_INFO_T and link it into rFreeMsduInfoList
486     QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList);
487
488     pucMemHandle = prTxCtrl->pucTxCached;
489     for (i = 0 ; i < CFG_TX_MAX_PKT_NUM ; i++) {
490         prMsduInfo = (P_MSDU_INFO_T)pucMemHandle;
491         kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T));
492
493         KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST);
494         QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T)prMsduInfo);
495         KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST);
496
497         pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T));
498     }
499
500     ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM);
501     /* Check if the memory allocation consist with this initialization function */
502     ASSERT((UINT_32)(pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize);
503
504     QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue);
505     prTxCtrl->i4TxMgmtPendingNum = 0;
506
507 #if CFG_HIF_STATISTICS
508     prTxCtrl->u4TotalTxAccessNum = 0;
509     prTxCtrl->u4TotalTxPacketNum = 0;
510 #endif
511
512     prTxCtrl->i4PendingFwdFrameCount = 0;
513
514     qmInit(prAdapter);
515
516     TX_RESET_ALL_CNTS(prTxCtrl);
517
518     return;
519 } /* end of nicTxInitialize() */
520
521
522 /*----------------------------------------------------------------------------*/
523 /*!
524 * \brief Driver maintain a variable that is synchronous with the usage of individual
525 *        TC Buffer Count. This function will check if has enough TC Buffer for incoming
526 *        packet and then update the value after promise to provide the resources.
527 *
528 * \param[in] prAdapter              Pointer to the Adapter structure.
529 * \param[in] ucTC                   Specify the resource of TC
530 *
531 * \retval WLAN_STATUS_SUCCESS   Resource is available and been assigned.
532 * \retval WLAN_STATUS_RESOURCES Resource is not available.
533 */
534 /*----------------------------------------------------------------------------*/
535 WLAN_STATUS
536 nicTxAcquireResource (
537     IN P_ADAPTER_T  prAdapter,
538     IN UINT_8       ucTC
539     )
540 {
541     P_TX_CTRL_T prTxCtrl;
542     WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES;
543     KAL_SPIN_LOCK_DECLARATION();
544
545     ASSERT(prAdapter);
546     prTxCtrl = &prAdapter->rTxCtrl;
547
548
549     KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
550
551 //    DbgPrint("nicTxAcquireResource prTxCtrl->rTc.aucFreeBufferCount[%d]=%d\n", ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]);
552
553     if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) {
554
555         prTxCtrl->rTc.aucFreeBufferCount[ucTC]--;
556
557         DBGLOG(TX, EVENT, ("Acquire: TC = %d aucFreeBufferCount = %d\n",
558             ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]));
559
560         u4Status = WLAN_STATUS_SUCCESS;
561     }
562     KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
563
564     return u4Status;
565
566 }/* end of nicTxAcquireResourceAndTFCBs() */
567
568
569 /*----------------------------------------------------------------------------*/
570 /*!
571 * @brief Driver maintain a variable that is synchronous with the usage of individual
572 *        TC Buffer Count. This function will do polling if FW has return the resource.
573 *        Used when driver start up before enable interrupt.
574 *
575 * @param prAdapter      Pointer to the Adapter structure.
576 * @param ucTC           Specify the resource of TC
577 *
578 * @retval WLAN_STATUS_SUCCESS   Resource is available.
579 * @retval WLAN_STATUS_FAILURE   Resource is not available.
580 */
581 /*----------------------------------------------------------------------------*/
582 WLAN_STATUS
583 nicTxPollingResource (
584     IN P_ADAPTER_T  prAdapter,
585     IN UINT_8       ucTC
586     )
587 {
588     P_TX_CTRL_T prTxCtrl;
589     WLAN_STATUS u4Status = WLAN_STATUS_FAILURE;
590     INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT;
591     UINT_32 au4WTSR[2];
592
593     ASSERT(prAdapter);
594     prTxCtrl = &prAdapter->rTxCtrl;
595
596     if (ucTC >= TC_NUM) {
597         return WLAN_STATUS_FAILURE;
598     }
599
600     if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) {
601         return WLAN_STATUS_SUCCESS;
602     }
603
604     while (i-- > 0) {
605         HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR);
606
607         if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE
608                 || fgIsBusAccessFailed == TRUE) {
609             u4Status = WLAN_STATUS_FAILURE;
610             break;
611         }
612         else if (nicTxReleaseResource(prAdapter, (PUINT_8)au4WTSR)) {
613             if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) {
614                 u4Status = WLAN_STATUS_SUCCESS;
615                 break;
616             }
617             else {
618                 kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC);
619             }
620         }
621         else {
622             kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC);
623         }
624     }
625
626 #if DBG
627     {
628         INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i+1);
629
630         if (i4Times) {
631             DBGLOG(TX, TRACE, ("Polling MCR_WTSR delay %d times, %d msec\n",
632                 i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)));
633         }
634     }
635 #endif /* DBG */
636
637     return u4Status;
638
639 } /* end of nicTxPollingResource() */
640
641
642 /*----------------------------------------------------------------------------*/
643 /*!
644 * \brief Driver maintain a variable that is synchronous with the usage of individual
645 *        TC Buffer Count. This function will release TC Buffer count according to
646 *        the given TX_STATUS COUNTER after TX Done.
647 *
648 * \param[in] prAdapter              Pointer to the Adapter structure.
649 * \param[in] u4TxStatusCnt          Value of TX STATUS
650 *
651 * @return (none)
652 */
653 /*----------------------------------------------------------------------------*/
654 BOOLEAN
655 nicTxReleaseResource (
656     IN P_ADAPTER_T  prAdapter,
657     IN UINT_8*      aucTxRlsCnt
658     )
659 {
660     PUINT_32 pu4Tmp = (PUINT_32)aucTxRlsCnt;
661     P_TX_CTRL_T prTxCtrl;
662     BOOLEAN bStatus = FALSE;
663     UINT_32 i;
664
665     KAL_SPIN_LOCK_DECLARATION();
666
667
668     ASSERT(prAdapter);
669     prTxCtrl = &prAdapter->rTxCtrl;
670
671     if (pu4Tmp[0] | pu4Tmp[1]) {
672
673         KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
674         for (i = 0; i < TC_NUM; i++) {
675             prTxCtrl->rTc.aucFreeBufferCount[i] += aucTxRlsCnt[i];
676
677             if ((i==1) || (i==5)){
678                 DBGLOG(TX, EVENT, ("Release: i = %d aucFreeBufferCount = %d\n",
679                     i, prTxCtrl->rTc.aucFreeBufferCount[i]));
680             }
681         }
682         KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
683 #if 0
684         for (i = 0; i < TC_NUM; i++) {
685             DBGLOG(INIT, TRACE, ("aucFreeBufferCount[%d]: %d, aucMaxNumOfBuffer[%d]: %d\n",
686                 i, prTxCtrl->rTc.aucFreeBufferCount[i], i, prTxCtrl->rTc.aucMaxNumOfBuffer[i]));
687         }
688         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[0]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[0]);
689         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[1]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[1]);
690         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[2]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[2]);
691         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[3]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[3]);
692         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[4]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[4]);
693         DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[5]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[5]);
694 #endif
695         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX]);
696         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX]);
697         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX]);
698         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX]);
699         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX]);
700         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX]);
701         bStatus = TRUE;
702     }
703
704     return bStatus;
705 } /* end of nicTxReleaseResource() */
706
707
708 /*----------------------------------------------------------------------------*/
709 /*!
710 * \brief Reset TC Buffer Count to initialized value
711 *
712 * \param[in] prAdapter              Pointer to the Adapter structure.
713 *
714 * @return WLAN_STATUS_SUCCESS
715 */
716 /*----------------------------------------------------------------------------*/
717 WLAN_STATUS
718 nicTxResetResource (
719     IN P_ADAPTER_T  prAdapter
720     )
721 {
722     P_TX_CTRL_T prTxCtrl;
723
724     KAL_SPIN_LOCK_DECLARATION();
725
726     DEBUGFUNC("nicTxResetResource");
727
728     ASSERT(prAdapter);
729     prTxCtrl = &prAdapter->rTxCtrl;
730
731     KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
732
733     prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0;
734     prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0;
735
736     prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1;
737     prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1;
738
739     prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2;
740     prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2;
741
742     prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3;
743     prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3;
744
745     prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4;
746     prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4;
747
748     prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5;
749     prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5;
750
751     KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
752
753     return WLAN_STATUS_SUCCESS;
754 }
755
756
757 /*----------------------------------------------------------------------------*/
758 /*!
759 * @brief Driver maintain a variable that is synchronous with the usage of individual
760 *        TC Buffer Count. This function will return the value for other component
761 *        which needs this information for making decisions
762 *
763 * @param prAdapter      Pointer to the Adapter structure.
764 * @param ucTC           Specify the resource of TC
765 *
766 * @retval UINT_8        The number of corresponding TC number
767 */
768 /*----------------------------------------------------------------------------*/
769 UINT_8
770 nicTxGetResource (
771     IN P_ADAPTER_T  prAdapter,
772     IN UINT_8       ucTC
773     )
774 {
775     P_TX_CTRL_T prTxCtrl;
776
777     ASSERT(prAdapter);
778     prTxCtrl = &prAdapter->rTxCtrl;
779
780     ASSERT(prTxCtrl);
781
782     if (ucTC >= TC_NUM) {
783         return 0;
784     }
785     else {
786         return prTxCtrl->rTc.aucFreeBufferCount[ucTC];
787     }
788 }
789
790
791 /*----------------------------------------------------------------------------*/
792 /*!
793 * @brief In this function, we'll aggregate frame(PACKET_INFO_T)
794 * corresponding to HIF TX port
795 *
796 * @param prAdapter              Pointer to the Adapter structure.
797 * @param prMsduInfoListHead     a link list of P_MSDU_INFO_T
798 *
799 * @retval WLAN_STATUS_SUCCESS   Bus access ok.
800 * @retval WLAN_STATUS_FAILURE   Bus access fail.
801 */
802 /*----------------------------------------------------------------------------*/
803 WLAN_STATUS
804 nicTxMsduInfoList (
805     IN P_ADAPTER_T      prAdapter,
806     IN P_MSDU_INFO_T    prMsduInfoListHead
807     )
808 {
809     P_MSDU_INFO_T prMsduInfo, prNextMsduInfo;
810     QUE_T qDataPort0, qDataPort1;
811     WLAN_STATUS status;
812
813     ASSERT(prAdapter);
814     ASSERT(prMsduInfoListHead);
815
816     prMsduInfo = prMsduInfoListHead;
817
818     QUEUE_INITIALIZE(&qDataPort0);
819     QUEUE_INITIALIZE(&qDataPort1);
820
821     // Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1
822     while(prMsduInfo) {
823         prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo);
824 #if DBG && 0
825         LOG_FUNC("nicTxMsduInfoList Acquire TC %d net %u mac len %u len %u Type %u 1x %u 11 %u\n",
826             prMsduInfo->ucTC,
827                 prMsduInfo->ucNetworkType,
828                 prMsduInfo->ucMacHeaderLength,
829             prMsduInfo->u2FrameLength,
830             prMsduInfo->ucPacketType,
831             prMsduInfo->fgIs802_1x,
832             prMsduInfo->fgIs802_11 );
833
834         LOG_FUNC("Dest Mac: " MACSTR "\n",
835                 MAC2STR(prMsduInfo->aucEthDestAddr));
836 #endif
837
838         switch(prMsduInfo->ucTC) {
839         case TC0_INDEX:
840         case TC1_INDEX:
841         case TC2_INDEX:
842         case TC3_INDEX:
843         case TC5_INDEX: // Broadcast/multicast data packets
844             QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL;
845             QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T)prMsduInfo);
846             status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC);
847             ASSERT(status == WLAN_STATUS_SUCCESS)
848
849             break;
850
851         case TC4_INDEX: // Command or 802.1x packets
852             QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL;
853             QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T)prMsduInfo);
854
855             status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC);
856             ASSERT(status == WLAN_STATUS_SUCCESS)
857
858             break;
859
860         default:
861             ASSERT(0);
862             break;
863         }
864
865         prMsduInfo = prNextMsduInfo;
866     }
867
868     if(qDataPort0.u4NumElem > 0) {
869         nicTxMsduQueue(prAdapter, 0, &qDataPort0);
870     }
871
872     if(qDataPort1.u4NumElem > 0) {
873         nicTxMsduQueue(prAdapter, 1, &qDataPort1);
874     }
875
876     return WLAN_STATUS_SUCCESS;
877 }
878
879 #if CFG_ENABLE_PKT_LIFETIME_PROFILE
880
881 #if CFG_PRINT_RTP_PROFILE
882 PKT_PROFILE_T rPrevRoundLastPkt;
883
884 BOOLEAN
885 nicTxLifetimePrintCheckRTP (
886     IN P_MSDU_INFO_T        prPrevProfileMsduInfo,
887     IN P_PKT_PROFILE_T      prPrevRoundLastPkt,
888     IN P_PKT_PROFILE_T      prPktProfile,
889     IN OUT PBOOLEAN         pfgGotFirst,
890     IN UINT_32              u4MaxDeltaTime,
891     IN UINT_8               ucSnToBePrinted
892     )
893 {
894     BOOLEAN fgPrintCurPkt = FALSE;
895
896     if(u4MaxDeltaTime) {
897         //4 1. check delta between current round first pkt and prevous round last pkt
898         if(!*pfgGotFirst) {
899             *pfgGotFirst = TRUE;
900
901             if(prPrevRoundLastPkt->fgIsValid) {
902                 if(CHK_PROFILES_DELTA(prPktProfile, prPrevRoundLastPkt, u4MaxDeltaTime)) {
903                     PRINT_PKT_PROFILE(prPrevRoundLastPkt, "PR");
904                     fgPrintCurPkt = TRUE;
905                 }
906             }
907         }
908
909         //4 2. check delta between current pkt and previous pkt
910         if(prPrevProfileMsduInfo) {
911             if(CHK_PROFILES_DELTA(prPktProfile, &prPrevProfileMsduInfo->rPktProfile, u4MaxDeltaTime)) {
912                 PRINT_PKT_PROFILE(&prPrevProfileMsduInfo->rPktProfile, "P");
913                 fgPrintCurPkt = TRUE;
914             }
915         }
916
917         //4 3. check delta of current pkt lifetime
918         if(CHK_PROFILE_DELTA(prPktProfile, u4MaxDeltaTime)) {
919             fgPrintCurPkt = TRUE;
920         }
921     }
922
923     //4 4. print every X RTP packets
924     #if CFG_SUPPORT_WFD
925     if((ucSnToBePrinted != 0) &&
926        (prPktProfile->u2RtpSn % ucSnToBePrinted) == 0) {
927         fgPrintCurPkt = TRUE;
928     }
929     #endif
930
931     return fgPrintCurPkt;
932 }
933
934 BOOLEAN
935 nicTxLifetimePrintCheckRTPSnSkip (
936     IN P_MSDU_INFO_T        prPrevProfileMsduInfo,
937     IN P_PKT_PROFILE_T      prPrevRoundLastPkt,
938     IN P_PKT_PROFILE_T      prPktProfile,
939     IN OUT PBOOLEAN         pfgGotFirst
940     )
941 {
942     BOOLEAN fgPrintCurPkt = FALSE;
943     UINT_16 u2PredictRtpSn = 0;
944     
945     //4 1. check RTP SN between current round first pkt and prevous round last pkt
946     if(!*pfgGotFirst) {
947         *pfgGotFirst = TRUE;
948
949         if(prPrevRoundLastPkt->fgIsValid) {
950             u2PredictRtpSn = prPrevRoundLastPkt->u2RtpSn + 1;
951             if(prPktProfile->u2RtpSn != u2PredictRtpSn) {
952                 PRINT_PKT_PROFILE(prPrevRoundLastPkt, "PR");
953                 fgPrintCurPkt = TRUE;
954             }
955         }
956     }
957
958     //4 2. check RTP SN between current pkt and previous pkt
959     if(prPrevProfileMsduInfo) {
960         u2PredictRtpSn = prPrevProfileMsduInfo->rPktProfile.u2RtpSn + 1;
961         if(prPktProfile->u2RtpSn != u2PredictRtpSn) {
962             PRINT_PKT_PROFILE(&prPrevProfileMsduInfo->rPktProfile, "P");
963             fgPrintCurPkt = TRUE;
964         }
965     }
966
967     return fgPrintCurPkt;
968 }
969 #endif
970
971
972 VOID
973 nicTxReturnMsduInfoProfiling (
974     IN P_ADAPTER_T    prAdapter,
975     IN P_MSDU_INFO_T  prMsduInfoListHead
976     )
977 {
978     P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo;
979     P_PKT_PROFILE_T prPktProfile;
980     UINT_16 u2MagicCode = 0;
981
982     #if CFG_PRINT_RTP_PROFILE
983     P_MSDU_INFO_T prPrevProfileMsduInfo = NULL;
984     P_PKT_PROFILE_T prPrevRoundLastPkt = &rPrevRoundLastPkt;
985
986     BOOLEAN fgPrintCurPkt = FALSE;
987     BOOLEAN fgGotFirst = FALSE;
988     UINT_8 ucSnToBePrinted = 0;
989
990     UINT_32 u4MaxDeltaTime = 50; // in ms
991     #endif
992
993     #if CFG_ENABLE_PER_STA_STATISTICS
994     UINT_32 u4PktPrintPeriod = 0;
995     #endif
996     
997     #if CFG_SUPPORT_WFD
998     P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL;
999     
1000     if(prAdapter->fgIsP2PRegistered) {        
1001         prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings;
1002         u2MagicCode = prWfdCfgSettings->u2WfdMaximumTp;
1003         if(prWfdCfgSettings->ucWfdEnable && (prWfdCfgSettings->u4WfdFlag & BIT(0))) {
1004             u2MagicCode = 0xE040;
1005         }
1006     }
1007     #endif  
1008
1009     #if CFG_PRINT_RTP_PROFILE
1010     if((u2MagicCode >= 0xF000)) {
1011         ucSnToBePrinted = (UINT_8)(u2MagicCode & BITS(0, 7));
1012         u4MaxDeltaTime = (UINT_8)(((u2MagicCode & BITS(8, 11)) >> 8) * 10);  
1013     }  
1014     else {
1015         ucSnToBePrinted = 0;
1016         u4MaxDeltaTime = 0;
1017     }    
1018     #endif
1019
1020     #if CFG_ENABLE_PER_STA_STATISTICS
1021     if((u2MagicCode >= 0xE000) && (u2MagicCode < 0xF000)) {
1022         u4PktPrintPeriod = (UINT_32)((u2MagicCode & BITS(0, 7)) * 32);
1023     }  
1024     else {
1025         u4PktPrintPeriod = 0;
1026     }    
1027     #endif
1028
1029     while(prMsduInfo) {
1030         prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo);
1031         prPktProfile = &prMsduInfo->rPktProfile;
1032             
1033         if(prPktProfile->fgIsValid) {
1034
1035             prPktProfile->rHifTxDoneTimestamp = kalGetTimeTick();
1036             
1037             #if CFG_PRINT_RTP_PROFILE
1038             #if CFG_PRINT_RTP_SN_SKIP
1039             fgPrintCurPkt = nicTxLifetimePrintCheckRTPSnSkip(
1040                                 prPrevProfileMsduInfo, 
1041                                 prPrevRoundLastPkt, 
1042                                 prPktProfile, 
1043                                 &fgGotFirst);
1044             #else
1045             fgPrintCurPkt = nicTxLifetimePrintCheckRTP(
1046                                 prPrevProfileMsduInfo,
1047                                 prPrevRoundLastPkt,
1048                                 prPktProfile,
1049                                 &fgGotFirst,
1050                                 u4MaxDeltaTime,
1051                                 ucSnToBePrinted);
1052             #endif
1053
1054             /* Print current pkt profile */
1055             if(fgPrintCurPkt) {
1056                 PRINT_PKT_PROFILE(prPktProfile, "C");
1057             }
1058
1059             prPrevProfileMsduInfo = prMsduInfo;   
1060             fgPrintCurPkt = FALSE;
1061             #endif
1062
1063             #if CFG_ENABLE_PER_STA_STATISTICS
1064             {
1065                 P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
1066                 UINT_32 u4DeltaTime;
1067                 P_QUE_MGT_T prQM = &prAdapter->rQM;
1068
1069                 if(prStaRec) {
1070                     u4DeltaTime = (UINT_32)(prPktProfile->rHifTxDoneTimestamp - prPktProfile->rHardXmitArrivalTimestamp);
1071                         
1072                     prStaRec->u4TotalTxPktsNumber++;
1073                     prStaRec->u4TotalTxPktsTime += u4DeltaTime;
1074                                         if(u4DeltaTime > prStaRec->u4MaxTxPktsTime) {
1075                                                 prStaRec->u4MaxTxPktsTime = u4DeltaTime;
1076                                         }
1077                     if(u4DeltaTime >= NIC_TX_TIME_THRESHOLD) {
1078                         prStaRec->u4ThresholdCounter++;
1079                     }
1080                                                          
1081                     if(u4PktPrintPeriod && (prStaRec->u4TotalTxPktsNumber >= u4PktPrintPeriod)) {
1082                         
1083                         DBGLOG(TX, TRACE, ("N[%4lu] A[%5lu] M[%4lu] T[%4lu] E[%4lu]\n", 
1084                             prStaRec->u4TotalTxPktsNumber, 
1085                             (prStaRec->u4TotalTxPktsTime/prStaRec->u4TotalTxPktsNumber),
1086                                                         prStaRec->u4MaxTxPktsTime,
1087                                                         prStaRec->u4ThresholdCounter,
1088                                                         prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][TC2_INDEX]));
1089                         
1090                         prStaRec->u4TotalTxPktsNumber = 0;
1091                         prStaRec->u4TotalTxPktsTime = 0;
1092                                                 prStaRec->u4MaxTxPktsTime = 0;
1093                         prStaRec->u4ThresholdCounter = 0;
1094                         prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][TC2_INDEX] = 0;    
1095                     }                    
1096                 }
1097             
1098             }
1099             #endif            
1100         }
1101             
1102         prMsduInfo = prNextMsduInfo;
1103     };
1104
1105 #if CFG_PRINT_RTP_PROFILE
1106     //4 4. record the lifetime of current round last pkt
1107     if(prPrevProfileMsduInfo) {
1108         prPktProfile = &prPrevProfileMsduInfo->rPktProfile;
1109         prPrevRoundLastPkt->u2IpSn = prPktProfile->u2IpSn;
1110         prPrevRoundLastPkt->u2RtpSn = prPktProfile->u2RtpSn;
1111         prPrevRoundLastPkt->rHardXmitArrivalTimestamp = prPktProfile->rHardXmitArrivalTimestamp;
1112         prPrevRoundLastPkt->rEnqueueTimestamp = prPktProfile->rEnqueueTimestamp;
1113         prPrevRoundLastPkt->rDequeueTimestamp = prPktProfile->rDequeueTimestamp;
1114         prPrevRoundLastPkt->rHifTxDoneTimestamp = prPktProfile->rHifTxDoneTimestamp;
1115         prPrevRoundLastPkt->ucTcxFreeCount = prPktProfile->ucTcxFreeCount;
1116         prPrevRoundLastPkt->fgIsPrinted = prPktProfile->fgIsPrinted;
1117         prPrevRoundLastPkt->fgIsValid = TRUE;
1118     }
1119 #endif
1120
1121     nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead);
1122
1123     return;
1124 }
1125
1126
1127 VOID
1128 nicTxLifetimeRecordEn (
1129     IN P_ADAPTER_T     prAdapter,
1130     IN P_MSDU_INFO_T   prMsduInfo,
1131     IN P_NATIVE_PACKET prPacket
1132     )
1133 {
1134     P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile;
1135     
1136     /* Enable packet lifetime profiling */
1137     prPktProfile->fgIsValid = TRUE;
1138
1139     /* Packet arrival time at kernel Hard Xmit */
1140     prPktProfile->rHardXmitArrivalTimestamp = GLUE_GET_PKT_ARRIVAL_TIME(prPacket);
1141
1142     /* Packet enqueue time */
1143     prPktProfile->rEnqueueTimestamp = (OS_SYSTIME)kalGetTimeTick();
1144
1145 }
1146
1147 #if CFG_PRINT_RTP_PROFILE
1148 /*
1149     in:
1150         data   RTP packet pointer
1151         size   RTP size    
1152     return 
1153         0:audio 1: video, -1:none
1154 */
1155 UINT8 checkRtpAV(PUINT_8 data, UINT_32 size)
1156 {
1157     PUINT_8 buf = data+12;
1158     while (buf+188 <= data+size) {
1159         int pid = ((buf[1] << 8 ) & 0x1F00) | (buf[2] & 0xFF);
1160         if (pid == 0 || pid == 0x100 || pid == 0x1000) {
1161             buf += 188;
1162         } 
1163         else if (pid == 0x1100){
1164             return 0;
1165         }
1166         else if (pid == 0x1011){
1167             return 1;
1168         }
1169     }
1170     return -1;
1171 }
1172
1173 VOID
1174 nicTxLifetimeCheckRTP (
1175     IN P_ADAPTER_T     prAdapter,
1176     IN P_MSDU_INFO_T   prMsduInfo,
1177     IN P_NATIVE_PACKET prPacket,
1178     IN UINT_32         u4PacketLen,
1179     IN UINT_8          ucNetworkType
1180     )
1181 {
1182     struct sk_buff *prSkb = (struct sk_buff *) prPacket;
1183     UINT_16 u2EtherTypeLen;        
1184     PUINT_8 aucLookAheadBuf = NULL;
1185     P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile;
1186
1187     //UINT_8 ucRtpHdrOffset = 28;
1188     UINT_8 ucRtpSnOffset = 30;
1189     //UINT_32 u4RtpSrcPort = 15550;
1190     P_TX_CTRL_T prTxCtrl;
1191 #if CFG_SUPPORT_WFD
1192     P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL;
1193     BOOLEAN fgEnProfiling = FALSE;
1194
1195     if(prAdapter->fgIsP2PRegistered) {    
1196         prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings;
1197
1198         #if CFG_PRINT_RTP_SN_SKIP
1199         if(ucNetworkType == NETWORK_TYPE_P2P_INDEX) {
1200             fgEnProfiling = TRUE;
1201         }
1202         else
1203         #endif
1204         if((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000) &&
1205               (ucNetworkType == NETWORK_TYPE_P2P_INDEX)) {
1206             fgEnProfiling = TRUE;
1207         }
1208     }
1209
1210     if(fgEnProfiling == FALSE) {
1211         //prPktProfile->fgIsValid = FALSE;
1212         return;
1213     }
1214 #endif
1215     
1216     prTxCtrl = &prAdapter->rTxCtrl;
1217     //prPktProfile->fgIsValid = FALSE;
1218
1219     aucLookAheadBuf = prSkb->data;
1220
1221     u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]);
1222
1223     if ((u2EtherTypeLen == ETH_P_IP) &&
1224         (u4PacketLen >= LOOK_AHEAD_LEN)) {
1225         PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN];
1226         UINT_8 ucIpVersion;
1227     
1228         ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET;
1229         if (ucIpVersion == IPVERSION) {
1230             if(pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) {
1231                 
1232                //if(checkRtpAV(&pucIpHdr[ucRtpHdrOffset], (u4PacketLen - ETH_HLEN - ucRtpHdrOffset)) == 0) {
1233
1234                 if(prPktProfile->fgIsValid == FALSE) {
1235                     nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket);
1236                 }
1237                 
1238                 prPktProfile->fgIsPrinted = FALSE;
1239
1240                 prPktProfile->ucTcxFreeCount = prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX];
1241
1242                 /* RTP SN */
1243                 prPktProfile->u2RtpSn = pucIpHdr[ucRtpSnOffset] << 8 | pucIpHdr[ucRtpSnOffset + 1];
1244
1245                 /* IP SN */
1246                 prPktProfile->u2IpSn = pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET] << 8 |
1247                                                             pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET + 1];
1248
1249                 //}
1250             }
1251         }
1252     }
1253
1254 }
1255 #endif
1256 #if CFG_ENABLE_PER_STA_STATISTICS
1257 VOID
1258 nicTxLifetimeCheckByAC (
1259     IN P_ADAPTER_T     prAdapter,
1260     IN P_MSDU_INFO_T   prMsduInfo,
1261     IN P_NATIVE_PACKET prPacket,
1262     IN UINT_8          ucPriorityParam
1263     )
1264 {
1265     switch(ucPriorityParam){
1266         /* BK */
1267         //case 1:
1268         //case 2:
1269         
1270         /* BE */
1271         //case 0:
1272         //case 3:
1273         
1274         /* VI */
1275         case 4:
1276         case 5:
1277             
1278         /* VO */
1279         case 6:
1280         case 7:
1281             nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket);
1282             break;
1283         default:
1284             break;
1285     }
1286 }
1287
1288 #endif
1289
1290 VOID
1291 nicTxLifetimeCheck (
1292     IN P_ADAPTER_T     prAdapter,
1293     IN P_MSDU_INFO_T   prMsduInfo,
1294     IN P_NATIVE_PACKET prPacket,
1295     IN UINT_8          ucPriorityParam,
1296     IN UINT_32         u4PacketLen,
1297     IN UINT_8          ucNetworkType
1298     )
1299 {
1300     P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile;
1301
1302     /* Reset packet profile */
1303     prPktProfile->fgIsValid = FALSE;
1304
1305     #if CFG_ENABLE_PER_STA_STATISTICS
1306     nicTxLifetimeCheckByAC(prAdapter, prMsduInfo, prPacket, ucPriorityParam);
1307     #endif
1308
1309     #if CFG_PRINT_RTP_PROFILE
1310     nicTxLifetimeCheckRTP(prAdapter, prMsduInfo, prPacket, u4PacketLen, ucNetworkType);
1311     #endif
1312
1313 }
1314
1315
1316 #endif
1317
1318 /*----------------------------------------------------------------------------*/
1319 /*!
1320 * @brief In this function, we'll write frame(PACKET_INFO_T) into HIF.
1321 *
1322 * @param prAdapter              Pointer to the Adapter structure.
1323 * @param ucPortIdx              Port Number
1324 * @param prQue                  a link list of P_MSDU_INFO_T
1325 *
1326 * @retval WLAN_STATUS_SUCCESS   Bus access ok.
1327 * @retval WLAN_STATUS_FAILURE   Bus access fail.
1328 */
1329 /*----------------------------------------------------------------------------*/
1330 WLAN_STATUS
1331 nicTxMsduQueue (
1332     IN P_ADAPTER_T  prAdapter,
1333     UINT_8          ucPortIdx,
1334     P_QUE_T         prQue
1335     )
1336 {
1337     P_MSDU_INFO_T prMsduInfo, prNextMsduInfo;
1338     HIF_TX_HEADER_T rHwTxHeader;
1339     P_NATIVE_PACKET prNativePacket;
1340     UINT_16 u2OverallBufferLength;
1341     UINT_8 ucEtherTypeOffsetInWord;
1342     PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */
1343     UINT_32 u4TxHdrSize;
1344     UINT_32 u4ValidBufSize;
1345     UINT_32 u4TotalLength;
1346     P_TX_CTRL_T prTxCtrl;
1347     QUE_T rFreeQueue;
1348 #if CFG_TCP_IP_CHKSUM_OFFLOAD
1349     UINT_8 ucChksumFlag;
1350 #endif
1351
1352     ASSERT(prAdapter);
1353     ASSERT(ucPortIdx < 2);
1354     ASSERT(prQue);
1355
1356     prTxCtrl = &prAdapter->rTxCtrl;
1357     u4ValidBufSize = prAdapter->u4CoalescingBufCachedSize;
1358
1359 #if CFG_HIF_STATISTICS
1360     prTxCtrl->u4TotalTxAccessNum++;
1361     prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem;
1362 #endif
1363
1364     QUEUE_INITIALIZE(&rFreeQueue);
1365
1366     if(prQue->u4NumElem > 0) {
1367         prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_HEAD(prQue);
1368         pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr;
1369         u4TotalLength = 0;
1370
1371         while(prMsduInfo) {
1372
1373             kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader));
1374
1375             prNativePacket = prMsduInfo->prPacket;
1376
1377             ASSERT(prNativePacket);
1378
1379             u4TxHdrSize = TX_HDR_SIZE;
1380
1381             u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) &
1382                     (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
1383
1384             rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength;
1385             rHwTxHeader.u2TxByteCount_UserPriority |=
1386                 ((UINT_16)prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET);
1387
1388             if (prMsduInfo->fgIs802_11) {
1389                 ucEtherTypeOffsetInWord =
1390                     (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1;
1391             }
1392             else {
1393                 ucEtherTypeOffsetInWord =
1394                     ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1;
1395             }
1396
1397             rHwTxHeader.ucEtherTypeOffset =
1398                 ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK;
1399
1400             rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET;
1401             rHwTxHeader.ucResource_PktType_CSflags |=
1402                 (UINT_8)(((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) &
1403                         (HIF_TX_HDR_PACKET_TYPE_MASK));
1404
1405 #if CFG_TCP_IP_CHKSUM_OFFLOAD
1406             if (prMsduInfo->eSrc == TX_PACKET_OS
1407                     || prMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1408                 if (prAdapter->u4CSUMFlags &
1409                         (CSUM_OFFLOAD_EN_TX_TCP |
1410                          CSUM_OFFLOAD_EN_TX_UDP |
1411                          CSUM_OFFLOAD_EN_TX_IP)) {
1412                     kalQueryTxChksumOffloadParam(prNativePacket, &ucChksumFlag);
1413
1414                     if (ucChksumFlag & TX_CS_IP_GEN) {
1415                         rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8)HIF_TX_HDR_IP_CSUM;
1416                     }
1417
1418                     if (ucChksumFlag & TX_CS_TCP_UDP_GEN) {
1419                         rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8)HIF_TX_HDR_TCP_CSUM;
1420                     }
1421                 }
1422             }
1423 #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */
1424
1425             rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH;
1426             rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex;
1427             rHwTxHeader.ucForwardingType_SessionID_Reserved =
1428                 (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET)
1429                 | ((prMsduInfo->fgIsBurstEnd)? HIF_TX_HDR_BURST_END_MASK : 0);
1430
1431             rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK);
1432             rHwTxHeader.ucPktFormtId_Flags =
1433                 (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK)
1434                 | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK)
1435                 | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK)
1436                 | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & HIF_TX_HDR_FLAG_802_11_FORMAT_MASK);
1437
1438             rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN;
1439
1440             if(prMsduInfo->pfTxDoneHandler) {
1441                 rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum;
1442                 rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK;
1443             }
1444             else {
1445                 rHwTxHeader.ucPacketSeqNo = 0;
1446                 rHwTxHeader.ucAck_BIP_BasicRate = 0;
1447             }
1448
1449             if(prMsduInfo->fgIsBIP) {
1450                 rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP;
1451             }
1452
1453             if(prMsduInfo->fgIsBasicRate) {
1454                 rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE;
1455             }
1456
1457 #if CFG_ENABLE_PKT_LIFETIME_PROFILE
1458             if(prMsduInfo->rPktProfile.fgIsValid) {
1459                 prMsduInfo->rPktProfile.rDequeueTimestamp = kalGetTimeTick();
1460             }
1461 #endif            
1462
1463 #if CFG_SDIO_TX_AGG
1464             // attach to coalescing buffer
1465             kalMemCopy(pucOutputBuf + u4TotalLength, &rHwTxHeader, u4TxHdrSize);
1466             u4TotalLength += u4TxHdrSize;
1467
1468             if (prMsduInfo->eSrc == TX_PACKET_OS
1469                     || prMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1470                 kalCopyFrame(prAdapter->prGlueInfo,
1471                         prNativePacket,
1472                         pucOutputBuf + u4TotalLength);
1473             }
1474             else if(prMsduInfo->eSrc == TX_PACKET_MGMT) {
1475                 kalMemCopy(pucOutputBuf + u4TotalLength,
1476                         prNativePacket,
1477                         prMsduInfo->u2FrameLength);
1478             }
1479             else {
1480                 ASSERT(0);
1481             }
1482
1483             u4TotalLength += ALIGN_4(prMsduInfo->u2FrameLength);
1484
1485 #else
1486             kalMemCopy(pucOutputBuf, &rHwTxHeader, u4TxHdrSize);
1487
1488             /* Copy Frame Body */
1489             if (prMsduInfo->eSrc == TX_PACKET_OS
1490                     || prMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1491                 kalCopyFrame(prAdapter->prGlueInfo,
1492                         prNativePacket,
1493                         pucOutputBuf + u4TxHdrSize);
1494             }
1495             else if(prMsduInfo->eSrc == TX_PACKET_MGMT) {
1496                 kalMemCopy(pucOutputBuf + u4TxHdrSize,
1497                         prNativePacket,
1498                         prMsduInfo->u2FrameLength);
1499             }
1500             else {
1501                 ASSERT(0);
1502             }
1503
1504             ASSERT(u2OverallBufferLength <= u4ValidBufSize);
1505
1506             HAL_WRITE_TX_PORT(prAdapter,
1507                     ucPortIdx,
1508                     (UINT_32)u2OverallBufferLength,
1509                     (PUINT_8)pucOutputBuf,
1510                     u4ValidBufSize);
1511
1512             // send immediately
1513 #endif
1514             prNextMsduInfo = (P_MSDU_INFO_T)
1515                         QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry);
1516
1517             if (prMsduInfo->eSrc == TX_PACKET_MGMT) {
1518                 GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum);
1519
1520                 if (prMsduInfo->pfTxDoneHandler == NULL) {
1521                     cnmMgtPktFree(prAdapter, prMsduInfo);
1522                 }
1523                 else {
1524                     KAL_SPIN_LOCK_DECLARATION();
1525                     DBGLOG(INIT, TRACE,("Wait TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum));
1526                     KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1527                     QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T)prMsduInfo);
1528                     KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1529                 }
1530             }
1531             else {
1532                 /* only free MSDU when it is not a MGMT frame */
1533                 QUEUE_INSERT_TAIL(&rFreeQueue, (P_QUE_ENTRY_T)prMsduInfo);
1534
1535                 if (prMsduInfo->eSrc == TX_PACKET_OS) {
1536                     kalSendComplete(prAdapter->prGlueInfo,
1537                             prNativePacket,
1538                             WLAN_STATUS_SUCCESS);
1539                 }
1540                 else if(prMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1541                     GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount);
1542                 }
1543             }
1544
1545             prMsduInfo = prNextMsduInfo;
1546         }
1547
1548 #if CFG_SDIO_TX_AGG
1549         ASSERT(u4TotalLength <= u4ValidBufSize);
1550
1551     #if CFG_DBG_GPIO_PINS
1552         {
1553             /* Start port write */
1554             mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_LOW);
1555             kalUdelay(1);
1556             mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_HIGH);
1557         }
1558     #endif
1559
1560         // send coalescing buffer
1561         HAL_WRITE_TX_PORT(prAdapter,
1562                 ucPortIdx,
1563                 u4TotalLength,
1564                 (PUINT_8)pucOutputBuf,
1565                 u4ValidBufSize);
1566 #endif
1567
1568 #if CFG_ENABLE_PKT_LIFETIME_PROFILE
1569         #if CFG_SUPPORT_WFD && CFG_PRINT_RTP_PROFILE && !CFG_ENABLE_PER_STA_STATISTICS
1570         do {          
1571             P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL;
1572             
1573             prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings;
1574
1575             if((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000)) {
1576                 //Enable profiling
1577                 nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue));
1578             }
1579             else {
1580                 //Skip profiling
1581                 nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue));
1582             }
1583         }while(FALSE);
1584         #else
1585             nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue));
1586         #endif
1587 #else
1588         // return
1589         nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue));
1590 #endif
1591     }
1592
1593     return WLAN_STATUS_SUCCESS;
1594 }
1595
1596
1597 /*----------------------------------------------------------------------------*/
1598 /*!
1599 * \brief In this function, we'll write Command(CMD_INFO_T) into HIF.
1600 *
1601 * @param prAdapter      Pointer to the Adapter structure.
1602 * @param prPacketInfo   Pointer of CMD_INFO_T
1603 * @param ucTC           Specify the resource of TC
1604 *
1605 * @retval WLAN_STATUS_SUCCESS   Bus access ok.
1606 * @retval WLAN_STATUS_FAILURE   Bus access fail.
1607 */
1608 /*----------------------------------------------------------------------------*/
1609 WLAN_STATUS
1610 nicTxCmd (
1611     IN P_ADAPTER_T      prAdapter,
1612     IN P_CMD_INFO_T     prCmdInfo,
1613     IN UINT_8           ucTC
1614     )
1615 {
1616     P_WIFI_CMD_T prWifiCmd;
1617     UINT_16 u2OverallBufferLength;
1618     PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */
1619     UINT_8 ucPortIdx;
1620     HIF_TX_HEADER_T rHwTxHeader;
1621     P_NATIVE_PACKET prNativePacket;
1622     UINT_8 ucEtherTypeOffsetInWord;
1623     P_MSDU_INFO_T prMsduInfo;
1624     P_TX_CTRL_T prTxCtrl;
1625
1626     KAL_SPIN_LOCK_DECLARATION();
1627
1628
1629     ASSERT(prAdapter);
1630     ASSERT(prCmdInfo);
1631
1632     prTxCtrl = &prAdapter->rTxCtrl;
1633     pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr;
1634
1635     // <1> Assign Data Port
1636     if (ucTC != TC4_INDEX) {
1637         ucPortIdx = 0;
1638     }
1639     else {
1640         // Broadcast/multicast data frames, 1x frames, command packets, MMPDU
1641         ucPortIdx = 1;
1642     }
1643
1644     if(prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) {
1645         // <2> Compose HIF_TX_HEADER
1646         kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader));
1647
1648         prNativePacket = prCmdInfo->prPacket;
1649
1650         ASSERT(prNativePacket);
1651
1652         u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE)
1653                 & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
1654
1655         rHwTxHeader.u2TxByteCount_UserPriority = ((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE)
1656                 & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
1657         ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1;
1658
1659         rHwTxHeader.ucEtherTypeOffset =
1660             ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK;
1661
1662         rHwTxHeader.ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET);
1663
1664         rHwTxHeader.ucStaRecIdx = prCmdInfo->ucStaRecIndex;
1665         rHwTxHeader.ucForwardingType_SessionID_Reserved = HIF_TX_HDR_BURST_END_MASK;
1666
1667         rHwTxHeader.ucWlanHeaderLength = (ETH_HLEN & HIF_TX_HDR_WLAN_HEADER_LEN_MASK);
1668         rHwTxHeader.ucPktFormtId_Flags =
1669             (((UINT_8)(prCmdInfo->eNetworkType) << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK)
1670             | ((1 << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK);
1671
1672         rHwTxHeader.u2SeqNo = 0;
1673         rHwTxHeader.ucPacketSeqNo = 0;
1674         rHwTxHeader.ucAck_BIP_BasicRate = 0;
1675
1676         // <2.3> Copy HIF TX HEADER
1677         kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE);
1678
1679         // <3> Copy Frame Body Copy
1680         kalCopyFrame(prAdapter->prGlueInfo,
1681                 prNativePacket,
1682                 pucOutputBuf + TX_HDR_SIZE);
1683     }
1684     else if(prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) {
1685         prMsduInfo = (P_MSDU_INFO_T)prCmdInfo->prPacket;
1686
1687         ASSERT(prMsduInfo->fgIs802_11 == TRUE);
1688         ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT);
1689
1690         // <2> Compose HIF_TX_HEADER
1691         kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader));
1692
1693         u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) &
1694                                   (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
1695
1696         rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength;
1697         rHwTxHeader.u2TxByteCount_UserPriority |=
1698                 ((UINT_16)prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET);
1699
1700         ucEtherTypeOffsetInWord =
1701                 (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1;
1702
1703         rHwTxHeader.ucEtherTypeOffset =
1704                 ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK;
1705
1706         rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET;
1707         rHwTxHeader.ucResource_PktType_CSflags |=
1708                 (UINT_8)(((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) &
1709                                     (HIF_TX_HDR_PACKET_TYPE_MASK));
1710
1711         rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH;
1712         rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex;
1713         rHwTxHeader.ucForwardingType_SessionID_Reserved =
1714             (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET)
1715             | ((prMsduInfo->fgIsBurstEnd)? HIF_TX_HDR_BURST_END_MASK : 0);
1716
1717         rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK);
1718         rHwTxHeader.ucPktFormtId_Flags =
1719             (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK)
1720             | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK)
1721             | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK)
1722             | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & HIF_TX_HDR_FLAG_802_11_FORMAT_MASK);
1723
1724         rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN;
1725
1726         if(prMsduInfo->pfTxDoneHandler) {
1727             rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum;
1728             rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK;
1729         }
1730         else {
1731             rHwTxHeader.ucPacketSeqNo = 0;
1732             rHwTxHeader.ucAck_BIP_BasicRate = 0;
1733         }
1734
1735         if(prMsduInfo->fgIsBIP) {
1736             rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP;
1737         }
1738
1739         if(prMsduInfo->fgIsBasicRate) {
1740             rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE;
1741         }
1742
1743         // <2.3> Copy HIF TX HEADER
1744         kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE);
1745
1746         // <3> Copy Frame Body
1747         kalMemCopy(pucOutputBuf + TX_HDR_SIZE,
1748                 prMsduInfo->prPacket,
1749                 prMsduInfo->u2FrameLength);
1750
1751         // <4> Management Frame Post-Processing
1752         GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum);
1753
1754         if (prMsduInfo->pfTxDoneHandler == NULL) {
1755             cnmMgtPktFree(prAdapter, prMsduInfo);
1756         }
1757         else {
1758
1759             DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum));
1760
1761             KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1762             QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T)prMsduInfo);
1763             KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1764         }
1765     }
1766     else {
1767         prWifiCmd = (P_WIFI_CMD_T)prCmdInfo->pucInfoBuffer;
1768
1769         // <2> Compose the Header of Transmit Data Structure for CMD Packet
1770         u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW(
1771                (prCmdInfo->u2InfoBufLen) & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
1772
1773         prWifiCmd->u2TxByteCount_UserPriority = u2OverallBufferLength;
1774         prWifiCmd->ucEtherTypeOffset = 0;
1775         prWifiCmd->ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET)
1776             | (UINT_8)((HIF_TX_PKT_TYPE_CMD << HIF_TX_HDR_PACKET_TYPE_OFFSET) & (HIF_TX_HDR_PACKET_TYPE_MASK));
1777
1778
1779         // <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached)
1780         kalMemCopy((PVOID)&pucOutputBuf[0],
1781                    (PVOID)prCmdInfo->pucInfoBuffer,
1782                    prCmdInfo->u2InfoBufLen);
1783
1784         ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize);
1785     }
1786
1787     // <4> Write frame to data port
1788     HAL_WRITE_TX_PORT(prAdapter,
1789             ucPortIdx,
1790             (UINT_32)u2OverallBufferLength,
1791             (PUINT_8)pucOutputBuf,
1792             (UINT_32)prAdapter->u4CoalescingBufCachedSize);
1793
1794     return WLAN_STATUS_SUCCESS;
1795 } /* end of nicTxCmd() */
1796
1797
1798 /*----------------------------------------------------------------------------*/
1799 /*!
1800 * @brief This function will clean up all the pending frames in internal SW Queues
1801 *        by return the pending TX packet to the system.
1802 *
1803 * @param prAdapter  Pointer to the Adapter structure.
1804 *
1805 * @return (none)
1806 */
1807 /*----------------------------------------------------------------------------*/
1808 VOID
1809 nicTxRelease (
1810     IN P_ADAPTER_T  prAdapter
1811     )
1812 {
1813     P_TX_CTRL_T prTxCtrl;
1814     P_MSDU_INFO_T prMsduInfo;
1815
1816     KAL_SPIN_LOCK_DECLARATION();
1817
1818     ASSERT(prAdapter);
1819
1820     prTxCtrl = &prAdapter->rTxCtrl;
1821
1822     nicTxFlush(prAdapter);
1823
1824     // free MSDU_INFO_T from rTxMgmtMsduInfoList
1825     do {
1826         KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1827         QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T);
1828         KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST);
1829
1830         if(prMsduInfo) {
1831             // the packet must be mgmt frame with tx done callback
1832             ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT);
1833             ASSERT(prMsduInfo->pfTxDoneHandler != NULL);
1834
1835             // invoke done handler
1836             prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_LIFE_TIMEOUT);
1837
1838             cnmMgtPktFree(prAdapter, prMsduInfo);
1839         }
1840         else {
1841             break;
1842         }
1843     } while(TRUE);
1844
1845     return;
1846 } /* end of nicTxRelease() */
1847
1848
1849 /*----------------------------------------------------------------------------*/
1850 /*!
1851 * @brief Process the TX Done interrupt and pull in more pending frames in SW
1852 *        Queues for transmission.
1853 *
1854 * @param prAdapter  Pointer to the Adapter structure.
1855 *
1856 * @return (none)
1857 */
1858 /*----------------------------------------------------------------------------*/
1859 VOID
1860 nicProcessTxInterrupt(
1861     IN P_ADAPTER_T prAdapter
1862     )
1863 {
1864     P_TX_CTRL_T prTxCtrl;
1865 #if CFG_SDIO_INTR_ENHANCE
1866     P_SDIO_CTRL_T prSDIOCtrl;
1867 #else
1868     UINT_32 au4TxCount[2];
1869 #endif /* CFG_SDIO_INTR_ENHANCE */
1870
1871     ASSERT(prAdapter);
1872
1873     prTxCtrl = &prAdapter->rTxCtrl;
1874     ASSERT(prTxCtrl);
1875
1876      /* Get the TX STATUS */
1877 #if CFG_SDIO_INTR_ENHANCE
1878
1879     prSDIOCtrl = prAdapter->prSDIOCtrl;
1880     #if DBG
1881     //dumpMemory8((PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T));
1882     #endif
1883
1884     nicTxReleaseResource(prAdapter, (PUINT_8)&prSDIOCtrl->rTxInfo);
1885     kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo));
1886
1887 #else
1888
1889     HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]);
1890     HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]);
1891     DBGLOG(EMU, TRACE, ("MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1]));
1892
1893     nicTxReleaseResource(prAdapter, (PUINT_8)au4TxCount);
1894
1895 #endif /* CFG_SDIO_INTR_ENHANCE */
1896
1897     nicTxAdjustTcq(prAdapter);
1898
1899     // Indicate Service Thread
1900     if(kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0
1901             || wlanGetTxPendingFrameCount(prAdapter) > 0) {
1902         kalSetEvent(prAdapter->prGlueInfo);
1903     }
1904
1905     return;
1906 } /* end of nicProcessTxInterrupt() */
1907
1908
1909 /*----------------------------------------------------------------------------*/
1910 /*!
1911 * @brief this function frees packet of P_MSDU_INFO_T linked-list
1912 *
1913 * @param prAdapter              Pointer to the Adapter structure.
1914 * @param prMsduInfoList         a link list of P_MSDU_INFO_T
1915 *
1916 * @return (none)
1917 */
1918 /*----------------------------------------------------------------------------*/
1919 VOID
1920 nicTxFreeMsduInfoPacket (
1921     IN P_ADAPTER_T    prAdapter,
1922     IN P_MSDU_INFO_T  prMsduInfoListHead
1923     )
1924 {
1925     P_NATIVE_PACKET prNativePacket;
1926     P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead;
1927     P_TX_CTRL_T prTxCtrl;
1928
1929
1930     ASSERT(prAdapter);
1931     ASSERT(prMsduInfoListHead);
1932
1933     prTxCtrl = &prAdapter->rTxCtrl;
1934
1935     while(prMsduInfo) {
1936         prNativePacket = prMsduInfo->prPacket;
1937
1938         if(prMsduInfo->eSrc == TX_PACKET_OS) {
1939             kalSendComplete(prAdapter->prGlueInfo,
1940                     prNativePacket,
1941                     WLAN_STATUS_FAILURE);
1942         }
1943         else if(prMsduInfo->eSrc == TX_PACKET_MGMT) {
1944             if (prMsduInfo->pfTxDoneHandler) {
1945                 prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER);
1946             }
1947             cnmMemFree(prAdapter, prNativePacket);
1948         }
1949         else if(prMsduInfo->eSrc == TX_PACKET_FORWARDING) {
1950             GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount);
1951         }
1952
1953         prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo);
1954     }
1955
1956     return;
1957 }
1958
1959
1960 /*----------------------------------------------------------------------------*/
1961 /*!
1962 * @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList
1963 *
1964 * @param prAdapter              Pointer to the Adapter structure.
1965 * @param prMsduInfoList         a link list of P_MSDU_INFO_T
1966 *
1967 * @return (none)
1968 */
1969 /*----------------------------------------------------------------------------*/
1970 VOID
1971 nicTxReturnMsduInfo (
1972     IN P_ADAPTER_T    prAdapter,
1973     IN P_MSDU_INFO_T  prMsduInfoListHead
1974     )
1975 {
1976     P_TX_CTRL_T prTxCtrl;
1977     P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo;
1978
1979     KAL_SPIN_LOCK_DECLARATION();
1980
1981     ASSERT(prAdapter);
1982
1983     prTxCtrl = &prAdapter->rTxCtrl;
1984     ASSERT(prTxCtrl);
1985
1986     while(prMsduInfo) {
1987         prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo);
1988
1989         switch(prMsduInfo->eSrc) {
1990         case TX_PACKET_FORWARDING:
1991             wlanReturnPacket(prAdapter, prMsduInfo->prPacket);
1992             break;
1993         case TX_PACKET_OS:
1994         case TX_PACKET_OS_OID:
1995         case TX_PACKET_MGMT:
1996         default:
1997             break;
1998         }
1999
2000         KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST);
2001         QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T)prMsduInfo);
2002         KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST);
2003         prMsduInfo = prNextMsduInfo;
2004     };
2005
2006     return;
2007 }
2008
2009 /*----------------------------------------------------------------------------*/
2010 /*!
2011 * @brief this function fills packet information to P_MSDU_INFO_T
2012 *
2013 * @param prAdapter              Pointer to the Adapter structure.
2014 * @param prMsduInfo             P_MSDU_INFO_T
2015 * @param prPacket               P_NATIVE_PACKET
2016 *
2017 * @retval TRUE      Success to extract information
2018 * @retval FALSE     Fail to extract correct information
2019 */
2020 /*----------------------------------------------------------------------------*/
2021 BOOLEAN
2022 nicTxFillMsduInfo (
2023     IN P_ADAPTER_T     prAdapter,
2024     IN P_MSDU_INFO_T   prMsduInfo,
2025     IN P_NATIVE_PACKET prPacket
2026     )
2027 {
2028     P_GLUE_INFO_T   prGlueInfo;
2029     UINT_8          ucPriorityParam;
2030     UINT_8          ucMacHeaderLen;
2031     UINT_8          aucEthDestAddr[PARAM_MAC_ADDR_LEN];
2032     BOOLEAN         fgIs1x = FALSE;
2033     BOOLEAN         fgIsPAL = FALSE;
2034     UINT_32         u4PacketLen;
2035     ULONG           u4SysTime;
2036     UINT_8          ucNetworkType;
2037
2038
2039     ASSERT(prAdapter);
2040
2041     prGlueInfo = prAdapter->prGlueInfo;
2042     ASSERT(prGlueInfo);
2043
2044     if (kalQoSFrameClassifierAndPacketInfo(prGlueInfo,
2045                 prPacket,
2046                 &ucPriorityParam,
2047                 &u4PacketLen,
2048                 aucEthDestAddr,
2049                 &fgIs1x,
2050                 &fgIsPAL,
2051                 &ucNetworkType) == FALSE) {
2052         return FALSE;
2053     }
2054
2055     #if CFG_ENABLE_PKT_LIFETIME_PROFILE
2056     nicTxLifetimeCheck (
2057         prAdapter,
2058         prMsduInfo,
2059         prPacket,
2060         ucPriorityParam,
2061         u4PacketLen,
2062         ucNetworkType);    
2063     #endif
2064
2065     /* Save the value of Priority Parameter */
2066     GLUE_SET_PKT_TID(prPacket, ucPriorityParam);
2067
2068     if (fgIs1x) {
2069         GLUE_SET_PKT_FLAG_1X(prPacket);
2070     }
2071
2072     if (fgIsPAL) {
2073         GLUE_SET_PKT_FLAG_PAL(prPacket);
2074     }
2075
2076     ucMacHeaderLen = ETH_HLEN;
2077
2078     /* Save the value of Header Length */
2079     GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen);
2080
2081     /* Save the value of Frame Length */
2082     GLUE_SET_PKT_FRAME_LEN(prPacket, (UINT_16)u4PacketLen);
2083
2084     /* Save the value of Arrival Time*/
2085     u4SysTime = (OS_SYSTIME)kalGetTimeTick();
2086     GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime);
2087
2088     prMsduInfo->prPacket = prPacket;
2089     prMsduInfo->fgIs802_1x = fgIs1x;
2090     prMsduInfo->fgIs802_11 = FALSE;
2091     prMsduInfo->ucNetworkType = ucNetworkType;
2092     prMsduInfo->ucUserPriority = ucPriorityParam;
2093     prMsduInfo->ucMacHeaderLength = ucMacHeaderLen;
2094     prMsduInfo->u2FrameLength = (UINT_16)u4PacketLen;
2095     COPY_MAC_ADDR(prMsduInfo->aucEthDestAddr, aucEthDestAddr);
2096
2097     return TRUE;
2098 }
2099
2100
2101 /*----------------------------------------------------------------------------*/
2102 /*!
2103 * @brief this function update TCQ values by passing current status to txAdjustTcQuotas
2104 *
2105 * @param prAdapter              Pointer to the Adapter structure.
2106 *
2107 * @retval WLAN_STATUS_SUCCESS   Updated successfully
2108 */
2109 /*----------------------------------------------------------------------------*/
2110 WLAN_STATUS
2111 nicTxAdjustTcq (
2112     IN P_ADAPTER_T  prAdapter
2113     )
2114 {
2115     UINT_32 u4Num;
2116     TX_TCQ_ADJUST_T rTcqAdjust;
2117     P_TX_CTRL_T prTxCtrl;
2118     KAL_SPIN_LOCK_DECLARATION();
2119
2120     ASSERT(prAdapter);
2121
2122     prTxCtrl = &prAdapter->rTxCtrl;
2123     ASSERT(prTxCtrl);
2124
2125     qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc);
2126     KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2127
2128     for (u4Num = 0 ; u4Num < TC_NUM ; u4Num++) {
2129         prTxCtrl->rTc.aucFreeBufferCount[u4Num] += rTcqAdjust.acVariation[u4Num];
2130         prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] += rTcqAdjust.acVariation[u4Num];
2131
2132         ASSERT(prTxCtrl->rTc.aucFreeBufferCount[u4Num] >= 0);
2133         ASSERT(prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] >= 0);
2134     }
2135
2136     KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE);
2137
2138     return WLAN_STATUS_SUCCESS;
2139 }
2140
2141
2142 /*----------------------------------------------------------------------------*/
2143 /*!
2144 * @brief this function flushes all packets queued in STA/AC queue
2145 *
2146 * @param prAdapter              Pointer to the Adapter structure.
2147 *
2148 * @retval WLAN_STATUS_SUCCESS   Flushed successfully
2149 */
2150 /*----------------------------------------------------------------------------*/
2151
2152 WLAN_STATUS
2153 nicTxFlush (
2154     IN P_ADAPTER_T  prAdapter
2155     )
2156 {
2157     P_MSDU_INFO_T prMsduInfo;
2158     KAL_SPIN_LOCK_DECLARATION();
2159
2160     ASSERT(prAdapter);
2161
2162     // ask Per STA/AC queue to be fllushed and return all queued packets
2163     KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE);
2164     prMsduInfo = qmFlushTxQueues(prAdapter);
2165     KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE);
2166
2167     if(prMsduInfo != NULL) {
2168         nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo);
2169         nicTxReturnMsduInfo(prAdapter, prMsduInfo);
2170     }
2171
2172     return WLAN_STATUS_SUCCESS;
2173 }
2174
2175
2176 #if CFG_ENABLE_FW_DOWNLOAD
2177 /*----------------------------------------------------------------------------*/
2178 /*!
2179 * \brief In this function, we'll write Command(CMD_INFO_T) into HIF.
2180 *        However this function is used for INIT_CMD.
2181 *
2182 *        In order to avoid further maintainance issues, these 2 functions are separated
2183 *
2184 * @param prAdapter      Pointer to the Adapter structure.
2185 * @param prPacketInfo   Pointer of CMD_INFO_T
2186 * @param ucTC           Specify the resource of TC
2187 *
2188 * @retval WLAN_STATUS_SUCCESS   Bus access ok.
2189 * @retval WLAN_STATUS_FAILURE   Bus access fail.
2190 */
2191 /*----------------------------------------------------------------------------*/
2192 WLAN_STATUS
2193 nicTxInitCmd (
2194     IN P_ADAPTER_T      prAdapter,
2195     IN P_CMD_INFO_T     prCmdInfo,
2196     IN UINT_8           ucTC
2197     )
2198 {
2199     P_INIT_HIF_TX_HEADER_T prInitTxHeader;
2200     UINT_16 u2OverallBufferLength;
2201     PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */
2202     UINT_32 ucPortIdx;
2203     P_TX_CTRL_T prTxCtrl;
2204
2205     ASSERT(prAdapter);
2206     ASSERT(prCmdInfo);
2207     ASSERT(ucTC == TC0_INDEX);
2208
2209     prTxCtrl = &prAdapter->rTxCtrl;
2210     pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr;
2211     prInitTxHeader = (P_INIT_HIF_TX_HEADER_T)prCmdInfo->pucInfoBuffer;
2212
2213     // <1> Compose the Header of Transmit Data Structure for CMD Packet
2214     u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW(
2215             (prCmdInfo->u2InfoBufLen) & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK);
2216
2217     prInitTxHeader->u2TxByteCount = u2OverallBufferLength;
2218     prInitTxHeader->ucEtherTypeOffset = 0;
2219     prInitTxHeader->ucCSflags = 0;
2220
2221     // <2> Assign Data Port
2222     if (ucTC != TC4_INDEX) {
2223         ucPortIdx = 0;
2224     }
2225     else { // Broadcast/multicast data packets
2226         ucPortIdx = 1;
2227     }
2228
2229     // <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached)
2230     kalMemCopy((PVOID)&pucOutputBuf[0],
2231                (PVOID)prCmdInfo->pucInfoBuffer,
2232                prCmdInfo->u2InfoBufLen);
2233
2234     ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize);
2235
2236     // <4> Write frame to data port
2237     HAL_WRITE_TX_PORT(prAdapter,
2238             ucPortIdx,
2239             (UINT_32)u2OverallBufferLength,
2240             (PUINT_8)pucOutputBuf,
2241             (UINT_32)prAdapter->u4CoalescingBufCachedSize);
2242
2243     return WLAN_STATUS_SUCCESS;
2244 }
2245
2246
2247 /*----------------------------------------------------------------------------*/
2248 /*!
2249 * \brief In this function, we'll reset TX resource counter to initial value used
2250 *        in F/W download state
2251 *
2252 * @param prAdapter      Pointer to the Adapter structure.
2253 *
2254 * @retval WLAN_STATUS_SUCCESS   Reset is done successfully.
2255 */
2256 /*----------------------------------------------------------------------------*/
2257 WLAN_STATUS
2258 nicTxInitResetResource (
2259     IN P_ADAPTER_T  prAdapter
2260     )
2261 {
2262     P_TX_CTRL_T prTxCtrl;
2263
2264     DEBUGFUNC("nicTxInitResetResource");
2265
2266     ASSERT(prAdapter);
2267     prTxCtrl = &prAdapter->rTxCtrl;
2268
2269     prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0;
2270     prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0;
2271
2272     prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1;
2273     prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1;
2274
2275     prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2;
2276     prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2;
2277
2278     prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3;
2279     prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3;
2280
2281     prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4;
2282     prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4;
2283
2284     prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5;
2285     prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5;
2286
2287     return WLAN_STATUS_SUCCESS;
2288
2289 }
2290
2291 #endif
2292
2293
2294 /*----------------------------------------------------------------------------*/
2295 /*!
2296 * \brief this function enqueues MSDU_INFO_T into queue management,
2297 *        or command queue
2298 *
2299 * @param prAdapter      Pointer to the Adapter structure.
2300 *        prMsduInfo     Pointer to MSDU
2301 *
2302 * @retval WLAN_STATUS_SUCCESS   Reset is done successfully.
2303 */
2304 /*----------------------------------------------------------------------------*/
2305 WLAN_STATUS
2306 nicTxEnqueueMsdu (
2307     IN P_ADAPTER_T      prAdapter,
2308     IN P_MSDU_INFO_T    prMsduInfo
2309     )
2310 {
2311     P_TX_CTRL_T prTxCtrl;
2312     P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead;
2313     QUE_T qDataPort0, qDataPort1;
2314     P_CMD_INFO_T prCmdInfo;
2315     WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
2316     KAL_SPIN_LOCK_DECLARATION();
2317
2318     ASSERT(prAdapter);
2319     ASSERT(prMsduInfo);
2320
2321     prTxCtrl = &prAdapter->rTxCtrl;
2322     ASSERT(prTxCtrl);
2323
2324     QUEUE_INITIALIZE(&qDataPort0);
2325     QUEUE_INITIALIZE(&qDataPort1);
2326
2327     /* check how many management frame are being queued */
2328     while(prMsduInfo) {
2329         prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo);
2330
2331         QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL;
2332
2333         if(prMsduInfo->eSrc == TX_PACKET_MGMT) {
2334             // MMPDU: force stick to TC4
2335             prMsduInfo->ucTC = TC4_INDEX;
2336
2337             QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T)prMsduInfo);
2338         }
2339         else {
2340             QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T)prMsduInfo);
2341         }
2342
2343         prMsduInfo = prNextMsduInfo;
2344     }
2345
2346     if(qDataPort0.u4NumElem) {
2347         /* send to QM */
2348         KAL_SPIN_LOCK_DECLARATION();
2349         KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE);
2350         prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&qDataPort0));
2351         KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE);
2352
2353         /* post-process for dropped packets */
2354         if(prRetMsduInfo != NULL) { // unable to enqueue
2355             nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo);
2356             nicTxReturnMsduInfo(prAdapter, prRetMsduInfo);
2357         }
2358     }
2359
2360     if(qDataPort1.u4NumElem) {
2361         prMsduInfoHead = (P_MSDU_INFO_T)QUEUE_GET_HEAD(&qDataPort1);
2362
2363         if(qDataPort1.u4NumElem > nicTxGetFreeCmdCount(prAdapter)) {
2364             // not enough descriptors for sending
2365             u4Status = WLAN_STATUS_FAILURE;
2366
2367             // free all MSDUs
2368             while(prMsduInfoHead) {
2369                 prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry);
2370
2371                 if (prMsduInfoHead->pfTxDoneHandler != NULL) {
2372                     prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, TX_RESULT_DROPPED_IN_DRIVER);
2373                 }
2374
2375
2376                 cnmMgtPktFree(prAdapter, prMsduInfoHead);
2377
2378                 prMsduInfoHead = prNextMsduInfo;
2379             }
2380         }
2381         else {
2382             /* send to command queue */
2383             while(prMsduInfoHead) {
2384                 prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry);
2385
2386                 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE);
2387                 QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T);
2388                 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE);
2389
2390                 if (prCmdInfo) {
2391                     GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum);
2392
2393                     kalMemZero(prCmdInfo, sizeof(CMD_INFO_T));
2394
2395                     prCmdInfo->eCmdType             = COMMAND_TYPE_MANAGEMENT_FRAME;
2396                     prCmdInfo->u2InfoBufLen         = prMsduInfoHead->u2FrameLength;
2397                     prCmdInfo->pucInfoBuffer        = NULL;
2398                     prCmdInfo->prPacket             = (P_NATIVE_PACKET)prMsduInfoHead;
2399                     prCmdInfo->ucStaRecIndex        = prMsduInfoHead->ucStaRecIndex;
2400                     prCmdInfo->eNetworkType         = prMsduInfoHead->ucNetworkType;
2401                     prCmdInfo->pfCmdDoneHandler     = NULL;
2402                     prCmdInfo->pfCmdTimeoutHandler  = NULL;
2403                     prCmdInfo->fgIsOid              = FALSE;
2404                     prCmdInfo->fgSetQuery           = TRUE;
2405                     prCmdInfo->fgNeedResp           = FALSE;
2406
2407                     kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo);
2408                 }
2409                 else {
2410                     /* Cmd free count is larger than expected, but allocation fail. */
2411                     ASSERT(0);
2412
2413                     u4Status = WLAN_STATUS_FAILURE;
2414                     cnmMgtPktFree(prAdapter, prMsduInfoHead);
2415                 }
2416
2417                 prMsduInfoHead = prNextMsduInfo;
2418             }
2419         }
2420     }
2421
2422     /* indicate service thread for sending */
2423     if(prTxCtrl->i4TxMgmtPendingNum > 0
2424             || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) {
2425         kalSetEvent(prAdapter->prGlueInfo);
2426     }
2427
2428     return u4Status;
2429 }
2430
2431
2432 /*----------------------------------------------------------------------------*/
2433 /*!
2434 * \brief this function returns available count in command queue
2435 *
2436 * @param prAdapter      Pointer to the Adapter structure.
2437 *
2438 * @retval
2439 */
2440 /*----------------------------------------------------------------------------*/
2441 UINT_32
2442 nicTxGetFreeCmdCount (
2443     IN P_ADAPTER_T  prAdapter
2444     )
2445 {
2446     ASSERT(prAdapter);
2447
2448     return prAdapter->rFreeCmdList.u4NumElem;
2449 }
2450