import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / conn_soc / drv_wlan / mt_wifi / wlan / mgmt / cnm_timer.c
CommitLineData
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/*----------------------------------------------------------------------------*/
137static BOOLEAN
138cnmTimerSetTimer (
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/*----------------------------------------------------------------------------*/
176VOID
177cnmTimerInitialize (
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/*----------------------------------------------------------------------------*/
209VOID
210cnmTimerDestroy (
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/*----------------------------------------------------------------------------*/
247VOID
248cnmTimerInitTimer (
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/*----------------------------------------------------------------------------*/
301static VOID
302cnmTimerStopTimer_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/*----------------------------------------------------------------------------*/
352VOID
353cnmTimerStopTimer (
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/*----------------------------------------------------------------------------*/
375VOID
376cnmTimerStartTimer (
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/*----------------------------------------------------------------------------*/
446VOID
447cnmTimerDoTimeOutCheck (
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