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 */ 69typedef void (* TSendPacketCompleteCb)(TI_HANDLE hCbObj, TxResultDescriptor_t *pTxResultInfo); 70 71/* Tx-Result SM states */ 72typedef enum 73{ 74 TX_RESULT_STATE_IDLE, 75 TX_RESULT_STATE_READING 76} ETxResultState; 77 78/* The host Tx-results counter write transaction structure. */ 79typedef struct 80{ 81 TTxnStruct tTxnStruct; 82 TI_UINT32 uCounter; 83} THostCounterWriteTxn; 84 85/* The Tx-results counters and table read transaction structure. */ 86typedef struct 87{ 88 TTxnStruct tTxnStruct; 89 TxResultInterface_t tTxResultInfo; 90} TResultsInfoReadTxn; 91 92/* The TxResult module object. */ 93typedef 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 114static void txResult_Restart (TTxResultObj *pTxResult); 115static void txResult_HandleNewResults (TTxResultObj *pTxResult); 116static 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 ****************************************************************************/ 131TI_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 ****************************************************************************/ 158TI_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 ****************************************************************************/ 176TI_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 ****************************************************************************/ 215static 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 ****************************************************************************/ 229void 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 ***************************************************************************/ 256void 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 ****************************************************************************/ 304static 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 ***************************************************************************/ 354static 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 { 376TRACE2(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 ****************************************************************************/ 408void 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 ****************************************************************************/ 434void 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 ****************************************************************************/ 453void 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