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