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 /*----------------------------------------------------------------------------*/
139 IN P_ADAPTER_T prAdapter,
140 IN OS_SYSTIME rTimeout
143 P_ROOT_TIMER prRootTimer;
144 BOOLEAN fgNeedWakeLock;
148 prRootTimer = &prAdapter->rRootTimer;
150 kalSetTimer(prAdapter->prGlueInfo, rTimeout);
152 if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) {
153 fgNeedWakeLock = TRUE;
155 if (!prRootTimer->fgWakeLocked) {
156 KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock);
157 prRootTimer->fgWakeLocked = TRUE;
161 fgNeedWakeLock = FALSE;
164 return fgNeedWakeLock;
167 /*----------------------------------------------------------------------------*/
169 * \brief This routines is called to initialize a root timer.
171 * \param[in] prAdapter
175 /*----------------------------------------------------------------------------*/
178 IN P_ADAPTER_T prAdapter
181 P_ROOT_TIMER prRootTimer;
182 KAL_SPIN_LOCK_DECLARATION();
186 prRootTimer = &prAdapter->rRootTimer;
188 /* Note: glue layer have configured timer */
190 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
191 LINK_INITIALIZE(&prRootTimer->rLinkHead);
192 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
194 KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer");
195 prRootTimer->fgWakeLocked = FALSE;
199 /*----------------------------------------------------------------------------*/
201 * \brief This routines is called to destroy a root timer.
202 * When WIFI is off, the token shall be returned back to system.
208 /*----------------------------------------------------------------------------*/
211 IN P_ADAPTER_T prAdapter
214 P_ROOT_TIMER prRootTimer;
215 KAL_SPIN_LOCK_DECLARATION();
219 prRootTimer = &prAdapter->rRootTimer;
221 if (prRootTimer->fgWakeLocked) {
222 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
223 prRootTimer->fgWakeLocked = FALSE;
225 KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock);
227 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
228 LINK_INITIALIZE(&prRootTimer->rLinkHead);
229 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
231 /* Note: glue layer will be responsible for timer destruction */
236 /*----------------------------------------------------------------------------*/
238 * \brief This routines is called to initialize a timer.
240 * \param[in] prTimer Pointer to a timer structure.
241 * \param[in] pfnFunc Pointer to the call back function.
242 * \param[in] u4Data Parameter for call back function.
246 /*----------------------------------------------------------------------------*/
249 IN P_ADAPTER_T prAdapter,
250 IN P_TIMER_T prTimer,
251 IN PFN_MGMT_TIMEOUT_FUNC pfFunc,
260 /* Note: NULL function pointer is permitted for HEM POWER */
261 if (pfFunc == NULL) {
262 DBGLOG(CNM, WARN, ("Init timer with NULL callback function!\n"));
267 ASSERT(prAdapter->rRootTimer.rLinkHead.prNext);
269 P_LINK_T prTimerList;
270 P_LINK_ENTRY_T prLinkEntry;
271 P_TIMER_T prPendingTimer;
273 prTimerList = &(prAdapter->rRootTimer.rLinkHead);
275 LINK_FOR_EACH(prLinkEntry, prTimerList) {
276 prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
277 ASSERT(prPendingTimer);
278 ASSERT(prPendingTimer != prTimer);
283 LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry);
285 prTimer->pfMgmtTimeOutFunc = pfFunc;
286 prTimer->u4Data = u4Data;
292 /*----------------------------------------------------------------------------*/
294 * \brief This routines is called to stop a timer.
296 * \param[in] prTimer Pointer to a timer structure.
300 /*----------------------------------------------------------------------------*/
302 cnmTimerStopTimer_impl (
303 IN P_ADAPTER_T prAdapter,
304 IN P_TIMER_T prTimer,
305 IN BOOLEAN fgAcquireSpinlock
308 P_ROOT_TIMER prRootTimer;
309 KAL_SPIN_LOCK_DECLARATION();
314 prRootTimer = &prAdapter->rRootTimer;
316 if (fgAcquireSpinlock) {
317 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
320 if (timerPendingTimer(prTimer)) {
321 LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead,
322 &prTimer->rLinkEntry);
324 /* Reduce dummy timeout for power saving, especially HIF activity.
325 * If two or more timers exist and being removed timer is smallest,
326 * this dummy timeout will still happen, but it is OK.
328 if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) {
329 kalCancelTimer(prAdapter->prGlueInfo);
331 if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) {
332 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
333 prRootTimer->fgWakeLocked = FALSE;
338 if (fgAcquireSpinlock) {
339 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
343 /*----------------------------------------------------------------------------*/
345 * \brief This routines is called to stop a timer.
347 * \param[in] prTimer Pointer to a timer structure.
351 /*----------------------------------------------------------------------------*/
354 IN P_ADAPTER_T prAdapter,
361 cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE);
364 /*----------------------------------------------------------------------------*/
366 * \brief This routines is called to start a timer with wake_lock.
368 * \param[in] prTimer Pointer to a timer structure.
369 * \param[in] u4TimeoutMs Timeout to issue the timer and call back function
374 /*----------------------------------------------------------------------------*/
377 IN P_ADAPTER_T prAdapter,
378 IN P_TIMER_T prTimer,
379 IN UINT_32 u4TimeoutMs
382 P_ROOT_TIMER prRootTimer;
383 P_LINK_T prTimerList;
384 OS_SYSTIME rExpiredSysTime, rTimeoutSystime;
385 KAL_SPIN_LOCK_DECLARATION();
390 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
392 prRootTimer = &prAdapter->rRootTimer;
393 prTimerList= &prRootTimer->rLinkHead;
395 /* If timeout interval is larger than 1 minute, the mod value is set
396 * to the timeout value first, then per minutue.
398 if (u4TimeoutMs > MSEC_PER_MIN) {
399 ASSERT(u4TimeoutMs <= ((UINT_32)0xFFFF * MSEC_PER_MIN));
401 prTimer->u2Minutes = (UINT_16)(u4TimeoutMs / MSEC_PER_MIN);
402 u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN);
403 if (u4TimeoutMs == 0) {
404 u4TimeoutMs = MSEC_PER_MIN;
405 prTimer->u2Minutes--;
409 prTimer->u2Minutes = 0;
412 /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */
413 ASSERT(u4TimeoutMs < (((UINT_32)0x80000000 - MSEC_PER_SEC) / KAL_HZ));
414 rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs);
415 rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime;
417 /* If no timer pending or the fast time interval is used. */
418 if (LINK_IS_EMPTY(prTimerList) ||
419 TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
421 prRootTimer->rNextExpiredSysTime = rExpiredSysTime;
422 cnmTimerSetTimer(prAdapter, rTimeoutSystime);
425 /* Add this timer to checking list */
426 prTimer->rExpiredSysTime = rExpiredSysTime;
428 if (!timerPendingTimer(prTimer)) {
429 LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
432 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
437 /*----------------------------------------------------------------------------*/
439 * \brief This routines is called to check the timer list.
445 /*----------------------------------------------------------------------------*/
447 cnmTimerDoTimeOutCheck (
448 IN P_ADAPTER_T prAdapter
451 P_ROOT_TIMER prRootTimer;
452 P_LINK_T prTimerList;
453 P_LINK_ENTRY_T prLinkEntry;
455 OS_SYSTIME rCurSysTime;
456 PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc;
457 UINT_32 u4TimeoutData;
458 BOOLEAN fgNeedWakeLock;
459 KAL_SPIN_LOCK_DECLARATION();
463 /* acquire spin lock */
464 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
466 prRootTimer = &prAdapter->rRootTimer;
467 prTimerList= &prRootTimer->rLinkHead;
469 rCurSysTime = kalGetTimeTick();
471 /* Set the permitted max timeout value for new one */
472 prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
474 LINK_FOR_EACH(prLinkEntry, prTimerList) {
475 prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
478 /* Check if this entry is timeout. */
479 if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) {
480 cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE);
482 pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc;
483 u4TimeoutData = prTimer->u4Data;
485 if (prTimer->u2Minutes > 0) {
486 prTimer->u2Minutes--;
487 prTimer->rExpiredSysTime =
488 rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN);
489 LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
491 else if (pfMgmtTimeOutFunc) {
492 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
493 (pfMgmtTimeOutFunc)(prAdapter, u4TimeoutData);
494 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
497 /* Search entire list again because of nest del and add timers
498 * and current MGMT_TIMER could be volatile after stopped
500 prLinkEntry = (P_LINK_ENTRY_T)prTimerList;
502 prRootTimer->rNextExpiredSysTime =
503 rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
505 else if (TIME_BEFORE(prTimer->rExpiredSysTime,
506 prRootTimer->rNextExpiredSysTime)) {
507 prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime;
509 } /* end of for loop */
511 /* Setup the prNext timeout event. It is possible the timer was already
512 * set in the above timeout callback function.
514 fgNeedWakeLock = FALSE;
515 if (!LINK_IS_EMPTY(prTimerList)) {
516 ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime));
518 fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME)
519 ((INT_32)prRootTimer->rNextExpiredSysTime - (INT_32)rCurSysTime));
522 if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) {
523 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
524 prRootTimer->fgWakeLocked = FALSE;
527 /* release spin lock */
528 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);