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