1 /* 2 * txResult.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 /**************************************************************************** 36 * 37 * MODULE: txResult.c 38 * 39 * PURPOSE: Handle packets Tx results upon Tx-complete from the FW. 40 * 41 * DESCRIPTION: 42 * ============ 43 * This module is called upon Tx-complete from FW. 44 * It retrieves the transmitted packets results from the FW TxResult table and 45 * calls the upper layer callback function for each packet with its results. 46 * 47 ****************************************************************************/ 48 49 #define __FILE_ID__ FILE_ID_107 50 #include "tidef.h" 51 #include "osApi.h" 52 #include "report.h" 53 #include "TwIf.h" 54 #include "txCtrlBlk_api.h" 55 #include "txResult_api.h" 56 #include "TWDriver.h" 57 #include "FwEvent_api.h" 58 59 60 61 #define TX_RESULT_QUEUE_DEPTH_MASK (TRQ_DEPTH - 1) 62 63 #if (TX_RESULT_QUEUE_DEPTH_MASK & TRQ_DEPTH) 64 #error TRQ_DEPTH should be a power of 2 !! 65 #endif 66 67 68 /* Callback function definition for Tx sendPacketComplete */ 69 typedef void (* TSendPacketCompleteCb)(TI_HANDLE hCbObj, TxResultDescriptor_t *pTxResultInfo); 70 71 /* Tx-Result SM states */ 72 typedef enum 73 { 74 TX_RESULT_STATE_IDLE, 75 TX_RESULT_STATE_READING 76 } ETxResultState; 77 78 /* The host Tx-results counter write transaction structure. */ 79 typedef struct 80 { 81 TTxnStruct tTxnStruct; 82 TI_UINT32 uCounter; 83 } THostCounterWriteTxn; 84 85 /* The Tx-results counters and table read transaction structure. */ 86 typedef struct 87 { 88 TTxnStruct tTxnStruct; 89 TxResultInterface_t tTxResultInfo; 90 } TResultsInfoReadTxn; 91 92 /* The TxResult module object. */ 93 typedef struct 94 { 95 TI_HANDLE hOs; 96 TI_HANDLE hReport; 97 TI_HANDLE hTwIf; 98 99 TI_UINT32 uTxResultInfoAddr; /* The HW Tx-Result Table address */ 100 TI_UINT32 uTxResultHostCounterAddr;/* The Tx-Result host counter address in SRAM */ 101 TI_UINT32 uHostResultsCounter; /* Number of results read by host from queue since FW-init (updated to FW) */ 102 ETxResultState eState; /* Current eState of SM */ 103 TSendPacketCompleteCb fSendPacketCompleteCb; /* Tx-Complete callback function */ 104 TI_HANDLE hSendPacketCompleteHndl; /* Tx-Complete callback function handle */ 105 THostCounterWriteTxn tHostCounterWriteTxn; /* The structure used for writing host results counter to FW */ 106 TResultsInfoReadTxn tResultsInfoReadTxn; /* The structure used for reading Tx-results counters and table from FW */ 107 #ifdef TI_DBG 108 TI_UINT32 uInterruptsCounter; /* Count number of Tx-results */ 109 #endif 110 111 } TTxResultObj; 112 113 114 static void txResult_Restart (TTxResultObj *pTxResult); 115 static void txResult_HandleNewResults (TTxResultObj *pTxResult); 116 static void txResult_StateMachine (TI_HANDLE hTxResult); 117 118 119 120 /**************************************************************************** 121 * txResult_Create() 122 **************************************************************************** 123 * DESCRIPTION: Create the Tx-Result object 124 * 125 * INPUTS: hOs 126 * 127 * OUTPUT: None 128 * 129 * RETURNS: The Created object 130 ****************************************************************************/ 131 TI_HANDLE txResult_Create(TI_HANDLE hOs) 132 { 133 TTxResultObj *pTxResult; 134 135 pTxResult = os_memoryAlloc(hOs, sizeof(TTxResultObj)); 136 if (pTxResult == NULL) 137 return NULL; 138 139 os_memoryZero(hOs, pTxResult, sizeof(TTxResultObj)); 140 141 pTxResult->hOs = hOs; 142 143 return( (TI_HANDLE)pTxResult ); 144 } 145 146 147 /**************************************************************************** 148 * txResult_Destroy() 149 **************************************************************************** 150 * DESCRIPTION: Destroy the Tx-Result object 151 * 152 * INPUTS: hTxResult - The object to free 153 * 154 * OUTPUT: None 155 * 156 * RETURNS: TI_OK or TI_NOK 157 ****************************************************************************/ 158 TI_STATUS txResult_Destroy(TI_HANDLE hTxResult) 159 { 160 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 161 162 if (pTxResult) 163 os_memoryFree(pTxResult->hOs, pTxResult, sizeof(TTxResultObj)); 164 165 return TI_OK; 166 } 167 168 169 /**************************************************************************** 170 * txResult_Init() 171 **************************************************************************** 172 DESCRIPTION: 173 ============ 174 Initialize the txResult module. 175 ****************************************************************************/ 176 TI_STATUS txResult_Init(TI_HANDLE hTxResult, TI_HANDLE hReport, TI_HANDLE hTwIf) 177 { 178 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 179 TTxnStruct *pTxn; 180 181 pTxResult->hReport = hReport; 182 pTxResult->hTwIf = hTwIf; 183 184 /* Prepare Host-Results-Counter write transaction (HwAddr is filled before each transaction) */ 185 pTxn = &pTxResult->tHostCounterWriteTxn.tTxnStruct; 186 TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) 187 BUILD_TTxnStruct(pTxn, 0, &pTxResult->tHostCounterWriteTxn.uCounter, REGISTER_SIZE, NULL, NULL) 188 189 /* Prepare Tx-Result counter and table read transaction (HwAddr is filled before each transaction) */ 190 pTxn = &pTxResult->tResultsInfoReadTxn.tTxnStruct; 191 TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) 192 BUILD_TTxnStruct(pTxn, 193 0, 194 &pTxResult->tResultsInfoReadTxn.tTxResultInfo, 195 sizeof(TxResultInterface_t), 196 (TTxnDoneCb)txResult_StateMachine, 197 hTxResult) 198 199 txResult_Restart (pTxResult); 200 201 return TI_OK; 202 } 203 204 205 /**************************************************************************** 206 * txResult_Restart() 207 **************************************************************************** 208 DESCRIPTION: 209 ============ 210 Restarts the Tx-Result module. 211 Called upon init and recovery. 212 Shouldn't be called upon disconnect, since the FW provides Tx-Complete 213 for all pending packets in FW!! 214 ****************************************************************************/ 215 static void txResult_Restart (TTxResultObj *pTxResult) 216 { 217 pTxResult->uHostResultsCounter = 0; 218 pTxResult->eState = TX_RESULT_STATE_IDLE; 219 } 220 221 222 /**************************************************************************** 223 * txResult_setHwInfo() 224 **************************************************************************** 225 * DESCRIPTION: 226 * Called after the HW configuration upon init or recovery. 227 * Store the Tx-result table HW address. 228 ****************************************************************************/ 229 void txResult_setHwInfo(TI_HANDLE hTxResult, TDmaParams *pDmaParams) 230 { 231 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 232 233 pTxResult->uTxResultInfoAddr = (TI_UINT32)(pDmaParams->fwTxResultInterface); 234 pTxResult->uTxResultHostCounterAddr = pTxResult->uTxResultInfoAddr + 235 TI_FIELD_OFFSET(TxResultControl_t, TxResultHostCounter); 236 237 txResult_Restart (pTxResult); 238 } 239 240 241 /**************************************************************************** 242 * txResult_TxCmpltIntrCb() 243 **************************************************************************** 244 * DESCRIPTION: 245 * ============ 246 * Called upon DATA interrupt from the FW. 247 * If new Tx results are available, start handling them. 248 * 249 * INPUTS: hTxResult - the txResult object handle. 250 * pFwStatus - The FW status registers read by the FwEvent 251 * 252 * OUTPUT: None 253 * 254 * RETURNS: ETxnStatus 255 ***************************************************************************/ 256 ETxnStatus txResult_TxCmpltIntrCb (TI_HANDLE hTxResult, FwStatus_t *pFwStatus) 257 { 258 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 259 TI_UINT32 uTempCounters; 260 FwStatCntrs_t *pFwStatusCounters; 261 262 #ifdef TI_DBG 263 pTxResult->uInterruptsCounter++; 264 265 if (pTxResult->eState != TX_RESULT_STATE_IDLE) 266 { 267 TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": called in eState %d, so exit\n", pTxResult->eState); 268 return TXN_STATUS_COMPLETE; 269 } 270 #endif 271 272 /* If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events) */ 273 uTempCounters = ENDIAN_HANDLE_LONG(pFwStatus->counters); 274 pFwStatusCounters = (FwStatCntrs_t *)&uTempCounters; 275 if (pFwStatusCounters->txResultsCntr == (TI_UINT8)pTxResult->uHostResultsCounter) 276 { 277 TRACE0(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": No new Tx results\n"); 278 return TXN_STATUS_COMPLETE; 279 } 280 281 /* Call the SM to handle the new Tx results */ 282 txResult_StateMachine (hTxResult); 283 return TXN_STATUS_COMPLETE; 284 } 285 286 287 /**************************************************************************** 288 * txResult_StateMachine() 289 **************************************************************************** 290 * DESCRIPTION: 291 * 292 * The main SM of the module. Called in IDLE eState by txResult_TxCmpltIntrCb() on 293 * Data interrupt from the FW. 294 * If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events) 295 * Read all Tx-Result cyclic table. 296 * Go over the new Tx-results and call the upper layer callback function for each packet result. 297 * At the end - write the new host counter to the FW. 298 * 299 * INPUTS: 300 * 301 * OUTPUT: 302 * 303 * RETURNS: None 304 ****************************************************************************/ 305 static void txResult_StateMachine (TI_HANDLE hTxResult) 306 { 307 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 308 ETxnStatus eTwifStatus = TXN_STATUS_COMPLETE; /* Last bus operation status: Complete (Sync) or Pending (Async). */ 309 TTxnStruct *pTxn = &(pTxResult->tResultsInfoReadTxn.tTxnStruct); 310 311 /* Loop while processing is completed in current context (sync), or until fully completed */ 312 while (eTwifStatus == TXN_STATUS_COMPLETE) 313 { 314 TRACE2(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": eState = %d, eTwifStatus = %d\n", pTxResult->eState, eTwifStatus); 315 316 switch(pTxResult->eState) 317 { 318 case TX_RESULT_STATE_IDLE: 319 /* Read Tx-Result queue and counters. */ 320 pTxn->uHwAddr = pTxResult->uTxResultInfoAddr; 321 eTwifStatus = twIf_Transact (pTxResult->hTwIf, pTxn); 322 323 pTxResult->eState = TX_RESULT_STATE_READING; 324 break; 325 326 case TX_RESULT_STATE_READING: 327 /* Process new Tx results, call upper layers to handle them and update host-index in the FW. */ 328 txResult_HandleNewResults (pTxResult); 329 pTxResult->eState = TX_RESULT_STATE_IDLE; 330 return; /********* Exit after all processing is finished **********/ 331 332 default: 333 TRACE1(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Unknown eState = %d\n", pTxResult->eState); 334 return; 335 } 336 } 337 338 if (eTwifStatus == TXN_STATUS_ERROR) 339 { 340 TRACE2(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": returning ERROR in eState %d, eTwifStatus=%d !!!\n", pTxResult->eState, eTwifStatus); 341 } 342 } 343 344 345 /**************************************************************************** 346 * txResult_HandleNewResults() 347 **************************************************************************** 348 * DESCRIPTION: 349 * ============ 350 * We now have the Tx Result table info from the FW so do as follows: 351 * 1. Find the number of new results (FW counter minus host counter), and if 0 exit. 352 * 2. Call the upper layers callback per Tx result. 353 * 3. Update Host-Counter to be equal to the FW-Counter, and write it to the FW. 354 ***************************************************************************/ 355 static void txResult_HandleNewResults (TTxResultObj *pTxResult) 356 { 357 TI_UINT32 uNumNewResults; /* The number of new Tx-Result entries to be processed. */ 358 TI_UINT32 uFwResultsCounter; /* The FW current results counter (accumulated). */ 359 TI_UINT32 uTableIndex; 360 TI_UINT32 i; 361 TxResultDescriptor_t *pCurrentResult; 362 TTxnStruct *pTxn = &(pTxResult->tHostCounterWriteTxn.tTxnStruct); 363 364 /* The uFwResultsCounter is the accumulated number of Tx-Results provided by the FW, and the 365 * uHostResultsCounter is the accumulated number of Tx-Results processed by the host. 366 * The delta is the number of new Tx-results in the queue, waiting for host processing. 367 * Since the difference is always a small positive number, a simple subtraction is good 368 * also for wrap around case. 369 */ 370 uFwResultsCounter = ENDIAN_HANDLE_LONG(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultControl.TxResultFwCounter); 371 uNumNewResults = uFwResultsCounter - pTxResult->uHostResultsCounter; 372 373 #ifdef TI_DBG 374 /* Verify there are new entries (was already checked in txResult_TxCmpltIntrCb) */ 375 if (uNumNewResults == 0) 376 { 377 TRACE2(pTxResult->hReport, REPORT_SEVERITY_WARNING, ": No New Results although indicated by FwStatus!! HostCount=%d, FwCount=%d\n", pTxResult->uHostResultsCounter, uFwResultsCounter); 378 return; 379 } 380 #endif 381 382 /* Update host results-counter in FW to be equal to the FW counter (all new results were processed). */ 383 pTxResult->tHostCounterWriteTxn.uCounter = ENDIAN_HANDLE_LONG(uFwResultsCounter); 384 pTxn->uHwAddr = pTxResult->uTxResultHostCounterAddr; 385 twIf_Transact(pTxResult->hTwIf, pTxn); 386 387 TRACE3(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": NumResults=%d, OriginalHostCount=%d, FwCount=%d\n", uNumNewResults, pTxResult->uHostResultsCounter, uFwResultsCounter); 388 389 /* Loop over all new Tx-results and call Tx-complete callback with current entry pointer. */ 390 /* NOTE: THIS SHOULD COME LAST because it may lead to driver-stop process!! */ 391 for (i = 0; i < uNumNewResults; i++) 392 { 393 uTableIndex = pTxResult->uHostResultsCounter & TX_RESULT_QUEUE_DEPTH_MASK; 394 pCurrentResult = &(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultQueue[uTableIndex]); 395 pTxResult->uHostResultsCounter++; 396 397 TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION , ": call upper layer CB, Status = %d\n", pCurrentResult->status); 398 399 pTxResult->fSendPacketCompleteCb (pTxResult->hSendPacketCompleteHndl, pCurrentResult); 400 } 401 } 402 403 404 /**************************************************************************** 405 * txResult_RegisterCb() 406 **************************************************************************** 407 * DESCRIPTION: Register the upper driver Tx-Result callback functions. 408 ****************************************************************************/ 409 void txResult_RegisterCb (TI_HANDLE hTxResult, TI_UINT32 uCallBackId, void *CBFunc, TI_HANDLE hCbObj) 410 { 411 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 412 413 switch (uCallBackId) 414 { 415 /* Set Tx-Complete callback */ 416 case TWD_INT_SEND_PACKET_COMPLETE: 417 pTxResult->fSendPacketCompleteCb = (TSendPacketCompleteCb)CBFunc; 418 pTxResult->hSendPacketCompleteHndl = hCbObj; 419 break; 420 421 default: 422 TRACE0(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Illegal value\n"); 423 return; 424 } 425 } 426 427 428 #ifdef TI_DBG /* Debug Functions */ 429 430 /**************************************************************************** 431 * txResult_PrintInfo() 432 **************************************************************************** 433 * DESCRIPTION: Prints TX result debug information. 434 ****************************************************************************/ 435 void txResult_PrintInfo (TI_HANDLE hTxResult) 436 { 437 #ifdef REPORT_LOG 438 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 439 440 WLAN_OS_REPORT(("Tx-Result Module Information:\n")); 441 WLAN_OS_REPORT(("=============================\n")); 442 WLAN_OS_REPORT(("uInterruptsCounter: %d\n", pTxResult->uInterruptsCounter)); 443 WLAN_OS_REPORT(("uHostResultsCounter: %d\n", pTxResult->uHostResultsCounter)); 444 WLAN_OS_REPORT(("=============================\n")); 445 #endif 446 } 447 448 449 /**************************************************************************** 450 * txResult_ClearInfo() 451 **************************************************************************** 452 * DESCRIPTION: Clears TX result debug information. 453 ****************************************************************************/ 454 void txResult_ClearInfo (TI_HANDLE hTxResult) 455 { 456 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 457 458 pTxResult->uInterruptsCounter = 0; 459 } 460 461 #endif /* TI_DBG */ 462 463 464