cnm_timer.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. ** 02 21 2013 cm.chang
  11. ** [BORA00002149] [MT6630 Wi-Fi] Initial software development
  12. ** Refine code to protect zero timeout interval like FW
  13. **
  14. ** 09 17 2012 cm.chang
  15. ** [BORA00002149] [MT6630 Wi-Fi] Initial software development
  16. ** Duplicate source from MT6620 v2.3 driver branch
  17. ** (Davinci label: MT6620_WIFI_Driver_V2_3_120913_1942_As_MT6630_Base)
  18. */
  19. /*******************************************************************************
  20. * C O M P I L E R F L A G S
  21. ********************************************************************************
  22. */
  23. /*******************************************************************************
  24. * E X T E R N A L R E F E R E N C E S
  25. ********************************************************************************
  26. */
  27. #include "precomp.h"
  28. /*******************************************************************************
  29. * C O N S T A N T S
  30. ********************************************************************************
  31. */
  32. /*******************************************************************************
  33. * D A T A T Y P E S
  34. ********************************************************************************
  35. */
  36. /*******************************************************************************
  37. * P U B L I C D A T A
  38. ********************************************************************************
  39. */
  40. /*******************************************************************************
  41. * P R I V A T E D A T A
  42. ********************************************************************************
  43. */
  44. /*******************************************************************************
  45. * M A C R O S
  46. ********************************************************************************
  47. */
  48. /*******************************************************************************
  49. * F U N C T I O N D E C L A R A T I O N S
  50. ********************************************************************************
  51. */
  52. /*******************************************************************************
  53. * F U N C T I O N S
  54. ********************************************************************************
  55. */
  56. /*----------------------------------------------------------------------------*/
  57. /*!
  58. * \brief This routine is called to set the time to do the time out check.
  59. *
  60. * \param[in] rTimeout Time out interval from current time.
  61. *
  62. * \retval TRUE Success.
  63. *
  64. */
  65. /*----------------------------------------------------------------------------*/
  66. static BOOLEAN cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout)
  67. {
  68. P_ROOT_TIMER prRootTimer;
  69. BOOLEAN fgNeedWakeLock;
  70. ASSERT(prAdapter);
  71. prRootTimer = &prAdapter->rRootTimer;
  72. kalSetTimer(prAdapter->prGlueInfo, rTimeout);
  73. if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) {
  74. fgNeedWakeLock = TRUE;
  75. if (!prRootTimer->fgWakeLocked) {
  76. KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock);
  77. prRootTimer->fgWakeLocked = TRUE;
  78. }
  79. } else {
  80. fgNeedWakeLock = FALSE;
  81. }
  82. return fgNeedWakeLock;
  83. }
  84. /*----------------------------------------------------------------------------*/
  85. /*!
  86. * \brief This routines is called to initialize a root timer.
  87. *
  88. * \param[in] prAdapter
  89. *
  90. * \return (none)
  91. */
  92. /*----------------------------------------------------------------------------*/
  93. VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter)
  94. {
  95. P_ROOT_TIMER prRootTimer;
  96. KAL_SPIN_LOCK_DECLARATION();
  97. ASSERT(prAdapter);
  98. prRootTimer = &prAdapter->rRootTimer;
  99. /* Note: glue layer have configured timer */
  100. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  101. LINK_INITIALIZE(&prRootTimer->rLinkHead);
  102. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  103. KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer");
  104. prRootTimer->fgWakeLocked = FALSE;
  105. }
  106. /*----------------------------------------------------------------------------*/
  107. /*!
  108. * \brief This routines is called to destroy a root timer.
  109. * When WIFI is off, the token shall be returned back to system.
  110. *
  111. * \param[in]
  112. *
  113. * \return (none)
  114. */
  115. /*----------------------------------------------------------------------------*/
  116. VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter)
  117. {
  118. P_ROOT_TIMER prRootTimer;
  119. KAL_SPIN_LOCK_DECLARATION();
  120. ASSERT(prAdapter);
  121. prRootTimer = &prAdapter->rRootTimer;
  122. if (prRootTimer->fgWakeLocked) {
  123. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  124. prRootTimer->fgWakeLocked = FALSE;
  125. }
  126. KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock);
  127. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  128. LINK_INITIALIZE(&prRootTimer->rLinkHead);
  129. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  130. /* Note: glue layer will be responsible for timer destruction */
  131. }
  132. /*----------------------------------------------------------------------------*/
  133. /*!
  134. * \brief This routines is called to initialize a timer.
  135. *
  136. * \param[in] prTimer Pointer to a timer structure.
  137. * \param[in] pfnFunc Pointer to the call back function.
  138. * \param[in] u4Data Parameter for call back function.
  139. *
  140. * \return (none)
  141. */
  142. /*----------------------------------------------------------------------------*/
  143. VOID
  144. cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulDataPtr)
  145. {
  146. ASSERT(prAdapter);
  147. ASSERT(prTimer);
  148. #if DBG
  149. /* Note: NULL function pointer is permitted for HEM POWER */
  150. if (pfFunc == NULL)
  151. DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n");
  152. #endif
  153. #if DBG
  154. ASSERT(prAdapter->rRootTimer.rLinkHead.prNext);
  155. {
  156. P_LINK_T prTimerList;
  157. P_LINK_ENTRY_T prLinkEntry;
  158. P_TIMER_T prPendingTimer;
  159. prTimerList = &(prAdapter->rRootTimer.rLinkHead);
  160. LINK_FOR_EACH(prLinkEntry, prTimerList) {
  161. prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
  162. ASSERT(prPendingTimer);
  163. ASSERT(prPendingTimer != prTimer);
  164. }
  165. }
  166. #endif
  167. LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry);
  168. prTimer->pfMgmtTimeOutFunc = pfFunc;
  169. prTimer->ulDataPtr = ulDataPtr;
  170. }
  171. /*----------------------------------------------------------------------------*/
  172. /*!
  173. * \brief This routines is called to stop a timer.
  174. *
  175. * \param[in] prTimer Pointer to a timer structure.
  176. *
  177. * \return (none)
  178. */
  179. /*----------------------------------------------------------------------------*/
  180. static VOID cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock)
  181. {
  182. P_ROOT_TIMER prRootTimer;
  183. KAL_SPIN_LOCK_DECLARATION();
  184. ASSERT(prAdapter);
  185. ASSERT(prTimer);
  186. prRootTimer = &prAdapter->rRootTimer;
  187. if (fgAcquireSpinlock)
  188. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  189. if (timerPendingTimer(prTimer)) {
  190. LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry);
  191. /* Reduce dummy timeout for power saving, especially HIF activity.
  192. * If two or more timers exist and being removed timer is smallest,
  193. * this dummy timeout will still happen, but it is OK.
  194. */
  195. if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) {
  196. kalCancelTimer(prAdapter->prGlueInfo);
  197. if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) {
  198. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  199. prRootTimer->fgWakeLocked = FALSE;
  200. }
  201. }
  202. }
  203. if (fgAcquireSpinlock)
  204. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  205. }
  206. /*----------------------------------------------------------------------------*/
  207. /*!
  208. * \brief This routines is called to stop a timer.
  209. *
  210. * \param[in] prTimer Pointer to a timer structure.
  211. *
  212. * \return (none)
  213. */
  214. /*----------------------------------------------------------------------------*/
  215. VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer)
  216. {
  217. ASSERT(prAdapter);
  218. ASSERT(prTimer);
  219. cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE);
  220. }
  221. /*----------------------------------------------------------------------------*/
  222. /*!
  223. * \brief This routines is called to start a timer with wake_lock.
  224. *
  225. * \param[in] prTimer Pointer to a timer structure.
  226. * \param[in] u4TimeoutMs Timeout to issue the timer and call back function
  227. * (unit: ms).
  228. *
  229. * \return (none)
  230. */
  231. /*----------------------------------------------------------------------------*/
  232. VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs)
  233. {
  234. P_ROOT_TIMER prRootTimer;
  235. P_LINK_T prTimerList;
  236. OS_SYSTIME rExpiredSysTime, rTimeoutSystime;
  237. KAL_SPIN_LOCK_DECLARATION();
  238. ASSERT(prAdapter);
  239. ASSERT(prTimer);
  240. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  241. prRootTimer = &prAdapter->rRootTimer;
  242. prTimerList = &prRootTimer->rLinkHead;
  243. /* If timeout interval is larger than 1 minute, the mod value is set
  244. * to the timeout value first, then per minutue.
  245. */
  246. if (u4TimeoutMs > MSEC_PER_MIN) {
  247. ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN));
  248. prTimer->u2Minutes = (UINT_16) (u4TimeoutMs / MSEC_PER_MIN);
  249. u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN);
  250. if (u4TimeoutMs == 0) {
  251. u4TimeoutMs = MSEC_PER_MIN;
  252. prTimer->u2Minutes--;
  253. }
  254. } else {
  255. prTimer->u2Minutes = 0;
  256. }
  257. /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */
  258. ASSERT(u4TimeoutMs < (((UINT_32) 0x80000000 - MSEC_PER_SEC) / KAL_HZ));
  259. rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs);
  260. if (rTimeoutSystime == 0)
  261. rTimeoutSystime = 1;
  262. rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime;
  263. /* If no timer pending or the fast time interval is used. */
  264. if (LINK_IS_EMPTY(prTimerList) || TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
  265. prRootTimer->rNextExpiredSysTime = rExpiredSysTime;
  266. cnmTimerSetTimer(prAdapter, rTimeoutSystime);
  267. }
  268. /* Add this timer to checking list */
  269. prTimer->rExpiredSysTime = rExpiredSysTime;
  270. if (!timerPendingTimer(prTimer))
  271. LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
  272. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  273. }
  274. /*----------------------------------------------------------------------------*/
  275. /*!
  276. * \brief This routines is called to check the timer list.
  277. *
  278. * \param[in]
  279. *
  280. * \return (none)
  281. */
  282. /*----------------------------------------------------------------------------*/
  283. VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter)
  284. {
  285. P_ROOT_TIMER prRootTimer;
  286. P_LINK_T prTimerList;
  287. P_LINK_ENTRY_T prLinkEntry;
  288. P_TIMER_T prTimer;
  289. OS_SYSTIME rCurSysTime;
  290. PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc;
  291. ULONG ulTimeoutDataPtr;
  292. BOOLEAN fgNeedWakeLock;
  293. KAL_SPIN_LOCK_DECLARATION();
  294. ASSERT(prAdapter);
  295. /* acquire spin lock */
  296. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  297. prRootTimer = &prAdapter->rRootTimer;
  298. prTimerList = &prRootTimer->rLinkHead;
  299. rCurSysTime = kalGetTimeTick();
  300. /* Set the permitted max timeout value for new one */
  301. prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
  302. LINK_FOR_EACH(prLinkEntry, prTimerList) {
  303. prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry);
  304. ASSERT(prTimer);
  305. /* Check if this entry is timeout. */
  306. if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) {
  307. cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE);
  308. pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc;
  309. ulTimeoutDataPtr = prTimer->ulDataPtr;
  310. if (prTimer->u2Minutes > 0) {
  311. prTimer->u2Minutes--;
  312. prTimer->rExpiredSysTime = rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN);
  313. LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry);
  314. } else if (pfMgmtTimeOutFunc) {
  315. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  316. (pfMgmtTimeOutFunc) (prAdapter, ulTimeoutDataPtr);
  317. KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  318. }
  319. /* Search entire list again because of nest del and add timers
  320. * and current MGMT_TIMER could be volatile after stopped
  321. */
  322. prLinkEntry = (P_LINK_ENTRY_T) prTimerList;
  323. prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL;
  324. } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) {
  325. prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime;
  326. }
  327. } /* end of for loop */
  328. /* Setup the prNext timeout event. It is possible the timer was already
  329. * set in the above timeout callback function.
  330. */
  331. fgNeedWakeLock = FALSE;
  332. if (!LINK_IS_EMPTY(prTimerList)) {
  333. ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime));
  334. fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME)
  335. ((INT_32) prRootTimer->rNextExpiredSysTime - (INT_32) rCurSysTime));
  336. }
  337. if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) {
  338. KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock);
  339. prRootTimer->fgWakeLocked = FALSE;
  340. }
  341. /* release spin lock */
  342. KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER);
  343. }