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