Home | History | Annotate | Download | only in FW_Transfer
      1 /*
      2  * txXfer.c
      3  *
      4  * Copyright(c) 1998 - 2009 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 /** \file   txXfer.c
     36  *  \brief  Handle Tx packets transfer to the firmware.
     37  *
     38  *  This module gets the upper driver's Tx packets after FW resources were
     39  *    allocated for them, aggregates them if possible, and handles their transfer
     40  *    to the FW via the host slave (indirect) interface, using the TwIf Transaction API.
     41  *  The aggregation processing is completed by the BusDrv where the packets are combined
     42  *    and sent to the FW in one transaction.
     43  *
     44  *  \see
     45  */
     46 
     47 
     48 #define __FILE_ID__  FILE_ID_108
     49 #include "tidef.h"
     50 #include "osApi.h"
     51 #include "report.h"
     52 #include "TwIf.h"
     53 #include "TWDriver.h"
     54 #include "txXfer_api.h"
     55 
     56 
     57 #ifdef TI_DBG
     58 #define     DBG_MAX_AGGREG_PKTS     16
     59 #endif
     60 
     61 typedef struct
     62 {
     63     TTxnStruct              tTxnStruct;
     64     TI_UINT32               uPktsCntr;
     65 } TPktsCntrTxn;
     66 
     67 /* The TxXfer module object. */
     68 typedef struct
     69 {
     70     TI_HANDLE               hOs;
     71     TI_HANDLE               hReport;
     72     TI_HANDLE               hTwIf;
     73 
     74     TI_UINT32               uAggregMaxPkts;          /* Max number of packets that may be aggregated */
     75     TI_UINT32               uAggregMaxLen;           /* Max length in bytes of a single aggregation */
     76     TI_UINT32               uAggregPktsNum;          /* Number of packets in current aggregation */
     77     TI_UINT32               uAggregPktsLen;          /* Aggregated length of current aggregation */
     78     TTxCtrlBlk *            pAggregFirstPkt;         /* Pointer to the first packet of current aggregation */
     79     TTxCtrlBlk *            pAggregLastPkt;          /* Pointer to the last packet of current aggregation */
     80     TSendPacketTranferCb    fSendPacketTransferCb;   /* Upper layer Xfer-Complete callback */
     81     TI_HANDLE               hSendPacketTransferHndl; /* Upper layer Xfer-Complete callback handle */
     82     TTxnDoneCb              fXferCompleteLocalCb;    /* TxXfer local CB for pkt transfer completion (NULL is not needed!) */
     83     TI_UINT32               uPktsCntr;               /* Counts all Tx packets. Written to FW after each packet transaction */
     84     TI_UINT32               uPktsCntrTxnIndex;       /* The current indext of the aPktsCntrTxn[] used for the counter workaround transactions */
     85     TPktsCntrTxn            aPktsCntrTxn[CTRL_BLK_ENTRIES_NUM]; /* Transaction structures for sending the packets counter */
     86 #ifdef TI_DBG
     87     TI_UINT32               aDbgCountPktAggreg[DBG_MAX_AGGREG_PKTS];
     88 #endif
     89 
     90 } TTxXferObj;
     91 
     92 static ETxnStatus txXfer_SendAggregatedPkts (TTxXferObj *pTxXfer, TI_BOOL bLastPktSentNow);
     93 static void       txXfer_TransferDoneCb     (TI_HANDLE hTxXfer, TTxnStruct *pTxn);
     94 
     95 
     96 /********************************************************************************
     97 *																				*
     98 *                       PUBLIC  FUNCTIONS  IMPLEMENTATION						*
     99 *																				*
    100 *********************************************************************************/
    101 
    102 
    103 TI_HANDLE txXfer_Create(TI_HANDLE hOs)
    104 {
    105     TTxXferObj *pTxXfer;
    106 
    107     pTxXfer = os_memoryAlloc (hOs, sizeof(TTxXferObj));
    108     if (pTxXfer == NULL)
    109     {
    110         return NULL;
    111     }
    112 
    113     os_memoryZero (hOs, pTxXfer, sizeof(TTxXferObj));
    114 
    115     pTxXfer->hOs = hOs;
    116 
    117     return (TI_HANDLE)pTxXfer;
    118 }
    119 
    120 
    121 TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
    122 {
    123     TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
    124 
    125     if (pTxXfer)
    126     {
    127         os_memoryFree (pTxXfer->hOs, pTxXfer, sizeof(TTxXferObj));
    128     }
    129 
    130     return TI_OK;
    131 }
    132 
    133 
    134 TI_STATUS txXfer_Init (TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTwIf)
    135 {
    136     TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
    137     TTxnStruct *pTxn;
    138     TI_UINT8    i;
    139 
    140     pTxXfer->hReport = hReport;
    141     pTxXfer->hTwIf   = hTwIf;
    142     pTxXfer->fSendPacketTransferCb = NULL;
    143     pTxXfer->fXferCompleteLocalCb  = NULL;
    144 
    145     for (i = 0; i < CTRL_BLK_ENTRIES_NUM; i++)
    146     {
    147         pTxn = &(pTxXfer->aPktsCntrTxn[i].tTxnStruct);
    148         TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
    149         BUILD_TTxnStruct(pTxn, HOST_WR_ACCESS_REG, &pTxXfer->aPktsCntrTxn[i].uPktsCntr, REGISTER_SIZE, NULL, NULL)
    150     }
    151 
    152     return txXfer_Restart(hTxXfer);
    153 }
    154 
    155 
    156 TI_STATUS txXfer_Restart (TI_HANDLE hTxXfer)
    157 {
    158     TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
    159 
    160     pTxXfer->uPktsCntr         = 0;
    161     pTxXfer->uPktsCntrTxnIndex = 0;
    162     pTxXfer->uAggregPktsNum    = 0;
    163 
    164     return TI_OK;
    165 }
    166 
    167 
    168 void txXfer_SetDefaults (TI_HANDLE hTxXfer, TTwdInitParams *pInitParams)
    169 {
    170     TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
    171 
    172     pTxXfer->uAggregMaxPkts = pInitParams->tGeneral.uTxAggregPktsLimit;
    173 }
    174 
    175 
    176 void txXfer_SetBusParams (TI_HANDLE hTxXfer, TI_UINT32 uDmaBufLen)
    177 {
    178     TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
    179 
    180     pTxXfer->uAggregMaxLen = uDmaBufLen;
    181 }
    182 
    183 
    184 void txXfer_RegisterCb (TI_HANDLE hTxXfer, TI_UINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
    185 {
    186     TTxXferObj* pTxXfer = (TTxXferObj*)hTxXfer;
    187 
    188     TRACE3(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_RegisterCb: CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj);
    189 
    190     switch(CallBackID)
    191     {
    192         /* Save upper layers Transfer-Done callback */
    193         case TWD_INT_SEND_PACKET_TRANSFER:
    194             pTxXfer->fSendPacketTransferCb   = (TSendPacketTranferCb)CBFunc;
    195             pTxXfer->hSendPacketTransferHndl = CBObj;
    196             /* Set also the local CB so we are called upon Async transaction completion to call the upper CB */
    197             pTxXfer->fXferCompleteLocalCb = (TTxnDoneCb)txXfer_TransferDoneCb;
    198             break;
    199 
    200         default:
    201             TRACE0(pTxXfer->hReport, REPORT_SEVERITY_ERROR, " - Illegal value\n");
    202             break;
    203     }
    204 }
    205 
    206 
    207 ETxnStatus txXfer_SendPacket (TI_HANDLE hTxXfer, TTxCtrlBlk *pPktCtrlBlk)
    208 {
    209     TTxXferObj   *pTxXfer = (TTxXferObj *)hTxXfer;
    210     TI_UINT32    uPktLen  = ENDIAN_HANDLE_WORD(pPktCtrlBlk->tTxDescriptor.length << 2); /* swap back for endianess if needed */
    211     ETxnStatus   eStatus;
    212 
    213     /* If starting a new aggregation, prepare it, and send packet if aggregation is disabled. */
    214     if (pTxXfer->uAggregPktsNum == 0)
    215     {
    216         pTxXfer->uAggregPktsNum  = 1;
    217         pTxXfer->uAggregPktsLen  = uPktLen;
    218         pTxXfer->pAggregFirstPkt = pPktCtrlBlk;
    219         pTxXfer->pAggregLastPkt  = pPktCtrlBlk;
    220         pPktCtrlBlk->pNextAggregEntry = pPktCtrlBlk;  /* First packet points to itself */
    221         if (pTxXfer->uAggregMaxPkts <= 1)
    222         {
    223             eStatus = txXfer_SendAggregatedPkts (pTxXfer, TI_TRUE);
    224             pTxXfer->uAggregPktsNum = 0;
    225         }
    226         else
    227         {
    228             eStatus = TXN_STATUS_PENDING;
    229         }
    230     }
    231 
    232     /* Else, if new packet can be added to aggregation, add it and set status as Pending. */
    233     else if ((pTxXfer->uAggregPktsNum + 1 <= pTxXfer->uAggregMaxPkts)  &&
    234              (pTxXfer->uAggregPktsLen + uPktLen <= pTxXfer->uAggregMaxLen))
    235     {
    236         pTxXfer->uAggregPktsNum++;
    237         pTxXfer->uAggregPktsLen += uPktLen;
    238         pTxXfer->pAggregLastPkt->pNextAggregEntry = pPktCtrlBlk;  /* Link new packet to last */
    239         pTxXfer->pAggregLastPkt = pPktCtrlBlk;                    /* Save new packet as last */
    240         pPktCtrlBlk->pNextAggregEntry = pTxXfer->pAggregFirstPkt; /* Point from last to first */
    241         eStatus = TXN_STATUS_PENDING;
    242     }
    243 
    244     /* Else, we can't add the new packet, so send current aggregation and start a new one */
    245     else
    246     {
    247         txXfer_SendAggregatedPkts (pTxXfer, TI_FALSE);
    248         eStatus = TXN_STATUS_PENDING;  /* The current packet is not sent yet so return Pending */
    249         pTxXfer->uAggregPktsNum  = 1;
    250         pTxXfer->uAggregPktsLen  = uPktLen;
    251         pTxXfer->pAggregFirstPkt = pPktCtrlBlk;
    252         pTxXfer->pAggregLastPkt  = pPktCtrlBlk;
    253         pPktCtrlBlk->pNextAggregEntry = pPktCtrlBlk;  /* First packet points to itself */
    254     }
    255 
    256 
    257     /* Return the Txn result - COMPLETE or PENDING. */
    258     /* Note: For PENDING, a callback function will be called only if registered (needed for WHA) */
    259     return eStatus;
    260 }
    261 
    262 
    263 void txXfer_EndOfBurst (TI_HANDLE hTxXfer)
    264 {
    265     TTxXferObj   *pTxXfer = (TTxXferObj *)hTxXfer;
    266 
    267     if (pTxXfer->uAggregPktsNum > 0)
    268     {
    269         /* No more packets from TxDataQ so send any aggregated packets and clear aggregation */
    270         txXfer_SendAggregatedPkts (pTxXfer, TI_FALSE);
    271         pTxXfer->uAggregPktsNum = 0;
    272     }
    273 }
    274 
    275 
    276 /********************************************************************************
    277 *																				*
    278 *                       INTERNAL  FUNCTIONS  IMPLEMENTATION						*
    279 *																				*
    280 *********************************************************************************/
    281 
    282 /**
    283  * \fn     txXfer_SendAggregatedPkts
    284  * \brief  Send aggregated Tx packets to bus Txn layer
    285  *
    286  * Send aggregated Tx packets to bus Txn layer one by one.
    287  * Increase the packets counter by the number of packets and send it to the FW (generates an interrupt).
    288  * If xfer completion CB is registered and status is Complete, call CB for all packets (except last one if inseted now).
    289  *
    290  * \note   The BusDrv combines the packets and sends them in one transaction.
    291  * \param  pTxXfer         - The module's object
    292  * \param  bLastPktSentNow - If TRUE, last packet in the aggregation was inserted in current call to txXfer_SendPacket.
    293  * \return COMPLETE if transaction completed in this context, PENDING if not, ERROR if failed
    294  * \sa
    295  */
    296 static ETxnStatus txXfer_SendAggregatedPkts (TTxXferObj *pTxXfer, TI_BOOL bLastPktSentNow)
    297 {
    298     TTxCtrlBlk   *pCurrPkt;
    299     TTxnStruct   *pTxn;
    300     TPktsCntrTxn *pPktsCntrTxn;
    301     ETxnStatus   eStatus = TXN_STATUS_COMPLETE;
    302     TI_UINT32    i;
    303 
    304     /* Prepare and send all aggregated packets (combined and sent in one transaction by the BusDrv) */
    305     pCurrPkt = pTxXfer->pAggregFirstPkt;
    306     for (i = 0; i < pTxXfer->uAggregPktsNum; i++)
    307     {
    308         pTxn = (TTxnStruct *)pCurrPkt;
    309 
    310         /* If not last packet, set aggregation flag, clear completion CB and progress to next packet */
    311         if (i < pTxXfer->uAggregPktsNum - 1)
    312         {
    313             TXN_PARAM_SET_AGGREGATE(pTxn, TXN_AGGREGATE_ON);
    314             pTxn->fTxnDoneCb = NULL;
    315             pCurrPkt = pCurrPkt->pNextAggregEntry;
    316         }
    317         /* If last packet, clear aggregation flag and set completion CB (exist only if registered) */
    318         else
    319         {
    320             TXN_PARAM_SET_AGGREGATE(pTxn, TXN_AGGREGATE_OFF);
    321             pTxn->fTxnDoneCb = pTxXfer->fXferCompleteLocalCb;
    322             pTxn->hCbHandle  = (TI_HANDLE)pTxXfer;
    323         }
    324 
    325         /* Send packet */
    326         pTxn->uHwAddr = SLV_MEM_DATA;
    327         eStatus = twIf_Transact (pTxXfer->hTwIf, pTxn);
    328     }
    329 
    330 #ifdef TI_DBG
    331     pTxXfer->aDbgCountPktAggreg[pTxXfer->uAggregPktsNum]++;
    332     TRACE5(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_SendAggregatedPkts: Status=%d, NumPkts=%d, AggregLen=%d, pFirstPkt=0x%x, pLastPkt=0x%x\n", eStatus, pTxXfer->uAggregPktsNum, pTxXfer->uAggregPktsLen, pTxXfer->pAggregFirstPkt, pTxXfer->pAggregLastPkt);
    333     if (eStatus == TXN_STATUS_ERROR)
    334     {
    335         TRACE5(pTxXfer->hReport, REPORT_SEVERITY_ERROR, "txXfer_SendAggregatedPkts: Status=%d, NumPkts=%d, AggregLen=%d, pFirstPkt=0x%x, pLastPkt=0x%x\n", eStatus, pTxXfer->uAggregPktsNum, pTxXfer->uAggregPktsLen, pTxXfer->pAggregFirstPkt, pTxXfer->pAggregLastPkt);
    336         return eStatus;
    337     }
    338 #endif  /* TI_DBG */
    339 
    340     /* Write packet counter to FW (generates an interrupt).
    341        Note: This may be removed once the host-slave HW counter functionality is verified */
    342     pTxXfer->uPktsCntr += pTxXfer->uAggregPktsNum;
    343     pTxXfer->uPktsCntrTxnIndex++;
    344     if (pTxXfer->uPktsCntrTxnIndex == CTRL_BLK_ENTRIES_NUM)
    345     {
    346         pTxXfer->uPktsCntrTxnIndex = 0;
    347     }
    348     pPktsCntrTxn = &(pTxXfer->aPktsCntrTxn[pTxXfer->uPktsCntrTxnIndex]);
    349     pPktsCntrTxn->uPktsCntr = ENDIAN_HANDLE_LONG(pTxXfer->uPktsCntr);
    350     pPktsCntrTxn->tTxnStruct.uHwAddr = HOST_WR_ACCESS_REG;
    351     twIf_Transact(pTxXfer->hTwIf, &pPktsCntrTxn->tTxnStruct);
    352 
    353     /* If xfer completion CB is registered and last packet status is Complete, call the CB for all
    354      *     packets except the input one (covered by the return code).
    355      */
    356     if (pTxXfer->fSendPacketTransferCb && (eStatus == TXN_STATUS_COMPLETE))
    357     {
    358         /* Don't call CB for last packet if inserted in current Tx */
    359         TI_UINT32 uNumCbCalls = bLastPktSentNow ? (pTxXfer->uAggregPktsNum - 1) : pTxXfer->uAggregPktsNum;
    360 
    361         pCurrPkt = pTxXfer->pAggregFirstPkt;
    362         for (i = 0; i < uNumCbCalls; i++)
    363         {
    364             pTxXfer->fSendPacketTransferCb (pTxXfer->hSendPacketTransferHndl, pCurrPkt);
    365             pCurrPkt = pCurrPkt->pNextAggregEntry;
    366         }
    367     }
    368 
    369     /* Return the Txn result - COMPLETE or PENDING. */
    370     /* Note: For PENDING, a callback function will be called only if registered (needed for WHA) */
    371     return eStatus;
    372 }
    373 
    374 
    375 /**
    376  * \fn     txXfer_TransferDoneCb
    377  * \brief  Send aggregated Tx packets to bus Txn layer
    378  *
    379  * Call the upper layers TranferDone CB for all packets of the completed aggregation
    380  * This function is called only if the upper layers registered their CB (used only by WHA)
    381  *
    382  * \note
    383  * \param  pTxXfer - The module's object
    384  * \return COMPLETE if completed in this context, PENDING if not, ERROR if failed
    385  * \sa
    386  */
    387 static void txXfer_TransferDoneCb (TI_HANDLE hTxXfer, TTxnStruct *pTxn)
    388 {
    389     TTxXferObj *pTxXfer   = (TTxXferObj*)hTxXfer;
    390     TTxCtrlBlk *pInputPkt = (TTxCtrlBlk *)pTxn; /* This is the last packet of the aggregation */
    391     TTxCtrlBlk *pCurrPkt;
    392     TI_UINT32   i;
    393 
    394     /* Call the upper layers TranferDone CB for all packets of the completed aggregation */
    395     /* Note: If this CB was called it means that the upper CB exists */
    396     pCurrPkt = pInputPkt->pNextAggregEntry;  /* The last packet of the aggregation point to the first one */
    397     for (i = 0; i < pTxXfer->uAggregMaxPkts; i++)
    398     {
    399         pTxXfer->fSendPacketTransferCb (pTxXfer->hSendPacketTransferHndl, pCurrPkt);
    400 
    401         /* If we got back to the input packet we went over all the aggregation */
    402         if (pCurrPkt == pInputPkt)
    403         {
    404             break;
    405         }
    406 
    407         pCurrPkt = pCurrPkt->pNextAggregEntry;
    408     }
    409 
    410     TRACE3(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_TransferDoneCb: NumPkts=%d, pInputPkt=0x%x, pCurrPkt=0x%x\n", i + 1, pInputPkt, pCurrPkt);
    411 }
    412 
    413 
    414 #ifdef TI_DBG
    415 
    416 void txXfer_ClearStats (TI_HANDLE hTxXfer)
    417 {
    418     TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
    419 
    420     os_memoryZero (pTxXfer->hOs, &pTxXfer->aDbgCountPktAggreg, sizeof(pTxXfer->aDbgCountPktAggreg));
    421 }
    422 
    423 void txXfer_PrintStats (TI_HANDLE hTxXfer)
    424 {
    425 #ifdef REPORT_LOG
    426     TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
    427     TI_UINT32   i;
    428 
    429     WLAN_OS_REPORT(("Print Tx Xfer module info\n"));
    430     WLAN_OS_REPORT(("=========================\n"));
    431     WLAN_OS_REPORT(("uAggregMaxPkts     = %d\n", pTxXfer->uAggregMaxPkts));
    432     WLAN_OS_REPORT(("uAggregMaxLen      = %d\n", pTxXfer->uAggregMaxLen));
    433     WLAN_OS_REPORT(("uAggregPktsNum     = %d\n", pTxXfer->uAggregPktsNum));
    434     WLAN_OS_REPORT(("uAggregPktsLen     = %d\n", pTxXfer->uAggregPktsLen));
    435     WLAN_OS_REPORT(("uPktsCntr          = %d\n", pTxXfer->uPktsCntr));
    436     WLAN_OS_REPORT(("uPktsCntrTxnIndex  = %d\n", pTxXfer->uPktsCntrTxnIndex));
    437     for (i = 1; i < DBG_MAX_AGGREG_PKTS; i++)
    438     {
    439         WLAN_OS_REPORT(("uCountPktAggreg-%2d = %d\n", i, pTxXfer->aDbgCountPktAggreg[i]));
    440     }
    441 #endif
    442 }
    443 
    444 #endif /* TI_DBG */
    445