xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c (revision 7b32946958ccd00534989da3a4b46d0af59a5b5c)
1 /*
2  * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
3  *
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.
20  */
21 
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 
28 /**
29  * DOC: qdf_mc_timer
30  * QCA driver framework timer APIs serialized to MC thread
31  */
32 
33 /* Include Files */
34 #include <qdf_mc_timer.h>
35 #include <qdf_lock.h>
36 #include "qdf_lock.h"
37 #include "qdf_list.h"
38 #include "qdf_mem.h"
39 #include <linux/export.h>
40 
41 /* Preprocessor definitions and constants */
42 #define LINUX_TIMER_COOKIE 0x12341234
43 #define LINUX_INVALID_TIMER_COOKIE 0xfeedface
44 #define TMR_INVALID_ID (0)
45 
46 /* qdf timer multiplier */
47 #ifdef QCA_WIFI_NAPIER_EMULATION
48 static uint32_t g_qdf_timer_multiplier = 100;
49 #else
50 static uint32_t g_qdf_timer_multiplier = 1;
51 #endif
52 
53 inline void qdf_timer_set_multiplier(uint32_t multiplier)
54 {
55 	g_qdf_timer_multiplier = multiplier;
56 }
57 EXPORT_SYMBOL(qdf_timer_set_multiplier);
58 
59 inline uint32_t qdf_timer_get_multiplier(void)
60 {
61 	return g_qdf_timer_multiplier;
62 }
63 EXPORT_SYMBOL(qdf_timer_get_multiplier);
64 
65 /* Type declarations */
66 
67 /* Static Variable Definitions */
68 static unsigned int persistent_timer_count;
69 static qdf_mutex_t persistent_timer_count_lock;
70 
71 static void (*scheduler_timer_callback) (unsigned long data);
72 void qdf_register_mc_timer_callback(void (*callback) (unsigned long data))
73 {
74 	scheduler_timer_callback = callback;
75 }
76 EXPORT_SYMBOL(qdf_register_mc_timer_callback);
77 
78 /* Function declarations and documenation */
79 
80 /**
81  * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated
82  * @type: timer type
83  *
84  * Clean up timer states after it has been deactivated check and try to allow
85  * sleep after a timer has been stopped or expired.
86  *
87  * Return: none
88  */
89 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type)
90 {
91 	if (QDF_TIMER_TYPE_WAKE_APPS == type) {
92 
93 		persistent_timer_count--;
94 		if (0 == persistent_timer_count) {
95 			/* since the number of persistent timers has
96 			 * decreased from 1 to 0, the timer should allow
97 			 * sleep
98 			 */
99 		}
100 	}
101 }
102 EXPORT_SYMBOL(qdf_try_allowing_sleep);
103 
104 /**
105  * qdf_mc_timer_get_current_state() - get the current state of the timer
106  * @timer: Pointer to timer object
107  *
108  * Return:
109  * QDF_TIMER_STATE - qdf timer state
110  */
111 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer)
112 {
113 	if (NULL == timer) {
114 		QDF_ASSERT(0);
115 		return QDF_TIMER_STATE_UNUSED;
116 	}
117 
118 	switch (timer->state) {
119 	case QDF_TIMER_STATE_STOPPED:
120 	case QDF_TIMER_STATE_STARTING:
121 	case QDF_TIMER_STATE_RUNNING:
122 	case QDF_TIMER_STATE_UNUSED:
123 		return timer->state;
124 	default:
125 		QDF_ASSERT(0);
126 		return QDF_TIMER_STATE_UNUSED;
127 	}
128 }
129 EXPORT_SYMBOL(qdf_mc_timer_get_current_state);
130 
131 /**
132  * qdf_timer_module_init() - initializes a QDF timer module.
133  *
134  * This API initializes the QDF timer module. This needs to be called
135  * exactly once prior to using any QDF timers.
136  *
137  * Return: none
138  */
139 void qdf_timer_module_init(void)
140 {
141 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
142 		  "Initializing the QDF MC timer module");
143 	qdf_mutex_create(&persistent_timer_count_lock);
144 }
145 EXPORT_SYMBOL(qdf_timer_module_init);
146 
147 #ifdef TIMER_MANAGER
148 
149 qdf_list_t qdf_timer_list;
150 qdf_spinlock_t qdf_timer_list_lock;
151 
152 static void qdf_timer_clean(void);
153 
154 /**
155  * qdf_mc_timer_manager_init() - initialize QDF debug timer manager
156  *
157  * This API initializes QDF timer debug functionality.
158  *
159  * Return: none
160  */
161 void qdf_mc_timer_manager_init(void)
162 {
163 	qdf_list_create(&qdf_timer_list, 1000);
164 	qdf_spinlock_create(&qdf_timer_list_lock);
165 }
166 EXPORT_SYMBOL(qdf_mc_timer_manager_init);
167 
168 /**
169  * qdf_timer_clean() - clean up QDF timer debug functionality
170  *
171  * This API cleans up QDF timer debug functionality and prints which QDF timers
172  * are leaked. This is called during driver unload.
173  *
174  * Return: none
175  */
176 static void qdf_timer_clean(void)
177 {
178 	uint32_t list_size;
179 	qdf_list_node_t *node;
180 	QDF_STATUS qdf_status;
181 
182 	qdf_mc_timer_node_t *timer_node;
183 
184 	list_size = qdf_list_size(&qdf_timer_list);
185 
186 	if (!list_size)
187 		return;
188 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
189 		  "%s: List is not Empty. list_size %d ",
190 		  __func__, (int)list_size);
191 
192 	do {
193 		qdf_spin_lock_irqsave(&qdf_timer_list_lock);
194 		qdf_status = qdf_list_remove_front(&qdf_timer_list, &node);
195 		qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
196 		if (QDF_STATUS_SUCCESS == qdf_status) {
197 			timer_node = (qdf_mc_timer_node_t *) node;
198 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
199 			"timer Leak@ File %s, @Line %d",
200 				  timer_node->file_name,
201 				  (int)timer_node->line_num);
202 			qdf_mem_free(timer_node);
203 		}
204 	} while (qdf_status == QDF_STATUS_SUCCESS);
205 }
206 EXPORT_SYMBOL(qdf_timer_clean);
207 
208 /**
209  * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality
210  *
211  * This API exists QDF timer debug functionality
212  *
213  * Return: none
214  */
215 void qdf_mc_timer_manager_exit(void)
216 {
217 	qdf_timer_clean();
218 	qdf_list_destroy(&qdf_timer_list);
219 	qdf_spinlock_destroy(&qdf_timer_list_lock);
220 }
221 EXPORT_SYMBOL(qdf_mc_timer_manager_exit);
222 #endif
223 
224 /**
225  * qdf_mc_timer_init() - initialize a QDF timer
226  * @timer: Pointer to timer object
227  * @timer_type: Type of timer
228  * @callback: Callback to be called after timer expiry
229  * @ser_data: User data which will be passed to callback function
230  *
231  * This API initializes a QDF timer object.
232  *
233  * qdf_mc_timer_init() initializes a QDF timer object. A timer must be
234  * initialized by calling qdf_mc_timer_initialize() before it may be used in
235  * any other timer functions.
236  *
237  * Attempting to initialize timer that is already initialized results in
238  * a failure. A destroyed timer object can be re-initialized with a call to
239  * qdf_mc_timer_init(). The results of otherwise referencing the object
240  * after it has been destroyed are undefined.
241  *
242  *  Calls to QDF timer functions to manipulate the timer such
243  *  as qdf_mc_timer_set() will fail if the timer is not initialized or has
244  *  been destroyed. Therefore, don't use the timer after it has been
245  *  destroyed until it has been re-initialized.
246  *
247  *  All callback will be executed within the CDS main thread unless it is
248  *  initialized from the Tx thread flow, in which case it will be executed
249  *  within the tx thread flow.
250  *
251  * Return:
252  * QDF_STATUS_SUCCESS: timer is initialized successfully
253  * QDF failure status: timer initialization failed
254  */
255 #ifdef TIMER_MANAGER
256 QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer,
257 				   QDF_TIMER_TYPE timer_type,
258 				   qdf_mc_timer_callback_t callback,
259 				   void *user_data, char *file_name,
260 				   uint32_t line_num)
261 {
262 	QDF_STATUS qdf_status;
263 
264 	/* check for invalid pointer */
265 	if ((timer == NULL) || (callback == NULL)) {
266 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
267 			  "%s: Null params being passed", __func__);
268 		QDF_ASSERT(0);
269 		return QDF_STATUS_E_FAULT;
270 	}
271 
272 	timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t));
273 
274 	if (timer->timer_node == NULL) {
275 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
276 			  "%s: Not able to allocate memory for time_node",
277 			  __func__);
278 		QDF_ASSERT(0);
279 		return QDF_STATUS_E_NOMEM;
280 	}
281 
282 	qdf_mem_set(timer->timer_node, sizeof(qdf_mc_timer_node_t), 0);
283 
284 	timer->timer_node->file_name = file_name;
285 	timer->timer_node->line_num = line_num;
286 	timer->timer_node->qdf_timer = timer;
287 
288 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
289 	qdf_status = qdf_list_insert_front(&qdf_timer_list,
290 					   &timer->timer_node->node);
291 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
292 	if (QDF_STATUS_SUCCESS != qdf_status) {
293 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
294 			  "%s: Unable to insert node into List qdf_status %d",
295 			  __func__, qdf_status);
296 	}
297 
298 	/* set the various members of the timer structure
299 	 * with arguments passed or with default values
300 	 */
301 	qdf_spinlock_create(&timer->platform_info.spinlock);
302 	if (QDF_TIMER_TYPE_SW == timer_type)
303 		init_timer_deferrable(&(timer->platform_info.timer));
304 	else
305 		init_timer(&(timer->platform_info.timer));
306 	timer->platform_info.timer.function = scheduler_timer_callback;
307 	timer->platform_info.timer.data = (unsigned long)timer;
308 	timer->callback = callback;
309 	timer->user_data = user_data;
310 	timer->type = timer_type;
311 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
312 	timer->platform_info.thread_id = 0;
313 	timer->state = QDF_TIMER_STATE_STOPPED;
314 
315 	return QDF_STATUS_SUCCESS;
316 }
317 EXPORT_SYMBOL(qdf_mc_timer_init_debug);
318 #else
319 QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type,
320 			     qdf_mc_timer_callback_t callback,
321 			     void *user_data)
322 {
323 	/* check for invalid pointer */
324 	if ((timer == NULL) || (callback == NULL)) {
325 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
326 			  "%s: Null params being passed", __func__);
327 		QDF_ASSERT(0);
328 		return QDF_STATUS_E_FAULT;
329 	}
330 
331 	/* set the various members of the timer structure
332 	 * with arguments passed or with default values
333 	 */
334 	qdf_spinlock_create(&timer->platform_info.spinlock);
335 	if (QDF_TIMER_TYPE_SW == timer_type)
336 		init_timer_deferrable(&(timer->platform_info.timer));
337 	else
338 		init_timer(&(timer->platform_info.timer));
339 	timer->platform_info.timer.function = scheduler_timer_callback;
340 	timer->platform_info.timer.data = (unsigned long)timer;
341 	timer->callback = callback;
342 	timer->user_data = user_data;
343 	timer->type = timer_type;
344 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
345 	timer->platform_info.thread_id = 0;
346 	timer->state = QDF_TIMER_STATE_STOPPED;
347 
348 	return QDF_STATUS_SUCCESS;
349 }
350 EXPORT_SYMBOL(qdf_mc_timer_init);
351 #endif
352 
353 /**
354  * qdf_mc_timer_destroy() - destroy QDF timer
355  * @timer: Pointer to timer object
356  *
357  * qdf_mc_timer_destroy() function shall destroy the timer object.
358  * After a successful return from \a qdf_mc_timer_destroy() the timer
359  * object becomes, in effect, uninitialized.
360  *
361  * A destroyed timer object can be re-initialized by calling
362  * qdf_mc_timer_init().  The results of otherwise referencing the object
363  * after it has been destroyed are undefined.
364  *
365  * Calls to QDF timer functions to manipulate the timer, such
366  * as qdf_mc_timer_set() will fail if the lock is destroyed.  Therefore,
367  * don't use the timer after it has been destroyed until it has
368  * been re-initialized.
369  *
370  * Return:
371  * QDF_STATUS_SUCCESS - timer is initialized successfully
372  * QDF failure status - timer initialization failed
373  */
374 #ifdef TIMER_MANAGER
375 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
376 {
377 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
378 
379 	/* check for invalid pointer */
380 	if (NULL == timer) {
381 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
382 			  "%s: Null timer pointer being passed", __func__);
383 		QDF_ASSERT(0);
384 		return QDF_STATUS_E_FAULT;
385 	}
386 
387 	/* Check if timer refers to an uninitialized object */
388 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
389 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
390 			  "%s: Cannot destroy uninitialized timer", __func__);
391 		QDF_ASSERT(0);
392 		return QDF_STATUS_E_INVAL;
393 	}
394 
395 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
396 	v_status = qdf_list_remove_node(&qdf_timer_list,
397 					&timer->timer_node->node);
398 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
399 	if (v_status != QDF_STATUS_SUCCESS) {
400 		QDF_ASSERT(0);
401 		return QDF_STATUS_E_INVAL;
402 	}
403 	qdf_mem_free(timer->timer_node);
404 
405 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
406 
407 	switch (timer->state) {
408 
409 	case QDF_TIMER_STATE_STARTING:
410 		v_status = QDF_STATUS_E_BUSY;
411 		break;
412 
413 	case QDF_TIMER_STATE_RUNNING:
414 		/* Stop the timer first */
415 		del_timer(&(timer->platform_info.timer));
416 		v_status = QDF_STATUS_SUCCESS;
417 		break;
418 	case QDF_TIMER_STATE_STOPPED:
419 		v_status = QDF_STATUS_SUCCESS;
420 		break;
421 
422 	case QDF_TIMER_STATE_UNUSED:
423 		v_status = QDF_STATUS_E_ALREADY;
424 		break;
425 
426 	default:
427 		v_status = QDF_STATUS_E_FAULT;
428 		break;
429 	}
430 
431 	if (QDF_STATUS_SUCCESS == v_status) {
432 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
433 		timer->state = QDF_TIMER_STATE_UNUSED;
434 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
435 		qdf_spinlock_destroy(&timer->platform_info.spinlock);
436 		return v_status;
437 	}
438 
439 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
440 
441 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
442 		  "%s: Cannot destroy timer in state = %d", __func__,
443 		  timer->state);
444 	QDF_ASSERT(0);
445 
446 	return v_status;
447 }
448 EXPORT_SYMBOL(qdf_mc_timer_destroy);
449 
450 #else
451 
452 /**
453  * qdf_mc_timer_destroy() - destroy QDF timer
454  * @timer: Pointer to timer object
455  *
456  * qdf_mc_timer_destroy() function shall destroy the timer object.
457  * After a successful return from \a qdf_mc_timer_destroy() the timer
458  * object becomes, in effect, uninitialized.
459  *
460  * A destroyed timer object can be re-initialized by calling
461  * qdf_mc_timer_init(). The results of otherwise referencing the object
462  * after it has been destroyed are undefined.
463  *
464  * Calls to QDF timer functions to manipulate the timer, such
465  * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore,
466  * don't use the timer after it has been destroyed until it has
467  * been re-initialized.
468  *
469  * Return:
470  * QDF_STATUS_SUCCESS - timer is initialized successfully
471  * QDF failure status - timer initialization failed
472  */
473 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
474 {
475 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
476 
477 	/* check for invalid pointer */
478 	if (NULL == timer) {
479 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
480 			  "%s: Null timer pointer being passed", __func__);
481 		QDF_ASSERT(0);
482 		return QDF_STATUS_E_FAULT;
483 	}
484 
485 	/* check if timer refers to an uninitialized object */
486 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
487 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
488 			  "%s: Cannot destroy uninitialized timer", __func__);
489 		QDF_ASSERT(0);
490 		return QDF_STATUS_E_INVAL;
491 	}
492 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
493 
494 	switch (timer->state) {
495 
496 	case QDF_TIMER_STATE_STARTING:
497 		v_status = QDF_STATUS_E_BUSY;
498 		break;
499 
500 	case QDF_TIMER_STATE_RUNNING:
501 		/* Stop the timer first */
502 		del_timer(&(timer->platform_info.timer));
503 		v_status = QDF_STATUS_SUCCESS;
504 		break;
505 
506 	case QDF_TIMER_STATE_STOPPED:
507 		v_status = QDF_STATUS_SUCCESS;
508 		break;
509 
510 	case QDF_TIMER_STATE_UNUSED:
511 		v_status = QDF_STATUS_E_ALREADY;
512 		break;
513 
514 	default:
515 		v_status = QDF_STATUS_E_FAULT;
516 		break;
517 	}
518 
519 	if (QDF_STATUS_SUCCESS == v_status) {
520 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
521 		timer->state = QDF_TIMER_STATE_UNUSED;
522 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
523 		return v_status;
524 	}
525 
526 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
527 
528 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
529 		  "%s: Cannot destroy timer in state = %d", __func__,
530 		  timer->state);
531 	QDF_ASSERT(0);
532 
533 	return v_status;
534 }
535 EXPORT_SYMBOL(qdf_mc_timer_destroy);
536 #endif
537 
538 /**
539  * qdf_mc_timer_start() - start a QDF timer object
540  * @timer: Pointer to timer object
541  * @expiration_time: Time to expire
542  *
543  * qdf_mc_timer_start() function starts a timer to expire after the
544  * specified interval, thus running the timer callback function when
545  * the interval expires.
546  *
547  * A timer only runs once (a one-shot timer). To re-start the
548  * timer, qdf_mc_timer_start() has to be called after the timer runs
549  * or has been cancelled.
550  *
551  * Return:
552  * QDF_STATUS_SUCCESS: timer is initialized successfully
553  * QDF failure status: timer initialization failed
554  */
555 QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time)
556 {
557 	/* check for invalid pointer */
558 	if (NULL == timer) {
559 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
560 			  "%s Null timer pointer being passed", __func__);
561 		QDF_ASSERT(0);
562 		return QDF_STATUS_E_INVAL;
563 	}
564 
565 	/* check if timer refers to an uninitialized object */
566 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
567 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
568 			  "%s: Cannot start uninitialized timer", __func__);
569 		QDF_ASSERT(0);
570 
571 		return QDF_STATUS_E_INVAL;
572 	}
573 
574 	/* check if timer has expiration time less than 10 ms */
575 	if (expiration_time < 10) {
576 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
577 			  "%s: Cannot start a timer with expiration less than 10 ms",
578 			  __func__);
579 		QDF_ASSERT(0);
580 		return QDF_STATUS_E_INVAL;
581 	}
582 
583 	/* update expiration time based on if emulation platform */
584 	expiration_time *= qdf_timer_get_multiplier();
585 
586 	/* make sure the remainer of the logic isn't interrupted */
587 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
588 
589 	/* ensure if the timer can be started */
590 	if (QDF_TIMER_STATE_STOPPED != timer->state) {
591 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
592 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
593 			  "%s: Cannot start timer in state = %d ", __func__,
594 			  timer->state);
595 		return QDF_STATUS_E_ALREADY;
596 	}
597 
598 	/* start the timer */
599 	mod_timer(&(timer->platform_info.timer),
600 		  jiffies + msecs_to_jiffies(expiration_time));
601 
602 	timer->state = QDF_TIMER_STATE_RUNNING;
603 
604 	/* get the thread ID on which the timer is being started */
605 	timer->platform_info.thread_id = current->pid;
606 
607 	if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) {
608 		persistent_timer_count++;
609 		if (1 == persistent_timer_count) {
610 			/* since we now have one persistent timer,
611 			 * we need to disallow sleep
612 			 * sleep_negate_okts(sleep_client_handle);
613 			 */
614 		}
615 	}
616 
617 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
618 
619 	return QDF_STATUS_SUCCESS;
620 }
621 EXPORT_SYMBOL(qdf_mc_timer_start);
622 
623 /**
624  * qdf_mc_timer_stop() - stop a QDF timer
625  * @timer: Pointer to timer object
626  * qdf_mc_timer_stop() function stops a timer that has been started but
627  * has not expired, essentially cancelling the 'start' request.
628  *
629  * After a timer is stopped, it goes back to the state it was in after it
630  * was created and can be started again via a call to qdf_mc_timer_start().
631  *
632  * Return:
633  * QDF_STATUS_SUCCESS: timer is initialized successfully
634  * QDF failure status: timer initialization failed
635  */
636 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer)
637 {
638 	/* check for invalid pointer */
639 	if (NULL == timer) {
640 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
641 			  "%s Null timer pointer being passed", __func__);
642 		QDF_ASSERT(0);
643 		return QDF_STATUS_E_INVAL;
644 	}
645 
646 	/* check if timer refers to an uninitialized object */
647 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
648 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
649 			  "%s: Cannot stop uninitialized timer", __func__);
650 		QDF_ASSERT(0);
651 
652 		return QDF_STATUS_E_INVAL;
653 	}
654 
655 	/* ensure the timer state is correct */
656 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
657 
658 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
659 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
660 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
661 			  "%s: Cannot stop timer in state = %d",
662 			  __func__, timer->state);
663 		return QDF_STATUS_SUCCESS;
664 	}
665 
666 	timer->state = QDF_TIMER_STATE_STOPPED;
667 
668 	del_timer(&(timer->platform_info.timer));
669 
670 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
671 
672 	qdf_try_allowing_sleep(timer->type);
673 
674 	return QDF_STATUS_SUCCESS;
675 }
676 EXPORT_SYMBOL(qdf_mc_timer_stop);
677 
678 /**
679  * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks
680 
681  * qdf_mc_timer_get_system_ticks() function returns the current number
682  * of timer ticks in 10msec intervals. This function is suitable timestamping
683  * and calculating time intervals by calculating the difference between two
684  * timestamps.
685  *
686  * Return:
687  * The current system tick count (in 10msec intervals).  This
688  * function cannot fail.
689  */
690 unsigned long qdf_mc_timer_get_system_ticks(void)
691 {
692 	return jiffies_to_msecs(jiffies) / 10;
693 }
694 EXPORT_SYMBOL(qdf_mc_timer_get_system_ticks);
695 
696 /**
697  * qdf_mc_timer_get_system_time() - Get the system time in milliseconds
698  *
699  * qdf_mc_timer_get_system_time() function returns the number of milliseconds
700  * that have elapsed since the system was started
701  *
702  * Return:
703  * The current system time in milliseconds
704  */
705 unsigned long qdf_mc_timer_get_system_time(void)
706 {
707 	struct timeval tv;
708 
709 	do_gettimeofday(&tv);
710 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
711 }
712 EXPORT_SYMBOL(qdf_mc_timer_get_system_time);
713 
714 s64 qdf_get_monotonic_boottime_ns(void)
715 {
716 	struct timespec ts;
717 
718 	ktime_get_ts(&ts);
719 	return timespec_to_ns(&ts);
720 }
721 EXPORT_SYMBOL(qdf_get_monotonic_boottime_ns);
722 
723 /**
724  * qdf_timer_module_deinit() - Deinitializes a QDF timer module.
725  *
726  * This API deinitializes the QDF timer module.
727  * Return: none
728  */
729 void qdf_timer_module_deinit(void)
730 {
731 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
732 		  "De-Initializing the QDF MC timer module");
733 	qdf_mutex_destroy(&persistent_timer_count_lock);
734 }
735 EXPORT_SYMBOL(qdf_timer_module_deinit);
736 
737 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
738 {
739 	struct timeval tv;
740 	struct rtc_time tm;
741 	unsigned long local_time;
742 
743 	/* Format the Log time R#: [hr:min:sec.microsec] */
744 	do_gettimeofday(&tv);
745 	/* Convert rtc to local time */
746 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
747 	rtc_time_to_tm(local_time, &tm);
748 	scnprintf(tbuf, len,
749 		"[%02d:%02d:%02d.%06lu]",
750 		tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
751 }
752 EXPORT_SYMBOL(qdf_get_time_of_the_day_in_hr_min_sec_usec);
753