1/****************************************************************************
2**+-----------------------------------------------------------------------+**
3**|                                                                       |**
4**| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved.      |**
5**| All rights reserved.                                                  |**
6**|                                                                       |**
7**| Redistribution and use in source and binary forms, with or without    |**
8**| modification, are permitted provided that the following conditions    |**
9**| are met:                                                              |**
10**|                                                                       |**
11**|  * Redistributions of source code must retain the above copyright     |**
12**|    notice, this list of conditions and the following disclaimer.      |**
13**|  * Redistributions in binary form must reproduce the above copyright  |**
14**|    notice, this list of conditions and the following disclaimer in    |**
15**|    the documentation and/or other materials provided with the         |**
16**|    distribution.                                                      |**
17**|  * Neither the name Texas Instruments nor the names of its            |**
18**|    contributors may be used to endorse or promote products derived    |**
19**|    from this software without specific prior written permission.      |**
20**|                                                                       |**
21**| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |**
22**| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |**
23**| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
24**| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |**
25**| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
26**| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |**
27**| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
28**| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
29**| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |**
30**| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
31**| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |**
32**|                                                                       |**
33**+-----------------------------------------------------------------------+**
34****************************************************************************/
35
36/****************************************************************************
37 *
38 *   MODULE:  txXfer.c
39 *
40 *   PURPOSE: Handle Tx frame transfer to the firmware in slave double-buffer scheme.
41 *
42 *   DESCRIPTION:
43 *   ============
44 *      This module gets the upper driver's Tx packets after FW resources were
45 *        allocated for it, and handles its transfer to the FW double-buffer.
46 *      It can handle two packets at a time, thus providing a pipe-line behavior.
47 *      It is planned to start an asynchronous copy of one packet to the FW,
48 *        and immediately indicate the upper layer to start handling the next
49 *        packet transmission in parallel.
50 *
51 ****************************************************************************/
52
53#include "osTIType.h"
54#include "paramIn.h"
55#include "commonTypes.h"
56#include "TNETWIF.h"
57#include "whalCommon.h"
58#include "whalHwDefs.h"
59#include "txXfer_api.h"
60#include "txXfer.h"  /* Local definitions */
61
62
63/****************************************************************************
64 *                      txXfer_Create()
65 ****************************************************************************
66 * DESCRIPTION: Create the Xfer module object
67 *
68 * INPUTS:  None
69 *
70 * OUTPUT:  None
71 *
72 * RETURNS: The Created object
73 ****************************************************************************/
74TI_HANDLE txXfer_Create(TI_HANDLE hOs)
75{
76    txXferObj_t *pTxXfer;
77
78    pTxXfer = os_memoryAlloc(hOs, sizeof(txXferObj_t));
79    if (pTxXfer == NULL)
80    {
81        return NULL;
82    }
83
84    os_memoryZero(hOs, pTxXfer, sizeof(txXferObj_t));
85
86    pTxXfer->hOs = hOs;
87
88    return (TI_HANDLE)pTxXfer;
89}
90
91
92/****************************************************************************
93 *                      txXfer_Destroy()
94 ****************************************************************************
95 * DESCRIPTION: Destroy the Xfer module object
96 *
97 * INPUTS:  hTxXfer - The object to free
98 *
99 * OUTPUT:  None
100 *
101 * RETURNS: OK or NOK
102 ****************************************************************************/
103TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
104{
105    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
106
107    if (pTxXfer)
108    {
109        os_memoryFree(pTxXfer->hOs, pTxXfer, sizeof(txXferObj_t));
110    }
111
112    return OK;
113}
114
115
116/****************************************************************************
117 *               txXfer_init()
118 ****************************************************************************
119   DESCRIPTION:
120   ============
121     Initialize the Xfer module.
122 ****************************************************************************/
123TI_STATUS txXfer_init(TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTNETWIF, TI_HANDLE hTxResult)
124{
125    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
126
127    pTxXfer->hReport = hReport;
128    pTxXfer->hTNETWIF = hTNETWIF;
129    pTxXfer->hTxResult = hTxResult;
130    pTxXfer->sendPacketTransferCB = NULL;
131    pTxXfer->sendPacketDebugCB = NULL;
132
133    return txXfer_restart(pTxXfer);
134}
135
136/****************************************************************************
137 *               txXfer_config()
138 ****************************************************************************
139 * DESCRIPTION:
140 *      Configures the TX XFER module with initialization parameters.
141 *
142 * INPUTS:
143 *      hTxXfer             The object
144 *      pInitParams         initialization parameters values
145 *
146 * OUTPUT:  None
147 *
148 * RETURNS: None
149 ****************************************************************************/
150void txXfer_config(TI_HANDLE hTxXfer, TnetwDrv_InitParams_t *pInitParams)
151{
152    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
153
154    pTxXfer->timeToTxStuckMs = pInitParams->txXferInitParams.timeToTxStuckMs;
155}
156
157
158/****************************************************************************
159 *                      txXfer_setHwInfo()
160 ****************************************************************************
161 * DESCRIPTION:
162 *      Called after the HW configuration upon init or recovery.
163 *      Store the HW addresses of the Double Buffer and the Tx-status.
164 *
165 * INPUTS:
166 *      hTxXfer             The object
167 *      pDataPathParams     Pointer to the Double Buffer Address
168 *
169 * OUTPUT:  None
170 *
171 * RETURNS: None
172 ****************************************************************************/
173void  txXfer_setHwInfo(TI_HANDLE hTxXfer, ACXDataPathParamsResp_t *pDataPathParams)
174{
175    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
176
177    pTxXfer->dblBufAddr[0] = pDataPathParams->txPacketRingAddr;
178    pTxXfer->dblBufAddr[1] = pDataPathParams->txPacketRingAddr + pDataPathParams->txPacketRingChunkSize;
179    pTxXfer->txPathStatusAddr = pDataPathParams->txControlAddr;
180
181    /* Print of the Tx double buffer address */
182    WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
183        ("TX DOUBLE BUFFER Addresses: Buf_0 = 0x%x,   Buf_1 = 0x%x\n",
184        pTxXfer->dblBufAddr[0], pTxXfer->dblBufAddr[1]));
185}
186
187
188
189
190
191/****************************************************************************
192 *               txXfer_restart()
193 ****************************************************************************
194   DESCRIPTION:
195   ============
196     Restarts the Xfer module.
197     Should be called upon init and recovery!!
198 ****************************************************************************/
199TI_STATUS txXfer_restart(TI_HANDLE hTxXfer)
200{
201    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
202
203    /* Initialize module variables. */
204    pTxXfer->txXferState = TX_XFER_STATE_IDLE;
205    pTxXfer->numBufferedPkts = 0;
206    pTxXfer->xferDonePostponed = FALSE;
207    pTxXfer->bRecovery = FALSE;
208    pTxXfer->dataInCount = 0;
209    pTxXfer->hwStatusReadLoopCount = 0;
210
211    return OK;
212}
213
214
215
216
217/****************************************************************************
218 *                  txXfer_sendPacket()
219 ****************************************************************************
220 * DESCRIPTION:
221   ============
222    Handle sent packet according to the number of packets already in the Xfer buffers:
223      If no buffered pkts:
224        If in IDLE state, update state to WAIT_BUS and request the bus.
225        Return SEND_PACKET_SUCCESS.
226      If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more).
227      If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets).
228 ****************************************************************************/
229systemStatus_e txXfer_sendPacket(TI_HANDLE hTxXfer, txCtrlBlkEntry_t *pPktCtrlBlk)
230{
231    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
232    TI_STATUS tnetwifStatus;
233
234#ifdef TI_DBG
235    pTxXfer->sendPacketCount++;
236#endif
237
238    /* Handle sent packet according to the number of packets already in the Xfer buffers. */
239    switch(pTxXfer->numBufferedPkts)
240    {
241
242        /* No buffered pkts. */
243        case 0:
244
245            pTxXfer->numBufferedPkts = 1;
246            pTxXfer->pPktCtrlBlk[0] = pPktCtrlBlk;    /* Save the first pkt Ctrl-Blk pointer. */
247
248            /* If in IDLE state, update state to WAIT_BUS and request the bus. */
249            if (pTxXfer->txXferState == TX_XFER_STATE_IDLE)
250            {
251                WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
252                    ("txXfer_sendPacket(): First Pkt, IDLE-STATE, Start Bus-Wait\n"));
253
254                /* Note: Update the Xfer-SM state before calling the TNETWIF because it will call the
255                         SM immediately if the bus is available. */
256                pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
257
258                /* Set to detect if the Xfer proces is completed in this context (returns XFER_DONE). */
259                pTxXfer->syncXferIndication = TRUE;
260
261                tnetwifStatus = TNETWIF_Start(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
262
263                if (pTxXfer->bRecovery)
264                    return SEND_PACKET_RECOVERY;
265
266#ifdef TI_DBG
267                if (tnetwifStatus == TNETWIF_COMPLETE)
268                {
269                    pTxXfer->busStartSyncCount++;
270                }
271                else if (tnetwifStatus == TNETWIF_PENDING)
272                {
273                    pTxXfer->busStartAsyncCount++;
274                }
275                else
276                {
277                    WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
278                                      ("txXfer_sendPacket(): TNETWIF_Start returned error=%d\n", tnetwifStatus));
279                }
280#endif
281
282                /* If the Xfer was completed in this context (Synchronous), return XFER_DONE. */
283                /* Note: In this case xferDone callback will not be called!  */
284                if (pTxXfer->syncXferIndication)
285                {
286                    pTxXfer->syncXferIndication = FALSE;
287
288                    if (tnetwifStatus == TNETWIF_COMPLETE) /* The SM was called from the Start function. */
289                    {
290#ifdef TI_DBG
291                        pTxXfer->xferDoneSyncCount++;
292                        WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
293                            ("txXfer_sendPacket(): Xfer Completed in upper driver context\n"));
294#endif
295                        return SEND_PACKET_XFER_DONE;  /* Xfer can get another packet. */
296                    }
297                }
298            }
299            else
300            {
301                WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
302                    ("txXfer_sendPacket(): First Pkt, not IDLE-STATE, XferState=%d\n", pTxXfer->txXferState));
303            }
304
305            /* If the Xfer wasn't completed in this context (Asynchronous), return SUCCESS
306                (xferDone callback will be called). */
307            return SEND_PACKET_SUCCESS;  /* Xfer can get another packet. */
308
309
310
311        /* If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more). */
312        case 1:
313
314            if (pTxXfer->bRecovery)
315            {
316                return SEND_PACKET_RECOVERY;
317            }
318
319            else
320            {
321                WLAN_REPORT_INFORMATION (pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
322                    ("txXfer_sendPacket(): Second Pkt Buffered, XferState=%d\n", pTxXfer->txXferState));
323
324                pTxXfer->numBufferedPkts = 2;  /* We now have two packets handled in the Xfer. */
325                pTxXfer->pPktCtrlBlk[1] = pPktCtrlBlk;  /* Save the second pkt Ctrl-Blk pointer. */
326
327                return SEND_PACKET_PENDING;  /* Xfer can't get further packets. */
328            }
329
330
331        /* If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets). */
332        default:
333
334            WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
335                ("txXfer_sendPacket(): Two Pkts Allready Buffered, XferState=%d, xferDonePostponed=%d, numPkts=%d\n",
336                pTxXfer->txXferState, pTxXfer->xferDonePostponed, pTxXfer->numBufferedPkts));
337
338            return SEND_PACKET_ERROR;
339    }
340}
341
342
343#define MAX_RECOVERY_LOOPS 1000
344
345
346/****************************************************************************
347 *                  xferStateMachine()
348 ****************************************************************************
349 * DESCRIPTION:
350   ============
351    This is the Xfer process state machine.
352    It handles the transfer of packets sent by the upper driver to the HW via TNETWIF.
353
354    The SM supports both Sync and Async accesses to the HW.
355    It loops and progresses from state to state as long as the HW is accessed synchronously.
356    Once the access is Asynchronous (TNETWIF_PENDING), it exits and is called later
357      by the TNETWIF when the HW is ready.
358    That's why it uses only unspecified-mode accesses (e.g. TNETWIF_ReadMemOpt) which
359      selects either Sync or Async automatically according to the platform.
360
361    When the SM is active (not in IDLE state), it has either one or two packets buffered.
362    This enables (in Async access) pipeline behavior, where one packet is transfered to
363      the HW, and the other is being processed from the upper driver to the Xfer in parallel.
364
365
366    The SM steps are:
367    =================
368
369Event:     Send-Pkt       Bus-Ready         HW-Buffer-Ready         Xfer-Done             Trigger-Done
370               |              |                    |                    |                       |
371               V              V                    V                    V                       V
372State:  IDLE ----> WAIT_BUS ----> WAIT_HW_BUFFER ----> WAIT_XFER_DONE ----> WAIT_TRIGGER_DONE ----> IDLE
373                       |                                                             |
374                       |                                                             |
375                        <---------<---------<---------<---------<---------<----------
376                                             Pending-Packet (*)
377
378  (*) When a packet transfer is finished but another packet is already waiting in the Xfer
379        for processing, the Xfer will postpone the Xfer-Done indication of the first packet
380        until it has started the second one's transfer to the HW.
381        It will request "Bus Restart" in order to prevent nesting and enable bus allocation
382          to other tasks.
383
384 ****************************************************************************/
385static void xferStateMachine(TI_HANDLE hTxXfer, UINT8 module_id, TI_STATUS status)
386{
387    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
388    TI_STATUS tnetwifStatus;
389
390#ifdef TI_DBG
391    if (hTxXfer == NULL)
392    {
393        WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
394            ("xferStateMachine(): ****  Called with NULL handle!!  ****\n"));
395        return;
396    }
397#endif
398
399    /*
400     * Loop through the states sequence as long as the process is synchronous.
401     * Exit when finished or if an Asynchronous process is required. In this case
402     *   the SM process will be resumed later (called back by TNETWIF).
403     */
404    while (1)
405    {
406        switch (pTxXfer->txXferState)
407        {
408
409            case TX_XFER_STATE_WAIT_BUS:
410
411                /* Call debug callback */
412                if (pTxXfer->sendPacketDebugCB)
413                {
414                    pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
415                                                pTxXfer->pPktCtrlBlk[0],
416                                                pTxXfer->txXferState);
417                }
418
419                /* We now own the bus, so request to read HW-Tx-Status and go to WAIT_HW_BUFFER state. */
420                pTxXfer->txXferState = TX_XFER_STATE_WAIT_HW_BUFFER;
421
422                /* also mark the time at which the first attemot is done */
423                pTxXfer->TimeStampFirstHwBufferRead = os_timeStampMs( pTxXfer->hOs );
424
425                tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
426                                                    pTxXfer->txPathStatusAddr,
427                                                    PADREAD (&pTxXfer->hwTxPathStatusRead),
428                                                    sizeof(UINT32),
429                                                    TX_XFER_MODULE_ID,
430                                                    xferStateMachine,
431                                                    pTxXfer);
432
433                break;
434
435
436
437            case TX_XFER_STATE_WAIT_HW_BUFFER:
438
439                /* Call debug callback */
440                if (pTxXfer->sendPacketDebugCB)
441                {
442                    pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
443                                                pTxXfer->pPktCtrlBlk[0],
444                                                pTxXfer->txXferState);
445                }
446
447                /* We now have the HW-Tx-Status read, so check if there are HW buffers available. */
448                if (hwBuffersOccupied(pTxXfer) < DP_TX_PACKET_RING_CHUNK_NUM)
449                {
450                    /* Handle actual packet transfer to HW buffer. */
451                    tnetwifStatus = transferPacket(pTxXfer);
452
453                    pTxXfer->txXferState = TX_XFER_STATE_WAIT_XFER_DONE;
454
455                    /*
456                     * If we've postponed the Xfer-Done callback of the previous transfered
457                     *   packet, call it now in parallel with the Xfer of the current packet.
458                     * Note that all variables are updated before calling the XferDone, since
459                     *   it may be used to send another packet.
460                     * The current transfered packet pointer is moved to the first buffer.
461                     */
462                    if (pTxXfer->xferDonePostponed)
463                    {
464                        txCtrlBlkEntry_t *pPostponedPktCtrlBlk = pTxXfer->pPktCtrlBlk[0];
465                        pTxXfer->numBufferedPkts = 1;
466                        pTxXfer->pPktCtrlBlk[0] = pTxXfer->pPktCtrlBlk[1];
467                        pTxXfer->xferDonePostponed = FALSE;
468                        pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pPostponedPktCtrlBlk);
469#ifdef TI_DBG
470                        pTxXfer->xferDoneCallCBCount++;
471#endif
472                    }
473                    pTxXfer->hwStatusReadLoopCount = 0;
474#ifdef TI_DBG
475                    pTxXfer->hwBufferReadCount++;
476#endif
477                }
478
479                /* If HW buffer isn't available, try reading the status again (loop on same state). */
480                else
481                {
482                    tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
483                                                        pTxXfer->txPathStatusAddr,
484                                                        PADREAD (&pTxXfer->hwTxPathStatusRead),
485                                                        sizeof(UINT32),
486                                                        TX_XFER_MODULE_ID,
487                                                        xferStateMachine,
488                                                        pTxXfer);
489
490#ifdef TI_DBG
491                    /* For Debug:  Update counters */
492                    pTxXfer->hwBufferFullCount++;
493                    pTxXfer->hwBufferReadCount++;
494#endif
495                    /* Detect endless loop and perform recovery if needed */
496                    pTxXfer->hwStatusReadLoopCount++;
497                    if (os_timeStampMs (pTxXfer->hOs) - pTxXfer->TimeStampFirstHwBufferRead >
498                        pTxXfer->timeToTxStuckMs)
499                    {
500                        WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
501                            ("xferStateMachine(): Looping too long for Tx-Status, LastTxStatus=%d\n",
502                            pTxXfer->hwTxPathStatusRead));
503                        WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
504                                          ("Loop count=%d, First time stamp:%d, current time stamp:%d\n",
505                                           pTxXfer->hwStatusReadLoopCount, pTxXfer->TimeStampFirstHwBufferRead,
506                                           os_timeStampMs( pTxXfer->hOs )) );
507
508                      #ifdef USE_RECOVERY
509                        pTxXfer->bRecovery = TRUE;
510                        /* Error Reporting - if after a configurable interval we could not
511                           transfer data a recovery will be called */
512                        if (pTxXfer->failureEventFunc)
513                        {
514                            pTxXfer->failureEventFunc(pTxXfer->failureEventObj, TX_STUCK);
515                        }
516
517                        return;
518                      #endif
519                    }
520                }
521
522                break;
523
524            case TX_XFER_STATE_WAIT_XFER_DONE:
525
526                /* Call debug callback */
527                if (pTxXfer->sendPacketDebugCB)
528                {
529                    pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
530                                                pTxXfer->pPktCtrlBlk[0],
531                                                pTxXfer->txXferState);
532                }
533
534                /* Now the last packet transfer to the HW is finished, so we issue a trigger to the FW. */
535
536                {
537                    UINT32 txInterruptRegAddress;
538                    UINT32 txInterruptRegData;
539
540                    /* Set the Tx-interrupt address and value according to the
541                         HW buffer used for the last transfer. */
542                    if (pTxXfer->dataInCount & 0x1)
543                    {
544                        txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG_H;
545                        txInterruptRegData = INTR_TRIG_TX_PROC1;
546                    }
547                    else
548                    {
549                        txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG;
550                        txInterruptRegData = INTR_TRIG_TX_PROC0;
551                    }
552
553                    /* Call debug callback */
554                    if (pTxXfer->sendPacketDebugCB)
555                    {
556                        pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
557                                                    pTxXfer->pPktCtrlBlk[0],
558                                                    0);
559                    }
560
561                    /* Issue the Tx interrupt trigger to the FW. */
562                    tnetwifStatus = TNETWIF_WriteRegOpt(pTxXfer->hTNETWIF,
563                                                        txInterruptRegAddress,
564                                                        txInterruptRegData,
565                                                        TX_XFER_MODULE_ID,
566                                                        xferStateMachine,
567                                                        pTxXfer);
568
569                    /* Increment the transfered packets counter modulo 16 (as FW data-out counter). */
570                    pTxXfer->dataInCount = (pTxXfer->dataInCount + 1) & TX_STATUS_DATA_OUT_COUNT_MASK;
571
572                    pTxXfer->txXferState = TX_XFER_STATE_WAIT_TRIGGER_DONE;
573                }
574
575                break;
576
577            case TX_XFER_STATE_WAIT_TRIGGER_DONE:
578
579                /* Call debug callback */
580                if (pTxXfer->sendPacketDebugCB)
581                {
582                    pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
583                                                pTxXfer->pPktCtrlBlk[0],
584                                                pTxXfer->txXferState);
585                }
586
587                /* Now the HW Tx trigger is done so we can continue to the next packet if waiting. */
588
589                /* If we don't have another packet pending for transfer. */
590                if (pTxXfer->numBufferedPkts == 1)
591                {
592                    pTxXfer->numBufferedPkts = 0;
593
594                    /*
595                     * Call the XferDone callback, but only if we are not in the original
596                     *   SendPacket context (i.e. completely synchronous).
597                     * This is to avoid nesting, since the callback may start another SendPacket.
598                     */
599                    if (!pTxXfer->syncXferIndication)
600                    {
601#ifdef TI_DBG
602                        pTxXfer->xferDoneCallCBCount++;
603                        WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
604                            ("sendPacketTransferCB: CB_Func=0x%x, CB_Handle=0x%x\n",
605                            pTxXfer->sendPacketTransferCB, pTxXfer->sendPacketTransferHandle));
606#endif
607                        pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pTxXfer->pPktCtrlBlk[0]);
608                    }
609
610                    /* If still no packet was sent, release bus (Finish), set IDLE state and exit. */
611                    if (pTxXfer->numBufferedPkts == 0)
612                    {
613                        pTxXfer->txXferState = TX_XFER_STATE_IDLE;
614                        TNETWIF_Finish (pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, NULL);
615
616                        WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
617                            ("txXferSM Finished -> IDLE: NumPkts=%d, XferDonePostponed=%d, SyncIndication=%d\n",
618                            pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed, pTxXfer->syncXferIndication));
619
620                        return;   /************    Exit State Machine (back to IDLE)   ************/
621                    }
622
623                    /*
624                     * A new packet was sent (in XferDone callback), so request the bus again using Restart.
625                     * This will call the SM later, and start the process again from WAIT_BUS state.
626                     */
627                    else
628                    {
629                        pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
630                        tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
631#ifdef TI_DBG
632                        pTxXfer->busRestartCount++;
633#endif
634                    }
635                }
636
637                /*
638                 * We have another packet pending.
639                 * So to enable parallel processing, we postpone the XferDone callback (just set flag).
640                 * Thus, we'll start first the new packet transfer and only than call the postponed
641                 *   XferDone (see WAIT_HW_BUFFER state), which may start another SendPacket in
642                 *   parallel to the HW transfer.
643                 * Note that we request the bus again using Restart (to avoid nesting or bus starvation).
644                 * This will call the SM later, and start the process again from WAIT_BUS state.
645                 */
646                else
647                {
648                    pTxXfer->xferDonePostponed = TRUE;
649                    pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
650                    tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
651#ifdef TI_DBG
652                    pTxXfer->busRestartCount++;
653                    pTxXfer->xferDonePostponeCount++;
654#endif
655                }
656
657                break;
658
659
660
661            default:
662                    WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
663                        ("xferStateMachine(): Unexpected state, txXferState=%d, NumPkts=%d\n",
664                        pTxXfer->txXferState, pTxXfer->numBufferedPkts));
665
666                return;
667
668        }  /* switch (pTxXfer->txXferState) */
669
670        WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
671            ("txXferSM(): SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
672            pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
673            tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
674
675        /*
676         * If the last HW access request was pended, exit the SM (Asynchronous process).
677         * The SM will be called back when the HW access is done.
678         * Also reset the Sync flag to notify that the Xfer wasn't completed in the SendPacket context.
679         */
680        if (tnetwifStatus == TNETWIF_PENDING)
681        {
682            pTxXfer->syncXferIndication = FALSE;
683
684            return;  /**********    Exit State Machine (to be called back by TNETWIF)   **********/
685        }
686
687#ifdef TI_DBG
688        else if (tnetwifStatus == TNETWIF_ERROR)
689        {
690            WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
691                ("txXferSM TNETWIF_ERROR: SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
692                pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
693                tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
694            return;
695        }
696#endif
697
698    }  /* while (1) */
699
700}
701
702
703
704
705/****************************************************************************
706 *                  hwBuffersOccupied()
707 ****************************************************************************
708 * DESCRIPTION:
709   ============
710   Return the number of occupied buffers in the HW Tx double buffer, based on
711     the last read of the HW Tx path status.
712 ****************************************************************************/
713static UINT32 hwBuffersOccupied(txXferObj_t *pTxXfer)
714{
715    UINT32 dataOutCount = pTxXfer->hwTxPathStatusRead & TX_STATUS_DATA_OUT_COUNT_MASK;
716
717    /* Return the difference between the packets transfered to the double buffer (by host)
718        and the packets copied from it (by FW). The else is for counter wrap around. */
719
720    if (pTxXfer->dataInCount >= dataOutCount)
721    {
722        return pTxXfer->dataInCount - dataOutCount;
723    }
724    else
725    {
726        return pTxXfer->dataInCount + TX_STATUS_DATA_OUT_COUNT_MASK + 1 - dataOutCount;
727    }
728}
729
730
731
732
733/****************************************************************************
734 *                  transferPacket()
735 ****************************************************************************
736 * DESCRIPTION:
737   ============
738   Handle the current packet transfer to the HW Tx double buffer.
739   Return the transfer status:
740     TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
741     TNETWIF_PENDING  - if pending, i.e. Asynchronous mode (callback function will be called).
742
743
744   If the packet was pending during disconnect, notify the TxResult to issue Tx-Complete,
745     and return TNETWIF_COMPLETE, since we don't transfer it to the FW.
746
747 ****************************************************************************/
748static TI_STATUS transferPacket(txXferObj_t *pTxXfer)
749{
750    UINT16 XferLength;  /* The actual length of the transfer. */
751    txCtrlBlkEntry_t *pPktCtrlBlk;  /* The packet control block pointer. */
752    TI_STATUS status;
753
754    /* Get the current packet control-block pointer. If we've postponed the last packet Xfer-Done (i.e.
755        was transfered but still buffered) than our current packet is the second one. */
756    pPktCtrlBlk = pTxXfer->pPktCtrlBlk[ ((pTxXfer->xferDonePostponed) ? 1 : 0) ];
757
758    /* Get the packet length, add descriptor length and align upward to 32 bit. */
759    XferLength = (pPktCtrlBlk->txDescriptor.length + sizeof(DbTescriptor) + ALIGN_32BIT_MASK) & ~ALIGN_32BIT_MASK;
760
761    /* Initiate the packet transfer. The status indicates if Sync or Async mode was used!! */
762    status = TNETWIF_WriteMemOpt (pTxXfer->hTNETWIF,
763                                  pTxXfer->dblBufAddr[pTxXfer->dataInCount & 0x1],
764                                  (UINT8 *)(pPktCtrlBlk->txPktParams.pFrame),
765                                  XferLength,
766                                  TX_XFER_MODULE_ID,
767                                  xferStateMachine,
768                                  pTxXfer);
769
770#ifdef TI_DBG
771    WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
772        ("transferPacket(): Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
773        status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
774        pPktCtrlBlk->txDescriptor.expiryTime));
775
776    if (status == TNETWIF_COMPLETE)
777    {
778        pTxXfer->pktTransferSyncCount++;
779    }
780    else if (status == TNETWIF_PENDING)
781    {
782        pTxXfer->pktTransferAsyncCount++;
783    }
784    else
785    {
786        WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
787            ("transferPacket - TNETWIF_ERROR: Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
788            status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
789            pPktCtrlBlk->txDescriptor.expiryTime));
790    }
791#endif
792
793    /* Return the transfer status:
794         TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
795         TNETWIF_PENDING  - if pending, i.e. Asynchronous mode (callback function will be called).
796    */
797    return status;
798}
799
800
801
802
803/****************************************************************************
804 *                      txXfer_RegisterCB()
805 ****************************************************************************
806 * DESCRIPTION:  Register the upper driver Xfer callback functions.
807 ****************************************************************************/
808void txXfer_RegisterCB(TI_HANDLE hTxXfer, tiUINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
809{
810    txXferObj_t* pTxXfer = (txXferObj_t*)hTxXfer;
811
812    WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
813        ("txXfer_RegisterCB(): CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj));
814
815    switch(CallBackID)
816    {
817        /* Set Transfer-Done callback */
818        case TX_XFER_SEND_PKT_TRANSFER:
819            pTxXfer->sendPacketTransferCB = (SendPacketTranferCB_t)CBFunc;
820            pTxXfer->sendPacketTransferHandle = CBObj;
821            break;
822
823        case TX_XFER_SEND_PKT_DEBUG:
824            pTxXfer->sendPacketDebugCB = (SendPacketDebugCB_t)CBFunc;
825            pTxXfer->sendPacketDebugHandle = CBObj;
826            break;
827
828        default:
829            WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG, ("txXfer_RegisterCB - Illegal value\n"));
830            break;
831    }
832}
833
834
835
836/****************************************************************************************
837 *                        txXfer_RegisterFailureEventCB                                                 *
838 ****************************************************************************************
839DESCRIPTION: Registers a failure event callback for scan error notifications.
840
841
842INPUT:      - hTxXfer       - handle to the xfer object.
843            - failureEventCB    - the failure event callback function.\n
844            - hFailureEventObj - handle to the object passed to the failure event callback function.
845
846OUTPUT:
847RETURN:    void.
848****************************************************************************************/
849
850void txXfer_RegisterFailureEventCB( TI_HANDLE hTxXfer,
851                                     void * failureEventCB, TI_HANDLE hFailureEventObj )
852{
853    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
854
855    pTxXfer->failureEventFunc   = (failureEventCB_t)failureEventCB;
856    pTxXfer->failureEventObj    = hFailureEventObj;
857}
858
859/****************************************************************************
860 *                      txXfer_printInfo()
861 ****************************************************************************
862 * DESCRIPTION:  Print the txXfer object main fields.
863 ****************************************************************************/
864void txXfer_printInfo(TI_HANDLE hTxXfer)
865{
866#ifdef TI_DBG
867    txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
868
869    WLAN_OS_REPORT(("Tx-Xfer Module Information:\n"));
870    WLAN_OS_REPORT(("===========================\n"));
871
872    switch (pTxXfer->txXferState)
873    {
874        case TX_XFER_STATE_IDLE:
875            WLAN_OS_REPORT(("State = IDLE\n"));
876            break;
877
878        case TX_XFER_STATE_WAIT_BUS:
879            WLAN_OS_REPORT(("State = WAIT_BUS\n"));
880        break;
881
882        case TX_XFER_STATE_WAIT_HW_BUFFER:
883            WLAN_OS_REPORT(("State = WAIT_HW_BUFFER\n"));
884        break;
885
886        case TX_XFER_STATE_WAIT_XFER_DONE:
887            WLAN_OS_REPORT(("State = WAIT_XFER_DONE\n"));
888        break;
889
890        case TX_XFER_STATE_WAIT_TRIGGER_DONE:
891            WLAN_OS_REPORT(("State = WAIT_TRIGGER_DONE\n"));
892        break;
893
894        default:
895            WLAN_OS_REPORT(("State = UNKNOWN !!\n"));
896        break;
897    }
898
899    WLAN_OS_REPORT(("numBufferedPkts    = %d\n", pTxXfer->numBufferedPkts));
900    WLAN_OS_REPORT(("xferDonePostponed  = %d\n", pTxXfer->xferDonePostponed));
901    WLAN_OS_REPORT(("syncXferIndication = %d\n", pTxXfer->syncXferIndication));
902    WLAN_OS_REPORT(("pPktCtrlBlk[0]     = 0x%x\n", pTxXfer->pPktCtrlBlk[0]));
903    WLAN_OS_REPORT(("pPktCtrlBlk[1]     = 0x%x\n", pTxXfer->pPktCtrlBlk[1]));
904    WLAN_OS_REPORT(("hwTxPathStatusRead = 0x%x\n", pTxXfer->hwTxPathStatusRead));
905    WLAN_OS_REPORT(("dataInCount        = 0x%x\n", pTxXfer->dataInCount));
906    WLAN_OS_REPORT(("txPathStatusAddr   = 0x%x\n", pTxXfer->txPathStatusAddr));
907    WLAN_OS_REPORT(("dblBufAddr[0]      = 0x%x\n", pTxXfer->dblBufAddr[0]));
908    WLAN_OS_REPORT(("dblBufAddr[1]      = 0x%x\n\n", pTxXfer->dblBufAddr[1]));
909
910    WLAN_OS_REPORT(("hwBufferReadCount      = %d\n", pTxXfer->hwBufferReadCount));
911    WLAN_OS_REPORT(("hwBufferFullCount      = %d\n", pTxXfer->hwBufferFullCount));
912    WLAN_OS_REPORT(("sendPacketCount        = %d\n", pTxXfer->sendPacketCount));
913    WLAN_OS_REPORT(("busStartSyncCount      = %d\n", pTxXfer->busStartSyncCount));
914    WLAN_OS_REPORT(("busStartAsyncCount     = %d\n", pTxXfer->busStartAsyncCount));
915    WLAN_OS_REPORT(("pktTransferSyncCount   = %d\n", pTxXfer->pktTransferSyncCount));
916    WLAN_OS_REPORT(("pktTransferAsyncCount  = %d\n", pTxXfer->pktTransferAsyncCount));
917    WLAN_OS_REPORT(("busRestartCount        = %d\n", pTxXfer->busRestartCount));
918    WLAN_OS_REPORT(("xferDonePostponeCount  = %d\n", pTxXfer->xferDonePostponeCount));
919    WLAN_OS_REPORT(("xferDoneSyncCount      = %d\n", pTxXfer->xferDoneSyncCount));
920    WLAN_OS_REPORT(("xferDoneCallCBCount    = %d\n", pTxXfer->xferDoneCallCBCount));
921#endif /* TI_DBG */
922}
923