1 /*
2  * osal_timer.c
3  *
4  * osal driver
5  *
6  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  */
18 
19 #include "osal_timer.h"
20 #include <linux/errno.h>
21 #include <linux/export.h>
22 #include <linux/signal.h>
23 #include <linux/timer.h>
24 #include "hdf_log.h"
25 #include "osal_mem.h"
26 #include "osal_mutex.h"
27 
28 #define HDF_LOG_TAG osal_timer
29 
30 typedef enum {
31 	OSAL_TIMER_ONCE,
32 	OSAL_TIMER_LOOP,
33 } OsalTimerMode;
34 
35 struct osal_ktimer {
36 	uintptr_t arg;
37 	struct timer_list timer;
38 	OsalTimerFunc func;
39 	uint32_t msec;
40 	struct OsalMutex mutex;
41 	OsalTimerMode mode;
42 	bool stop_flag;
43 };
44 
osal_timer_callback(struct timer_list * arg)45 static void osal_timer_callback(struct timer_list *arg)
46 {
47 	struct osal_ktimer *ktimer = NULL;
48 	uint32_t msec;
49 	OsalTimerMode mode;
50 	bool stop_flag = false;
51 
52 	if (arg == NULL) {
53 		HDF_LOGI("%s timer is stopped", __func__);
54 		return;
55 	}
56 
57 	ktimer = from_timer(ktimer, arg, timer);
58 
59 	OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
60 	mode = ktimer->mode;
61 	stop_flag = ktimer->stop_flag;
62 	OsalMutexUnlock(&ktimer->mutex);
63 
64 	if (!stop_flag) {
65 		ktimer->func(ktimer->arg);
66 		OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
67 		msec = ktimer->msec;
68 		OsalMutexUnlock(&ktimer->mutex);
69 		if (mode == OSAL_TIMER_LOOP) {
70 			ktimer->timer.expires = jiffies + msecs_to_jiffies(msec);
71 			mod_timer(&ktimer->timer, ktimer->timer.expires);
72 		}
73 	} else {
74 		del_timer(&ktimer->timer);
75 		OsalMutexDestroy(&ktimer->mutex);
76 		OsalMemFree(ktimer);
77 		HDF_LOGI("%s timer is stop", __func__);
78 	}
79 }
80 
OsalTimerCreate(OsalTimer * timer,uint32_t interval,OsalTimerFunc func,uintptr_t arg)81 int32_t OsalTimerCreate(OsalTimer *timer, uint32_t interval, OsalTimerFunc func, uintptr_t arg)
82 {
83 	struct osal_ktimer *ktimer = NULL;
84 
85 	if (func == NULL || timer == NULL || interval == 0) {
86 		HDF_LOGE("%s invalid para", __func__);
87 		return HDF_ERR_INVALID_PARAM;
88 	}
89 
90 	ktimer = (struct osal_ktimer *)OsalMemCalloc(sizeof(*ktimer));
91 	if (ktimer == NULL) {
92 		HDF_LOGE("%s malloc fail", __func__);
93 		timer->realTimer = NULL;
94 		return HDF_ERR_MALLOC_FAIL;
95 	}
96 
97 	ktimer->arg = arg;
98 	ktimer->func = func;
99 	ktimer->msec = interval;
100 	ktimer->stop_flag = false;
101 	OsalMutexInit(&ktimer->mutex);
102 	timer->realTimer = (void *)ktimer;
103 
104 	return HDF_SUCCESS;
105 }
106 EXPORT_SYMBOL(OsalTimerCreate);
107 
OsalTimerStart(OsalTimer * timer,OsalTimerMode mode)108 static int32_t OsalTimerStart(OsalTimer *timer, OsalTimerMode mode)
109 {
110 	struct osal_ktimer *ktimer = NULL;
111 	struct timer_list *timer_id = NULL;
112 
113 	if (timer == NULL || timer->realTimer == NULL) {
114 		HDF_LOGE("%s invalid para", __func__);
115 		return HDF_ERR_INVALID_PARAM;
116     }
117 
118 	ktimer = (struct osal_ktimer *)timer->realTimer;
119 	timer_id = &ktimer->timer;
120 	timer_setup(timer_id, osal_timer_callback, 0);
121 	ktimer->mode = mode;
122 	timer_id->expires = jiffies + msecs_to_jiffies(ktimer->msec);
123 	add_timer(timer_id);
124 
125 	return HDF_SUCCESS;
126 }
127 
OsalTimerStartOnce(OsalTimer * timer)128 int32_t OsalTimerStartOnce(OsalTimer *timer)
129 {
130 	return OsalTimerStart(timer, OSAL_TIMER_ONCE);
131 }
132 EXPORT_SYMBOL(OsalTimerStartOnce);
133 
OsalTimerStartLoop(OsalTimer * timer)134 int32_t OsalTimerStartLoop(OsalTimer *timer)
135 {
136 	return OsalTimerStart(timer, OSAL_TIMER_LOOP);
137 }
138 
139 EXPORT_SYMBOL(OsalTimerStartLoop);
140 
OsalTimerSetTimeout(OsalTimer * timer,uint32_t interval)141 int32_t OsalTimerSetTimeout(OsalTimer *timer, uint32_t interval)
142 {
143 	struct osal_ktimer *ktimer = NULL;
144 
145 	if (timer == NULL || timer->realTimer == NULL || interval == 0) {
146 		HDF_LOGE("%s invalid para", __func__);
147 		return HDF_ERR_INVALID_PARAM;
148 	}
149 
150 	ktimer = (struct osal_ktimer *)timer->realTimer;
151 	if (ktimer->msec == interval)
152 		return HDF_SUCCESS;
153 
154 	OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
155 	ktimer->msec = interval;
156 	OsalMutexUnlock(&ktimer->mutex);
157 
158 	return HDF_SUCCESS;
159 }
160 EXPORT_SYMBOL(OsalTimerSetTimeout);
161 
OsalTimerDelete(OsalTimer * timer)162 int32_t OsalTimerDelete(OsalTimer *timer)
163 {
164 	struct osal_ktimer *ktimer = NULL;
165 
166 	if (timer == NULL || timer->realTimer == NULL) {
167 		HDF_LOGE("%s invalid para", __func__);
168 		return HDF_ERR_INVALID_PARAM;
169 	}
170 
171 	ktimer = (struct osal_ktimer *)timer->realTimer;
172 	OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
173 	ktimer->stop_flag = true;
174 	OsalMutexUnlock(&ktimer->mutex);
175 
176 	if (ktimer->mode == OSAL_TIMER_ONCE)
177 		mod_timer(&ktimer->timer, ktimer->timer.expires);
178 
179 	timer->realTimer = NULL;
180 
181 	return HDF_SUCCESS;
182 }
183 EXPORT_SYMBOL(OsalTimerDelete);
184 
185