• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
fwEvent_Create(TI_HANDLE hOs)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  */
fwEvent_Destroy(TI_HANDLE hFwEvent)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  */
fwEvent_Init(TI_HANDLE hFwEvent,TI_HANDLE hTWD)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  */
fwEvent_InterruptRequest(TI_HANDLE hFwEvent)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  */
fwEvent_NewEvent(TI_HANDLE hFwEvent)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  */
fwEvent_StateMachine(TfwEvent * pFwEvent)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  */
fwEvent_SmReadIntrInfo(TfwEvent * pFwEvent)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  */
fwEvent_SmHandleEvents(TfwEvent * pFwEvent)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  */
fwEvent_CallHandlers(TfwEvent * pFwEvent)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  */
fwEvent_HandlerCompleted(TI_HANDLE hFwEvent)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  */
fwEvent_TranslateToFwTime(TI_HANDLE hFwEvent,TI_UINT32 uHostTime)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  */
fwEvent_SetInitMask(TI_HANDLE hFwEvent)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  */
fwEvent_Stop(TI_HANDLE hFwEvent)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  */
fwEvent_EnableExternalEvents(TI_HANDLE hFwEvent)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  */
fwEvent_DisableInterrupts(TI_HANDLE hFwEvent)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  */
fwEvent_EnableInterrupts(TI_HANDLE hFwEvent)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 
fwEvent_PrintStat(TI_HANDLE hFwEvent)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