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