1 /* 2 * FwEvent.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 FwEvent.c 36 * \brief Handle firmware events 37 * 38 * 39 * \par Description 40 * Call the appropriate event handler. 41 * 42 * \see FwEvent.h 43 */ 44 45 #define __FILE_ID__ FILE_ID_104 46 #include "tidef.h" 47 #include "report.h" 48 #include "context.h" 49 #include "osApi.h" 50 #include "TWDriver.h" 51 #include "TWDriverInternal.h" 52 #include "txResult_api.h" 53 #include "CmdMBox_api.h" 54 #include "rxXfer_api.h" 55 #include "txXfer_api.h" 56 #include "txHwQueue_api.h" 57 #include "eventMbox_api.h" 58 #include "TwIf.h" 59 #include "public_host_int.h" 60 #include "FwEvent_api.h" 61 #ifdef TI_DBG 62 #include "tracebuf_api.h" 63 #endif 64 #include "bmtrace_api.h" 65 66 67 #ifdef _VLCT_ 68 extern int trigger_another_read; 69 #endif 70 71 72 /* 73 * Address of FW-Status structure in FW memory ==> Special mapping, see note!! 74 * 75 * Note: This structure actually includes two separate areas in the FW: 76 * 1) Interrupt-Status register - a 32 bit register (clear on read). 77 * 2) FW-Status structure - 64 bytes memory area 78 * The two areas are read in a single transaction thanks to a special memory 79 * partition that maps them as contiguous memory. 80 */ 81 #define FW_STATUS_ADDR 0x14FC0 + 0xA000 82 83 84 #define ALL_EVENTS_VECTOR ACX_INTR_WATCHDOG | ACX_INTR_INIT_COMPLETE | ACX_INTR_EVENT_A |\ 85 ACX_INTR_EVENT_B | ACX_INTR_CMD_COMPLETE |ACX_INTR_HW_AVAILABLE |\ 86 ACX_INTR_DATA 87 88 #define TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) pFwEvent->tMaskTxn.tTxnStruct.uHwAddr = HINT_MASK; 89 #define TXN_FW_EVENT_SET_FW_STAT_ADDR(pFwEvent) pFwEvent->tFwStatusTxn.tTxnStruct.uHwAddr = FW_STATUS_ADDR; 90 91 #define UPDATE_PENDING_HANDLERS_NUMBER(eStatus) if (eStatus == TXN_STATUS_PENDING) {pFwEvent->uNumPendHndlrs++;} 92 93 94 typedef enum 95 { 96 FWEVENT_STATE_IDLE, 97 FWEVENT_STATE_WAIT_INTR_INFO, 98 FWEVENT_STATE_WAIT_HANDLE_COMPLT 99 100 } EFwEventState; 101 102 typedef struct 103 { 104 TTxnStruct tTxnStruct; 105 TI_UINT32 uData; 106 107 } TRegisterTxn; 108 109 typedef struct 110 { 111 TTxnStruct tTxnStruct; 112 FwStatus_t tFwStatus; 113 114 } TFwStatusTxn; 115 116 /* The FwEvent module's main structure */ 117 typedef struct 118 { 119 EFwEventState eSmState; /* State machine state */ 120 TI_UINT32 uEventMask; /* Static interrupt event mask */ 121 TI_UINT32 uEventVector; /* Saves the current active FW interrupts */ 122 TRegisterTxn tMaskTxn; /* The host mask register transaction */ 123 TFwStatusTxn tFwStatusTxn; /* The FW status structure transaction (read from FW memory) */ 124 TI_UINT32 uFwTimeOffset; /* Offset in microseconds between driver and FW clocks */ 125 TI_UINT32 uContextId; /* Client ID got upon registration to the context module */ 126 TI_BOOL bIntrPending; /* If TRUE a new interrupt is pending while handling the previous one */ 127 TI_UINT32 uNumPendHndlrs; /* Number of event handlers that didn't complete their event processing */ 128 129 /* Other modules handles */ 130 TI_HANDLE hOs; 131 TI_HANDLE hTWD; 132 TI_HANDLE hReport; 133 TI_HANDLE hContext; 134 TI_HANDLE hTwIf; 135 TI_HANDLE hHealthMonitor; 136 TI_HANDLE hEventMbox; 137 TI_HANDLE hCmdMbox; 138 TI_HANDLE hRxXfer; 139 TI_HANDLE hTxXfer; 140 TI_HANDLE hTxHwQueue; 141 TI_HANDLE hTxResult; 142 143 } TfwEvent; 144 145 146 static void fwEvent_NewEvent (TI_HANDLE hFwEvent); 147 static void fwEvent_StateMachine (TfwEvent *pFwEvent); 148 static ETxnStatus fwEvent_SmReadIntrInfo (TfwEvent *pFwEvent); 149 static ETxnStatus fwEvent_SmHandleEvents (TfwEvent *pFwEvent); 150 static ETxnStatus fwEvent_CallHandlers (TfwEvent *pFwEvent); 151 152 153 /* 154 * \brief Create the FwEvent module object 155 * 156 * \param hOs - OS module object handle 157 * \return Handle to the created object 158 * 159 * \par Description 160 * Calling this function creates a FwEvent object 161 * 162 * \sa fwEvent_Destroy 163 */ 164 TI_HANDLE fwEvent_Create (TI_HANDLE hOs) 165 { 166 TfwEvent *pFwEvent; 167 168 pFwEvent = os_memoryAlloc (hOs, sizeof(TfwEvent)); 169 if (pFwEvent == NULL) 170 { 171 return NULL; 172 } 173 174 os_memoryZero (hOs, pFwEvent, sizeof(TfwEvent)); 175 176 pFwEvent->hOs = hOs; 177 178 return (TI_HANDLE)pFwEvent; 179 } 180 181 182 /* 183 * \brief Destroys the FwEvent object 184 * 185 * \param hFwEvent - The object to free 186 * \return TI_OK 187 * 188 * \par Description 189 * Calling this function destroys a FwEvent object 190 * 191 * \sa fwEvent_Create 192 */ 193 TI_STATUS fwEvent_Destroy (TI_HANDLE hFwEvent) 194 { 195 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 196 197 if (pFwEvent) 198 { 199 os_memoryFree (pFwEvent->hOs, pFwEvent, sizeof(TfwEvent)); 200 } 201 202 return TI_OK; 203 } 204 205 206 /* 207 * \brief Config the FwEvent module object 208 * 209 * \param hFwEvent - FwEvent Driver handle 210 * \param hTWD - Handle to TWD module 211 * \return TI_OK 212 * 213 * \par Description 214 * From hTWD we extract : hOs, hReport, hTwIf, hContext, 215 * hHealthMonitor, hEventMbox, hCmdMbox, hRxXfer, 216 * hTxHwQueue, hTxResult 217 * In this function we also register the FwEvent to the context engine 218 * 219 * \sa 220 */ 221 TI_STATUS fwEvent_Init (TI_HANDLE hFwEvent, TI_HANDLE hTWD) 222 { 223 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 224 TTwd *pTWD = (TTwd *)hTWD; 225 TTxnStruct* pTxn; 226 227 pFwEvent->hTWD = hTWD; 228 pFwEvent->hOs = pTWD->hOs; 229 pFwEvent->hReport = pTWD->hReport; 230 pFwEvent->hContext = pTWD->hContext; 231 pFwEvent->hTwIf = pTWD->hTwIf; 232 pFwEvent->hHealthMonitor = pTWD->hHealthMonitor; 233 pFwEvent->hEventMbox = pTWD->hEventMbox; 234 pFwEvent->hCmdMbox = pTWD->hCmdMbox; 235 pFwEvent->hRxXfer = pTWD->hRxXfer; 236 pFwEvent->hTxHwQueue = pTWD->hTxHwQueue; 237 pFwEvent->hTxXfer = pTWD->hTxXfer; 238 pFwEvent->hTxResult = pTWD->hTxResult; 239 240 pFwEvent->eSmState = FWEVENT_STATE_IDLE; 241 pFwEvent->bIntrPending = TI_FALSE; 242 pFwEvent->uNumPendHndlrs = 0; 243 pFwEvent->uEventMask = 0; 244 pFwEvent->uEventVector = 0; 245 246 /* Prepare Interrupts Mask regiter Txn structure */ 247 /* 248 * Note!!: The mask transaction is sent in low priority because it is used in the 249 * init process which includes a long sequence of low priority transactions, 250 * and the order of this sequence is important so we must use the same priority 251 */ 252 pTxn = (TTxnStruct*)&pFwEvent->tMaskTxn.tTxnStruct; 253 TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) 254 BUILD_TTxnStruct(pTxn, HINT_MASK, &pFwEvent->tMaskTxn.uData, REGISTER_SIZE, NULL, NULL) 255 256 /* Prepare FW status Txn structure (includes 4 bytes interrupt status reg and 64 bytes FW-status from memory area) */ 257 /* Note: This is the only transaction that is sent in high priority. 258 * The original reason was to lower the interrupt latency, but we may consider using the 259 * same priority as all other transaction for simplicity. 260 */ 261 pTxn = (TTxnStruct*)&pFwEvent->tFwStatusTxn.tTxnStruct; 262 TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) 263 BUILD_TTxnStruct(pTxn, FW_STATUS_ADDR, &pFwEvent->tFwStatusTxn.tFwStatus, sizeof(FwStatus_t), (TTxnDoneCb)fwEvent_StateMachine, hFwEvent) 264 265 /* 266 * Register the FwEvent to the context engine and get the client ID. 267 * The FwEvent() will be called from the context_DriverTask() after scheduled 268 * by a FW-Interrupt (see fwEvent_InterruptRequest()). 269 */ 270 pFwEvent->uContextId = context_RegisterClient (pFwEvent->hContext, 271 fwEvent_NewEvent, 272 hFwEvent, 273 TI_FALSE, 274 "FW_EVENT", 275 sizeof("FW_EVENT")); 276 277 return TI_OK; 278 } 279 280 281 /* 282 * \brief FW interrupt handler, just switch to WLAN context for handling 283 * 284 * \param hFwEvent - FwEvent Driver handle 285 * \return void 286 * 287 * \par Description 288 * Called by the FW-Interrupt ISR (external context!). 289 * Requests the context engine to schedule the driver task for handling the FW-Events. 290 * 291 * \sa 292 */ 293 void fwEvent_InterruptRequest (TI_HANDLE hFwEvent) 294 { 295 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 296 CL_TRACE_START_L1(); 297 298 TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_InterruptRequest()\n"); 299 300 /* Request switch to driver context for handling the FW-Interrupt event */ 301 context_RequestSchedule (pFwEvent->hContext, pFwEvent->uContextId); 302 303 CL_TRACE_END_L1("tiwlan_drv.ko", "IRQ", "FwEvent", ""); 304 } 305 306 307 /* 308 * \brief The CB called in the driver context upon new interrupt 309 * 310 * \param hFwEvent - FwEvent Driver handle 311 * \return void 312 * 313 * \par Description 314 * Called by the context module after scheduled by fwEvent_InterruptRequest(). 315 * If IDLE, start the SM, and if not just indicate pending event for later. 316 * 317 * \sa 318 */ 319 static void fwEvent_NewEvent (TI_HANDLE hFwEvent) 320 { 321 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 322 CL_TRACE_START_L2(); 323 324 /* If the SM is idle, call it to start handling new events */ 325 if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) 326 { 327 TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_NewEvent: Start SM\n"); 328 329 fwEvent_StateMachine (pFwEvent); 330 } 331 /* Else - SM is busy so set flag to handle it when finished with current events */ 332 else 333 { 334 TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_NewEvent: SM busy, set IntrPending flag\n"); 335 336 pFwEvent->bIntrPending = TI_TRUE; 337 } 338 339 CL_TRACE_END_L2("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 340 } 341 342 343 /* 344 * \brief FW-Event state machine 345 * 346 * \param hFwEvent - FwEvent Driver handle 347 * \return void 348 * 349 * \par Description 350 * 351 * Process the current FW events in a sequence that may progress in the same context, 352 * or exit if pending an Async transaction, which will call back the SM when finished. 353 * 354 * \sa 355 */ 356 static void fwEvent_StateMachine (TfwEvent *pFwEvent) 357 { 358 ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ 359 CL_TRACE_START_L3(); 360 361 /* 362 * Loop through the states sequence as long as the process is synchronous. 363 * Exit when finished or if an Asynchronous process is required. 364 * In this case the SM will be called back upon Async operation completion. 365 */ 366 while (1) 367 { 368 switch (pFwEvent->eSmState) 369 { 370 /* IDLE: Update TwIf and read interrupt info from FW */ 371 case FWEVENT_STATE_IDLE: 372 { 373 CL_TRACE_START_L5(); 374 twIf_Awake(pFwEvent->hTwIf); 375 eStatus = fwEvent_SmReadIntrInfo (pFwEvent); 376 pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; 377 CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".ReadInfo"); 378 break; 379 } 380 /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ 381 case FWEVENT_STATE_WAIT_INTR_INFO: 382 { 383 CL_TRACE_START_L5(); 384 eStatus = fwEvent_SmHandleEvents (pFwEvent); 385 /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ 386 if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) 387 { 388 CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); 389 CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 390 return; 391 } 392 pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; 393 CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); 394 break; 395 } 396 /* WAIT_HANDLE_COMPLT: Current handling is completed. */ 397 case FWEVENT_STATE_WAIT_HANDLE_COMPLT: 398 { 399 /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ 400 if (pFwEvent->bIntrPending) 401 { 402 CL_TRACE_START_L5(); 403 pFwEvent->bIntrPending = TI_FALSE; 404 eStatus = fwEvent_SmReadIntrInfo (pFwEvent); 405 pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; 406 CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlCmplt"); 407 } 408 /* Else - all done so release TwIf to sleep and exit */ 409 else 410 { 411 twIf_Sleep(pFwEvent->hTwIf); 412 pFwEvent->eSmState = FWEVENT_STATE_IDLE; 413 414 TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: Completed, NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); 415 CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 416 417 /**** Finished all current events handling so exit ****/ 418 return; 419 } 420 break; 421 } 422 423 } /* switch */ 424 425 TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); 426 427 /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ 428 if (eStatus == TXN_STATUS_PENDING) 429 { 430 CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 431 return; 432 } 433 434 /* If error occured, stop the process and exit (should be cleaned by recovery process) */ 435 else if (eStatus == TXN_STATUS_ERROR) 436 { 437 TRACE5(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d, EventVector=0x%x, EventMask=0x%x\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending, pFwEvent->uEventVector, pFwEvent->uEventMask); 438 CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 439 fwEvent_Stop ((TI_HANDLE)pFwEvent); 440 return; 441 } 442 443 /* If we got here the status is COMPLETE so continue in the while loop to the next state */ 444 445 } /* while */ 446 } 447 448 449 /* 450 * \brief Read interrupt info from FW 451 * 452 * \param hFwEvent - FwEvent Driver handle 453 * \return void 454 * 455 * \par Description 456 * 457 * Indicate the TwIf that HW is available and initiate transactions for reading 458 * the Interrupt status and the FW status. 459 * 460 * \sa 461 */ 462 static ETxnStatus fwEvent_SmReadIntrInfo (TfwEvent *pFwEvent) 463 { 464 ETxnStatus eStatus; 465 CL_TRACE_START_L4(); 466 467 #ifdef HOST_INTR_MODE_EDGE 468 /* Acknowledge the host interrupt for EDGE mode (must be before HINT_STT_CLR register clear on read) */ 469 os_InterruptServiced (pFwEvent->hOs); 470 #endif 471 472 /* Indicate that the chip is awake (since it interrupted us) */ 473 twIf_HwAvailable(pFwEvent->hTwIf); 474 475 /* 476 * Read FW-Status structure from HW ==> Special mapping, see note!! 477 * 478 * Note: This structure actually includes two separate areas in the FW: 479 * 1) Interrupt-Status register - a 32 bit register (clear on read). 480 * 2) FW-Status structure - 64 bytes memory area 481 * The two areas are read in a single transaction thanks to a special memory 482 * partition that maps them as contiguous memory. 483 */ 484 TXN_FW_EVENT_SET_FW_STAT_ADDR(pFwEvent) 485 eStatus = twIf_TransactReadFWStatus (pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); 486 487 CL_TRACE_END_L4("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 488 489 /* Return the status of the FwStatus read (complete, pending or error) */ 490 return eStatus; 491 } 492 493 494 /* 495 * \brief Handle the Fw Status information 496 * 497 * \param hFwEvent - FwEvent Driver handle 498 * \return void 499 * 500 * \par Description 501 * This function is called from fwEvent_Handle on a sync read, or from TwIf as a CB on an async read. 502 * It calls fwEvent_CallHandlers to handle the triggered interrupts. 503 * 504 * \sa fwEvent_Handle 505 */ 506 static ETxnStatus fwEvent_SmHandleEvents (TfwEvent *pFwEvent) 507 { 508 ETxnStatus eStatus; 509 CL_TRACE_START_L4(); 510 511 /* Save delta between driver and FW time (needed for Tx packets lifetime) */ 512 pFwEvent->uFwTimeOffset = (os_timeStampMs (pFwEvent->hOs) * 1000) - 513 ENDIAN_HANDLE_LONG (pFwEvent->tFwStatusTxn.tFwStatus.fwLocalTime); 514 515 #ifdef HOST_INTR_MODE_LEVEL 516 /* Acknowledge the host interrupt for LEVEL mode (must be after HINT_STT_CLR register clear on read) */ 517 os_InterruptServiced (pFwEvent->hOs); 518 #endif 519 520 /* Save the interrupts status retreived from the FW */ 521 pFwEvent->uEventVector = pFwEvent->tFwStatusTxn.tFwStatus.intrStatus; 522 523 /* Mask unwanted interrupts */ 524 pFwEvent->uEventVector &= pFwEvent->uEventMask; 525 526 /* Call the interrupts handlers */ 527 eStatus = fwEvent_CallHandlers (pFwEvent); 528 529 TRACE5(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_SmHandleEvents: Status=%d, EventVector=0x%x, IntrPending=%d, NumPendHndlrs=%d, FwTimeOfst=%d\n", eStatus, pFwEvent->uEventVector, pFwEvent->bIntrPending, pFwEvent->uNumPendHndlrs, pFwEvent->uFwTimeOffset); 530 CL_TRACE_END_L4("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 531 532 /* Return the status of the handlers processing (complete, pending or error) */ 533 return eStatus; 534 } 535 536 537 /* 538 * \brief Call FwEvent clients event handlers 539 * 540 * \param hFwEvent - FwEvent Driver handle 541 * \return void 542 * 543 * \par Description 544 * 545 * \sa 546 */ 547 static ETxnStatus fwEvent_CallHandlers (TfwEvent *pFwEvent) 548 { 549 ETxnStatus eStatus; 550 CL_TRACE_START_L4(); 551 552 pFwEvent->uNumPendHndlrs = 0; 553 554 if (pFwEvent->uEventVector & ACX_INTR_WATCHDOG) 555 { 556 /* Fw watchdog timeout has occured */ 557 eStatus = TWD_WdExpireEvent (pFwEvent->hTWD); 558 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 559 } 560 561 if (pFwEvent->uEventVector & ACX_INTR_INIT_COMPLETE) 562 { 563 TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_CallHandlers: INIT_COMPLETE\n"); 564 } 565 /* Note: Handle Cmd-MBOX before Event-MBOX to keep command response and command complete order (for WHA) */ 566 if (pFwEvent->uEventVector & ACX_INTR_CMD_COMPLETE) 567 { 568 /* Command Mbox completed */ 569 eStatus = cmdMbox_CommandComplete(pFwEvent->hCmdMbox); 570 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 571 } 572 if (pFwEvent->uEventVector & ACX_INTR_EVENT_A) 573 { 574 eStatus = eventMbox_Handle(pFwEvent->hEventMbox,&pFwEvent->tFwStatusTxn.tFwStatus); 575 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 576 } 577 if (pFwEvent->uEventVector & ACX_INTR_EVENT_B) 578 { 579 eStatus = eventMbox_Handle(pFwEvent->hEventMbox,&pFwEvent->tFwStatusTxn.tFwStatus); 580 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 581 } 582 583 /* The DATA interrupt is shared by all data path events, so call all Tx and Rx clients */ 584 if (pFwEvent->uEventVector & ACX_INTR_DATA) 585 { 586 eStatus = rxXfer_RxEvent (pFwEvent->hRxXfer, &pFwEvent->tFwStatusTxn.tFwStatus); 587 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 588 589 eStatus = txHwQueue_UpdateFreeResources (pFwEvent->hTxHwQueue, &pFwEvent->tFwStatusTxn.tFwStatus); 590 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 591 592 eStatus = txResult_TxCmpltIntrCb (pFwEvent->hTxResult, &pFwEvent->tFwStatusTxn.tFwStatus); 593 UPDATE_PENDING_HANDLERS_NUMBER(eStatus) 594 } 595 596 CL_TRACE_END_L4("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); 597 598 /* Return COMPLETE if all handlers completed, and PENDING if not. */ 599 return ((pFwEvent->uNumPendHndlrs == 0) ? TXN_STATUS_COMPLETE : TXN_STATUS_PENDING); 600 } 601 602 603 /* 604 * \brief Called by any handler that completed after pending 605 * 606 * \param hFwEvent - FwEvent Driver handle 607 * 608 * \par Description 609 * 610 * Decrement pending handlers counter and if 0 call the SM to complete its process. 611 * 612 * \sa 613 */ 614 void fwEvent_HandlerCompleted (TI_HANDLE hFwEvent) 615 { 616 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 617 618 #ifdef TI_DBG 619 TRACE2(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_HandlerCompleted: state=%d, NumPendHndlrs=%d\n", pFwEvent->eSmState, pFwEvent->uNumPendHndlrs); 620 /* Verify that we really have pending handlers, otherwise it an error */ 621 if (pFwEvent->uNumPendHndlrs == 0) 622 { 623 TRACE0(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_HandlerCompleted: Called while no handlers are pending\n"); 624 return; 625 } 626 /* Verify that we are in */ 627 if (pFwEvent->eSmState != FWEVENT_STATE_WAIT_HANDLE_COMPLT) 628 { 629 TRACE1(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_HandlerCompleted: Called while not in WAIT_HANDLE_COMPLT state (state=%d)\n", pFwEvent->eSmState); 630 return; 631 } 632 #endif 633 634 /* Decrement the pending handlers counter and if zero call the SM to complete the process */ 635 pFwEvent->uNumPendHndlrs--; 636 if (pFwEvent->uNumPendHndlrs == 0) 637 { 638 fwEvent_StateMachine (pFwEvent); 639 } 640 } 641 642 643 /* 644 * \brief Translate host to FW time (Usec) 645 * 646 * \param hFwEvent - FwEvent Driver handle 647 * \param uHostTime - The host time in MS to translate 648 * 649 * \return FW Time in Usec 650 * 651 * \par Description 652 * 653 * \sa 654 */ 655 TI_UINT32 fwEvent_TranslateToFwTime (TI_HANDLE hFwEvent, TI_UINT32 uHostTime) 656 { 657 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 658 659 return ((uHostTime * 1000) - pFwEvent->uFwTimeOffset); 660 } 661 662 663 /* 664 * \brief Unmask only cmd-cmplt and events interrupts (needed for init phase) 665 * 666 * \param hFwEvent - FwEvent Driver handle 667 * \return Event mask 668 * 669 * \par Description 670 * Unmask only cmd-cmplt and events interrupts (needed for init phase). 671 * 672 * \sa 673 */ 674 void fwEvent_SetInitMask (TI_HANDLE hFwEvent) 675 { 676 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 677 678 /* Unmask only the interrupts needed for the FW configuration process. */ 679 pFwEvent->uEventMask = ACX_INTR_CMD_COMPLETE | ACX_INTR_EVENT_A | ACX_INTR_EVENT_B; 680 pFwEvent->tMaskTxn.uData = ~pFwEvent->uEventMask; 681 TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) 682 twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct)); 683 } 684 685 686 /* 687 * \brief Stop & reset FwEvent (called by the driver stop process) 688 * 689 * \param hFwEvent - FwEvent Driver handle 690 * \return TI_OK 691 * 692 * \par Description 693 * 694 * \sa 695 */ 696 TI_STATUS fwEvent_Stop (TI_HANDLE hFwEvent) 697 { 698 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 699 700 pFwEvent->eSmState = FWEVENT_STATE_IDLE; 701 pFwEvent->bIntrPending = TI_FALSE; 702 pFwEvent->uNumPendHndlrs = 0; 703 pFwEvent->uEventMask = 0; 704 pFwEvent->uEventVector = 0; 705 706 return TI_OK; 707 } 708 709 710 /* 711 * \brief Unmask all interrupts 712 * 713 * \param hFwEvent - FwEvent Driver handle 714 * \return void 715 * 716 * \par Description 717 * 718 * Called after driver Start or Recovery process are completed. 719 * Unmask all interrupts. 720 * 721 * \sa 722 */ 723 void fwEvent_EnableExternalEvents (TI_HANDLE hFwEvent) 724 { 725 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 726 727 /* Unmask all interrupts */ 728 pFwEvent->uEventMask = ALL_EVENTS_VECTOR; 729 pFwEvent->tMaskTxn.uData = ~pFwEvent->uEventMask; 730 TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) 731 twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct)); 732 } 733 734 735 /* 736 * \brief Disable the FwEvent client in the context handler 737 * 738 * \param hFwEvent - FwEvent Driver handle 739 * \return void 740 * 741 * \par Description 742 * 743 * \sa 744 */ 745 void fwEvent_DisableInterrupts(TI_HANDLE hFwEvent) 746 { 747 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 748 749 context_DisableClient (pFwEvent->hContext,pFwEvent->uContextId); 750 } 751 752 753 /* 754 * \brief Enable the FwEvent client in the context handler 755 * 756 * \param hFwEvent - FwEvent Driver handle 757 * \return void 758 * 759 * \par Description 760 * 761 * \sa 762 */ 763 void fwEvent_EnableInterrupts(TI_HANDLE hFwEvent) 764 { 765 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 766 767 context_EnableClient (pFwEvent->hContext,pFwEvent->uContextId); 768 } 769 770 771 #ifdef TI_DBG 772 773 void fwEvent_PrintStat (TI_HANDLE hFwEvent) 774 { 775 #ifdef REPORT_LOG 776 TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; 777 778 WLAN_OS_REPORT(("Print FW event module info\n")); 779 WLAN_OS_REPORT(("==========================\n")); 780 WLAN_OS_REPORT(("uEventVector = 0x%x\n", pFwEvent->uEventVector)); 781 WLAN_OS_REPORT(("uEventMask = 0x%x\n", pFwEvent->uEventMask)); 782 WLAN_OS_REPORT(("eSmState = %d\n", pFwEvent->eSmState)); 783 WLAN_OS_REPORT(("bIntrPending = %d\n", pFwEvent->bIntrPending)); 784 WLAN_OS_REPORT(("uNumPendHndlrs = %d\n", pFwEvent->uNumPendHndlrs)); 785 WLAN_OS_REPORT(("uFwTimeOffset = %d\n", pFwEvent->uFwTimeOffset)); 786 #endif 787 } 788 789 #endif /* TI_DBG */ 790 791 792 793