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_
68extern 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
94typedef enum
95{
96    FWEVENT_STATE_IDLE,
97    FWEVENT_STATE_WAIT_INTR_INFO,
98    FWEVENT_STATE_WAIT_HANDLE_COMPLT
99
100} EFwEventState;
101
102typedef struct
103{
104    TTxnStruct              tTxnStruct;
105    TI_UINT32               uData;
106
107} TRegisterTxn;
108
109typedef struct
110{
111    TTxnStruct     tTxnStruct;
112    FwStatus_t     tFwStatus;
113
114} TFwStatusTxn;
115
116/* The FwEvent module's main structure */
117typedef 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
146static void       fwEvent_NewEvent       (TI_HANDLE hFwEvent);
147static void       fwEvent_StateMachine   (TfwEvent *pFwEvent);
148static ETxnStatus fwEvent_SmReadIntrInfo (TfwEvent *pFwEvent);
149static ETxnStatus fwEvent_SmHandleEvents (TfwEvent *pFwEvent);
150static 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 */
164TI_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 */
193TI_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 */
221TI_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 */
293void 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 */
319static 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 */
356static 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 */
462static 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 */
506static 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 */
547static 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 */
614void 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 */
655TI_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 */
674void 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 */
696TI_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 */
723void 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 */
745void 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 */
763void 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
773void 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