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