Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | ** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1 $ | |
3 | */ | |
4 | ||
5 | /*! \file "cnm_timer.c" | |
6 | \brief | |
7 | ||
8 | */ | |
9 | ||
10 | ||
11 | ||
12 | /* | |
13 | ** $Log: cnm_timer.c $ | |
14 | * | |
15 | * 12 13 2011 cm.chang | |
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 | |
18 | * | |
19 | * 02 24 2011 cp.wu | |
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 | |
22 | * | |
23 | * 07 08 2010 cp.wu | |
24 | * | |
25 | * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. | |
26 | * | |
27 | * 06 08 2010 cp.wu | |
28 | * [WPD00003833][MT6620 and MT5931] Driver migration | |
29 | * cnm_timer has been migrated. | |
30 | * | |
31 | * 05 28 2010 cm.chang | |
32 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
33 | * Support sleep notification to host | |
34 | * | |
35 | * 05 19 2010 cm.chang | |
36 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
37 | * Add some checking assertions | |
38 | * | |
39 | * 04 24 2010 cm.chang | |
40 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
41 | * Return timer token back to COS when entering wait off state | |
42 | * | |
43 | * 01 11 2010 cm.chang | |
44 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
45 | * Remove compiling warning | |
46 | * | |
47 | * 01 08 2010 cm.chang | |
48 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
49 | * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb | |
50 | * | |
51 | * 01 06 2010 cm.chang | |
52 | * [BORA00000018]Integrate WIFI part into BORA for the 1st time | |
53 | * Fix system time is 32KHz instead of 1ms | |
54 | * | |
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 | |
58 | * | |
59 | * Dec 3 2009 mtk01461 | |
60 | * [BORA00000018] Integrate WIFI part into BORA for the 1st time | |
61 | * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer | |
62 | * | |
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. | |
66 | * | |
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 | |
70 | * | |
71 | * Oct 30 2009 mtk01461 | |
72 | * [BORA00000018] Integrate WIFI part into BORA for the 1st time | |
73 | * Fix lint warning | |
74 | * | |
75 | * Oct 28 2009 mtk01104 | |
76 | * [BORA00000018] Integrate WIFI part into BORA for the 1st time | |
77 | * | |
78 | ** | |
79 | */ | |
80 | ||
81 | /******************************************************************************* | |
82 | * C O M P I L E R F L A G S | |
83 | ******************************************************************************** | |
84 | */ | |
85 | ||
86 | /******************************************************************************* | |
87 | * E X T E R N A L R E F E R E N C E S | |
88 | ******************************************************************************** | |
89 | */ | |
90 | #include "precomp.h" | |
91 | ||
92 | /******************************************************************************* | |
93 | * C O N S T A N T S | |
94 | ******************************************************************************** | |
95 | */ | |
96 | ||
97 | /******************************************************************************* | |
98 | * D A T A T Y P E S | |
99 | ******************************************************************************** | |
100 | */ | |
101 | ||
102 | /******************************************************************************* | |
103 | * P U B L I C D A T A | |
104 | ******************************************************************************** | |
105 | */ | |
106 | ||
107 | /******************************************************************************* | |
108 | * P R I V A T E D A T A | |
109 | ******************************************************************************** | |
110 | */ | |
111 | ||
112 | /******************************************************************************* | |
113 | * M A C R O S | |
114 | ******************************************************************************** | |
115 | */ | |
116 | ||
117 | /******************************************************************************* | |
118 | * F U N C T I O N D E C L A R A T I O N S | |
119 | ******************************************************************************** | |
120 | */ | |
121 | ||
122 | /******************************************************************************* | |
123 | * F U N C T I O N S | |
124 | ******************************************************************************** | |
125 | */ | |
126 | ||
127 | /*----------------------------------------------------------------------------*/ | |
128 | /*! | |
129 | * \brief This routine is called to set the time to do the time out check. | |
130 | * | |
131 | * \param[in] rTimeout Time out interval from current time. | |
132 | * | |
133 | * \retval TRUE Success. | |
134 | * | |
135 | */ | |
136 | /*----------------------------------------------------------------------------*/ | |
137 | static BOOLEAN | |
138 | cnmTimerSetTimer ( | |
139 | IN P_ADAPTER_T prAdapter, | |
140 | IN OS_SYSTIME rTimeout | |
141 | ) | |
142 | { | |
143 | P_ROOT_TIMER prRootTimer; | |
144 | BOOLEAN fgNeedWakeLock; | |
145 | ||
146 | ASSERT(prAdapter); | |
147 | ||
148 | prRootTimer = &prAdapter->rRootTimer; | |
149 | ||
150 | kalSetTimer(prAdapter->prGlueInfo, rTimeout); | |
151 | ||
152 | if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) { | |
153 | fgNeedWakeLock = TRUE; | |
154 | ||
155 | if (!prRootTimer->fgWakeLocked) { | |
156 | KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock); | |
157 | prRootTimer->fgWakeLocked = TRUE; | |
158 | } | |
159 | } | |
160 | else { | |
161 | fgNeedWakeLock = FALSE; | |
162 | } | |
163 | ||
164 | return fgNeedWakeLock; | |
165 | } | |
166 | ||
167 | /*----------------------------------------------------------------------------*/ | |
168 | /*! | |
169 | * \brief This routines is called to initialize a root timer. | |
170 | * | |
171 | * \param[in] prAdapter | |
172 | * | |
173 | * \return (none) | |
174 | */ | |
175 | /*----------------------------------------------------------------------------*/ | |
176 | VOID | |
177 | cnmTimerInitialize ( | |
178 | IN P_ADAPTER_T prAdapter | |
179 | ) | |
180 | { | |
181 | P_ROOT_TIMER prRootTimer; | |
182 | KAL_SPIN_LOCK_DECLARATION(); | |
183 | ||
184 | ASSERT(prAdapter); | |
185 | ||
186 | prRootTimer = &prAdapter->rRootTimer; | |
187 | ||
188 | /* Note: glue layer have configured timer */ | |
189 | ||
190 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
191 | LINK_INITIALIZE(&prRootTimer->rLinkHead); | |
192 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
193 | ||
194 | KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer"); | |
195 | prRootTimer->fgWakeLocked = FALSE; | |
196 | return; | |
197 | } | |
198 | ||
199 | /*----------------------------------------------------------------------------*/ | |
200 | /*! | |
201 | * \brief This routines is called to destroy a root timer. | |
202 | * When WIFI is off, the token shall be returned back to system. | |
203 | * | |
204 | * \param[in] | |
205 | * | |
206 | * \return (none) | |
207 | */ | |
208 | /*----------------------------------------------------------------------------*/ | |
209 | VOID | |
210 | cnmTimerDestroy ( | |
211 | IN P_ADAPTER_T prAdapter | |
212 | ) | |
213 | { | |
214 | P_ROOT_TIMER prRootTimer; | |
215 | KAL_SPIN_LOCK_DECLARATION(); | |
216 | ||
217 | ASSERT(prAdapter); | |
218 | ||
219 | prRootTimer = &prAdapter->rRootTimer; | |
220 | ||
221 | if (prRootTimer->fgWakeLocked) { | |
222 | KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); | |
223 | prRootTimer->fgWakeLocked = FALSE; | |
224 | } | |
225 | KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock); | |
226 | ||
227 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
228 | LINK_INITIALIZE(&prRootTimer->rLinkHead); | |
229 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
230 | ||
231 | /* Note: glue layer will be responsible for timer destruction */ | |
232 | ||
233 | return; | |
234 | } | |
235 | ||
236 | /*----------------------------------------------------------------------------*/ | |
237 | /*! | |
238 | * \brief This routines is called to initialize a timer. | |
239 | * | |
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. | |
243 | * | |
244 | * \return (none) | |
245 | */ | |
246 | /*----------------------------------------------------------------------------*/ | |
247 | VOID | |
248 | cnmTimerInitTimer ( | |
249 | IN P_ADAPTER_T prAdapter, | |
250 | IN P_TIMER_T prTimer, | |
251 | IN PFN_MGMT_TIMEOUT_FUNC pfFunc, | |
252 | IN ULONG ulData | |
253 | ) | |
254 | { | |
255 | ASSERT(prAdapter); | |
256 | ||
257 | ASSERT(prTimer); | |
258 | ||
259 | #if DBG | |
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")); | |
263 | } | |
264 | #endif | |
265 | ||
266 | #if DBG | |
267 | ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); | |
268 | { | |
269 | P_LINK_T prTimerList; | |
270 | P_LINK_ENTRY_T prLinkEntry; | |
271 | P_TIMER_T prPendingTimer; | |
272 | ||
273 | prTimerList = &(prAdapter->rRootTimer.rLinkHead); | |
274 | ||
275 | LINK_FOR_EACH(prLinkEntry, prTimerList) { | |
276 | prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); | |
277 | ASSERT(prPendingTimer); | |
278 | ASSERT(prPendingTimer != prTimer); | |
279 | } | |
280 | } | |
281 | #endif | |
282 | ||
283 | LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); | |
284 | ||
285 | prTimer->pfMgmtTimeOutFunc = pfFunc; | |
286 | prTimer->ulData = ulData; | |
287 | ||
288 | return; | |
289 | } | |
290 | ||
291 | ||
292 | /*----------------------------------------------------------------------------*/ | |
293 | /*! | |
294 | * \brief This routines is called to stop a timer. | |
295 | * | |
296 | * \param[in] prTimer Pointer to a timer structure. | |
297 | * | |
298 | * \return (none) | |
299 | */ | |
300 | /*----------------------------------------------------------------------------*/ | |
301 | static VOID | |
302 | cnmTimerStopTimer_impl ( | |
303 | IN P_ADAPTER_T prAdapter, | |
304 | IN P_TIMER_T prTimer, | |
305 | IN BOOLEAN fgAcquireSpinlock | |
306 | ) | |
307 | { | |
308 | P_ROOT_TIMER prRootTimer; | |
309 | KAL_SPIN_LOCK_DECLARATION(); | |
310 | ||
311 | ASSERT(prAdapter); | |
312 | ASSERT(prTimer); | |
313 | ||
314 | prRootTimer = &prAdapter->rRootTimer; | |
315 | ||
316 | if (fgAcquireSpinlock) { | |
317 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
318 | } | |
319 | ||
320 | if (timerPendingTimer(prTimer)) { | |
321 | LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, | |
322 | &prTimer->rLinkEntry); | |
323 | ||
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. | |
327 | */ | |
328 | if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { | |
329 | kalCancelTimer(prAdapter->prGlueInfo); | |
330 | ||
331 | if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) { | |
332 | KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); | |
333 | prRootTimer->fgWakeLocked = FALSE; | |
334 | } | |
335 | } | |
336 | } | |
337 | ||
338 | if (fgAcquireSpinlock) { | |
339 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
340 | } | |
341 | } | |
342 | ||
343 | /*----------------------------------------------------------------------------*/ | |
344 | /*! | |
345 | * \brief This routines is called to stop a timer. | |
346 | * | |
347 | * \param[in] prTimer Pointer to a timer structure. | |
348 | * | |
349 | * \return (none) | |
350 | */ | |
351 | /*----------------------------------------------------------------------------*/ | |
352 | VOID | |
353 | cnmTimerStopTimer ( | |
354 | IN P_ADAPTER_T prAdapter, | |
355 | IN P_TIMER_T prTimer | |
356 | ) | |
357 | { | |
358 | ASSERT(prAdapter); | |
359 | ASSERT(prTimer); | |
360 | ||
361 | cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE); | |
362 | } | |
363 | ||
364 | /*----------------------------------------------------------------------------*/ | |
365 | /*! | |
366 | * \brief This routines is called to start a timer with wake_lock. | |
367 | * | |
368 | * \param[in] prTimer Pointer to a timer structure. | |
369 | * \param[in] u4TimeoutMs Timeout to issue the timer and call back function | |
370 | * (unit: ms). | |
371 | * | |
372 | * \return (none) | |
373 | */ | |
374 | /*----------------------------------------------------------------------------*/ | |
375 | VOID | |
376 | cnmTimerStartTimer ( | |
377 | IN P_ADAPTER_T prAdapter, | |
378 | IN P_TIMER_T prTimer, | |
379 | IN UINT_32 u4TimeoutMs | |
380 | ) | |
381 | { | |
382 | P_ROOT_TIMER prRootTimer; | |
383 | P_LINK_T prTimerList; | |
384 | OS_SYSTIME rExpiredSysTime, rTimeoutSystime; | |
385 | KAL_SPIN_LOCK_DECLARATION(); | |
386 | ||
387 | ASSERT(prAdapter); | |
388 | ASSERT(prTimer); | |
389 | ||
390 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
391 | ||
392 | prRootTimer = &prAdapter->rRootTimer; | |
393 | prTimerList= &prRootTimer->rLinkHead; | |
394 | ||
395 | /* If timeout interval is larger than 1 minute, the mod value is set | |
396 | * to the timeout value first, then per minutue. | |
397 | */ | |
398 | if (u4TimeoutMs > MSEC_PER_MIN) { | |
399 | ASSERT(u4TimeoutMs <= ((UINT_32)0xFFFF * MSEC_PER_MIN)); | |
400 | ||
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--; | |
406 | } | |
407 | } | |
408 | else { | |
409 | prTimer->u2Minutes = 0; | |
410 | } | |
411 | ||
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; | |
416 | ||
417 | /* If no timer pending or the fast time interval is used. */ | |
418 | if (LINK_IS_EMPTY(prTimerList) || | |
419 | TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { | |
420 | ||
421 | prRootTimer->rNextExpiredSysTime = rExpiredSysTime; | |
422 | cnmTimerSetTimer(prAdapter, rTimeoutSystime); | |
423 | } | |
424 | ||
425 | /* Add this timer to checking list */ | |
426 | prTimer->rExpiredSysTime = rExpiredSysTime; | |
427 | ||
428 | if (!timerPendingTimer(prTimer)) { | |
429 | LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); | |
430 | } | |
431 | ||
432 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
433 | ||
434 | return; | |
435 | } | |
436 | ||
437 | /*----------------------------------------------------------------------------*/ | |
438 | /*! | |
439 | * \brief This routines is called to check the timer list. | |
440 | * | |
441 | * \param[in] | |
442 | * | |
443 | * \return (none) | |
444 | */ | |
445 | /*----------------------------------------------------------------------------*/ | |
446 | VOID | |
447 | cnmTimerDoTimeOutCheck ( | |
448 | IN P_ADAPTER_T prAdapter | |
449 | ) | |
450 | { | |
451 | P_ROOT_TIMER prRootTimer; | |
452 | P_LINK_T prTimerList; | |
453 | P_LINK_ENTRY_T prLinkEntry; | |
454 | P_TIMER_T prTimer; | |
455 | OS_SYSTIME rCurSysTime; | |
456 | PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; | |
457 | ULONG ulTimeoutData; | |
458 | BOOLEAN fgNeedWakeLock; | |
459 | KAL_SPIN_LOCK_DECLARATION(); | |
460 | ||
461 | ASSERT(prAdapter); | |
462 | ||
463 | /* acquire spin lock */ | |
464 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
465 | ||
466 | prRootTimer = &prAdapter->rRootTimer; | |
467 | prTimerList= &prRootTimer->rLinkHead; | |
468 | ||
469 | rCurSysTime = kalGetTimeTick(); | |
470 | ||
471 | /* Set the permitted max timeout value for new one */ | |
472 | prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; | |
473 | ||
474 | LINK_FOR_EACH(prLinkEntry, prTimerList) { | |
475 | prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); | |
476 | ASSERT(prTimer); | |
477 | ||
478 | /* Check if this entry is timeout. */ | |
479 | if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { | |
480 | cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE); | |
481 | ||
482 | pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; | |
483 | ulTimeoutData = prTimer->ulData; | |
484 | ||
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); | |
490 | } | |
491 | else if (pfMgmtTimeOutFunc) { | |
492 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
493 | (pfMgmtTimeOutFunc)(prAdapter, ulTimeoutData); | |
494 | KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
495 | } | |
496 | ||
497 | /* Search entire list again because of nest del and add timers | |
498 | * and current MGMT_TIMER could be volatile after stopped | |
499 | */ | |
500 | prLinkEntry = (P_LINK_ENTRY_T)prTimerList; | |
501 | ||
502 | prRootTimer->rNextExpiredSysTime = | |
503 | rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; | |
504 | } | |
505 | else if (TIME_BEFORE(prTimer->rExpiredSysTime, | |
506 | prRootTimer->rNextExpiredSysTime)) { | |
507 | prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime; | |
508 | } | |
509 | } /* end of for loop */ | |
510 | ||
511 | /* Setup the prNext timeout event. It is possible the timer was already | |
512 | * set in the above timeout callback function. | |
513 | */ | |
514 | fgNeedWakeLock = FALSE; | |
515 | if (!LINK_IS_EMPTY(prTimerList)) { | |
516 | ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime)); | |
517 | ||
518 | fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME) | |
519 | ((INT_32)prRootTimer->rNextExpiredSysTime - (INT_32)rCurSysTime)); | |
520 | } | |
521 | ||
522 | if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) { | |
523 | KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); | |
524 | prRootTimer->fgWakeLocked = FALSE; | |
525 | } | |
526 | ||
527 | /* release spin lock */ | |
528 | KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); | |
529 | } | |
530 | ||
531 |