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