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 
qdf_timer_set_multiplier(uint32_t multiplier)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 
qdf_timer_get_multiplier(void)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 *);
qdf_register_mc_timer_callback(void (* 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 
qdf_try_allowing_sleep(QDF_TIMER_TYPE type)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 
qdf_mc_timer_get_current_state(qdf_mc_timer_t * timer)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 
qdf_timer_module_init(void)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 
qdf_timer_list_get(enum qdf_debug_domain domain)129 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain)
130 {
131 	return &qdf_timer_domains[domain];
132 }
133 
qdf_mc_timer_manager_init(void)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 
qdf_mc_timer_print_list(qdf_list_t * timers)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 
qdf_mc_timer_check_for_leaks(void)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 
qdf_mc_timer_free_leaked_timers(qdf_list_t * timers)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  */
qdf_timer_clean(void)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 
qdf_mc_timer_manager_exit(void)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)
__os_mc_timer_shim(struct timer_list * os_timer)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 
qdf_mc_timer_setup(qdf_mc_timer_t * timer,QDF_TIMER_TYPE timer_type)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
__os_mc_timer_shim(unsigned long data)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 
qdf_mc_timer_setup(qdf_mc_timer_t * timer,QDF_TIMER_TYPE timer_type)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
qdf_mc_timer_init_debug(qdf_mc_timer_t * timer,QDF_TIMER_TYPE timer_type,qdf_mc_timer_callback_t callback,void * user_data,char * file_name,uint32_t line_num)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
qdf_mc_timer_init(qdf_mc_timer_t * timer,QDF_TIMER_TYPE timer_type,qdf_mc_timer_callback_t callback,void * user_data)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
qdf_mc_timer_destroy(qdf_mc_timer_t * timer)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 
qdf_mc_timer_destroy(qdf_mc_timer_t * timer)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 
qdf_mc_timer_start(qdf_mc_timer_t * timer,uint32_t expiration_time)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 		return QDF_STATUS_E_INVAL;
546 	}
547 
548 	/* make sure the remainder of the logic isn't interrupted */
549 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
550 
551 	/* ensure if the timer can be started */
552 	if (QDF_TIMER_STATE_STOPPED != timer->state) {
553 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
554 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
555 			  "%s: Cannot start timer in state = %d %ps",
556 			  __func__, timer->state, (void *)timer->callback);
557 		return QDF_STATUS_E_ALREADY;
558 	}
559 
560 	/* start the timer */
561 	mod_timer(&(timer->platform_info.timer),
562 		  jiffies + __qdf_scaled_msecs_to_jiffies(expiration_time));
563 
564 	timer->state = QDF_TIMER_STATE_RUNNING;
565 
566 	/* Save the jiffies value in a per-timer context in qdf_mc_timer_t
567 	 * It will help the debugger to know the exact time at which the host
568 	 * starts the QDF timer.
569 	 */
570 	timer->timer_start_jiffies = jiffies;
571 
572 	/* get the thread ID on which the timer is being started */
573 	timer->platform_info.thread_id = current->pid;
574 
575 	if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) {
576 		persistent_timer_count++;
577 		if (1 == persistent_timer_count) {
578 			/* since we now have one persistent timer,
579 			 * we need to disallow sleep
580 			 * sleep_negate_okts(sleep_client_handle);
581 			 */
582 		}
583 	}
584 
585 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
586 
587 	return QDF_STATUS_SUCCESS;
588 }
589 qdf_export_symbol(qdf_mc_timer_start);
590 
qdf_mc_timer_stop(qdf_mc_timer_t * timer)591 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer)
592 {
593 	/* check for invalid pointer */
594 	if (!timer) {
595 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
596 				   "%s Null timer pointer", __func__);
597 		QDF_ASSERT(0);
598 		return QDF_STATUS_E_INVAL;
599 	}
600 
601 	/* check if timer refers to an uninitialized object */
602 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
603 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
604 				   "%s: Cannot stop uninit timer", __func__);
605 		QDF_ASSERT(0);
606 
607 		return QDF_STATUS_E_INVAL;
608 	}
609 
610 	/* ensure the timer state is correct */
611 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
612 
613 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
614 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
615 		return QDF_STATUS_SUCCESS;
616 	}
617 
618 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
619 
620 	del_timer(&(timer->platform_info.timer));
621 
622 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
623 	timer->state = QDF_TIMER_STATE_STOPPED;
624 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
625 
626 	qdf_try_allowing_sleep(timer->type);
627 
628 	return QDF_STATUS_SUCCESS;
629 }
630 qdf_export_symbol(qdf_mc_timer_stop);
631 
qdf_mc_timer_stop_sync(qdf_mc_timer_t * timer)632 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer)
633 {
634 	/* check for invalid pointer */
635 	if (!timer) {
636 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
637 				   "%s Null timer pointer", __func__);
638 		QDF_ASSERT(0);
639 		return QDF_STATUS_E_INVAL;
640 	}
641 
642 	/* check if timer refers to an uninitialized object */
643 	if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) {
644 		QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF,
645 				   "%s: Cannot stop uninit timer", __func__);
646 		QDF_ASSERT(0);
647 
648 		return QDF_STATUS_E_INVAL;
649 	}
650 
651 	/* ensure the timer state is correct */
652 	qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
653 
654 	if (QDF_TIMER_STATE_RUNNING != timer->state) {
655 		qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
656 		return QDF_STATUS_SUCCESS;
657 	}
658 
659 	timer->state = QDF_TIMER_STATE_STOPPED;
660 
661 	qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
662 	del_timer_sync(&(timer->platform_info.timer));
663 
664 	qdf_try_allowing_sleep(timer->type);
665 
666 	return QDF_STATUS_SUCCESS;
667 }
668 qdf_export_symbol(qdf_mc_timer_stop_sync);
669 
qdf_mc_timer_get_system_ticks(void)670 unsigned long qdf_mc_timer_get_system_ticks(void)
671 {
672 	return jiffies_to_msecs(jiffies) / 10;
673 }
674 qdf_export_symbol(qdf_mc_timer_get_system_ticks);
675 
676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
qdf_mc_timer_get_system_time(void)677 unsigned long qdf_mc_timer_get_system_time(void)
678 {
679 	struct timespec64 tv;
680 
681 	ktime_get_real_ts64(&tv);
682 	return tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
683 }
684 qdf_export_symbol(qdf_mc_timer_get_system_time);
685 
686 #else
qdf_mc_timer_get_system_time(void)687 unsigned long qdf_mc_timer_get_system_time(void)
688 {
689 	struct timeval tv;
690 
691 	do_gettimeofday(&tv);
692 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
693 }
694 qdf_export_symbol(qdf_mc_timer_get_system_time);
695 #endif
696 
qdf_get_monotonic_boottime_ns(void)697 s64 qdf_get_monotonic_boottime_ns(void)
698 {
699 	return ktime_to_ns(ktime_get_boottime());
700 }
701 qdf_export_symbol(qdf_get_monotonic_boottime_ns);
702 
qdf_timer_module_deinit(void)703 void qdf_timer_module_deinit(void)
704 {
705 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
706 		  "De-Initializing the QDF MC timer module");
707 	qdf_mutex_destroy(&persistent_timer_count_lock);
708 }
709 qdf_export_symbol(qdf_timer_module_deinit);
710 
711 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
qdf_get_time_of_the_day_in_hr_min_sec_usec(char * tbuf,int len)712 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
713 {
714 	struct timespec64 tv;
715 	struct rtc_time tm;
716 	unsigned long local_time;
717 
718 	/* Format the Log time R#: [hr:min:sec.microsec] */
719 	ktime_get_real_ts64(&tv);
720 	/* Convert rtc to local time */
721 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
722 	rtc_time64_to_tm(local_time, &tm);
723 	scnprintf(tbuf, len,
724 		  "[%02d:%02d:%02d.%06lu]",
725 		  tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_nsec / 1000);
726 }
727 
728 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
729 
qdf_get_time_of_the_day_us(void)730 uint64_t qdf_get_time_of_the_day_us(void)
731 {
732 	struct timespec64 tv;
733 	struct rtc_time tm;
734 	unsigned long local_time;
735 	uint64_t time_of_day_us = 0;
736 
737 	ktime_get_real_ts64(&tv);
738 	/* Convert rtc to local time */
739 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
740 	rtc_time64_to_tm(local_time, &tm);
741 
742 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
743 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
744 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
745 	time_of_day_us += qdf_do_div((uint64_t)tv.tv_nsec,  1000);
746 
747 	return time_of_day_us;
748 }
749 
750 qdf_export_symbol(qdf_get_time_of_the_day_us);
751 #else
qdf_get_time_of_the_day_in_hr_min_sec_usec(char * tbuf,int len)752 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len)
753 {
754 	struct timeval tv;
755 	struct rtc_time tm;
756 	unsigned long local_time;
757 
758 	/* Format the Log time R#: [hr:min:sec.microsec] */
759 	do_gettimeofday(&tv);
760 	/* Convert rtc to local time */
761 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
762 	rtc_time_to_tm(local_time, &tm);
763 	scnprintf(tbuf, len,
764 		"[%02d:%02d:%02d.%06lu]",
765 		tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
766 }
767 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec);
768 
qdf_get_time_of_the_day_us(void)769 uint64_t qdf_get_time_of_the_day_us(void)
770 {
771 	struct timeval tv;
772 	struct rtc_time tm;
773 	unsigned long local_time;
774 	uint64_t time_of_day_us = 0;
775 
776 	do_gettimeofday(&tv);
777 	/* Convert rtc to local time */
778 	local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60));
779 	rtc_time_to_tm(local_time, &tm);
780 
781 	time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000;
782 	time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000;
783 	time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000;
784 	time_of_day_us += (uint64_t)tv.tv_usec;
785 
786 	return time_of_day_us;
787 }
788 
789 qdf_export_symbol(qdf_get_time_of_the_day_us);
790 #endif
791 
qdf_get_time_of_the_day_ms(void)792 qdf_time_t qdf_get_time_of_the_day_ms(void)
793 {
794 	qdf_time_t time_of_the_day_ms;
795 
796 	time_of_the_day_ms = qdf_do_div(qdf_get_time_of_the_day_us(), 1000);
797 
798 	return time_of_the_day_ms;
799 }
800 
801 qdf_export_symbol(qdf_get_time_of_the_day_ms);
802