blob: 324a5d2e6dca3aaed71b206d0069d68d100bbf24 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Abdul Muqtadeer Ahmedc295fa82021-02-16 10:07:32 +05302 * Copyright (c) 2012-2013, 2015-2021 The Linux Foundation. All rights reserved.
Kiet Lam988a5522014-02-19 01:15:45 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
Gopichand Nakkala9c070ad2013-01-08 21:16:34 -080020 */
Kiet Lam988a5522014-02-19 01:15:45 -080021
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
Jeff Johnson295189b2012-06-20 16:38:30 -070028/**=========================================================================
Jeff Johnson14a9d382013-02-22 21:25:10 -080029
Jeff Johnson295189b2012-06-20 16:38:30 -070030 \file vos_timer.c
Jeff Johnson14a9d382013-02-22 21:25:10 -080031
Jeff Johnson295189b2012-06-20 16:38:30 -070032 \brief virtual Operating System Servies (vOS)
Jeff Johnson14a9d382013-02-22 21:25:10 -080033
Jeff Johnson295189b2012-06-20 16:38:30 -070034 Definitions for vOSS Timer services
Jeff Johnson295189b2012-06-20 16:38:30 -070035 ========================================================================*/
36
37/* $Header$ */
38
39/*--------------------------------------------------------------------------
40 Include Files
41 ------------------------------------------------------------------------*/
42#include <vos_timer.h>
43#include <vos_lock.h>
44#include <vos_api.h>
45#include "wlan_qct_sys.h"
46#include "vos_sched.h"
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +053047#include <linux/wcnss_wlan.h>
Jeff Johnson295189b2012-06-20 16:38:30 -070048
49/*--------------------------------------------------------------------------
50 Preprocessor definitions and constants
51 ------------------------------------------------------------------------*/
52
53#define LINUX_TIMER_COOKIE 0x12341234
54#define LINUX_INVALID_TIMER_COOKIE 0xfeedface
55#define TMR_INVALID_ID ( 0 )
56
57/*--------------------------------------------------------------------------
58 Type declarations
59 ------------------------------------------------------------------------*/
60
61/*----------------------------------------------------------------------------
62 * Static Variable Definitions
63 * -------------------------------------------------------------------------*/
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -070064static unsigned int persistentTimerCount;
Jeff Johnson295189b2012-06-20 16:38:30 -070065static vos_lock_t persistentTimerCountLock;
66// static sleep_okts_handle sleepClientHandle;
67
68/*-------------------------------------------------------------------------
69 Function declarations and documenation
70 ------------------------------------------------------------------------*/
71// TBD: Need to add code for deferred timers implementation
72
73// clean up timer states after it has been deactivated
74// check and try to allow sleep after a timer has been stopped or expired
75static void tryAllowingSleep( VOS_TIMER_TYPE type )
76{
77 if ( VOS_TIMER_TYPE_WAKE_APPS == type )
78 {
79 // vos_lock_acquire( &persistentTimerCountLock );
80 persistentTimerCount--;
81 if ( 0 == persistentTimerCount )
82 {
83 // since the number of persistent timers has decreased from 1 to 0,
84 // the timer should allow sleep
85 //sleep_assert_okts( sleepClientHandle );
86 }
87 //vos_lock_release( &persistentTimerCountLock );
88 }
89}
90
91
92/*----------------------------------------------------------------------------
Jeff Johnson295189b2012-06-20 16:38:30 -070093
Jeff Johnson9a2f5832013-10-26 19:17:13 -070094 \brief vos_linux_timer_callback() - internal vos entry point which is
95 called when the timer interval expires
Jeff Johnson295189b2012-06-20 16:38:30 -070096
Jeff Johnson9a2f5832013-10-26 19:17:13 -070097 This function in turn calls the vOS client callback and changes the
98 state of the timer from running (ACTIVE) to expired (INIT).
Jeff Johnson295189b2012-06-20 16:38:30 -070099
Jeff Johnson295189b2012-06-20 16:38:30 -0700100
Jeff Johnson9a2f5832013-10-26 19:17:13 -0700101 \param data - pointer to the timer control block which describes the
102 timer that expired
Jeff Johnson295189b2012-06-20 16:38:30 -0700103
Jeff Johnson295189b2012-06-20 16:38:30 -0700104 \return nothing
Jeff Johnson9a2f5832013-10-26 19:17:13 -0700105
106 Note: function signature is defined by the Linux kernel. The fact
107 that the argument is "unsigned long" instead of "void *" is
108 unfortunately imposed upon us. But we can safely pass a pointer via
109 this parameter for LP32 and LP64 architectures.
110
Jeff Johnson295189b2012-06-20 16:38:30 -0700111 --------------------------------------------------------------------------*/
112
Abdul Muqtadeer Ahmedc295fa82021-02-16 10:07:32 +0530113static void vos_linux_timer_callback(vos_timer_t *timer)
Jeff Johnson295189b2012-06-20 16:38:30 -0700114{
Jeff Johnson295189b2012-06-20 16:38:30 -0700115 vos_msg_t msg;
116 VOS_STATUS vStatus;
117 unsigned long flags;
118
119 vos_timer_callback_t callback=NULL;
120 v_PVOID_t userData=NULL;
121 int threadId;
122 VOS_TIMER_TYPE type=VOS_TIMER_TYPE_SW;
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +0530123 v_CONTEXT_t vos_context = NULL;
124 pVosContextType vos_global_context;
125 vos_wdthread_timer_work_t *wdthread_timer_work;
126
Jeff Johnson295189b2012-06-20 16:38:30 -0700127 VOS_ASSERT(timer);
128
129 if (timer == NULL)
130 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700131 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s Null pointer passed in!",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700132 return;
133 }
134
135 threadId = timer->platformInfo.threadID;
136 spin_lock_irqsave( &timer->platformInfo.spinlock,flags );
137
138 switch ( timer->state )
139 {
140 case VOS_TIMER_STATE_STARTING:
141 // we are in this state because someone just started the timer, MM timer
142 // got started and expired, but the time content have not bee updated
143 // this is a rare race condition!
144 timer->state = VOS_TIMER_STATE_STOPPED;
145 vStatus = VOS_STATUS_E_ALREADY;
146 break;
147 case VOS_TIMER_STATE_STOPPED:
148 vStatus = VOS_STATUS_E_ALREADY;
149 break;
150 case VOS_TIMER_STATE_UNUSED:
151 vStatus = VOS_STATUS_E_EXISTS;
152 break;
153 case VOS_TIMER_STATE_RUNNING:
154 // need to go to stop state here because the call-back function may restart
155 // timer (to emulate periodic timer)
156 timer->state = VOS_TIMER_STATE_STOPPED;
157 // copy the relevant timer information to local variables;
158 // once we exist from this critical section, the timer content may be modified
159 // by other tasks
160 callback = timer->callback;
161 userData = timer->userData;
162 threadId = timer->platformInfo.threadID;
163 type = timer->type;
164 vStatus = VOS_STATUS_SUCCESS;
165 break;
166 default:
167 VOS_ASSERT(0);
168 vStatus = VOS_STATUS_E_FAULT;
169 break;
170 }
171
172 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
173
174 if ( VOS_STATUS_SUCCESS != vStatus )
175 {
176 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
177 "TIMER callback called in a wrong state=%d", timer->state);
178 return;
179 }
180
181 tryAllowingSleep( type );
182
Manjunathappa Prakash6172f582013-12-23 19:07:07 -0800183 if (callback == NULL)
184 {
185 VOS_ASSERT(0);
186 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
187 "%s: No TIMER callback, Could not enqueue timer to any queue",
188 __func__);
189 return;
190 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700191
192 // If timer has expired then call vos_client specific callback
193 if ( vos_sched_is_tx_thread( threadId ) )
194 {
195 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
196 "TIMER callback: running on TX thread");
197
198 //Serialize to the Tx thread
199 sysBuildMessageHeader( SYS_MSG_ID_TX_TIMER, &msg );
Jeff Johnson88aaa562013-12-09 09:19:48 -0800200 msg.callback = callback;
201 msg.bodyptr = userData;
202 msg.bodyval = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700203
204 if(vos_tx_mq_serialize( VOS_MQ_ID_SYS, &msg ) == VOS_STATUS_SUCCESS)
205 return;
206 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700207 else if ( vos_sched_is_rx_thread( threadId ) )
208 {
209 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
210 "TIMER callback: running on RX thread");
211
212 //Serialize to the Rx thread
213 sysBuildMessageHeader( SYS_MSG_ID_RX_TIMER, &msg );
Jeff Johnson88aaa562013-12-09 09:19:48 -0800214 msg.callback = callback;
215 msg.bodyptr = userData;
216 msg.bodyval = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700217
218 if(vos_rx_mq_serialize( VOS_MQ_ID_SYS, &msg ) == VOS_STATUS_SUCCESS)
219 return;
220 }
Abhishek Singh880d7122015-08-26 16:23:04 +0530221#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
Abhishek Singhe7ea25c2015-11-23 16:23:24 +0530222 else if (vos_is_wd_thread(threadId))
Abhishek Singh880d7122015-08-26 16:23:04 +0530223 {
224 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
Abhishek Singhe7ea25c2015-11-23 16:23:24 +0530225 "TIMER callback: running on wd thread");
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +0530226 vos_context = vos_get_global_context(VOS_MODULE_ID_HDD, NULL);
227 if(!vos_context)
228 {
229 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
230 "%s: Global VOS context is Null", __func__);
231 return;
232 }
233 vos_global_context = (pVosContextType)vos_context;
234 wdthread_timer_work = vos_mem_malloc(sizeof(*wdthread_timer_work));
235 if (NULL == wdthread_timer_work) {
236 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
237 "%s: No memory available", __func__);
238 return;
239 }
240 wdthread_timer_work->callback = callback;
241 wdthread_timer_work->userData = userData;
242 spin_lock(&vos_global_context->wdthread_work_lock);
243 list_add(&wdthread_timer_work->node,
244 &vos_global_context->wdthread_timer_work_list);
245 spin_unlock(&vos_global_context->wdthread_work_lock);
246
247 schedule_work(&vos_global_context->wdthread_work);
Abhishek Singh880d7122015-08-26 16:23:04 +0530248 return;
249 }
250#endif
251 else
Jeff Johnson295189b2012-06-20 16:38:30 -0700252 {
253 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
254 "TIMER callback: running on MC thread");
255
256 // Serialize to the MC thread
257 sysBuildMessageHeader( SYS_MSG_ID_MC_TIMER, &msg );
Jeff Johnson88aaa562013-12-09 09:19:48 -0800258 msg.callback = callback;
259 msg.bodyptr = userData;
260 msg.bodyval = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700261
262 if(vos_mq_post_message( VOS_MQ_ID_SYS, &msg ) == VOS_STATUS_SUCCESS)
263 return;
Abhishek Singh880d7122015-08-26 16:23:04 +0530264 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700265
266 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
267 "%s: Could not enqueue timer to any queue", __func__);
268 VOS_ASSERT(0);
269}
270
271/*---------------------------------------------------------------------------
272
273 \brief vos_timer_getCurrentState() - Get the current state of the timer
274
275 \param pTimer - the timer object
276
277 \return timer state
278
279 \sa
280
281---------------------------------------------------------------------------*/
282VOS_TIMER_STATE vos_timer_getCurrentState( vos_timer_t *pTimer )
283{
284 if ( NULL == pTimer )
285 {
286 VOS_ASSERT(0);
287 return VOS_TIMER_STATE_UNUSED;
288 }
289
290 switch ( pTimer->state )
291 {
292 case VOS_TIMER_STATE_STOPPED:
293 case VOS_TIMER_STATE_STARTING:
294 case VOS_TIMER_STATE_RUNNING:
295 case VOS_TIMER_STATE_UNUSED:
296 return pTimer->state;
297 default:
298 VOS_ASSERT(0);
299 return VOS_TIMER_STATE_UNUSED;
300 }
301}
302
303/*----------------------------------------------------------------------------
304
305 \brief vos_timer_module_init() - Initializes a vOSS timer module.
306
307 This API initializes the VOSS timer module. This needs to be called
308 exactly once prior to using any VOSS timers.
309
310 \sa
311
312 --------------------------------------------------------------------------*/
313
314void vos_timer_module_init( void )
315{
316 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
317 "Initializing the VOSS timer module");
318 vos_lock_init( &persistentTimerCountLock );
319}
320
321#ifdef TIMER_MANAGER
322#include "wlan_hdd_dp_utils.h"
323
324hdd_list_t vosTimerList;
325
326static void vos_timer_clean(void);
327
328void vos_timer_manager_init()
329{
330 /* Initalizing the list with maximum size of 60000 */
331 hdd_list_init(&vosTimerList, 1000);
332 return;
333}
334
335static void vos_timer_clean()
336{
337 v_SIZE_t listSize;
338 unsigned long flags;
339
340 hdd_list_size(&vosTimerList, &listSize);
341
342 if (listSize)
343 {
344 hdd_list_node_t* pNode;
345 VOS_STATUS vosStatus;
346
347 timer_node_t *ptimerNode;
348 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
349 "%s: List is not Empty. listSize %d ",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700350 __func__, (int)listSize);
Jeff Johnson295189b2012-06-20 16:38:30 -0700351
352 do
353 {
354 spin_lock_irqsave(&vosTimerList.lock, flags);
355 vosStatus = hdd_list_remove_front(&vosTimerList, &pNode);
356 spin_unlock_irqrestore(&vosTimerList.lock, flags);
357 if (VOS_STATUS_SUCCESS == vosStatus)
358 {
359 ptimerNode = (timer_node_t*)pNode;
360 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
361 "Timer Leak@ File %s, @Line %d",
362 ptimerNode->fileName, (int)ptimerNode->lineNum);
363
364 vos_mem_free(ptimerNode);
365 }
366 } while (vosStatus == VOS_STATUS_SUCCESS);
367 }
368}
369
370void vos_timer_exit()
371{
372 vos_timer_clean();
373 hdd_list_destroy(&vosTimerList);
374}
375#endif
376
Abdul Muqtadeer Ahmedc295fa82021-02-16 10:07:32 +0530377#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
378static void vos_timer_shim(struct timer_list *vos_timer)
379{
380 vos_timer_platform_t *platformInfo_ptr = container_of(vos_timer,
381 vos_timer_platform_t,
382 Timer);
383
384 vos_timer_t *timer = container_of(platformInfo_ptr, vos_timer_t,
385 platformInfo);
386
387 vos_linux_timer_callback(timer);
388}
389
390static void vos_timer_setup(vos_timer_t *timer, bool deferrable)
391{
392 uint32_t flags = 0;
393
394 if (deferrable)
395 flags |= TIMER_DEFERRABLE;
396 timer_setup(&(timer->platformInfo.Timer), vos_timer_shim,
397 flags);
398}
399#else
400static void vos_timer_shim(unsigned long data)
401{
402 vos_timer_t *timer = (vos_timer_t *)data;
403
404 vos_linux_timer_callback(timer);
405}
406
407static void vos_timer_setup(vos_timer_t *timer, bool deferrable)
408{
409 if (deferrable)
410 init_timer_deferrable(&timer->platformInfo.Timer);
411 else
412 init_timer(&timer->platformInfo.Timer);
413 timer->platformInfo.Timer.function = vos_timer_shim;
414 timer->platformInfo.Timer.data = (unsigned long)timer;
415}
416#endif
417
Jeff Johnson295189b2012-06-20 16:38:30 -0700418/*--------------------------------------------------------------------------
419
420 \brief vos_timer_init() - Initialize a vOSS timer.
421
422 This API initializes a vOS Timer object.
423
424 The \a vos_timer_init() initializes a vOS Timer object. A timer must be
425 initialized by calling vos_timer_initialize() before it may be used in
426 any other timer functions.
427
428 Attempting to initialize timer that is already initialized results in
429 a failure. A destroyed timer object can be re-initialized with a call to
430 \a vos_timer_init(). The results of otherwise referencing the object
431 after it has been destroyed are undefined.
432
433 Calls to vOSS timer functions to manipulate the timer such
434 as vos_timer_set() will fail if the timer is not initialized or has
435 been destroyed. Therefore, don't use the timer after it has been
436 destroyed until it has been re-initialized.
437
438 All callback will be executed within the VOS main thread unless it is
439 initialized from the Tx thread flow, in which case it will be executed
440 within the tx thread flow.
441
442 \param timer - pointer to the opaque timer object to initialize
443
444 \param timerType - specifies the type of timer. We have two different
445 timer types.
446 <ol>
447 <li> VOS_TIMER_TYPE_SW - Pure software timer. The Apps processor
448 may not be awoken when this timer expires.
449 <li> VOS_TIMER_TYPE_WAKE_APPS - The Apps processor will be awoken
450 from power collapse when this type of timer expires.
451 </ol>
452
453 \param callback - the callback function to be called when the timer
454 expires.
455
456 \param userData - a user data (or context) that is returned to the
457 callback function as a parameter when the timer expires.
458
459 \return VOS_STATUS_SUCCESS - timer was successfully initialized and
460 is ready to be used.
461
462 VOS_STATUS_E_RESOURCES - System resources (other than memory)
463 are unavailable to initialize the timer
464
465 VOS_STATUS_E_NOMEM - insufficient memory exists to initialize
466 the timer
467
468 VOS_STATUS_E_BUSY - The implementation has detected an attempt
469 to initialize the object referenced by timer, a previously
470 initialized but not yet destroyed timer.
471
472 VOS_STATUS_E_FAULT - timer is an invalid pointer.
473 \sa
474
475---------------------------------------------------------------------------*/
476#ifdef TIMER_MANAGER
Abhishek Singh92d0a062016-02-26 14:47:41 +0530477static inline VOS_STATUS __vos_timer_init_debug(vos_timer_t *timer,
478 VOS_TIMER_TYPE timerType,
479 vos_timer_callback_t callback,
480 v_PVOID_t userData,
481 bool deferrable,
482 char* fileName,
483 v_U32_t lineNum)
Jeff Johnson295189b2012-06-20 16:38:30 -0700484{
485 VOS_STATUS vosStatus;
486 unsigned long flags;
487 // Check for invalid pointer
Abhishek Singh92d0a062016-02-26 14:47:41 +0530488 if ((timer == NULL) || (callback == NULL))
Jeff Johnson295189b2012-06-20 16:38:30 -0700489 {
Abhishek Singh92d0a062016-02-26 14:47:41 +0530490 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700491 "%s: Null params being passed",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700492 VOS_ASSERT(0);
493 return VOS_STATUS_E_FAULT;
494 }
495
496 timer->ptimerNode = vos_mem_malloc(sizeof(timer_node_t));
497
Abhishek Singh92d0a062016-02-26 14:47:41 +0530498 if (timer->ptimerNode == NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700499 {
500 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Abhishek Singh92d0a062016-02-26 14:47:41 +0530501 "%s: Not able to allocate memory for timeNode",
502 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700503 VOS_ASSERT(0);
504 return VOS_STATUS_E_FAULT;
505 }
506
507 vos_mem_set(timer->ptimerNode, sizeof(timer_node_t), 0);
508
509 timer->ptimerNode->fileName = fileName;
510 timer->ptimerNode->lineNum = lineNum;
511 timer->ptimerNode->vosTimer = timer;
512
513 spin_lock_irqsave(&vosTimerList.lock, flags);
514 vosStatus = hdd_list_insert_front(&vosTimerList, &timer->ptimerNode->pNode);
515 spin_unlock_irqrestore(&vosTimerList.lock, flags);
Abhishek Singh92d0a062016-02-26 14:47:41 +0530516 if (VOS_STATUS_SUCCESS != vosStatus)
Jeff Johnson295189b2012-06-20 16:38:30 -0700517 {
518 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Abhishek Singh92d0a062016-02-26 14:47:41 +0530519 "%s: Unable to insert node into List vosStatus %d",
520 __func__, vosStatus);
Jeff Johnson295189b2012-06-20 16:38:30 -0700521 }
Abhishek Singh92d0a062016-02-26 14:47:41 +0530522
523 /* set the various members of the timer structure
524 * with arguments passed or with default values
525 */
Jeff Johnson295189b2012-06-20 16:38:30 -0700526 spin_lock_init(&timer->platformInfo.spinlock);
Abdul Muqtadeer Ahmedc295fa82021-02-16 10:07:32 +0530527 vos_timer_setup(timer, deferrable);
Abhishek Singh92d0a062016-02-26 14:47:41 +0530528 timer->callback = callback;
529 timer->userData = userData;
530 timer->type = timerType;
531 timer->platformInfo.cookie = LINUX_TIMER_COOKIE;
532 timer->platformInfo.threadID = 0;
533 timer->state = VOS_TIMER_STATE_STOPPED;
534
535 return VOS_STATUS_SUCCESS;
536}
537
538VOS_STATUS vos_timer_init_debug(vos_timer_t *timer,
539 VOS_TIMER_TYPE timerType,
540 vos_timer_callback_t callback,
541 v_PVOID_t userData,
542 char* fileName,
543 v_U32_t lineNum)
544{
545 return __vos_timer_init_debug(timer, timerType,
546 callback, userData, false, fileName, lineNum);
547}
548
549VOS_STATUS vos_timer_init_deferrable_debug(vos_timer_t *timer,
550 VOS_TIMER_TYPE timerType,
551 vos_timer_callback_t callback,
552 v_PVOID_t userData,
553 char* fileName,
554 v_U32_t lineNum)
555{
556 return __vos_timer_init_debug(timer, timerType,
557 callback, userData, true, fileName, lineNum);
558}
559#else
560static inline VOS_STATUS __vos_timer_init(vos_timer_t *timer,
561 VOS_TIMER_TYPE timerType,
562 vos_timer_callback_t callback,
563 v_PVOID_t userData,
564 bool deferrable)
565{
566 /* Check for invalid pointer */
567 if ((timer == NULL) || (callback == NULL))
568 {
569 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
570 "%s: Null params being passed",__func__);
571 VOS_ASSERT(0);
572 return VOS_STATUS_E_FAULT;
573 }
574
575 /* set the various members of the timer structure
576 * with arguments passed or with default values
577 */
578 spin_lock_init(&timer->platformInfo.spinlock);
Abdul Muqtadeer Ahmedc295fa82021-02-16 10:07:32 +0530579 vos_timer_setup(timer, deferrable);
Jeff Johnson295189b2012-06-20 16:38:30 -0700580 timer->callback = callback;
581 timer->userData = userData;
582 timer->type = timerType;
583 timer->platformInfo.cookie = LINUX_TIMER_COOKIE;
584 timer->platformInfo.threadID = 0;
585 timer->state = VOS_TIMER_STATE_STOPPED;
586
587 return VOS_STATUS_SUCCESS;
588}
Abhishek Singh92d0a062016-02-26 14:47:41 +0530589VOS_STATUS vos_timer_init(vos_timer_t *timer,
590 VOS_TIMER_TYPE timerType,
591 vos_timer_callback_t callback,
592 v_PVOID_t userData)
Jeff Johnson295189b2012-06-20 16:38:30 -0700593{
Abhishek Singh92d0a062016-02-26 14:47:41 +0530594 return __vos_timer_init(timer, timerType,
595 callback, userData, false);
596
597}
598
599VOS_STATUS vos_timer_init_deferrable(vos_timer_t *timer,
600 VOS_TIMER_TYPE timerType,
601 vos_timer_callback_t callback,
602 v_PVOID_t userData)
603{
604 return __vos_timer_init(timer, timerType,
605 callback, userData, true);
Jeff Johnson295189b2012-06-20 16:38:30 -0700606}
607#endif
608
609
610/*---------------------------------------------------------------------------
611
612 \brief vos_timer_destroy() - Destroy a vOSS Timer object
613
614 The \a vos_timer_destroy() function shall destroy the timer object.
615 After a successful return from \a vos_timer_destroy() the timer
616 object becomes, in effect, uninitialized.
617
618 A destroyed timer object can be re-initialized by calling
619 vos_timer_init(). The results of otherwise referencing the object
620 after it has been destroyed are undefined.
621
622 Calls to vOSS timer functions to manipulate the timer, such
623 as vos_timer_set() will fail if the lock is destroyed. Therefore,
624 don't use the timer after it has been destroyed until it has
625 been re-initialized.
626
627 \param timer - the timer object to be destroyed.
628
629 \return VOS_STATUS_SUCCESS - timer was successfully destroyed.
630
631 VOS_STATUS_E_BUSY - The implementation has detected an attempt
632 to destroy the object referenced by timer while it is still
633 still referenced. The timer must be stopped before it can be
634 destroyed.
635
636 VOS_STATUS_E_INVAL - The value specified by timer is invalid.
637
638 VOS_STATUS_E_FAULT - timer is an invalid pointer.
639 \sa
640
641---------------------------------------------------------------------------*/
642#ifdef TIMER_MANAGER
643VOS_STATUS vos_timer_destroy ( vos_timer_t *timer )
644{
645 VOS_STATUS vStatus=VOS_STATUS_SUCCESS;
646 unsigned long flags;
647
648 // Check for invalid pointer
649 if ( NULL == timer )
650 {
651 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700652 "%s: Null timer pointer being passed",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700653 VOS_ASSERT(0);
654 return VOS_STATUS_E_FAULT;
655 }
656
657 // Check if timer refers to an uninitialized object
658 if ( LINUX_TIMER_COOKIE != timer->platformInfo.cookie )
659 {
660 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700661 "%s: Cannot destroy uninitialized timer",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700662 return VOS_STATUS_E_INVAL;
663 }
664
665 spin_lock_irqsave(&vosTimerList.lock, flags);
666 vStatus = hdd_list_remove_node(&vosTimerList, &timer->ptimerNode->pNode);
667 spin_unlock_irqrestore(&vosTimerList.lock, flags);
668 if(vStatus != VOS_STATUS_SUCCESS)
669 {
670 VOS_ASSERT(0);
671 return VOS_STATUS_E_INVAL;
672 }
673 vos_mem_free(timer->ptimerNode);
674
675
676 spin_lock_irqsave( &timer->platformInfo.spinlock,flags );
677
678 switch ( timer->state )
679 {
680 case VOS_TIMER_STATE_STARTING:
681 vStatus = VOS_STATUS_E_BUSY;
682 break;
683 case VOS_TIMER_STATE_RUNNING:
684 /* Stop the timer first */
685 del_timer(&(timer->platformInfo.Timer));
686 vStatus = VOS_STATUS_SUCCESS;
687 break;
688 case VOS_TIMER_STATE_STOPPED:
689 vStatus = VOS_STATUS_SUCCESS;
690 break;
691 case VOS_TIMER_STATE_UNUSED:
692 vStatus = VOS_STATUS_E_ALREADY;
693 break;
694 default:
695 vStatus = VOS_STATUS_E_FAULT;
696 break;
697 }
698
699 if ( VOS_STATUS_SUCCESS == vStatus )
700 {
701 timer->platformInfo.cookie = LINUX_INVALID_TIMER_COOKIE;
702 timer->state = VOS_TIMER_STATE_UNUSED;
703 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
704 return vStatus;
705 }
706
707 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
708
709
710 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
711 "%s: Cannot destroy timer in state = %d",__func__, timer->state);
712 VOS_ASSERT(0);
713
714 return vStatus;
715}
716
717#else
718VOS_STATUS vos_timer_destroy ( vos_timer_t *timer )
719{
720 VOS_STATUS vStatus=VOS_STATUS_SUCCESS;
721 unsigned long flags;
722
723 // Check for invalid pointer
724 if ( NULL == timer )
725 {
726 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700727 "%s: Null timer pointer being passed",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700728 VOS_ASSERT(0);
729 return VOS_STATUS_E_FAULT;
730 }
731
732 // Check if timer refers to an uninitialized object
733 if ( LINUX_TIMER_COOKIE != timer->platformInfo.cookie )
734 {
735 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700736 "%s: Cannot destroy uninitialized timer",__func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700737 return VOS_STATUS_E_INVAL;
738 }
739 spin_lock_irqsave( &timer->platformInfo.spinlock,flags );
740
741 switch ( timer->state )
742 {
743 case VOS_TIMER_STATE_STARTING:
744 vStatus = VOS_STATUS_E_BUSY;
745 break;
746 case VOS_TIMER_STATE_RUNNING:
747 /* Stop the timer first */
748 del_timer(&(timer->platformInfo.Timer));
749 vStatus = VOS_STATUS_SUCCESS;
750 break;
751 case VOS_TIMER_STATE_STOPPED:
752 vStatus = VOS_STATUS_SUCCESS;
753 break;
754 case VOS_TIMER_STATE_UNUSED:
755 vStatus = VOS_STATUS_E_ALREADY;
756 break;
757 default:
758 vStatus = VOS_STATUS_E_FAULT;
759 break;
760 }
761
762 if ( VOS_STATUS_SUCCESS == vStatus )
763 {
764 timer->platformInfo.cookie = LINUX_INVALID_TIMER_COOKIE;
765 timer->state = VOS_TIMER_STATE_UNUSED;
766 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
767 return vStatus;
768 }
769
770 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
771
772 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
773 "%s: Cannot destroy timer in state = %d",__func__, timer->state);
774 VOS_ASSERT(0);
775
776 return vStatus;
777}
778#endif
779
780/*--------------------------------------------------------------------------
781
782 \brief vos_timer_start() - Start a vOSS Timer object
783
784 The \a vos_timer_start() function starts a timer to expire after the
785 specified interval, thus running the timer callback function when
786 the interval expires.
787
788 A timer only runs once (a one-shot timer). To re-start the
789 timer, vos_timer_start() has to be called after the timer runs
790 or has been cancelled.
791
792 \param timer - the timer object to be started
793
794 \param expirationTime - expiration time for the timer (in milliseconds)
795
796 \return VOS_STATUS_SUCCESS - timer was successfully started.
797
798 VOS_STATUS_E_ALREADY - The implementation has detected an attempt
799 to start a timer while it is already started. The timer must
800 be stopped or expire before it can be started again.
801
802 VOS_STATUS_E_INVAL - The value specified by timer is invalid.
803
804 VOS_STATUS_E_FAULT - timer is an invalid pointer.
805 \sa
806
807 -------------------------------------------------------------------------*/
808VOS_STATUS vos_timer_start( vos_timer_t *timer, v_U32_t expirationTime )
809{
810 unsigned long flags;
811
812 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
Jeff Johnson1b067b52017-09-19 08:33:10 -0700813 "Timer Addr inside voss_start : 0x%pK ", timer );
Jeff Johnson295189b2012-06-20 16:38:30 -0700814
815 // Check for invalid pointer
816 if ( NULL == timer )
817 {
818 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
819 "%s Null timer pointer being passed", __func__);
820 VOS_ASSERT(0);
821 return VOS_STATUS_E_INVAL;
822 }
823
824 // Check if timer refers to an uninitialized object
825 if ( LINUX_TIMER_COOKIE != timer->platformInfo.cookie )
826 {
Madan Mohan Koyyalamudi17683bc2013-07-26 18:33:00 +0530827 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
828 "%s: Cannot start uninitialized timer",__func__);
829 if ( LINUX_INVALID_TIMER_COOKIE != timer->platformInfo.cookie )
830 {
831 VOS_ASSERT(0);
832 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700833 return VOS_STATUS_E_INVAL;
834 }
835
836 // Check if timer has expiration time less than 10 ms
837 if ( expirationTime < 10 )
838 {
839 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
840 "%s: Cannot start a "
841 "timer with expiration less than 10 ms", __func__);
842 VOS_ASSERT(0);
843 return VOS_STATUS_E_INVAL;
844 }
845
846 // make sure the remainer of the logic isn't interrupted
847 spin_lock_irqsave( &timer->platformInfo.spinlock,flags );
848
849 // Ensure if the timer can be started
850 if ( VOS_TIMER_STATE_STOPPED != timer->state )
851 {
852 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
Mohit Khanna23863762012-09-11 17:40:09 -0700853 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
Jeff Johnson295189b2012-06-20 16:38:30 -0700854 "%s: Cannot start timer in state = %d ",__func__, timer->state);
855 return VOS_STATUS_E_ALREADY;
856 }
857
858 // Start the timer
859 mod_timer( &(timer->platformInfo.Timer),
860 jiffies + msecs_to_jiffies(expirationTime));
861
862 timer->state = VOS_TIMER_STATE_RUNNING;
863
864 // Get the thread ID on which the timer is being started
865 timer->platformInfo.threadID = current->pid;
866
867 if ( VOS_TIMER_TYPE_WAKE_APPS == timer->type )
868 {
869 persistentTimerCount++;
870 if ( 1 == persistentTimerCount )
871 {
872 // Since we now have one persistent timer, we need to disallow sleep
873 // sleep_negate_okts( sleepClientHandle );
874 }
875 }
876
877 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
878
879 return VOS_STATUS_SUCCESS;
880}
881
882
883/*--------------------------------------------------------------------------
884
885 \brief vos_timer_stop() - Stop a vOSS Timer
886
887 The \a vos_timer_stop() function stops a timer that has been started but
888 has not expired, essentially cancelling the 'start' request.
889
890 After a timer is stopped, it goes back to the state it was in after it
891 was created and can be started again via a call to vos_timer_start().
892
893 \param timer - the timer object to be stopped
894
895 \return VOS_STATUS_SUCCESS - timer was successfully stopped.
896
Jeff Johnson295189b2012-06-20 16:38:30 -0700897 VOS_STATUS_E_INVAL - The value specified by timer is invalid.
898
899 VOS_STATUS_E_FAULT - timer is an invalid pointer.
900 \sa
901
902 ------------------------------------------------------------------------*/
903VOS_STATUS vos_timer_stop ( vos_timer_t *timer )
904{
905 unsigned long flags;
906
907 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
Jeff Johnson1b067b52017-09-19 08:33:10 -0700908 "%s: Timer Addr inside voss_stop : 0x%pK",__func__,timer );
Jeff Johnson295189b2012-06-20 16:38:30 -0700909
910 // Check for invalid pointer
911 if ( NULL == timer )
912 {
913 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
914 "%s Null timer pointer being passed", __func__);
915 VOS_ASSERT(0);
916 return VOS_STATUS_E_INVAL;
917 }
918
919 // Check if timer refers to an uninitialized object
920 if ( LINUX_TIMER_COOKIE != timer->platformInfo.cookie )
921 {
922 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi17683bc2013-07-26 18:33:00 +0530923 "%s: Cannot stop uninitialized timer",__func__);
924 if ( LINUX_INVALID_TIMER_COOKIE != timer->platformInfo.cookie )
925 {
926 VOS_ASSERT(0);
927 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700928 return VOS_STATUS_E_INVAL;
929 }
930
931 // Ensure the timer state is correct
932 spin_lock_irqsave( &timer->platformInfo.spinlock,flags );
933
934 if ( VOS_TIMER_STATE_RUNNING != timer->state )
935 {
936 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
Mohit Khanna23863762012-09-11 17:40:09 -0700937 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
Jeff Johnson295189b2012-06-20 16:38:30 -0700938 "%s: Cannot stop timer in state = %d",
939 __func__, timer->state);
Madan Mohan Koyyalamudia9a5c702013-08-23 12:10:03 +0530940 return VOS_STATUS_SUCCESS;
Jeff Johnson295189b2012-06-20 16:38:30 -0700941 }
942
943 timer->state = VOS_TIMER_STATE_STOPPED;
944
945 del_timer(&(timer->platformInfo.Timer));
946
947 spin_unlock_irqrestore( &timer->platformInfo.spinlock,flags );
948
949 tryAllowingSleep( timer->type );
950
951 return VOS_STATUS_SUCCESS;
952}
953
954
955/*--------------------------------------------------------------------------
956
957 \brief vos_timer_get_system_ticks() - Get the system time in 10ms ticks
958
959 The \a vos_timer_get_system_ticks() function returns the current number
960 of timer ticks in 10msec intervals. This function is suitable timestamping
961 and calculating time intervals by calculating the difference between two
962 timestamps.
963
964 \returns - The current system tick count (in 10msec intervals). This
965 function cannot fail.
966
967 \sa
968
969 ------------------------------------------------------------------------*/
970v_TIME_t vos_timer_get_system_ticks( v_VOID_t )
971{
972 return( jiffies_to_msecs(jiffies) / 10 );
973}
974
975
976/*--------------------------------------------------------------------------
977
978 \brief vos_timer_get_system_time() - Get the system time in milliseconds
979
980 The \a vos_timer_get_system_time() function returns the number of milliseconds
981 that have elapsed since the system was started
982
983 \returns - The current system time in milliseconds.
984
985 \sa
986
987 ------------------------------------------------------------------------*/
988v_TIME_t vos_timer_get_system_time( v_VOID_t )
989{
990 struct timeval tv;
991 do_gettimeofday(&tv);
992 return tv.tv_sec*1000 + tv.tv_usec/1000;
993}
Ganesh Kondabattinicbfdc392015-09-11 19:12:59 +0530994
995/*--------------------------------------------------------------------------
996
997 \brief vos_timer_is_initialized() - check if timer is initialized or not
998
999 The \a vos_timer_is_initialized() function returns VOS_TRUE if timer is
1000 initialized and VOS_FALSE if timer is not initialized
1001
1002 \returns - VOS_TRUE or VOS_FALSE
1003
1004 \sa
1005
1006 ------------------------------------------------------------------------*/
1007v_BOOL_t vos_timer_is_initialized(vos_timer_t *timer)
1008{
1009 if (LINUX_TIMER_COOKIE == timer->platformInfo.cookie)
1010 return VOS_TRUE;
1011 else
1012 return VOS_FALSE;
1013}
1014
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +05301015/**
1016 * vos_wdthread_init_timer_work() - Initialize timer work
1017 * @callbackptr: timer work callback
1018 *
1019 * Initialize watchdog thread timer work structure and linked
1020 * list.
1021 * return - void
1022 */
1023void vos_wdthread_init_timer_work(void *callbackptr)
1024{
1025 pVosContextType context;
1026
1027 context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
1028 if (!context) {
1029 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
1030 "%s: Global VOS context is Null", __func__);
1031 return;
1032 }
1033
1034 spin_lock_init(&context->wdthread_work_lock);
1035 INIT_LIST_HEAD(&context->wdthread_timer_work_list);
1036#if defined (WLAN_OPEN_SOURCE)
1037 INIT_WORK(&context->wdthread_work, callbackptr);
1038#else
1039 wcnss_init_work(&context->wdthread_work, callbackptr);
1040#endif
1041}
1042
1043/**
1044 * vos_wdthread_flush_timer_work() - Flush timer work
1045 *
1046 * Flush watchdog thread timer work structure.
1047 * return - void
1048 */
1049void vos_wdthread_flush_timer_work()
1050{
1051 pVosContextType context;
1052
1053 context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
1054 if (!context) {
1055 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
1056 "%s: Global VOS context is Null", __func__);
1057 return;
1058 }
1059
1060#if defined (WLAN_OPEN_SOURCE)
1061 cancel_work_sync(&context->wdthread_work);
1062#else
1063 wcnss_flush_work(&context->wdthread_work);
1064#endif
1065}
1066
1067/**
1068 * __vos_process_wd_timer() - Handle wathdog thread timer work
1069 *
1070 * Process watchdog thread timer work.
1071 * return - void
1072 */
1073static void __vos_process_wd_timer(void)
1074{
1075 v_CONTEXT_t vos_context = NULL;
1076 pVosContextType vos_global_context;
1077 vos_wdthread_timer_work_t *wdthread_timer_work;
1078 struct list_head *pos, *next;
1079
1080 vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
1081
1082 if(!vos_context)
1083 {
1084 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
1085 "%s: Global VOS context is Null", __func__);
1086 return;
1087 }
1088
1089 vos_global_context = (pVosContextType)vos_context;
1090
1091 spin_lock(&vos_global_context->wdthread_work_lock);
1092 list_for_each_safe(pos, next,
1093 &vos_global_context->wdthread_timer_work_list) {
1094 wdthread_timer_work = list_entry(pos,
1095 vos_wdthread_timer_work_t,
1096 node);
1097 list_del(pos);
1098 spin_unlock(&vos_global_context->wdthread_work_lock);
Hanumanth Reddy Pothula3c0a56e2016-11-08 15:17:23 +05301099 if (NULL != wdthread_timer_work->callback)
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +05301100 wdthread_timer_work->callback(wdthread_timer_work->userData);
Mahesh A Saptasagara67b86d2016-04-26 21:20:41 +05301101 vos_mem_free(wdthread_timer_work);
1102 spin_lock(&vos_global_context->wdthread_work_lock);
1103 }
1104 spin_unlock(&vos_global_context->wdthread_work_lock);
1105
1106 return;
1107}
1108
1109/**
1110 * vos_process_wd_timer() - Wrapper function to handle timer work
1111 *
1112 * Wrapper function to process timer work.
1113 * return - void
1114 */
1115void vos_process_wd_timer(void)
1116{
1117 vos_ssr_protect(__func__);
1118 __vos_process_wd_timer();
1119 vos_ssr_unprotect(__func__);
1120}
1121