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