2 ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1 $
5 /*! \file "cnm_timer.c"
13 ** $Log: cnm_timer.c $
16 * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer
17 * Add wake lock if timer timeout value is smaller than 5 seconds
20 * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep long enough for specified interval such as 500ms
21 * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions
25 * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
28 * [WPD00003833][MT6620 and MT5931] Driver migration
29 * cnm_timer has been migrated.
32 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
33 * Support sleep notification to host
36 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
37 * Add some checking assertions
40 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
41 * Return timer token back to COS when entering wait off state
44 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
45 * Remove compiling warning
48 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
49 * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb
52 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
53 * Fix system time is 32KHz instead of 1ms
55 * 01 04 2010 tehuang.liu
56 * [BORA00000018]Integrate WIFI part into BORA for the 1st time
57 * For working out the first connection Chariot-verified version
60 * [BORA00000018] Integrate WIFI part into BORA for the 1st time
61 * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer
63 * Oct 30 2009 mtk01104
64 * [BORA00000018] Integrate WIFI part into BORA for the 1st time
65 * In cnmTimerInitialize(), just stop timer if it was already created.
67 * Oct 30 2009 mtk01461
68 * [BORA00000018] Integrate WIFI part into BORA for the 1st time
69 * Move the external reference for Lint to precomp.h
71 * Oct 30 2009 mtk01461
72 * [BORA00000018] Integrate WIFI part into BORA for the 1st time
75 * Oct 28 2009 mtk01104
76 * [BORA00000018] Integrate WIFI part into BORA for the 1st time
81 /*******************************************************************************
82 * C O M P I L E R F L A G S
83 ********************************************************************************
86 /*******************************************************************************
87 * E X T E R N A L R E F E R E N C E S
88 ********************************************************************************
92 /*******************************************************************************
94 ********************************************************************************
97 /*******************************************************************************
99 ********************************************************************************
102 /*******************************************************************************
103 * P U B L I C D A T A
104 ********************************************************************************
107 /*******************************************************************************
108 * P R I V A T E D A T A
109 ********************************************************************************
112 /*******************************************************************************
114 ********************************************************************************
117 /*******************************************************************************
118 * F U N C T I O N D E C L A R A T I O N S
119 ********************************************************************************
122 /*******************************************************************************
124 ********************************************************************************
127 /*----------------------------------------------------------------------------*/
129 * \brief This routine is called to set the time to do the time out check.
131 * \param[in] rTimeout Time out interval from current time.
133 * \retval TRUE Success.
136 /*----------------------------------------------------------------------------*/
137 static BOOLEAN
cnmTimerSetTimer(IN P_ADAPTER_T prAdapter
, IN OS_SYSTIME rTimeout
)
139 P_ROOT_TIMER prRootTimer
;
140 BOOLEAN fgNeedWakeLock
;
144 prRootTimer
= &prAdapter
->rRootTimer
;
146 kalSetTimer(prAdapter
->prGlueInfo
, rTimeout
);
148 if (rTimeout
<= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME
)) {
149 fgNeedWakeLock
= TRUE
;
151 if (!prRootTimer
->fgWakeLocked
) {
152 KAL_WAKE_LOCK(prAdapter
, &prRootTimer
->rWakeLock
);
153 prRootTimer
->fgWakeLocked
= TRUE
;
156 fgNeedWakeLock
= FALSE
;
159 return fgNeedWakeLock
;
162 /*----------------------------------------------------------------------------*/
164 * \brief This routines is called to initialize a root timer.
166 * \param[in] prAdapter
170 /*----------------------------------------------------------------------------*/
171 VOID
cnmTimerInitialize(IN P_ADAPTER_T prAdapter
)
173 P_ROOT_TIMER prRootTimer
;
174 KAL_SPIN_LOCK_DECLARATION();
178 prRootTimer
= &prAdapter
->rRootTimer
;
180 /* Note: glue layer have configured timer */
182 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
183 LINK_INITIALIZE(&prRootTimer
->rLinkHead
);
184 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
186 KAL_WAKE_LOCK_INIT(prAdapter
, &prRootTimer
->rWakeLock
, "WLAN Timer");
187 prRootTimer
->fgWakeLocked
= FALSE
;
191 /*----------------------------------------------------------------------------*/
193 * \brief This routines is called to destroy a root timer.
194 * When WIFI is off, the token shall be returned back to system.
200 /*----------------------------------------------------------------------------*/
201 VOID
cnmTimerDestroy(IN P_ADAPTER_T prAdapter
)
203 P_ROOT_TIMER prRootTimer
;
204 KAL_SPIN_LOCK_DECLARATION();
208 prRootTimer
= &prAdapter
->rRootTimer
;
210 if (prRootTimer
->fgWakeLocked
) {
211 KAL_WAKE_UNLOCK(prAdapter
, &prRootTimer
->rWakeLock
);
212 prRootTimer
->fgWakeLocked
= FALSE
;
214 KAL_WAKE_LOCK_DESTROY(prAdapter
, &prRootTimer
->rWakeLock
);
216 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
217 LINK_INITIALIZE(&prRootTimer
->rLinkHead
);
218 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
220 /* Note: glue layer will be responsible for timer destruction */
225 /*----------------------------------------------------------------------------*/
227 * \brief This routines is called to initialize a timer.
229 * \param[in] prTimer Pointer to a timer structure.
230 * \param[in] pfnFunc Pointer to the call back function.
231 * \param[in] u4Data Parameter for call back function.
235 /*----------------------------------------------------------------------------*/
237 cnmTimerInitTimer(IN P_ADAPTER_T prAdapter
,
238 IN P_TIMER_T prTimer
, IN PFN_MGMT_TIMEOUT_FUNC pfFunc
, IN UINT_32 u4Data
)
245 /* Note: NULL function pointer is permitted for HEM POWER */
246 if (pfFunc
== NULL
) {
247 DBGLOG(CNM
, WARN
, ("Init timer with NULL callback function!\n"));
252 ASSERT(prAdapter
->rRootTimer
.rLinkHead
.prNext
);
254 P_LINK_T prTimerList
;
255 P_LINK_ENTRY_T prLinkEntry
;
256 P_TIMER_T prPendingTimer
;
258 prTimerList
= &(prAdapter
->rRootTimer
.rLinkHead
);
260 LINK_FOR_EACH(prLinkEntry
, prTimerList
) {
261 prPendingTimer
= LINK_ENTRY(prLinkEntry
, TIMER_T
, rLinkEntry
);
262 ASSERT(prPendingTimer
);
263 ASSERT(prPendingTimer
!= prTimer
);
268 LINK_ENTRY_INITIALIZE(&prTimer
->rLinkEntry
);
270 prTimer
->pfMgmtTimeOutFunc
= pfFunc
;
271 prTimer
->u4Data
= u4Data
;
277 /*----------------------------------------------------------------------------*/
279 * \brief This routines is called to stop a timer.
281 * \param[in] prTimer Pointer to a timer structure.
285 /*----------------------------------------------------------------------------*/
287 cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter
, IN P_TIMER_T prTimer
, IN BOOLEAN fgAcquireSpinlock
)
289 P_ROOT_TIMER prRootTimer
;
290 KAL_SPIN_LOCK_DECLARATION();
295 prRootTimer
= &prAdapter
->rRootTimer
;
297 if (fgAcquireSpinlock
) {
298 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
301 if (timerPendingTimer(prTimer
)) {
302 LINK_REMOVE_KNOWN_ENTRY(&prRootTimer
->rLinkHead
, &prTimer
->rLinkEntry
);
304 /* Reduce dummy timeout for power saving, especially HIF activity.
305 * If two or more timers exist and being removed timer is smallest,
306 * this dummy timeout will still happen, but it is OK.
308 if (LINK_IS_EMPTY(&prRootTimer
->rLinkHead
)) {
309 kalCancelTimer(prAdapter
->prGlueInfo
);
311 if (fgAcquireSpinlock
&& prRootTimer
->fgWakeLocked
) {
312 KAL_WAKE_UNLOCK(prAdapter
, &prRootTimer
->rWakeLock
);
313 prRootTimer
->fgWakeLocked
= FALSE
;
318 if (fgAcquireSpinlock
) {
319 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
323 /*----------------------------------------------------------------------------*/
325 * \brief This routines is called to stop a timer.
327 * \param[in] prTimer Pointer to a timer structure.
331 /*----------------------------------------------------------------------------*/
332 VOID
cnmTimerStopTimer(IN P_ADAPTER_T prAdapter
, IN P_TIMER_T prTimer
)
337 cnmTimerStopTimer_impl(prAdapter
, prTimer
, TRUE
);
340 /*----------------------------------------------------------------------------*/
342 * \brief This routines is called to start a timer with wake_lock.
344 * \param[in] prTimer Pointer to a timer structure.
345 * \param[in] u4TimeoutMs Timeout to issue the timer and call back function
350 /*----------------------------------------------------------------------------*/
351 VOID
cnmTimerStartTimer(IN P_ADAPTER_T prAdapter
, IN P_TIMER_T prTimer
, IN UINT_32 u4TimeoutMs
)
353 P_ROOT_TIMER prRootTimer
;
354 P_LINK_T prTimerList
;
355 OS_SYSTIME rExpiredSysTime
, rTimeoutSystime
;
356 KAL_SPIN_LOCK_DECLARATION();
361 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
363 prRootTimer
= &prAdapter
->rRootTimer
;
364 prTimerList
= &prRootTimer
->rLinkHead
;
366 /* If timeout interval is larger than 1 minute, the mod value is set
367 * to the timeout value first, then per minutue.
369 if (u4TimeoutMs
> MSEC_PER_MIN
) {
370 ASSERT(u4TimeoutMs
<= ((UINT_32
) 0xFFFF * MSEC_PER_MIN
));
372 prTimer
->u2Minutes
= (UINT_16
) (u4TimeoutMs
/ MSEC_PER_MIN
);
373 u4TimeoutMs
-= (prTimer
->u2Minutes
* MSEC_PER_MIN
);
374 if (u4TimeoutMs
== 0) {
375 u4TimeoutMs
= MSEC_PER_MIN
;
376 prTimer
->u2Minutes
--;
379 prTimer
->u2Minutes
= 0;
382 /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */
383 ASSERT(u4TimeoutMs
< (((UINT_32
) 0x80000000 - MSEC_PER_SEC
) / KAL_HZ
));
384 rTimeoutSystime
= MSEC_TO_SYSTIME(u4TimeoutMs
);
385 rExpiredSysTime
= kalGetTimeTick() + rTimeoutSystime
;
387 /* If no timer pending or the fast time interval is used. */
388 if (LINK_IS_EMPTY(prTimerList
) ||
389 TIME_BEFORE(rExpiredSysTime
, prRootTimer
->rNextExpiredSysTime
)) {
391 prRootTimer
->rNextExpiredSysTime
= rExpiredSysTime
;
392 cnmTimerSetTimer(prAdapter
, rTimeoutSystime
);
395 /* Add this timer to checking list */
396 prTimer
->rExpiredSysTime
= rExpiredSysTime
;
398 if (!timerPendingTimer(prTimer
)) {
399 LINK_INSERT_TAIL(prTimerList
, &prTimer
->rLinkEntry
);
402 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
407 /*----------------------------------------------------------------------------*/
409 * \brief This routines is called to check the timer list.
415 /*----------------------------------------------------------------------------*/
416 VOID
cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter
)
418 P_ROOT_TIMER prRootTimer
;
419 P_LINK_T prTimerList
;
420 P_LINK_ENTRY_T prLinkEntry
;
422 OS_SYSTIME rCurSysTime
;
423 PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc
;
424 UINT_32 u4TimeoutData
;
425 BOOLEAN fgNeedWakeLock
;
426 KAL_SPIN_LOCK_DECLARATION();
430 /* acquire spin lock */
431 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
433 prRootTimer
= &prAdapter
->rRootTimer
;
434 prTimerList
= &prRootTimer
->rLinkHead
;
436 rCurSysTime
= kalGetTimeTick();
438 /* Set the permitted max timeout value for new one */
439 prRootTimer
->rNextExpiredSysTime
= rCurSysTime
+ MGMT_MAX_TIMEOUT_INTERVAL
;
441 LINK_FOR_EACH(prLinkEntry
, prTimerList
) {
442 prTimer
= LINK_ENTRY(prLinkEntry
, TIMER_T
, rLinkEntry
);
445 /* Check if this entry is timeout. */
446 if (!TIME_BEFORE(rCurSysTime
, prTimer
->rExpiredSysTime
)) {
447 cnmTimerStopTimer_impl(prAdapter
, prTimer
, FALSE
);
449 pfMgmtTimeOutFunc
= prTimer
->pfMgmtTimeOutFunc
;
450 u4TimeoutData
= prTimer
->u4Data
;
452 if (prTimer
->u2Minutes
> 0) {
453 prTimer
->u2Minutes
--;
454 prTimer
->rExpiredSysTime
=
455 rCurSysTime
+ MSEC_TO_SYSTIME(MSEC_PER_MIN
);
456 LINK_INSERT_TAIL(prTimerList
, &prTimer
->rLinkEntry
);
457 } else if (pfMgmtTimeOutFunc
) {
458 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
459 (pfMgmtTimeOutFunc
) (prAdapter
, u4TimeoutData
);
460 KAL_ACQUIRE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);
463 /* Search entire list again because of nest del and add timers
464 * and current MGMT_TIMER could be volatile after stopped
466 prLinkEntry
= (P_LINK_ENTRY_T
) prTimerList
;
468 prRootTimer
->rNextExpiredSysTime
= rCurSysTime
+ MGMT_MAX_TIMEOUT_INTERVAL
;
469 } else if (TIME_BEFORE(prTimer
->rExpiredSysTime
, prRootTimer
->rNextExpiredSysTime
)) {
470 prRootTimer
->rNextExpiredSysTime
= prTimer
->rExpiredSysTime
;
472 } /* end of for loop */
474 /* Setup the prNext timeout event. It is possible the timer was already
475 * set in the above timeout callback function.
477 fgNeedWakeLock
= FALSE
;
478 if (!LINK_IS_EMPTY(prTimerList
)) {
479 ASSERT(TIME_AFTER(prRootTimer
->rNextExpiredSysTime
, rCurSysTime
));
481 fgNeedWakeLock
= cnmTimerSetTimer(prAdapter
, (OS_SYSTIME
)
482 ((INT_32
) prRootTimer
->rNextExpiredSysTime
-
483 (INT_32
) rCurSysTime
));
486 if (prRootTimer
->fgWakeLocked
&& !fgNeedWakeLock
) {
487 KAL_WAKE_UNLOCK(prAdapter
, &prRootTimer
->rWakeLock
);
488 prRootTimer
->fgWakeLocked
= FALSE
;
491 /* release spin lock */
492 KAL_RELEASE_SPIN_LOCK(prAdapter
, SPIN_LOCK_TIMER
);