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