xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c (revision 54ab05a36f58e470e5b322a774385b90ea47f785)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type)
76 {
77 	if (QDF_TIMER_TYPE_WAKE_APPS == type) {
78 
79 		persistent_timer_count--;
80 		if (0 == persistent_timer_count) {
81 			/* since the number of persistent timers has
82 			 * decreased from 1 to 0, the timer should allow
83 			 * sleep
84 			 */
85 		}
86 	}
87 }
88 qdf_export_symbol(qdf_try_allowing_sleep);
89 
90 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer)
91 {
92 	QDF_TIMER_STATE timer_state = QDF_TIMER_STATE_UNUSED;
93 
94 	if (!timer) {
95 		QDF_ASSERT(0);
96 		return timer_state;
97 	}
98 
99 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
100 
101 	switch (timer->state) {
102 	case QDF_TIMER_STATE_STOPPED:
103 	case QDF_TIMER_STATE_STARTING:
104 	case QDF_TIMER_STATE_RUNNING:
105 	case QDF_TIMER_STATE_UNUSED:
106 		timer_state = timer->state;
107 		break;
108 	default:
109 		QDF_ASSERT(0);
110 	}
111 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
112 	return timer_state;
113 }
114 qdf_export_symbol(qdf_mc_timer_get_current_state);
115 
116 void qdf_timer_module_init(void)
117 {
118 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
119 		  "Initializing the QDF MC timer module");
120 	qdf_mutex_create(&persistent_timer_count_lock);
121 }
122 qdf_export_symbol(qdf_timer_module_init);
123 
124 #ifdef TIMER_MANAGER
125 
126 static qdf_list_t qdf_timer_domains[QDF_DEBUG_DOMAIN_COUNT];
127 static qdf_spinlock_t qdf_timer_list_lock;
128 
129 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain)
130 {
131 	return &qdf_timer_domains[domain];
132 }
133 
134 void qdf_mc_timer_manager_init(void)
135 {
136 	int i;
137 
138 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
139 		qdf_list_create(&qdf_timer_domains[i], 1000);
140 	qdf_spinlock_create(&qdf_timer_list_lock);
141 }
142 qdf_export_symbol(qdf_mc_timer_manager_init);
143 
144 static void qdf_mc_timer_print_list(qdf_list_t *timers)
145 {
146 	QDF_STATUS status;
147 	qdf_list_node_t *node;
148 
149 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
150 	status = qdf_list_peek_front(timers, &node);
151 	while (QDF_IS_STATUS_SUCCESS(status)) {
152 		qdf_mc_timer_node_t *timer_node = (qdf_mc_timer_node_t *)node;
153 		const char *filename = kbasename(timer_node->file_name);
154 		uint32_t line = timer_node->line_num;
155 
156 		qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
157 		qdf_err("timer Leak@ File %s, @Line %u", filename, line);
158 		qdf_spin_lock_irqsave(&qdf_timer_list_lock);
159 
160 		status = qdf_list_peek_next(timers, node, &node);
161 	}
162 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
163 }
164 
165 void qdf_mc_timer_check_for_leaks(void)
166 {
167 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
168 	qdf_list_t *timers = qdf_timer_list_get(current_domain);
169 
170 	if (qdf_list_empty(timers))
171 		return;
172 
173 	qdf_err("Timer leaks detected in %s domain!",
174 		qdf_debug_domain_name(current_domain));
175 	qdf_mc_timer_print_list(timers);
176 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
177 }
178 
179 static void qdf_mc_timer_free_leaked_timers(qdf_list_t *timers)
180 {
181 	QDF_STATUS status;
182 	qdf_list_node_t *node;
183 
184 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
185 	status = qdf_list_remove_front(timers, &node);
186 	while (QDF_IS_STATUS_SUCCESS(status)) {
187 		qdf_mem_free(node);
188 		status = qdf_list_remove_front(timers, &node);
189 	}
190 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
191 }
192 
193 /**
194  * qdf_timer_clean() - clean up QDF timer debug functionality
195  *
196  * This API cleans up QDF timer debug functionality and prints which QDF timers
197  * are leaked. This is called during driver unload.
198  *
199  * Return: none
200  */
201 static void qdf_timer_clean(void)
202 {
203 	bool leaks_detected = false;
204 	int i;
205 
206 	/* detect and print leaks */
207 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) {
208 		qdf_list_t *timers = &qdf_timer_domains[i];
209 
210 		if (qdf_list_empty(timers))
211 			continue;
212 
213 		leaks_detected = true;
214 
215 		qdf_err("\nTimer leaks detected in the %s (Id %d) domain!",
216 			qdf_debug_domain_name(i), i);
217 		qdf_mc_timer_print_list(timers);
218 	}
219 
220 	/* we're done if there were no leaks */
221 	if (!leaks_detected)
222 		return;
223 
224 	/* panic, if enabled */
225 	QDF_DEBUG_PANIC("Previously reported timer leaks detected");
226 
227 	/* if we didn't crash, release the leaked timers */
228 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
229 		qdf_mc_timer_free_leaked_timers(&qdf_timer_domains[i]);
230 }
231 
232 void qdf_mc_timer_manager_exit(void)
233 {
234 	int i;
235 
236 	qdf_timer_clean();
237 
238 	for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
239 		qdf_list_destroy(&qdf_timer_domains[i]);
240 
241 	qdf_spinlock_destroy(&qdf_timer_list_lock);
242 }
243 qdf_export_symbol(qdf_mc_timer_manager_exit);
244 #endif
245 
246 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
247 static void __os_mc_timer_shim(struct timer_list *os_timer)
248 {
249 	qdf_mc_timer_platform_t *platform_info_ptr =
250 				qdf_container_of(os_timer,
251 						 qdf_mc_timer_platform_t,
252 						 timer);
253 	qdf_mc_timer_t *timer = qdf_container_of(platform_info_ptr,
254 						 qdf_mc_timer_t,
255 						 platform_info);
256 
257 	scheduler_timer_callback(timer);
258 }
259 
260 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer,
261 			       QDF_TIMER_TYPE timer_type)
262 {
263 	uint32_t flags = 0;
264 
265 	if (QDF_TIMER_TYPE_SW == timer_type)
266 		flags |= TIMER_DEFERRABLE;
267 
268 	timer_setup(&timer->platform_info.timer,
269 		    __os_mc_timer_shim, flags);
270 }
271 #else
272 static void __os_mc_timer_shim(unsigned long data)
273 {
274 	qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data;
275 
276 	scheduler_timer_callback(timer);
277 }
278 
279 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer,
280 			       QDF_TIMER_TYPE timer_type)
281 {
282 	if (QDF_TIMER_TYPE_SW == timer_type)
283 		init_timer_deferrable(&timer->platform_info.timer);
284 	else
285 		init_timer(&timer->platform_info.timer);
286 
287 	timer->platform_info.timer.function = __os_mc_timer_shim;
288 	timer->platform_info.timer.data = (unsigned long)timer;
289 }
290 #endif
291 #ifdef TIMER_MANAGER
292 QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer,
293 				   QDF_TIMER_TYPE timer_type,
294 				   qdf_mc_timer_callback_t callback,
295 				   void *user_data, char *file_name,
296 				   uint32_t line_num)
297 {
298 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
299 	qdf_list_t *active_timers = qdf_timer_list_get(current_domain);
300 	QDF_STATUS qdf_status;
301 
302 	/* check for invalid pointer */
303 	if ((!timer) || (!callback)) {
304 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
305 			  "%s: Null params being passed", __func__);
306 		QDF_ASSERT(0);
307 		return QDF_STATUS_E_FAULT;
308 	}
309 
310 	timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t));
311 
312 	if (!timer->timer_node) {
313 		QDF_ASSERT(0);
314 		return QDF_STATUS_E_NOMEM;
315 	}
316 
317 	timer->timer_node->file_name = file_name;
318 	timer->timer_node->line_num = line_num;
319 	timer->timer_node->qdf_timer = timer;
320 
321 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
322 	qdf_status = qdf_list_insert_front(active_timers,
323 					   &timer->timer_node->node);
324 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
325 	if (QDF_STATUS_SUCCESS != qdf_status) {
326 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
327 			  "%s: Unable to insert node into List qdf_status %d",
328 			  __func__, qdf_status);
329 	}
330 
331 	/* set the various members of the timer structure
332 	 * with arguments passed or with default values
333 	 */
334 	qdf_spinlock_create(&timer->platform_info.spinlock);
335 	qdf_mc_timer_setup(timer, timer_type);
336 	timer->callback = callback;
337 	timer->user_data = user_data;
338 	timer->type = timer_type;
339 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
340 	timer->platform_info.thread_id = 0;
341 	timer->state = QDF_TIMER_STATE_STOPPED;
342 
343 	return QDF_STATUS_SUCCESS;
344 }
345 qdf_export_symbol(qdf_mc_timer_init_debug);
346 #else
347 QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type,
348 			     qdf_mc_timer_callback_t callback,
349 			     void *user_data)
350 {
351 	/* check for invalid pointer */
352 	if ((!timer) || (!callback)) {
353 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
354 			  "%s: Null params being passed", __func__);
355 		QDF_ASSERT(0);
356 		return QDF_STATUS_E_FAULT;
357 	}
358 
359 	/* set the various members of the timer structure
360 	 * with arguments passed or with default values
361 	 */
362 	qdf_spinlock_create(&timer->platform_info.spinlock);
363 	qdf_mc_timer_setup(timer, timer_type);
364 	timer->callback = callback;
365 	timer->user_data = user_data;
366 	timer->type = timer_type;
367 	timer->platform_info.cookie = LINUX_TIMER_COOKIE;
368 	timer->platform_info.thread_id = 0;
369 	timer->state = QDF_TIMER_STATE_STOPPED;
370 
371 	return QDF_STATUS_SUCCESS;
372 }
373 qdf_export_symbol(qdf_mc_timer_init);
374 #endif
375 
376 #ifdef TIMER_MANAGER
377 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
378 {
379 	enum qdf_debug_domain current_domain = qdf_debug_domain_get();
380 	qdf_list_t *active_timers = qdf_timer_list_get(current_domain);
381 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
382 
383 	/* check for invalid pointer */
384 	if (!timer) {
385 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
386 			  "%s: Null timer pointer being passed", __func__);
387 		QDF_ASSERT(0);
388 		return QDF_STATUS_E_FAULT;
389 	}
390 
391 	/* Check if timer refers to an uninitialized object */
392 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
393 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
394 			  "%s: Cannot destroy uninitialized timer", __func__);
395 		QDF_ASSERT(0);
396 		return QDF_STATUS_E_INVAL;
397 	}
398 
399 	qdf_spin_lock_irqsave(&qdf_timer_list_lock);
400 	v_status = qdf_list_remove_node(active_timers,
401 					&timer->timer_node->node);
402 	qdf_spin_unlock_irqrestore(&qdf_timer_list_lock);
403 	if (v_status != QDF_STATUS_SUCCESS) {
404 		QDF_ASSERT(0);
405 		return QDF_STATUS_E_INVAL;
406 	}
407 	qdf_mem_free(timer->timer_node);
408 
409 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
410 
411 	switch (timer->state) {
412 
413 	case QDF_TIMER_STATE_STARTING:
414 		v_status = QDF_STATUS_E_BUSY;
415 		break;
416 
417 	case QDF_TIMER_STATE_RUNNING:
418 		/* Stop the timer first */
419 		del_timer(&(timer->platform_info.timer));
420 		v_status = QDF_STATUS_SUCCESS;
421 		break;
422 	case QDF_TIMER_STATE_STOPPED:
423 		v_status = QDF_STATUS_SUCCESS;
424 		break;
425 
426 	case QDF_TIMER_STATE_UNUSED:
427 		v_status = QDF_STATUS_E_ALREADY;
428 		break;
429 
430 	default:
431 		v_status = QDF_STATUS_E_FAULT;
432 		break;
433 	}
434 
435 	if (QDF_STATUS_SUCCESS == v_status) {
436 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
437 		timer->state = QDF_TIMER_STATE_UNUSED;
438 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
439 		qdf_spinlock_destroy(&timer->platform_info.spinlock);
440 		return v_status;
441 	}
442 
443 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
444 
445 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
446 		  "%s: Cannot destroy timer in state = %d", __func__,
447 		  timer->state);
448 	QDF_ASSERT(0);
449 
450 	return v_status;
451 }
452 qdf_export_symbol(qdf_mc_timer_destroy);
453 
454 #else
455 
456 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer)
457 {
458 	QDF_STATUS v_status = QDF_STATUS_SUCCESS;
459 
460 	/* check for invalid pointer */
461 	if (!timer) {
462 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
463 			  "%s: Null timer pointer being passed", __func__);
464 		QDF_ASSERT(0);
465 		return QDF_STATUS_E_FAULT;
466 	}
467 
468 	/* check if timer refers to an uninitialized object */
469 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
470 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
471 			  "%s: Cannot destroy uninitialized timer", __func__);
472 		QDF_ASSERT(0);
473 		return QDF_STATUS_E_INVAL;
474 	}
475 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
476 
477 	switch (timer->state) {
478 
479 	case QDF_TIMER_STATE_STARTING:
480 		v_status = QDF_STATUS_E_BUSY;
481 		break;
482 
483 	case QDF_TIMER_STATE_RUNNING:
484 		/* Stop the timer first */
485 		del_timer(&(timer->platform_info.timer));
486 		v_status = QDF_STATUS_SUCCESS;
487 		break;
488 
489 	case QDF_TIMER_STATE_STOPPED:
490 		v_status = QDF_STATUS_SUCCESS;
491 		break;
492 
493 	case QDF_TIMER_STATE_UNUSED:
494 		v_status = QDF_STATUS_E_ALREADY;
495 		break;
496 
497 	default:
498 		v_status = QDF_STATUS_E_FAULT;
499 		break;
500 	}
501 
502 	if (QDF_STATUS_SUCCESS == v_status) {
503 		timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE;
504 		timer->state = QDF_TIMER_STATE_UNUSED;
505 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
506 		return v_status;
507 	}
508 
509 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
510 
511 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
512 		  "%s: Cannot destroy timer in state = %d", __func__,
513 		  timer->state);
514 	QDF_ASSERT(0);
515 
516 	return v_status;
517 }
518 qdf_export_symbol(qdf_mc_timer_destroy);
519 #endif
520 
521 QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time)
522 {
523 	/* check for invalid pointer */
524 	if (!timer) {
525 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
526 			  "%s Null timer pointer being passed", __func__);
527 		QDF_ASSERT(0);
528 		return QDF_STATUS_E_INVAL;
529 	}
530 
531 	/* check if timer refers to an uninitialized object */
532 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
533 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
534 			  "%s: Cannot start uninitialized timer", __func__);
535 		QDF_ASSERT(0);
536 
537 		return QDF_STATUS_E_INVAL;
538 	}
539 
540 	/* check if timer has expiration time less than 10 ms */
541 	if (expiration_time < 10) {
542 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
543 			  "%s: Cannot start a timer with expiration less than 10 ms",
544 			  __func__);
545 		QDF_ASSERT(0);
546 		return QDF_STATUS_E_INVAL;
547 	}
548 
549 	/* make sure the remainder of the logic isn't interrupted */
550 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
551 
552 	/* ensure if the timer can be started */
553 	if (QDF_TIMER_STATE_STOPPED != timer->state) {
554 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
555 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
556 			  "%s: Cannot start timer in state = %d %ps",
557 			  __func__, timer->state, (void *)timer->callback);
558 		return QDF_STATUS_E_ALREADY;
559 	}
560 
561 	/* start the timer */
562 	mod_timer(&(timer->platform_info.timer),
563 		  jiffies + __qdf_scaled_msecs_to_jiffies(expiration_time));
564 
565 	timer->state = QDF_TIMER_STATE_RUNNING;
566 
567 	/* Save the jiffies value in a per-timer context in qdf_mc_timer_t
568 	 * It will help the debugger to know the exact time at which the host
569 	 * starts the QDF timer.
570 	 */
571 	timer->timer_start_jiffies = jiffies;
572 
573 	/* get the thread ID on which the timer is being started */
574 	timer->platform_info.thread_id = current->pid;
575 
576 	if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) {
577 		persistent_timer_count++;
578 		if (1 == persistent_timer_count) {
579 			/* since we now have one persistent timer,
580 			 * we need to disallow sleep
581 			 * sleep_negate_okts(sleep_client_handle);
582 			 */
583 		}
584 	}
585 
586 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
587 
588 	return QDF_STATUS_SUCCESS;
589 }
590 qdf_export_symbol(qdf_mc_timer_start);
591 
592 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer)
593 {
594 	/* check for invalid pointer */
595 	if (!timer) {
596 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
597 				   "%s Null timer pointer", __func__);
598 		QDF_ASSERT(0);
599 		return QDF_STATUS_E_INVAL;
600 	}
601 
602 	/* check if timer refers to an uninitialized object */
603 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
604 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
605 				   "%s: Cannot stop uninit timer", __func__);
606 		QDF_ASSERT(0);
607 
608 		return QDF_STATUS_E_INVAL;
609 	}
610 
611 	/* ensure the timer state is correct */
612 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
613 
614 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
615 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
616 		return QDF_STATUS_SUCCESS;
617 	}
618 
619 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
620 
621 	del_timer(&(timer->platform_info.timer));
622 
623 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
624 	timer->state = QDF_TIMER_STATE_STOPPED;
625 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
626 
627 	qdf_try_allowing_sleep(timer->type);
628 
629 	return QDF_STATUS_SUCCESS;
630 }
631 qdf_export_symbol(qdf_mc_timer_stop);
632 
633 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer)
634 {
635 	/* check for invalid pointer */
636 	if (!timer) {
637 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
638 				   "%s Null timer pointer", __func__);
639 		QDF_ASSERT(0);
640 		return QDF_STATUS_E_INVAL;
641 	}
642 
643 	/* check if timer refers to an uninitialized object */
644 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
645 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
646 				   "%s: Cannot stop uninit timer", __func__);
647 		QDF_ASSERT(0);
648 
649 		return QDF_STATUS_E_INVAL;
650 	}
651 
652 	/* ensure the timer state is correct */
653 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
654 
655 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
656 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
657 		return QDF_STATUS_SUCCESS;
658 	}
659 
660 	timer->state = QDF_TIMER_STATE_STOPPED;
661 
662 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
663 	del_timer_sync(&(timer->platform_info.timer));
664 
665 	qdf_try_allowing_sleep(timer->type);
666 
667 	return QDF_STATUS_SUCCESS;
668 }
669 qdf_export_symbol(qdf_mc_timer_stop_sync);
670 
671 unsigned long qdf_mc_timer_get_system_ticks(void)
672 {
673 	return jiffies_to_msecs(jiffies) / 10;
674 }
675 qdf_export_symbol(qdf_mc_timer_get_system_ticks);
676 
677 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
678 unsigned long qdf_mc_timer_get_system_time(void)
679 {
680 	struct timespec64 tv;
681 
682 	ktime_get_real_ts64(&tv);
683 	return tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
684 }
685 qdf_export_symbol(qdf_mc_timer_get_system_time);
686 
687 #else
688 unsigned long qdf_mc_timer_get_system_time(void)
689 {
690 	struct timeval tv;
691 
692 	do_gettimeofday(&tv);
693 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
694 }
695 qdf_export_symbol(qdf_mc_timer_get_system_time);
696 #endif
697 
698 s64 qdf_get_monotonic_boottime_ns(void)
699 {
700 	return ktime_to_ns(ktime_get_boottime());
701 }
702 qdf_export_symbol(qdf_get_monotonic_boottime_ns);
703 
704 void qdf_timer_module_deinit(void)
705 {
706 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
707 		  "De-Initializing the QDF MC timer module");
708 	qdf_mutex_destroy(&persistent_timer_count_lock);
709 }
710 qdf_export_symbol(qdf_timer_module_deinit);
711 
712 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
713 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
714 {
715 	struct timespec64 tv;
716 	struct rtc_time tm;
717 	unsigned long local_time;
718 
719 	/* Format the Log time R#: [hr:min:sec.microsec] */
720 	ktime_get_real_ts64(&tv);
721 	/* Convert rtc to local time */
722 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
723 	rtc_time64_to_tm(local_time, &tm);
724 	scnprintf(tbuf, len,
725 		  "[%02d:%02d:%02d.%06lu]",
726 		  tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_nsec / 1000);
727 }
728 
729 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
730 
731 uint64_t qdf_get_time_of_the_day_us(void)
732 {
733 	struct timespec64 tv;
734 	struct rtc_time tm;
735 	unsigned long local_time;
736 	uint64_t time_of_day_us = 0;
737 
738 	ktime_get_real_ts64(&tv);
739 	/* Convert rtc to local time */
740 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
741 	rtc_time64_to_tm(local_time, &tm);
742 
743 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
744 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
745 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
746 	time_of_day_us += qdf_do_div((uint64_t)tv.tv_nsec,  1000);
747 
748 	return time_of_day_us;
749 }
750 
751 qdf_export_symbol(qdf_get_time_of_the_day_us);
752 #else
753 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
754 {
755 	struct timeval tv;
756 	struct rtc_time tm;
757 	unsigned long local_time;
758 
759 	/* Format the Log time R#: [hr:min:sec.microsec] */
760 	do_gettimeofday(&tv);
761 	/* Convert rtc to local time */
762 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
763 	rtc_time_to_tm(local_time, &tm);
764 	scnprintf(tbuf, len,
765 		"[%02d:%02d:%02d.%06lu]",
766 		tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
767 }
768 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
769 
770 uint64_t qdf_get_time_of_the_day_us(void)
771 {
772 	struct timeval tv;
773 	struct rtc_time tm;
774 	unsigned long local_time;
775 	uint64_t time_of_day_us = 0;
776 
777 	do_gettimeofday(&tv);
778 	/* Convert rtc to local time */
779 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
780 	rtc_time_to_tm(local_time, &tm);
781 
782 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
783 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
784 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
785 	time_of_day_us += (uint64_t)tv.tv_usec;
786 
787 	return time_of_day_us;
788 }
789 
790 qdf_export_symbol(qdf_get_time_of_the_day_us);
791 #endif
792 
793 qdf_time_t qdf_get_time_of_the_day_ms(void)
794 {
795 	qdf_time_t time_of_the_day_ms;
796 
797 	time_of_the_day_ms = qdf_do_div(qdf_get_time_of_the_day_us(), 1000);
798 
799 	return time_of_the_day_ms;
800 }
801 
802 qdf_export_symbol(qdf_get_time_of_the_day_ms);
803