xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: qdf_mc_timer
21  * QCA driver framework timer APIs serialized to MC thread
22  */
23 
24 /* Include Files */
25 #include <qdf_debug_domain.h>
26 #include <qdf_mc_timer.h>
27 #include <qdf_lock.h>
28 #include "qdf_lock.h"
29 #include "qdf_list.h"
30 #include "qdf_mem.h"
31 #include <qdf_module.h>
32 #include "qdf_timer.h"
33 
34 /* Preprocessor definitions and constants */
35 #define LINUX_TIMER_COOKIE 0x12341234
36 #define LINUX_INVALID_TIMER_COOKIE 0xfeedface
37 #define TMR_INVALID_ID (0)
38 
39 static uint32_t g_qdf_timer_multiplier = 1;
40 
41 inline void qdf_timer_set_multiplier(uint32_t multiplier)
42 {
43 	g_qdf_timer_multiplier = multiplier;
44 }
45 qdf_export_symbol(qdf_timer_set_multiplier);
46 
47 inline uint32_t qdf_timer_get_multiplier(void)
48 {
49 	return g_qdf_timer_multiplier;
50 }
51 qdf_export_symbol(qdf_timer_get_multiplier);
52 
53 /* Type declarations */
54 
55 /* Static Variable Definitions */
56 static unsigned int persistent_timer_count;
57 static qdf_mutex_t persistent_timer_count_lock;
58 
59 static void (*scheduler_timer_callback)(qdf_mc_timer_t *);
60 void qdf_register_mc_timer_callback(void (*callback) (qdf_mc_timer_t *))
61 {
62 	scheduler_timer_callback = callback;
63 }
64 
65 qdf_export_symbol(qdf_register_mc_timer_callback);
66 
67 /* Function declarations and documenation */
68 
69 /**
70  * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated
71  * @type: timer type
72  *
73  * Clean up timer states after it has been deactivated check and try to allow
74  * sleep after a timer has been stopped or expired.
75  *
76  * Return: none
77  */
78 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type)
79 {
80 	if (QDF_TIMER_TYPE_WAKE_APPS == type) {
81 
82 		persistent_timer_count--;
83 		if (0 == persistent_timer_count) {
84 			/* since the number of persistent timers has
85 			 * decreased from 1 to 0, the timer should allow
86 			 * sleep
87 			 */
88 		}
89 	}
90 }
91 qdf_export_symbol(qdf_try_allowing_sleep);
92 
93 /**
94  * qdf_mc_timer_get_current_state() - get the current state of the timer
95  * @timer: Pointer to timer object
96  *
97  * Return:
98  * QDF_TIMER_STATE - qdf timer state
99  */
100 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer)
101 {
102 	if (!timer) {
103 		QDF_ASSERT(0);
104 		return QDF_TIMER_STATE_UNUSED;
105 	}
106 
107 	switch (timer->state) {
108 	case QDF_TIMER_STATE_STOPPED:
109 	case QDF_TIMER_STATE_STARTING:
110 	case QDF_TIMER_STATE_RUNNING:
111 	case QDF_TIMER_STATE_UNUSED:
112 		return timer->state;
113 	default:
114 		QDF_ASSERT(0);
115 		return QDF_TIMER_STATE_UNUSED;
116 	}
117 }
118 qdf_export_symbol(qdf_mc_timer_get_current_state);
119 
120 /**
121  * qdf_timer_module_init() - initializes a QDF timer module.
122  *
123  * This API initializes the QDF timer module. This needs to be called
124  * exactly once prior to using any QDF timers.
125  *
126  * Return: none
127  */
128 void qdf_timer_module_init(void)
129 {
130 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
131 		  "Initializing the QDF MC timer module");
132 	qdf_mutex_create(&persistent_timer_count_lock);
133 }
134 qdf_export_symbol(qdf_timer_module_init);
135 
136 #ifdef TIMER_MANAGER
137 
138 static qdf_list_t qdf_timer_domains[QDF_DEBUG_DOMAIN_COUNT];
139 static qdf_spinlock_t qdf_timer_list_lock;
140 
141 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain)
142 {
143 	return &qdf_timer_domains[domain];
144 }
145 
146 /**
147  * qdf_mc_timer_manager_init() - initialize QDF debug timer manager
148  *
149  * This API initializes QDF timer debug functionality.
150  *
151  * Return: none
152  */
153 void qdf_mc_timer_manager_init(void)
154 {
155 	int i;
156 
157 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
158 		qdf_list_create(&qdf_timer_domains[i], 1000);
159 	qdf_spinlock_create(&qdf_timer_list_lock);
160 }
161 qdf_export_symbol(qdf_mc_timer_manager_init);
162 
163 static void qdf_mc_timer_print_list(qdf_list_t *timers)
164 {
165 	QDF_STATUS status;
166 	qdf_list_node_t *node;
167 
168 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
169 	status = qdf_list_peek_front(timers, &node);
170 	while (QDF_IS_STATUS_SUCCESS(status)) {
171 		qdf_mc_timer_node_t *timer_node = (qdf_mc_timer_node_t *)node;
172 		const char *filename = kbasename(timer_node->file_name);
173 		uint32_t line = timer_node->line_num;
174 
175 		qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
176 		qdf_err("timer Leak@ File %s, @Line %u", filename, line);
177 		qdf_spin_lock_irqsave(&qdf_timer_list_lock);
178 
179 		status = qdf_list_peek_next(timers, node, &node);
180 	}
181 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
182 }
183 
184 void qdf_mc_timer_check_for_leaks(void)
185 {
186 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
187 	qdf_list_t *timers = qdf_timer_list_get(current_domain);
188 
189 	if (qdf_list_empty(timers))
190 		return;
191 
192 	qdf_err("Timer leaks detected in %s domain!",
193 		qdf_debug_domain_name(current_domain));
194 	qdf_mc_timer_print_list(timers);
195 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
196 }
197 
198 static void qdf_mc_timer_free_leaked_timers(qdf_list_t *timers)
199 {
200 	QDF_STATUS status;
201 	qdf_list_node_t *node;
202 
203 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
204 	status = qdf_list_remove_front(timers, &node);
205 	while (QDF_IS_STATUS_SUCCESS(status)) {
206 		qdf_mem_free(node);
207 		status = qdf_list_remove_front(timers, &node);
208 	}
209 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
210 }
211 
212 /**
213  * qdf_timer_clean() - clean up QDF timer debug functionality
214  *
215  * This API cleans up QDF timer debug functionality and prints which QDF timers
216  * are leaked. This is called during driver unload.
217  *
218  * Return: none
219  */
220 static void qdf_timer_clean(void)
221 {
222 	bool leaks_detected = false;
223 	int i;
224 
225 	/* detect and print leaks */
226 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) {
227 		qdf_list_t *timers = &qdf_timer_domains[i];
228 
229 		if (qdf_list_empty(timers))
230 			continue;
231 
232 		leaks_detected = true;
233 
234 		qdf_err("\nTimer leaks detected in the %s (Id %d) domain!",
235 			qdf_debug_domain_name(i), i);
236 		qdf_mc_timer_print_list(timers);
237 	}
238 
239 	/* we're done if there were no leaks */
240 	if (!leaks_detected)
241 		return;
242 
243 	/* panic, if enabled */
244 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
245 
246 	/* if we didn't crash, release the leaked timers */
247 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
248 		qdf_mc_timer_free_leaked_timers(&qdf_timer_domains[i]);
249 }
250 qdf_export_symbol(qdf_timer_clean);
251 
252 /**
253  * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality
254  *
255  * This API exists QDF timer debug functionality
256  *
257  * Return: none
258  */
259 void qdf_mc_timer_manager_exit(void)
260 {
261 	int i;
262 
263 	qdf_timer_clean();
264 
265 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
266 		qdf_list_destroy(&qdf_timer_domains[i]);
267 
268 	qdf_spinlock_destroy(&qdf_timer_list_lock);
269 }
270 qdf_export_symbol(qdf_mc_timer_manager_exit);
271 #endif
272 
273 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
274 static void __os_mc_timer_shim(struct timer_list *os_timer)
275 {
276 	qdf_mc_timer_platform_t *platform_info_ptr =
277 				qdf_container_of(os_timer,
278 						 qdf_mc_timer_platform_t,
279 						 timer);
280 	qdf_mc_timer_t *timer = qdf_container_of(platform_info_ptr,
281 						 qdf_mc_timer_t,
282 						 platform_info);
283 
284 	scheduler_timer_callback(timer);
285 }
286 
287 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer,
288 			       QDF_TIMER_TYPE timer_type)
289 {
290 	uint32_t flags = 0;
291 
292 	if (QDF_TIMER_TYPE_SW == timer_type)
293 		flags |= TIMER_DEFERRABLE;
294 
295 	timer_setup(&timer->platform_info.timer,
296 		    __os_mc_timer_shim, flags);
297 }
298 #else
299 static void __os_mc_timer_shim(unsigned long data)
300 {
301 	qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data;
302 
303 	scheduler_timer_callback(timer);
304 }
305 
306 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer,
307 			       QDF_TIMER_TYPE timer_type)
308 {
309 	if (QDF_TIMER_TYPE_SW == timer_type)
310 		init_timer_deferrable(&timer->platform_info.timer);
311 	else
312 		init_timer(&timer->platform_info.timer);
313 
314 	timer->platform_info.timer.function = __os_mc_timer_shim;
315 	timer->platform_info.timer.data = (unsigned long)timer;
316 }
317 #endif
318 /**
319  * qdf_mc_timer_init() - initialize a QDF timer
320  * @timer: Pointer to timer object
321  * @timer_type: Type of timer
322  * @callback: Callback to be called after timer expiry
323  * @ser_data: User data which will be passed to callback function
324  *
325  * This API initializes a QDF timer object.
326  *
327  * qdf_mc_timer_init() initializes a QDF timer object. A timer must be
328  * initialized by calling qdf_mc_timer_initialize() before it may be used in
329  * any other timer functions.
330  *
331  * Attempting to initialize timer that is already initialized results in
332  * a failure. A destroyed timer object can be re-initialized with a call to
333  * qdf_mc_timer_init(). The results of otherwise referencing the object
334  * after it has been destroyed are undefined.
335  *
336  *  Calls to QDF timer functions to manipulate the timer such
337  *  as qdf_mc_timer_set() will fail if the timer is not initialized or has
338  *  been destroyed. Therefore, don't use the timer after it has been
339  *  destroyed until it has been re-initialized.
340  *
341  *  All callback will be executed within the CDS main thread unless it is
342  *  initialized from the Tx thread flow, in which case it will be executed
343  *  within the tx thread flow.
344  *
345  * Return:
346  * QDF_STATUS_SUCCESS: timer is initialized successfully
347  * QDF failure status: timer initialization failed
348  */
349 #ifdef TIMER_MANAGER
350 QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer,
351 				   QDF_TIMER_TYPE timer_type,
352 				   qdf_mc_timer_callback_t callback,
353 				   void *user_data, char *file_name,
354 				   uint32_t line_num)
355 {
356 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
357 	qdf_list_t *active_timers = qdf_timer_list_get(current_domain);
358 	QDF_STATUS qdf_status;
359 
360 	/* check for invalid pointer */
361 	if ((!timer) || (!callback)) {
362 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
363 			  "%s: Null params being passed", __func__);
364 		QDF_ASSERT(0);
365 		return QDF_STATUS_E_FAULT;
366 	}
367 
368 	timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t));
369 
370 	if (!timer->timer_node) {
371 		QDF_ASSERT(0);
372 		return QDF_STATUS_E_NOMEM;
373 	}
374 
375 	timer->timer_node->file_name = file_name;
376 	timer->timer_node->line_num = line_num;
377 	timer->timer_node->qdf_timer = timer;
378 
379 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
380 	qdf_status = qdf_list_insert_front(active_timers,
381 					   &timer->timer_node->node);
382 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
383 	if (QDF_STATUS_SUCCESS != qdf_status) {
384 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
385 			  "%s: Unable to insert node into List qdf_status %d",
386 			  __func__, qdf_status);
387 	}
388 
389 	/* set the various members of the timer structure
390 	 * with arguments passed or with default values
391 	 */
392 	qdf_spinlock_create(&timer->platform_info.spinlock);
393 	qdf_mc_timer_setup(timer, timer_type);
394 	timer->callback = callback;
395 	timer->user_data = user_data;
396 	timer->type = timer_type;
397 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
398 	timer->platform_info.thread_id = 0;
399 	timer->state = QDF_TIMER_STATE_STOPPED;
400 
401 	return QDF_STATUS_SUCCESS;
402 }
403 qdf_export_symbol(qdf_mc_timer_init_debug);
404 #else
405 QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type,
406 			     qdf_mc_timer_callback_t callback,
407 			     void *user_data)
408 {
409 	/* check for invalid pointer */
410 	if ((!timer) || (!callback)) {
411 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
412 			  "%s: Null params being passed", __func__);
413 		QDF_ASSERT(0);
414 		return QDF_STATUS_E_FAULT;
415 	}
416 
417 	/* set the various members of the timer structure
418 	 * with arguments passed or with default values
419 	 */
420 	qdf_spinlock_create(&timer->platform_info.spinlock);
421 	qdf_mc_timer_setup(timer, timer_type);
422 	timer->callback = callback;
423 	timer->user_data = user_data;
424 	timer->type = timer_type;
425 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
426 	timer->platform_info.thread_id = 0;
427 	timer->state = QDF_TIMER_STATE_STOPPED;
428 
429 	return QDF_STATUS_SUCCESS;
430 }
431 qdf_export_symbol(qdf_mc_timer_init);
432 #endif
433 
434 /**
435  * qdf_mc_timer_destroy() - destroy QDF timer
436  * @timer: Pointer to timer object
437  *
438  * qdf_mc_timer_destroy() function shall destroy the timer object.
439  * After a successful return from \a qdf_mc_timer_destroy() the timer
440  * object becomes, in effect, uninitialized.
441  *
442  * A destroyed timer object can be re-initialized by calling
443  * qdf_mc_timer_init().  The results of otherwise referencing the object
444  * after it has been destroyed are undefined.
445  *
446  * Calls to QDF timer functions to manipulate the timer, such
447  * as qdf_mc_timer_set() will fail if the lock is destroyed.  Therefore,
448  * don't use the timer after it has been destroyed until it has
449  * been re-initialized.
450  *
451  * Return:
452  * QDF_STATUS_SUCCESS - timer is initialized successfully
453  * QDF failure status - timer initialization failed
454  */
455 #ifdef TIMER_MANAGER
456 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
457 {
458 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
459 	qdf_list_t *active_timers = qdf_timer_list_get(current_domain);
460 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
461 
462 	/* check for invalid pointer */
463 	if (!timer) {
464 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
465 			  "%s: Null timer pointer being passed", __func__);
466 		QDF_ASSERT(0);
467 		return QDF_STATUS_E_FAULT;
468 	}
469 
470 	/* Check if timer refers to an uninitialized object */
471 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
472 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
473 			  "%s: Cannot destroy uninitialized timer", __func__);
474 		QDF_ASSERT(0);
475 		return QDF_STATUS_E_INVAL;
476 	}
477 
478 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
479 	v_status = qdf_list_remove_node(active_timers,
480 					&timer->timer_node->node);
481 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
482 	if (v_status != QDF_STATUS_SUCCESS) {
483 		QDF_ASSERT(0);
484 		return QDF_STATUS_E_INVAL;
485 	}
486 	qdf_mem_free(timer->timer_node);
487 
488 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
489 
490 	switch (timer->state) {
491 
492 	case QDF_TIMER_STATE_STARTING:
493 		v_status = QDF_STATUS_E_BUSY;
494 		break;
495 
496 	case QDF_TIMER_STATE_RUNNING:
497 		/* Stop the timer first */
498 		del_timer(&(timer->platform_info.timer));
499 		v_status = QDF_STATUS_SUCCESS;
500 		break;
501 	case QDF_TIMER_STATE_STOPPED:
502 		v_status = QDF_STATUS_SUCCESS;
503 		break;
504 
505 	case QDF_TIMER_STATE_UNUSED:
506 		v_status = QDF_STATUS_E_ALREADY;
507 		break;
508 
509 	default:
510 		v_status = QDF_STATUS_E_FAULT;
511 		break;
512 	}
513 
514 	if (QDF_STATUS_SUCCESS == v_status) {
515 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
516 		timer->state = QDF_TIMER_STATE_UNUSED;
517 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
518 		qdf_spinlock_destroy(&timer->platform_info.spinlock);
519 		return v_status;
520 	}
521 
522 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
523 
524 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
525 		  "%s: Cannot destroy timer in state = %d", __func__,
526 		  timer->state);
527 	QDF_ASSERT(0);
528 
529 	return v_status;
530 }
531 qdf_export_symbol(qdf_mc_timer_destroy);
532 
533 #else
534 
535 /**
536  * qdf_mc_timer_destroy() - destroy QDF timer
537  * @timer: Pointer to timer object
538  *
539  * qdf_mc_timer_destroy() function shall destroy the timer object.
540  * After a successful return from \a qdf_mc_timer_destroy() the timer
541  * object becomes, in effect, uninitialized.
542  *
543  * A destroyed timer object can be re-initialized by calling
544  * qdf_mc_timer_init(). The results of otherwise referencing the object
545  * after it has been destroyed are undefined.
546  *
547  * Calls to QDF timer functions to manipulate the timer, such
548  * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore,
549  * don't use the timer after it has been destroyed until it has
550  * been re-initialized.
551  *
552  * Return:
553  * QDF_STATUS_SUCCESS - timer is initialized successfully
554  * QDF failure status - timer initialization failed
555  */
556 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
557 {
558 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
559 
560 	/* check for invalid pointer */
561 	if (!timer) {
562 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
563 			  "%s: Null timer pointer being passed", __func__);
564 		QDF_ASSERT(0);
565 		return QDF_STATUS_E_FAULT;
566 	}
567 
568 	/* check if timer refers to an uninitialized object */
569 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
570 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
571 			  "%s: Cannot destroy uninitialized timer", __func__);
572 		QDF_ASSERT(0);
573 		return QDF_STATUS_E_INVAL;
574 	}
575 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
576 
577 	switch (timer->state) {
578 
579 	case QDF_TIMER_STATE_STARTING:
580 		v_status = QDF_STATUS_E_BUSY;
581 		break;
582 
583 	case QDF_TIMER_STATE_RUNNING:
584 		/* Stop the timer first */
585 		del_timer(&(timer->platform_info.timer));
586 		v_status = QDF_STATUS_SUCCESS;
587 		break;
588 
589 	case QDF_TIMER_STATE_STOPPED:
590 		v_status = QDF_STATUS_SUCCESS;
591 		break;
592 
593 	case QDF_TIMER_STATE_UNUSED:
594 		v_status = QDF_STATUS_E_ALREADY;
595 		break;
596 
597 	default:
598 		v_status = QDF_STATUS_E_FAULT;
599 		break;
600 	}
601 
602 	if (QDF_STATUS_SUCCESS == v_status) {
603 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
604 		timer->state = QDF_TIMER_STATE_UNUSED;
605 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
606 		return v_status;
607 	}
608 
609 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
610 
611 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
612 		  "%s: Cannot destroy timer in state = %d", __func__,
613 		  timer->state);
614 	QDF_ASSERT(0);
615 
616 	return v_status;
617 }
618 qdf_export_symbol(qdf_mc_timer_destroy);
619 #endif
620 
621 /**
622  * qdf_mc_timer_start() - start a QDF timer object
623  * @timer: Pointer to timer object
624  * @expiration_time: Time to expire
625  *
626  * qdf_mc_timer_start() function starts a timer to expire after the
627  * specified interval, thus running the timer callback function when
628  * the interval expires.
629  *
630  * A timer only runs once (a one-shot timer). To re-start the
631  * timer, qdf_mc_timer_start() has to be called after the timer runs
632  * or has been cancelled.
633  *
634  * Return:
635  * QDF_STATUS_SUCCESS: timer is initialized successfully
636  * QDF failure status: timer initialization failed
637  */
638 QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time)
639 {
640 	/* check for invalid pointer */
641 	if (!timer) {
642 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
643 			  "%s Null timer pointer being passed", __func__);
644 		QDF_ASSERT(0);
645 		return QDF_STATUS_E_INVAL;
646 	}
647 
648 	/* check if timer refers to an uninitialized object */
649 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
650 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
651 			  "%s: Cannot start uninitialized timer", __func__);
652 		QDF_ASSERT(0);
653 
654 		return QDF_STATUS_E_INVAL;
655 	}
656 
657 	/* check if timer has expiration time less than 10 ms */
658 	if (expiration_time < 10) {
659 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
660 			  "%s: Cannot start a timer with expiration less than 10 ms",
661 			  __func__);
662 		QDF_ASSERT(0);
663 		return QDF_STATUS_E_INVAL;
664 	}
665 
666 	/* make sure the remainer of the logic isn't interrupted */
667 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
668 
669 	/* ensure if the timer can be started */
670 	if (QDF_TIMER_STATE_STOPPED != timer->state) {
671 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
672 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
673 			  "%s: Cannot start timer in state = %d %ps",
674 			  __func__, timer->state, (void *)timer->callback);
675 		return QDF_STATUS_E_ALREADY;
676 	}
677 
678 	/* start the timer */
679 	mod_timer(&(timer->platform_info.timer),
680 		  jiffies + __qdf_scaled_msecs_to_jiffies(expiration_time));
681 
682 	timer->state = QDF_TIMER_STATE_RUNNING;
683 
684 	/* get the thread ID on which the timer is being started */
685 	timer->platform_info.thread_id = current->pid;
686 
687 	if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) {
688 		persistent_timer_count++;
689 		if (1 == persistent_timer_count) {
690 			/* since we now have one persistent timer,
691 			 * we need to disallow sleep
692 			 * sleep_negate_okts(sleep_client_handle);
693 			 */
694 		}
695 	}
696 
697 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
698 
699 	return QDF_STATUS_SUCCESS;
700 }
701 qdf_export_symbol(qdf_mc_timer_start);
702 
703 /**
704  * qdf_mc_timer_stop() - stop a QDF timer
705  * @timer: Pointer to timer object
706  * qdf_mc_timer_stop() function stops a timer that has been started but
707  * has not expired, essentially cancelling the 'start' request.
708  *
709  * After a timer is stopped, it goes back to the state it was in after it
710  * was created and can be started again via a call to qdf_mc_timer_start().
711  *
712  * Return:
713  * QDF_STATUS_SUCCESS: timer is initialized successfully
714  * QDF failure status: timer initialization failed
715  */
716 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer)
717 {
718 	/* check for invalid pointer */
719 	if (!timer) {
720 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
721 			  "%s Null timer pointer being passed", __func__);
722 		QDF_ASSERT(0);
723 		return QDF_STATUS_E_INVAL;
724 	}
725 
726 	/* check if timer refers to an uninitialized object */
727 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
728 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
729 			  "%s: Cannot stop uninitialized timer", __func__);
730 		QDF_ASSERT(0);
731 
732 		return QDF_STATUS_E_INVAL;
733 	}
734 
735 	/* ensure the timer state is correct */
736 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
737 
738 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
739 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
740 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
741 			  "%s: Cannot stop timer in state = %d",
742 			  __func__, timer->state);
743 		return QDF_STATUS_SUCCESS;
744 	}
745 
746 	timer->state = QDF_TIMER_STATE_STOPPED;
747 
748 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
749 
750 	del_timer(&(timer->platform_info.timer));
751 
752 	qdf_try_allowing_sleep(timer->type);
753 
754 	return QDF_STATUS_SUCCESS;
755 }
756 qdf_export_symbol(qdf_mc_timer_stop);
757 
758 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer)
759 {
760 	/* check for invalid pointer */
761 	if (!timer) {
762 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
763 			  "%s Null timer pointer being passed", __func__);
764 		QDF_ASSERT(0);
765 		return QDF_STATUS_E_INVAL;
766 	}
767 
768 	/* check if timer refers to an uninitialized object */
769 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
770 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
771 			  "%s: Cannot stop uninitialized timer", __func__);
772 		QDF_ASSERT(0);
773 
774 		return QDF_STATUS_E_INVAL;
775 	}
776 
777 	/* ensure the timer state is correct */
778 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
779 
780 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
781 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
782 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
783 			  "%s: Cannot stop timer in state = %d",
784 			  __func__, timer->state);
785 		return QDF_STATUS_SUCCESS;
786 	}
787 
788 	timer->state = QDF_TIMER_STATE_STOPPED;
789 
790 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
791 	del_timer_sync(&(timer->platform_info.timer));
792 
793 	qdf_try_allowing_sleep(timer->type);
794 
795 	return QDF_STATUS_SUCCESS;
796 }
797 qdf_export_symbol(qdf_mc_timer_stop_sync);
798 /**
799  * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks
800 
801  * qdf_mc_timer_get_system_ticks() function returns the current number
802  * of timer ticks in 10msec intervals. This function is suitable timestamping
803  * and calculating time intervals by calculating the difference between two
804  * timestamps.
805  *
806  * Return:
807  * The current system tick count (in 10msec intervals).  This
808  * function cannot fail.
809  */
810 unsigned long qdf_mc_timer_get_system_ticks(void)
811 {
812 	return jiffies_to_msecs(jiffies) / 10;
813 }
814 qdf_export_symbol(qdf_mc_timer_get_system_ticks);
815 
816 /**
817  * qdf_mc_timer_get_system_time() - Get the system time in milliseconds
818  *
819  * qdf_mc_timer_get_system_time() function returns the number of milliseconds
820  * that have elapsed since the system was started
821  *
822  * Return:
823  * The current system time in milliseconds
824  */
825 unsigned long qdf_mc_timer_get_system_time(void)
826 {
827 	struct timeval tv;
828 
829 	do_gettimeofday(&tv);
830 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
831 }
832 qdf_export_symbol(qdf_mc_timer_get_system_time);
833 
834 s64 qdf_get_monotonic_boottime_ns(void)
835 {
836 	struct timespec ts;
837 
838 	get_monotonic_boottime(&ts);
839 
840 	return timespec_to_ns(&ts);
841 }
842 qdf_export_symbol(qdf_get_monotonic_boottime_ns);
843 
844 qdf_time_t qdf_get_time_of_the_day_ms(void)
845 {
846 	struct timeval tv;
847 	qdf_time_t local_time;
848 	struct rtc_time tm;
849 
850 	do_gettimeofday(&tv);
851 	local_time = (qdf_time_t)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
852 	rtc_time_to_tm(local_time, &tm);
853 
854 	return (tm.tm_hour * 60 * 60 * 1000) +
855 		(tm.tm_min * 60 * 1000) + (tm.tm_sec * 1000) +
856 		(tv.tv_usec / 1000);
857 }
858 qdf_export_symbol(qdf_get_time_of_the_day_ms);
859 
860 /**
861  * qdf_timer_module_deinit() - Deinitializes a QDF timer module.
862  *
863  * This API deinitializes the QDF timer module.
864  * Return: none
865  */
866 void qdf_timer_module_deinit(void)
867 {
868 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
869 		  "De-Initializing the QDF MC timer module");
870 	qdf_mutex_destroy(&persistent_timer_count_lock);
871 }
872 qdf_export_symbol(qdf_timer_module_deinit);
873 
874 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
875 {
876 	struct timeval tv;
877 	struct rtc_time tm;
878 	unsigned long local_time;
879 
880 	/* Format the Log time R#: [hr:min:sec.microsec] */
881 	do_gettimeofday(&tv);
882 	/* Convert rtc to local time */
883 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
884 	rtc_time_to_tm(local_time, &tm);
885 	scnprintf(tbuf, len,
886 		"[%02d:%02d:%02d.%06lu]",
887 		tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
888 }
889 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
890