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