xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c (revision f49b3a17535861c81c96f561e6e9be8a33a99f15)
1 /*
2  * Copyright (c) 2014-2021 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 #include "qdf_timer.h"
33 #include <linux/time64.h>
34 
35 /* Preprocessor definitions and constants */
36 #define LINUX_TIMER_COOKIE 0x12341234
37 #define LINUX_INVALID_TIMER_COOKIE 0xfeedface
38 #define TMR_INVALID_ID (0)
39 
40 #ifdef QDF_TIMER_MULTIPLIER_FRAC
41 static uint32_t g_qdf_timer_multiplier = QDF_TIMER_MULTIPLIER_FRAC;
42 #else
43 static uint32_t g_qdf_timer_multiplier = 1;
44 #endif
45 
46 inline void qdf_timer_set_multiplier(uint32_t multiplier)
47 {
48 	g_qdf_timer_multiplier = multiplier;
49 }
50 qdf_export_symbol(qdf_timer_set_multiplier);
51 
52 inline uint32_t qdf_timer_get_multiplier(void)
53 {
54 	return g_qdf_timer_multiplier;
55 }
56 qdf_export_symbol(qdf_timer_get_multiplier);
57 
58 /* Type declarations */
59 
60 /* Static Variable Definitions */
61 static unsigned int persistent_timer_count;
62 static qdf_mutex_t persistent_timer_count_lock;
63 
64 static void (*scheduler_timer_callback)(qdf_mc_timer_t *);
65 void qdf_register_mc_timer_callback(void (*callback) (qdf_mc_timer_t *))
66 {
67 	scheduler_timer_callback = callback;
68 }
69 
70 qdf_export_symbol(qdf_register_mc_timer_callback);
71 
72 /* Function declarations and documenation */
73 
74 /**
75  * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated
76  * @type: timer type
77  *
78  * Clean up timer states after it has been deactivated check and try to allow
79  * sleep after a timer has been stopped or expired.
80  *
81  * Return: none
82  */
83 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type)
84 {
85 	if (QDF_TIMER_TYPE_WAKE_APPS == type) {
86 
87 		persistent_timer_count--;
88 		if (0 == persistent_timer_count) {
89 			/* since the number of persistent timers has
90 			 * decreased from 1 to 0, the timer should allow
91 			 * sleep
92 			 */
93 		}
94 	}
95 }
96 qdf_export_symbol(qdf_try_allowing_sleep);
97 
98 /**
99  * qdf_mc_timer_get_current_state() - get the current state of the timer
100  * @timer: Pointer to timer object
101  *
102  * Return:
103  * QDF_TIMER_STATE - qdf timer state
104  */
105 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer)
106 {
107 	QDF_TIMER_STATE timer_state = QDF_TIMER_STATE_UNUSED;
108 
109 	if (!timer) {
110 		QDF_ASSERT(0);
111 		return timer_state;
112 	}
113 
114 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
115 
116 	switch (timer->state) {
117 	case QDF_TIMER_STATE_STOPPED:
118 	case QDF_TIMER_STATE_STARTING:
119 	case QDF_TIMER_STATE_RUNNING:
120 	case QDF_TIMER_STATE_UNUSED:
121 		timer_state = timer->state;
122 		break;
123 	default:
124 		QDF_ASSERT(0);
125 	}
126 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
127 	return timer_state;
128 }
129 qdf_export_symbol(qdf_mc_timer_get_current_state);
130 
131 /**
132  * qdf_timer_module_init() - initializes a QDF timer module.
133  *
134  * This API initializes the QDF timer module. This needs to be called
135  * exactly once prior to using any QDF timers.
136  *
137  * Return: none
138  */
139 void qdf_timer_module_init(void)
140 {
141 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
142 		  "Initializing the QDF MC timer module");
143 	qdf_mutex_create(&persistent_timer_count_lock);
144 }
145 qdf_export_symbol(qdf_timer_module_init);
146 
147 #ifdef TIMER_MANAGER
148 
149 static qdf_list_t qdf_timer_domains[QDF_DEBUG_DOMAIN_COUNT];
150 static qdf_spinlock_t qdf_timer_list_lock;
151 
152 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain)
153 {
154 	return &qdf_timer_domains[domain];
155 }
156 
157 /**
158  * qdf_mc_timer_manager_init() - initialize QDF debug timer manager
159  *
160  * This API initializes QDF timer debug functionality.
161  *
162  * Return: none
163  */
164 void qdf_mc_timer_manager_init(void)
165 {
166 	int i;
167 
168 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
169 		qdf_list_create(&qdf_timer_domains[i], 1000);
170 	qdf_spinlock_create(&qdf_timer_list_lock);
171 }
172 qdf_export_symbol(qdf_mc_timer_manager_init);
173 
174 static void qdf_mc_timer_print_list(qdf_list_t *timers)
175 {
176 	QDF_STATUS status;
177 	qdf_list_node_t *node;
178 
179 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
180 	status = qdf_list_peek_front(timers, &node);
181 	while (QDF_IS_STATUS_SUCCESS(status)) {
182 		qdf_mc_timer_node_t *timer_node = (qdf_mc_timer_node_t *)node;
183 		const char *filename = kbasename(timer_node->file_name);
184 		uint32_t line = timer_node->line_num;
185 
186 		qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
187 		qdf_err("timer Leak@ File %s, @Line %u", filename, line);
188 		qdf_spin_lock_irqsave(&qdf_timer_list_lock);
189 
190 		status = qdf_list_peek_next(timers, node, &node);
191 	}
192 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
193 }
194 
195 void qdf_mc_timer_check_for_leaks(void)
196 {
197 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
198 	qdf_list_t *timers = qdf_timer_list_get(current_domain);
199 
200 	if (qdf_list_empty(timers))
201 		return;
202 
203 	qdf_err("Timer leaks detected in %s domain!",
204 		qdf_debug_domain_name(current_domain));
205 	qdf_mc_timer_print_list(timers);
206 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
207 }
208 
209 static void qdf_mc_timer_free_leaked_timers(qdf_list_t *timers)
210 {
211 	QDF_STATUS status;
212 	qdf_list_node_t *node;
213 
214 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
215 	status = qdf_list_remove_front(timers, &node);
216 	while (QDF_IS_STATUS_SUCCESS(status)) {
217 		qdf_mem_free(node);
218 		status = qdf_list_remove_front(timers, &node);
219 	}
220 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
221 }
222 
223 /**
224  * qdf_timer_clean() - clean up QDF timer debug functionality
225  *
226  * This API cleans up QDF timer debug functionality and prints which QDF timers
227  * are leaked. This is called during driver unload.
228  *
229  * Return: none
230  */
231 static void qdf_timer_clean(void)
232 {
233 	bool leaks_detected = false;
234 	int i;
235 
236 	/* detect and print leaks */
237 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) {
238 		qdf_list_t *timers = &qdf_timer_domains[i];
239 
240 		if (qdf_list_empty(timers))
241 			continue;
242 
243 		leaks_detected = true;
244 
245 		qdf_err("\nTimer leaks detected in the %s (Id %d) domain!",
246 			qdf_debug_domain_name(i), i);
247 		qdf_mc_timer_print_list(timers);
248 	}
249 
250 	/* we're done if there were no leaks */
251 	if (!leaks_detected)
252 		return;
253 
254 	/* panic, if enabled */
255 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
256 
257 	/* if we didn't crash, release the leaked timers */
258 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
259 		qdf_mc_timer_free_leaked_timers(&qdf_timer_domains[i]);
260 }
261 qdf_export_symbol(qdf_timer_clean);
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 remainer 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 	/* get the thread ID on which the timer is being started */
696 	timer->platform_info.thread_id = current->pid;
697 
698 	if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) {
699 		persistent_timer_count++;
700 		if (1 == persistent_timer_count) {
701 			/* since we now have one persistent timer,
702 			 * we need to disallow sleep
703 			 * sleep_negate_okts(sleep_client_handle);
704 			 */
705 		}
706 	}
707 
708 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
709 
710 	return QDF_STATUS_SUCCESS;
711 }
712 qdf_export_symbol(qdf_mc_timer_start);
713 
714 /**
715  * qdf_mc_timer_stop() - stop a QDF timer
716  * @timer: Pointer to timer object
717  * qdf_mc_timer_stop() function stops a timer that has been started but
718  * has not expired, essentially cancelling the 'start' request.
719  *
720  * After a timer is stopped, it goes back to the state it was in after it
721  * was created and can be started again via a call to qdf_mc_timer_start().
722  *
723  * Return:
724  * QDF_STATUS_SUCCESS: timer is initialized successfully
725  * QDF failure status: timer initialization failed
726  */
727 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer)
728 {
729 	/* check for invalid pointer */
730 	if (!timer) {
731 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
732 				   "%s Null timer pointer", __func__);
733 		QDF_ASSERT(0);
734 		return QDF_STATUS_E_INVAL;
735 	}
736 
737 	/* check if timer refers to an uninitialized object */
738 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
739 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
740 				   "%s: Cannot stop uninit timer", __func__);
741 		QDF_ASSERT(0);
742 
743 		return QDF_STATUS_E_INVAL;
744 	}
745 
746 	/* ensure the timer state is correct */
747 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
748 
749 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
750 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
751 		return QDF_STATUS_SUCCESS;
752 	}
753 
754 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
755 
756 	del_timer(&(timer->platform_info.timer));
757 
758 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
759 	timer->state = QDF_TIMER_STATE_STOPPED;
760 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
761 
762 	qdf_try_allowing_sleep(timer->type);
763 
764 	return QDF_STATUS_SUCCESS;
765 }
766 qdf_export_symbol(qdf_mc_timer_stop);
767 
768 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer)
769 {
770 	/* check for invalid pointer */
771 	if (!timer) {
772 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
773 				   "%s Null timer pointer", __func__);
774 		QDF_ASSERT(0);
775 		return QDF_STATUS_E_INVAL;
776 	}
777 
778 	/* check if timer refers to an uninitialized object */
779 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
780 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
781 				   "%s: Cannot stop uninit timer", __func__);
782 		QDF_ASSERT(0);
783 
784 		return QDF_STATUS_E_INVAL;
785 	}
786 
787 	/* ensure the timer state is correct */
788 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
789 
790 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
791 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
792 		return QDF_STATUS_SUCCESS;
793 	}
794 
795 	timer->state = QDF_TIMER_STATE_STOPPED;
796 
797 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
798 	del_timer_sync(&(timer->platform_info.timer));
799 
800 	qdf_try_allowing_sleep(timer->type);
801 
802 	return QDF_STATUS_SUCCESS;
803 }
804 qdf_export_symbol(qdf_mc_timer_stop_sync);
805 /**
806  * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks
807 
808  * qdf_mc_timer_get_system_ticks() function returns the current number
809  * of timer ticks in 10msec intervals. This function is suitable timestamping
810  * and calculating time intervals by calculating the difference between two
811  * timestamps.
812  *
813  * Return:
814  * The current system tick count (in 10msec intervals).  This
815  * function cannot fail.
816  */
817 unsigned long qdf_mc_timer_get_system_ticks(void)
818 {
819 	return jiffies_to_msecs(jiffies) / 10;
820 }
821 qdf_export_symbol(qdf_mc_timer_get_system_ticks);
822 
823 /**
824  * qdf_mc_timer_get_system_time() - Get the system time in milliseconds
825  *
826  * qdf_mc_timer_get_system_time() function returns the number of milliseconds
827  * that have elapsed since the system was started
828  *
829  * Return:
830  * The current system time in milliseconds
831  */
832 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
833 unsigned long qdf_mc_timer_get_system_time(void)
834 {
835 	struct timespec64 tv;
836 
837 	ktime_get_real_ts64(&tv);
838 	return tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
839 }
840 qdf_export_symbol(qdf_mc_timer_get_system_time);
841 
842 #else
843 unsigned long qdf_mc_timer_get_system_time(void)
844 {
845 	struct timeval tv;
846 
847 	do_gettimeofday(&tv);
848 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
849 }
850 qdf_export_symbol(qdf_mc_timer_get_system_time);
851 #endif
852 
853 s64 qdf_get_monotonic_boottime_ns(void)
854 {
855 	return ktime_to_ns(ktime_get_boottime());
856 }
857 qdf_export_symbol(qdf_get_monotonic_boottime_ns);
858 
859 /**
860  * qdf_timer_module_deinit() - Deinitializes a QDF timer module.
861  *
862  * This API deinitializes the QDF timer module.
863  * Return: none
864  */
865 void qdf_timer_module_deinit(void)
866 {
867 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
868 		  "De-Initializing the QDF MC timer module");
869 	qdf_mutex_destroy(&persistent_timer_count_lock);
870 }
871 qdf_export_symbol(qdf_timer_module_deinit);
872 
873 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
874 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
875 {
876 	struct timespec64 tv;
877 	struct rtc_time tm;
878 	unsigned long local_time;
879 
880 	/* Format the Log time R#: [hr:min:sec.microsec] */
881 	ktime_get_real_ts64(&tv);
882 	/* Convert rtc to local time */
883 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
884 	rtc_time64_to_tm(local_time, &tm);
885 	scnprintf(tbuf, len,
886 		  "[%02d:%02d:%02d.%06lu]",
887 		  tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_nsec / 1000);
888 }
889 
890 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
891 
892 uint64_t qdf_get_time_of_the_day_us(void)
893 {
894 	struct timespec64 tv;
895 	struct rtc_time tm;
896 	unsigned long local_time;
897 	uint64_t time_of_day_us = 0;
898 
899 	ktime_get_real_ts64(&tv);
900 	/* Convert rtc to local time */
901 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
902 	rtc_time64_to_tm(local_time, &tm);
903 
904 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
905 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
906 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
907 	time_of_day_us += qdf_do_div((uint64_t)tv.tv_nsec,  1000);
908 
909 	return time_of_day_us;
910 }
911 
912 qdf_export_symbol(qdf_get_time_of_the_day_us);
913 #else
914 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
915 {
916 	struct timeval tv;
917 	struct rtc_time tm;
918 	unsigned long local_time;
919 
920 	/* Format the Log time R#: [hr:min:sec.microsec] */
921 	do_gettimeofday(&tv);
922 	/* Convert rtc to local time */
923 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
924 	rtc_time_to_tm(local_time, &tm);
925 	scnprintf(tbuf, len,
926 		"[%02d:%02d:%02d.%06lu]",
927 		tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
928 }
929 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
930 
931 uint64_t qdf_get_time_of_the_day_us(void)
932 {
933 	struct timeval tv;
934 	struct rtc_time tm;
935 	unsigned long local_time;
936 	uint64_t time_of_day_us = 0;
937 
938 	do_gettimeofday(&tv);
939 	/* Convert rtc to local time */
940 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
941 	rtc_time_to_tm(local_time, &tm);
942 
943 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
944 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
945 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
946 	time_of_day_us += (uint64_t)tv.tv_usec;
947 
948 	return time_of_day_us;
949 }
950 
951 qdf_export_symbol(qdf_get_time_of_the_day_us);
952 #endif
953 
954 qdf_time_t qdf_get_time_of_the_day_ms(void)
955 {
956 	qdf_time_t time_of_the_day_ms;
957 
958 	time_of_the_day_ms = qdf_do_div(qdf_get_time_of_the_day_us(), 1000);
959 
960 	return time_of_the_day_ms;
961 }
962 
963 qdf_export_symbol(qdf_get_time_of_the_day_ms);
964