Home | History | Annotate | Download | only in Slave_Dbl_Buf
      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  ****************************************************************************/
     74 TI_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  ****************************************************************************/
    103 TI_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  ****************************************************************************/
    123 TI_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  ****************************************************************************/
    150 void 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  ****************************************************************************/
    173 void  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  ****************************************************************************/
    199 TI_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  ****************************************************************************/
    229 systemStatus_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 
    369 Event:     Send-Pkt       Bus-Ready         HW-Buffer-Ready         Xfer-Done             Trigger-Done
    370                |              |                    |                    |                       |
    371                V              V                    V                    V                       V
    372 State:  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  ****************************************************************************/
    385 static 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  ****************************************************************************/
    713 static 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  ****************************************************************************/
    748 static 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  ****************************************************************************/
    808 void 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  ****************************************************************************************
    839 DESCRIPTION: Registers a failure event callback for scan error notifications.
    840 
    841 
    842 INPUT:      - 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 
    846 OUTPUT:
    847 RETURN:    void.
    848 ****************************************************************************************/
    849 
    850 void 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  ****************************************************************************/
    864 void 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