cnm_timer.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. ** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1
  3. */
  4. /*! \file "cnm_timer.c"
  5. \brief
  6. */
  7. /*
  8. ** Log: cnm_timer.c
  9. *
  10. * 12 13 2011 cm.chang
  11. * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer
  12. * Add wake lock if timer timeout value is smaller than 5 seconds
  13. *
  14. * 02 24 2011 cp.wu
  15. * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation
  16. * because NdisMSleep() won't sleep long enough for specified interval such as 500ms
  17. * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions
  18. *
  19. * 07 08 2010 cp.wu
  20. *
  21. * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository.
  22. *
  23. * 06 08 2010 cp.wu
  24. * [WPD00003833][MT6620 and MT5931] Driver migration
  25. * cnm_timer has been migrated.
  26. *
  27. * 05 28 2010 cm.chang
  28. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  29. * Support sleep notification to host
  30. *
  31. * 05 19 2010 cm.chang
  32. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  33. * Add some checking assertions
  34. *
  35. * 04 24 2010 cm.chang
  36. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  37. * Return timer token back to COS when entering wait off state
  38. *
  39. * 01 11 2010 cm.chang
  40. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  41. * Remove compiling warning
  42. *
  43. * 01 08 2010 cm.chang
  44. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  45. * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb
  46. *
  47. * 01 06 2010 cm.chang
  48. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  49. * Fix system time is 32KHz instead of 1ms
  50. *
  51. * 01 04 2010 tehuang.liu
  52. * [BORA00000018]Integrate WIFI part into BORA for the 1st time
  53. * For working out the first connection Chariot-verified version
  54. *
  55. * Dec 3 2009 mtk01461
  56. * [BORA00000018] Integrate WIFI part into BORA for the 1st time
  57. * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer
  58. *
  59. * Oct 30 2009 mtk01104
  60. * [BORA00000018] Integrate WIFI part into BORA for the 1st time
  61. * In cnmTimerInitialize(), just stop timer if it was already created.
  62. *
  63. * Oct 30 2009 mtk01461
  64. * [BORA00000018] Integrate WIFI part into BORA for the 1st time
  65. * Move the external reference for Lint to precomp.h
  66. *
  67. * Oct 30 2009 mtk01461
  68. * [BORA00000018] Integrate WIFI part into BORA for the 1st time
  69. * Fix lint warning
  70. *
  71. * Oct 28 2009 mtk01104
  72. * [BORA00000018] Integrate WIFI part into BORA for the 1st time
  73. *
  74. **
  75. */
  76. /*******************************************************************************
  77. * C O M P I L E R F L A G S
  78. ********************************************************************************
  79. */
  80. /*******************************************************************************
  81. * E X T E R N A L R E F E R E N C E S
  82. ********************************************************************************
  83. */
  84. #include "precomp.h"
  85. /*******************************************************************************
  86. * C O N S T A N T S
  87. ********************************************************************************
  88. */
  89. /*******************************************************************************
  90. * D A T A T Y P E S
  91. ********************************************************************************
  92. */
  93. /*******************************************************************************
  94. * P U B L I C D A T A
  95. ********************************************************************************
  96. */
  97. /*******************************************************************************
  98. * P R I V A T E D A T A
  99. ********************************************************************************
  100. */
  101. /*******************************************************************************
  102. * M A C R O S
  103. ********************************************************************************
  104. */
  105. /*******************************************************************************
  106. * F U N C T I O N D E C L A R A T I O N S
  107. ********************************************************************************
  108. */
  109. /*******************************************************************************
  110. * F U N C T I O N S
  111. ********************************************************************************
  112. */
  113. /*----------------------------------------------------------------------------*/
  114. /*!
  115. * \brief This routine is called to set the time to do the time out check.
  116. *
  117. * \param[in] rTimeout Time out interval from current time.
  118. *
  119. * \retval TRUE Success.
  120. *
  121. */
  122. /*----------------------------------------------------------------------------*/
  123. static BOOLEAN cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout)
  124. {
  125. P_ROOT_TIMER prRootTimer;
  126. BOOLEAN fgNeedWakeLock;
  127. ASSERT(prAdapter);
  128. prRootTimer = &prAdapter->rRootTimer;
  129. kalSetTimer(prAdapter->prGlueInfo, rTimeout);
  130. if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) {
  131. fgNeedWakeLock = TRUE;
  132. if (!prRootTimer->fgWakeLocked) {
  133. KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock);
  134. prRootTimer->fgWakeLocked = TRUE;
  135. }
  136. } else {
  137. fgNeedWakeLock = FALSE;
  138. }
  139. return fgNeedWakeLock;
  140. }
  141. /*----------------------------------------------------------------------------*/
  142. /*!
  143. * \brief This routines is called to initialize a root timer.
  144. *
  145. * \param[in] prAdapter
  146. *
  147. * \return (none)
  148. */
  149. /*----------------------------------------------------------------------------*/
  150. VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter)
  151. {
  152. P_ROOT_TIMER prRootTimer;
  153. KAL_SPIN_LOCK_DECLARATION();
  154. ASSERT(prAdapter);
  155. prRootTimer = &prAdapter->rRootTimer;
  156. /* Note: glue layer have configured timer */
  157. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  158. LINK_INITIALIZE(&prRootTimer->rLinkHead);
  159. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  160. KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer");
  161. prRootTimer->fgWakeLocked = FALSE;
  162. }
  163. /*----------------------------------------------------------------------------*/
  164. /*!
  165. * \brief This routines is called to destroy a root timer.
  166. * When WIFI is off, the token shall be returned back to system.
  167. *
  168. * \param[in]
  169. *
  170. * \return (none)
  171. */
  172. /*----------------------------------------------------------------------------*/
  173. VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter)
  174. {
  175. P_ROOT_TIMER prRootTimer;
  176. KAL_SPIN_LOCK_DECLARATION();
  177. ASSERT(prAdapter);
  178. prRootTimer = &prAdapter->rRootTimer;
  179. if (prRootTimer->fgWakeLocked) {
  180. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  181. prRootTimer->fgWakeLocked = FALSE;
  182. }
  183. KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock);
  184. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  185. LINK_INITIALIZE(&prRootTimer->rLinkHead);
  186. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  187. /* Note: glue layer will be responsible for timer destruction */
  188. }
  189. /*----------------------------------------------------------------------------*/
  190. /*!
  191. * \brief This routines is called to initialize a timer.
  192. *
  193. * \param[in] prTimer Pointer to a timer structure.
  194. * \param[in] pfnFunc Pointer to the call back function.
  195. * \param[in] u4Data Parameter for call back function.
  196. *
  197. * \return (none)
  198. */
  199. /*----------------------------------------------------------------------------*/
  200. VOID cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData)
  201. {
  202. ASSERT(prAdapter);
  203. ASSERT(prTimer);
  204. #if DBG
  205. /* Note: NULL function pointer is permitted for HEM POWER */
  206. if (pfFunc == NULL)
  207. DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n");
  208. #endif
  209. #if DBG
  210. ASSERT(prAdapter->rRootTimer.rLinkHead.prNext);
  211. {
  212. P_LINK_T prTimerList;
  213. P_LINK_ENTRY_T prLinkEntry;
  214. P_TIMER_T prPendingTimer;
  215. prTimerList = &(prAdapter->rRootTimer.rLinkHead);
  216. LINK_FOR_EACH(prLinkEntry, prTimerList) {
  217. prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
  218. ASSERT(prPendingTimer);
  219. ASSERT(prPendingTimer != prTimer);
  220. }
  221. }
  222. #endif
  223. LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry);
  224. prTimer->pfMgmtTimeOutFunc = pfFunc;
  225. prTimer->ulData = ulData;
  226. }
  227. /*----------------------------------------------------------------------------*/
  228. /*!
  229. * \brief This routines is called to stop a timer.
  230. *
  231. * \param[in] prTimer Pointer to a timer structure.
  232. *
  233. * \return (none)
  234. */
  235. /*----------------------------------------------------------------------------*/
  236. static VOID cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock)
  237. {
  238. P_ROOT_TIMER prRootTimer;
  239. KAL_SPIN_LOCK_DECLARATION();
  240. ASSERT(prAdapter);
  241. ASSERT(prTimer);
  242. prRootTimer = &prAdapter->rRootTimer;
  243. if (fgAcquireSpinlock)
  244. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  245. if (timerPendingTimer(prTimer)) {
  246. LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry);
  247. /* Reduce dummy timeout for power saving, especially HIF activity.
  248. * If two or more timers exist and being removed timer is smallest,
  249. * this dummy timeout will still happen, but it is OK.
  250. */
  251. if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) {
  252. kalCancelTimer(prAdapter->prGlueInfo);
  253. if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) {
  254. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  255. prRootTimer->fgWakeLocked = FALSE;
  256. }
  257. }
  258. }
  259. if (fgAcquireSpinlock)
  260. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  261. }
  262. /*----------------------------------------------------------------------------*/
  263. /*!
  264. * \brief This routines is called to stop a timer.
  265. *
  266. * \param[in] prTimer Pointer to a timer structure.
  267. *
  268. * \return (none)
  269. */
  270. /*----------------------------------------------------------------------------*/
  271. VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer)
  272. {
  273. ASSERT(prAdapter);
  274. ASSERT(prTimer);
  275. cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE);
  276. }
  277. /*----------------------------------------------------------------------------*/
  278. /*!
  279. * \brief This routines is called to start a timer with wake_lock.
  280. *
  281. * \param[in] prTimer Pointer to a timer structure.
  282. * \param[in] u4TimeoutMs Timeout to issue the timer and call back function
  283. * (unit: ms).
  284. *
  285. * \return (none)
  286. */
  287. /*----------------------------------------------------------------------------*/
  288. VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs)
  289. {
  290. P_ROOT_TIMER prRootTimer;
  291. P_LINK_T prTimerList;
  292. OS_SYSTIME rExpiredSysTime, rTimeoutSystime;
  293. KAL_SPIN_LOCK_DECLARATION();
  294. ASSERT(prAdapter);
  295. ASSERT(prTimer);
  296. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  297. prRootTimer = &prAdapter->rRootTimer;
  298. prTimerList = &prRootTimer->rLinkHead;
  299. /* If timeout interval is larger than 1 minute, the mod value is set
  300. * to the timeout value first, then per minutue.
  301. */
  302. if (u4TimeoutMs > MSEC_PER_MIN) {
  303. ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN));
  304. prTimer->u2Minutes = (UINT_16) (u4TimeoutMs / MSEC_PER_MIN);
  305. u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN);
  306. if (u4TimeoutMs == 0) {
  307. u4TimeoutMs = MSEC_PER_MIN;
  308. prTimer->u2Minutes--;
  309. }
  310. } else {
  311. prTimer->u2Minutes = 0;
  312. }
  313. /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */
  314. ASSERT(u4TimeoutMs < (((UINT_32) 0x80000000 - MSEC_PER_SEC) / KAL_HZ));
  315. rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs);
  316. rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime;
  317. /* If no timer pending or the fast time interval is used. */
  318. if (LINK_IS_EMPTY(prTimerList) || TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
  319. prRootTimer->rNextExpiredSysTime = rExpiredSysTime;
  320. cnmTimerSetTimer(prAdapter, rTimeoutSystime);
  321. }
  322. /* Add this timer to checking list */
  323. prTimer->rExpiredSysTime = rExpiredSysTime;
  324. if (!timerPendingTimer(prTimer))
  325. LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
  326. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  327. }
  328. /*----------------------------------------------------------------------------*/
  329. /*!
  330. * \brief This routines is called to check the timer list.
  331. *
  332. * \param[in]
  333. *
  334. * \return (none)
  335. */
  336. /*----------------------------------------------------------------------------*/
  337. VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter)
  338. {
  339. P_ROOT_TIMER prRootTimer;
  340. P_LINK_T prTimerList;
  341. P_LINK_ENTRY_T prLinkEntry;
  342. P_TIMER_T prTimer;
  343. OS_SYSTIME rCurSysTime;
  344. PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc;
  345. ULONG ulTimeoutData;
  346. BOOLEAN fgNeedWakeLock;
  347. KAL_SPIN_LOCK_DECLARATION();
  348. ASSERT(prAdapter);
  349. /* acquire spin lock */
  350. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  351. prRootTimer = &prAdapter->rRootTimer;
  352. prTimerList = &prRootTimer->rLinkHead;
  353. rCurSysTime = kalGetTimeTick();
  354. /* Set the permitted max timeout value for new one */
  355. prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
  356. LINK_FOR_EACH(prLinkEntry, prTimerList) {
  357. prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
  358. ASSERT(prTimer);
  359. /* Check if this entry is timeout. */
  360. if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) {
  361. cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE);
  362. pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc;
  363. ulTimeoutData = prTimer->ulData;
  364. if (prTimer->u2Minutes > 0) {
  365. prTimer->u2Minutes--;
  366. prTimer->rExpiredSysTime = rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN);
  367. LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
  368. } else if (pfMgmtTimeOutFunc) {
  369. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  370. (pfMgmtTimeOutFunc) (prAdapter, ulTimeoutData);
  371. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  372. }
  373. /* Search entire list again because of nest del and add timers
  374. * and current MGMT_TIMER could be volatile after stopped
  375. */
  376. prLinkEntry = (P_LINK_ENTRY_T) prTimerList;
  377. prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
  378. } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
  379. prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime;
  380. }
  381. } /* end of for loop */
  382. /* Setup the prNext timeout event. It is possible the timer was already
  383. * set in the above timeout callback function.
  384. */
  385. fgNeedWakeLock = FALSE;
  386. if (!LINK_IS_EMPTY(prTimerList)) {
  387. ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime));
  388. fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME)
  389. ((INT_32) prRootTimer->rNextExpiredSysTime - (INT_32) rCurSysTime));
  390. }
  391. if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) {
  392. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  393. prRootTimer->fgWakeLocked = FALSE;
  394. }
  395. /* release spin lock */
  396. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  397. }