Home | History | Annotate | Download | only in FW_Transfer
      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