import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / drv_wlan / mt6628 / wlan / mgmt / cnm_timer.c
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 cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout)
138 {
139 P_ROOT_TIMER prRootTimer;
140 BOOLEAN fgNeedWakeLock;
141
142 ASSERT(prAdapter);
143
144 prRootTimer = &prAdapter->rRootTimer;
145
146 kalSetTimer(prAdapter->prGlueInfo, rTimeout);
147
148 if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) {
149 fgNeedWakeLock = TRUE;
150
151 if (!prRootTimer->fgWakeLocked) {
152 KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock);
153 prRootTimer->fgWakeLocked = TRUE;
154 }
155 } else {
156 fgNeedWakeLock = FALSE;
157 }
158
159 return fgNeedWakeLock;
160 }
161
162 /*----------------------------------------------------------------------------*/
163 /*!
164 * \brief This routines is called to initialize a root timer.
165 *
166 * \param[in] prAdapter
167 *
168 * \return (none)
169 */
170 /*----------------------------------------------------------------------------*/
171 VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter)
172 {
173 P_ROOT_TIMER prRootTimer;
174 KAL_SPIN_LOCK_DECLARATION();
175
176 ASSERT(prAdapter);
177
178 prRootTimer = &prAdapter->rRootTimer;
179
180 /* Note: glue layer have configured timer */
181
182 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
183 LINK_INITIALIZE(&prRootTimer->rLinkHead);
184 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
185
186 KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer");
187 prRootTimer->fgWakeLocked = FALSE;
188 return;
189 }
190
191 /*----------------------------------------------------------------------------*/
192 /*!
193 * \brief This routines is called to destroy a root timer.
194 * When WIFI is off, the token shall be returned back to system.
195 *
196 * \param[in]
197 *
198 * \return (none)
199 */
200 /*----------------------------------------------------------------------------*/
201 VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter)
202 {
203 P_ROOT_TIMER prRootTimer;
204 KAL_SPIN_LOCK_DECLARATION();
205
206 ASSERT(prAdapter);
207
208 prRootTimer = &prAdapter->rRootTimer;
209
210 if (prRootTimer->fgWakeLocked) {
211 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
212 prRootTimer->fgWakeLocked = FALSE;
213 }
214 KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock);
215
216 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
217 LINK_INITIALIZE(&prRootTimer->rLinkHead);
218 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
219
220 /* Note: glue layer will be responsible for timer destruction */
221
222 return;
223 }
224
225 /*----------------------------------------------------------------------------*/
226 /*!
227 * \brief This routines is called to initialize a timer.
228 *
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.
232 *
233 * \return (none)
234 */
235 /*----------------------------------------------------------------------------*/
236 VOID
237 cnmTimerInitTimer(IN P_ADAPTER_T prAdapter,
238 IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN UINT_32 u4Data)
239 {
240 ASSERT(prAdapter);
241
242 ASSERT(prTimer);
243
244 #if DBG
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"));
248 }
249 #endif
250
251 #if DBG
252 ASSERT(prAdapter->rRootTimer.rLinkHead.prNext);
253 {
254 P_LINK_T prTimerList;
255 P_LINK_ENTRY_T prLinkEntry;
256 P_TIMER_T prPendingTimer;
257
258 prTimerList = &(prAdapter->rRootTimer.rLinkHead);
259
260 LINK_FOR_EACH(prLinkEntry, prTimerList) {
261 prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
262 ASSERT(prPendingTimer);
263 ASSERT(prPendingTimer != prTimer);
264 }
265 }
266 #endif
267
268 LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry);
269
270 prTimer->pfMgmtTimeOutFunc = pfFunc;
271 prTimer->u4Data = u4Data;
272
273 return;
274 }
275
276
277 /*----------------------------------------------------------------------------*/
278 /*!
279 * \brief This routines is called to stop a timer.
280 *
281 * \param[in] prTimer Pointer to a timer structure.
282 *
283 * \return (none)
284 */
285 /*----------------------------------------------------------------------------*/
286 static VOID
287 cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock)
288 {
289 P_ROOT_TIMER prRootTimer;
290 KAL_SPIN_LOCK_DECLARATION();
291
292 ASSERT(prAdapter);
293 ASSERT(prTimer);
294
295 prRootTimer = &prAdapter->rRootTimer;
296
297 if (fgAcquireSpinlock) {
298 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
299 }
300
301 if (timerPendingTimer(prTimer)) {
302 LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry);
303
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.
307 */
308 if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) {
309 kalCancelTimer(prAdapter->prGlueInfo);
310
311 if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) {
312 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
313 prRootTimer->fgWakeLocked = FALSE;
314 }
315 }
316 }
317
318 if (fgAcquireSpinlock) {
319 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
320 }
321 }
322
323 /*----------------------------------------------------------------------------*/
324 /*!
325 * \brief This routines is called to stop a timer.
326 *
327 * \param[in] prTimer Pointer to a timer structure.
328 *
329 * \return (none)
330 */
331 /*----------------------------------------------------------------------------*/
332 VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer)
333 {
334 ASSERT(prAdapter);
335 ASSERT(prTimer);
336
337 cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE);
338 }
339
340 /*----------------------------------------------------------------------------*/
341 /*!
342 * \brief This routines is called to start a timer with wake_lock.
343 *
344 * \param[in] prTimer Pointer to a timer structure.
345 * \param[in] u4TimeoutMs Timeout to issue the timer and call back function
346 * (unit: ms).
347 *
348 * \return (none)
349 */
350 /*----------------------------------------------------------------------------*/
351 VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs)
352 {
353 P_ROOT_TIMER prRootTimer;
354 P_LINK_T prTimerList;
355 OS_SYSTIME rExpiredSysTime, rTimeoutSystime;
356 KAL_SPIN_LOCK_DECLARATION();
357
358 ASSERT(prAdapter);
359 ASSERT(prTimer);
360
361 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
362
363 prRootTimer = &prAdapter->rRootTimer;
364 prTimerList = &prRootTimer->rLinkHead;
365
366 /* If timeout interval is larger than 1 minute, the mod value is set
367 * to the timeout value first, then per minutue.
368 */
369 if (u4TimeoutMs > MSEC_PER_MIN) {
370 ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN));
371
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--;
377 }
378 } else {
379 prTimer->u2Minutes = 0;
380 }
381
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;
386
387 /* If no timer pending or the fast time interval is used. */
388 if (LINK_IS_EMPTY(prTimerList) ||
389 TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
390
391 prRootTimer->rNextExpiredSysTime = rExpiredSysTime;
392 cnmTimerSetTimer(prAdapter, rTimeoutSystime);
393 }
394
395 /* Add this timer to checking list */
396 prTimer->rExpiredSysTime = rExpiredSysTime;
397
398 if (!timerPendingTimer(prTimer)) {
399 LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
400 }
401
402 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
403
404 return;
405 }
406
407 /*----------------------------------------------------------------------------*/
408 /*!
409 * \brief This routines is called to check the timer list.
410 *
411 * \param[in]
412 *
413 * \return (none)
414 */
415 /*----------------------------------------------------------------------------*/
416 VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter)
417 {
418 P_ROOT_TIMER prRootTimer;
419 P_LINK_T prTimerList;
420 P_LINK_ENTRY_T prLinkEntry;
421 P_TIMER_T prTimer;
422 OS_SYSTIME rCurSysTime;
423 PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc;
424 UINT_32 u4TimeoutData;
425 BOOLEAN fgNeedWakeLock;
426 KAL_SPIN_LOCK_DECLARATION();
427
428 ASSERT(prAdapter);
429
430 /* acquire spin lock */
431 KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
432
433 prRootTimer = &prAdapter->rRootTimer;
434 prTimerList = &prRootTimer->rLinkHead;
435
436 rCurSysTime = kalGetTimeTick();
437
438 /* Set the permitted max timeout value for new one */
439 prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
440
441 LINK_FOR_EACH(prLinkEntry, prTimerList) {
442 prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
443 ASSERT(prTimer);
444
445 /* Check if this entry is timeout. */
446 if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) {
447 cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE);
448
449 pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc;
450 u4TimeoutData = prTimer->u4Data;
451
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);
461 }
462
463 /* Search entire list again because of nest del and add timers
464 * and current MGMT_TIMER could be volatile after stopped
465 */
466 prLinkEntry = (P_LINK_ENTRY_T) prTimerList;
467
468 prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
469 } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
470 prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime;
471 }
472 } /* end of for loop */
473
474 /* Setup the prNext timeout event. It is possible the timer was already
475 * set in the above timeout callback function.
476 */
477 fgNeedWakeLock = FALSE;
478 if (!LINK_IS_EMPTY(prTimerList)) {
479 ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime));
480
481 fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME)
482 ((INT_32) prRootTimer->rNextExpiredSysTime -
483 (INT_32) rCurSysTime));
484 }
485
486 if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) {
487 KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
488 prRootTimer->fgWakeLocked = FALSE;
489 }
490
491 /* release spin lock */
492 KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
493 }