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: void 255 ***************************************************************************/ 256 void 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; 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; 279 } 280 281 /* Call the SM to handle the new Tx results */ 282 txResult_StateMachine (hTxResult); 283 } 284 285 286 /**************************************************************************** 287 * txResult_StateMachine() 288 **************************************************************************** 289 * DESCRIPTION: 290 * 291 * The main SM of the module. Called in IDLE eState by txResult_TxCmpltIntrCb() on 292 * Data interrupt from the FW. 293 * If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events) 294 * Read all Tx-Result cyclic table. 295 * Go over the new Tx-results and call the upper layer callback function for each packet result. 296 * At the end - write the new host counter to the FW. 297 * 298 * INPUTS: 299 * 300 * OUTPUT: 301 * 302 * RETURNS: None 303 ****************************************************************************/ 304 static void txResult_StateMachine (TI_HANDLE hTxResult) 305 { 306 TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; 307 ETxnStatus eTwifStatus = TXN_STATUS_COMPLETE; /* Last bus operation status: Complete (Sync) or Pending (Async). */ 308 TTxnStruct *pTxn = &(pTxResult->tResultsInfoReadTxn.tTxnStruct); 309 310 /* Loop while processing is completed in current context (sync), or until fully completed */ 311 while (eTwifStatus == TXN_STATUS_COMPLETE) 312 { 313 TRACE2(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": eState = %d, eTwifStatus = %d\n", pTxResult->eState, eTwifStatus); 314 315 switch(pTxResult->eState) 316 { 317 case TX_RESULT_STATE_IDLE: 318 /* Read Tx-Result queue and counters. */ 319 pTxn->uHwAddr = pTxResult->uTxResultInfoAddr; 320 eTwifStatus = twIf_Transact (pTxResult->hTwIf, pTxn); 321 322 pTxResult->eState = TX_RESULT_STATE_READING; 323 break; 324 325 case TX_RESULT_STATE_READING: 326 /* Process new Tx results, call upper layers to handle them and update host-index in the FW. */ 327 txResult_HandleNewResults (pTxResult); 328 pTxResult->eState = TX_RESULT_STATE_IDLE; 329 return; /********* Exit after all processing is finished **********/ 330 331 default: 332 TRACE1(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Unknown eState = %d\n", pTxResult->eState); 333 return; 334 } 335 } 336 337 if (eTwifStatus == TXN_STATUS_ERROR) 338 { 339 TRACE2(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": returning ERROR in eState %d, eTwifStatus=%d !!!\n", pTxResult->eState, eTwifStatus); 340 } 341 } 342 343 344 /**************************************************************************** 345 * txResult_HandleNewResults() 346 **************************************************************************** 347 * DESCRIPTION: 348 * ============ 349 * We now have the Tx Result table info from the FW so do as follows: 350 * 1. Find the number of new results (FW counter minus host counter), and if 0 exit. 351 * 2. Call the upper layers callback per Tx result. 352 * 3. Update Host-Counter to be equal to the FW-Counter, and write it to the FW. 353 ***************************************************************************/ 354 static void txResult_HandleNewResults (TTxResultObj *pTxResult) 355 { 356 TI_UINT32 uNumNewResults; /* The number of new Tx-Result entries to be processed. */ 357 TI_UINT32 uFwResultsCounter; /* The FW current results counter (accumulated). */ 358 TI_UINT32 uTableIndex; 359 TI_UINT32 i; 360 TxResultDescriptor_t *pCurrentResult; 361 TTxnStruct *pTxn = &(pTxResult->tHostCounterWriteTxn.tTxnStruct); 362 363 /* The uFwResultsCounter is the accumulated number of Tx-Results provided by the FW, and the 364 * uHostResultsCounter is the accumulated number of Tx-Results processed by the host. 365 * The delta is the number of new Tx-results in the queue, waiting for host processing. 366 * Since the difference is always a small positive number, a simple subtraction is good 367 * also for wrap around case. 368 */ 369 uFwResultsCounter = ENDIAN_HANDLE_LONG(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultControl.TxResultFwCounter); 370 uNumNewResults = uFwResultsCounter - pTxResult->uHostResultsCounter; 371 372 #ifdef TI_DBG 373 /* Verify there are new entries (was already checked in txResult_TxCmpltIntrCb) */ 374 if (uNumNewResults == 0) 375 { 376 TRACE2(pTxResult->hReport, REPORT_SEVERITY_WARNING, ": No New Results although indicated by FwStatus!! HostCount=%d, FwCount=%d\n", pTxResult->uHostResultsCounter, uFwResultsCounter); 377 return; 378 } 379 #endif 380 381 /* Update host results-counter in FW to be equal to the FW counter (all new results were processed). */ 382 pTxResult->tHostCounterWriteTxn.uCounter = ENDIAN_HANDLE_LONG(uFwResultsCounter); 383 pTxn->uHwAddr = pTxResult->uTxResultHostCounterAddr; 384 twIf_Transact(pTxResult->hTwIf, pTxn); 385 386 TRACE3(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": NumResults=%d, OriginalHostCount=%d, FwCount=%d\n", uNumNewResults, pTxResult->uHostResultsCounter, uFwResultsCounter); 387 388 /* Loop over all new Tx-results and call Tx-complete callback with current entry pointer. */ 389 /* NOTE: THIS SHOULD COME LAST because it may lead to driver-stop process!! */ 390 for (i = 0; i < uNumNewResults; i++) 391 { 392 uTableIndex = pTxResult->uHostResultsCounter & TX_RESULT_QUEUE_DEPTH_MASK; 393 pCurrentResult = &(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultQueue[uTableIndex]); 394 pTxResult->uHostResultsCounter++; 395 396 TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION , ": call upper layer CB, Status = %d\n", pCurrentResult->status); 397 398 pTxResult->fSendPacketCompleteCb (pTxResult->hSendPacketCompleteHndl, pCurrentResult); 399 } 400 } 401 402 403 /**************************************************************************** 404 * txResult_RegisterCb() 405 **************************************************************************** 406 * DESCRIPTION: Register the upper driver Tx-Result callback functions. 407 ****************************************************************************/ 408 void txResult_RegisterCb (TI_HANDLE hTxResult, TI_UINT32 uCallBackId, void *CBFunc, TI_HANDLE hCbObj) 409 { 410 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 411 412 switch (uCallBackId) 413 { 414 /* Set Tx-Complete callback */ 415 case TWD_INT_SEND_PACKET_COMPLETE: 416 pTxResult->fSendPacketCompleteCb = (TSendPacketCompleteCb)CBFunc; 417 pTxResult->hSendPacketCompleteHndl = hCbObj; 418 break; 419 420 default: 421 TRACE0(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Illegal value\n"); 422 return; 423 } 424 } 425 426 427 #ifdef TI_DBG /* Debug Functions */ 428 429 /**************************************************************************** 430 * txResult_PrintInfo() 431 **************************************************************************** 432 * DESCRIPTION: Prints TX result debug information. 433 ****************************************************************************/ 434 void txResult_PrintInfo (TI_HANDLE hTxResult) 435 { 436 #ifdef REPORT_LOG 437 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 438 439 WLAN_OS_REPORT(("Tx-Result Module Information:\n")); 440 WLAN_OS_REPORT(("=============================\n")); 441 WLAN_OS_REPORT(("uInterruptsCounter: %d\n", pTxResult->uInterruptsCounter)); 442 WLAN_OS_REPORT(("uHostResultsCounter: %d\n", pTxResult->uHostResultsCounter)); 443 WLAN_OS_REPORT(("=============================\n")); 444 #endif 445 } 446 447 448 /**************************************************************************** 449 * txResult_ClearInfo() 450 **************************************************************************** 451 * DESCRIPTION: Clears TX result debug information. 452 ****************************************************************************/ 453 void txResult_ClearInfo (TI_HANDLE hTxResult) 454 { 455 TTxResultObj* pTxResult = (TTxResultObj*)hTxResult; 456 457 pTxResult->uInterruptsCounter = 0; 458 } 459 460 #endif /* TI_DBG */ 461 462 463