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