1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-07-10 xqyjlj The first version.
9 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
10 */
11
12 #include <rtdevice.h>
13 #include <rthw.h>
14 #include <rtthread.h>
15
16 #define DBG_SECTION_NAME "drv.ktime"
17 #define DBG_LEVEL DBG_INFO
18 #include <rtdbg.h>
19
20 #include "ktime.h"
21
22 #ifdef ARCH_CPU_64BIT
23 #define _HRTIMER_MAX_CNT UINT64_MAX
24 #else
25 #define _HRTIMER_MAX_CNT UINT32_MAX
26 #endif
27
28 static rt_list_t _timer_list = RT_LIST_OBJECT_INIT(_timer_list);
29 static RT_DEFINE_SPINLOCK(_spinlock);
30
_first_hrtimer(void)31 rt_inline rt_ktime_hrtimer_t _first_hrtimer(void)
32 {
33 return rt_list_isempty(&_timer_list) ? RT_NULL : rt_list_first_entry(&_timer_list, struct rt_ktime_hrtimer, node);
34 }
35
rt_ktime_hrtimer_getres(void)36 rt_weak rt_uint64_t rt_ktime_hrtimer_getres(void)
37 {
38 return ((1000ULL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
39 }
40
rt_ktime_hrtimer_getfrq(void)41 rt_weak unsigned long rt_ktime_hrtimer_getfrq(void)
42 {
43 return RT_TICK_PER_SECOND;
44 }
45
rt_ktime_hrtimer_getcnt(void)46 rt_weak unsigned long rt_ktime_hrtimer_getcnt(void)
47 {
48 return rt_tick_get();
49 }
50
rt_ktime_hrtimer_settimeout(unsigned long cnt)51 rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt)
52 {
53 static rt_timer_t timer = RT_NULL;
54 static struct rt_timer _sh_rtimer;
55
56 RT_ASSERT(cnt > 0);
57
58 if (timer == RT_NULL)
59 {
60 timer = &_sh_rtimer;
61 rt_timer_init(timer, "shrtimer", (void (*)(void *))rt_ktime_hrtimer_process, RT_NULL, cnt, RT_TIMER_FLAG_ONE_SHOT);
62 }
63 else
64 {
65 rt_tick_t tick = cnt;
66 rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick);
67 rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, RT_NULL);
68 }
69
70 if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
71 {
72 rt_timer_stop(timer);
73 }
74
75 rt_timer_start(timer);
76 return RT_EOK;
77 }
78
79 /**
80 * @brief convert cnt from cputimer cnt to hrtimer cnt
81 *
82 * @param cnt
83 * @return unsigned long
84 */
_cnt_convert(unsigned long cnt)85 static unsigned long _cnt_convert(unsigned long cnt)
86 {
87 unsigned long rtn = 0;
88 unsigned long count = cnt - rt_ktime_cputimer_getcnt();
89 if (count > (_HRTIMER_MAX_CNT / 2))
90 return 0;
91
92 rtn = (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres();
93 return rtn == 0 ? 1 : rtn; /* at least 1 */
94 }
95
_sleep_timeout(void * parameter)96 static void _sleep_timeout(void *parameter)
97 {
98 struct rt_ktime_hrtimer *timer = parameter;
99 rt_completion_done(&timer->completion);
100 }
101
_insert_timer_to_list_locked(rt_ktime_hrtimer_t timer)102 static void _insert_timer_to_list_locked(rt_ktime_hrtimer_t timer)
103 {
104 rt_ktime_hrtimer_t iter;
105
106 rt_list_for_each_entry(iter, &_timer_list, node)
107 {
108 if (iter->timeout_cnt > timer->timeout_cnt)
109 {
110 break;
111 }
112 }
113 rt_list_insert_before(&iter->node, &(timer->node));
114
115 timer->flag |= RT_TIMER_FLAG_ACTIVATED;
116 }
117
_hrtimer_process_locked(void)118 static void _hrtimer_process_locked(void)
119 {
120 rt_ktime_hrtimer_t timer;
121
122 for (timer = _first_hrtimer();
123 (timer != RT_NULL) && (timer->timeout_cnt <= rt_ktime_cputimer_getcnt());
124 timer = _first_hrtimer())
125 {
126 rt_list_remove(&(timer->node));
127
128 if (timer->flag & RT_TIMER_FLAG_PERIODIC)
129 {
130 timer->timeout_cnt = timer->delay_cnt + rt_ktime_cputimer_getcnt();
131 _insert_timer_to_list_locked(timer);
132 }
133 else
134 {
135 timer->flag &= ~RT_TIMER_FLAG_ACTIVATED;
136 }
137
138 if (timer->timeout_func)
139 {
140 timer->timeout_func(timer->parameter);
141 }
142 }
143 }
144
_set_next_timeout_locked(void)145 static void _set_next_timeout_locked(void)
146 {
147 rt_ktime_hrtimer_t timer;
148 rt_ubase_t next_timeout_hrtimer_cnt;
149 rt_bool_t find_next;
150
151 do
152 {
153 find_next = RT_FALSE;
154 if ((timer = _first_hrtimer()) != RT_NULL)
155 {
156 next_timeout_hrtimer_cnt = _cnt_convert(timer->timeout_cnt);
157 if (next_timeout_hrtimer_cnt > 0)
158 {
159 rt_ktime_hrtimer_settimeout(next_timeout_hrtimer_cnt);
160 }
161 else
162 {
163 _hrtimer_process_locked();
164 find_next = RT_TRUE;
165 }
166 }
167 }
168 while (find_next);
169 }
170
rt_ktime_hrtimer_process(void)171 void rt_ktime_hrtimer_process(void)
172 {
173 rt_base_t level = rt_spin_lock_irqsave(&_spinlock);
174
175 _hrtimer_process_locked();
176 _set_next_timeout_locked();
177
178 rt_spin_unlock_irqrestore(&_spinlock, level);
179 }
180
rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer,const char * name,rt_uint8_t flag,void (* timeout)(void * parameter),void * parameter)181 void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer,
182 const char *name,
183 rt_uint8_t flag,
184 void (*timeout)(void *parameter),
185 void *parameter)
186 {
187 /* parameter check */
188 RT_ASSERT(timer != RT_NULL);
189 RT_ASSERT(timeout != RT_NULL);
190
191 rt_memset(timer, 0, sizeof(struct rt_ktime_hrtimer));
192
193 timer->flag = flag & ~RT_TIMER_FLAG_ACTIVATED;
194 timer->timeout_func = timeout;
195 timer->parameter = parameter;
196 rt_strncpy(timer->name, name, RT_NAME_MAX - 1);
197 rt_list_init(&(timer->node));
198 rt_completion_init(&timer->completion);
199 }
200
rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer,unsigned long delay_cnt)201 rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer, unsigned long delay_cnt)
202 {
203 rt_base_t level;
204
205 /* parameter check */
206 RT_ASSERT(timer != RT_NULL);
207 RT_ASSERT(delay_cnt < (_HRTIMER_MAX_CNT / 2));
208
209 timer->delay_cnt = delay_cnt;
210 timer->timeout_cnt = timer->delay_cnt + rt_ktime_cputimer_getcnt();
211
212 level = rt_spin_lock_irqsave(&_spinlock);
213
214 if (timer->flag & RT_TIMER_FLAG_ACTIVATED)
215 {
216 rt_spin_unlock_irqrestore(&_spinlock, level);
217 return -RT_ERROR;
218 }
219
220 _insert_timer_to_list_locked(timer);
221 _set_next_timeout_locked();
222
223 rt_spin_unlock_irqrestore(&_spinlock, level);
224
225 return RT_EOK;
226 }
227
rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)228 rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)
229 {
230 rt_base_t level;
231
232 RT_ASSERT(timer != RT_NULL); /* timer check */
233
234 level = rt_spin_lock_irqsave(&_spinlock);
235
236 if (!(timer->flag & RT_TIMER_FLAG_ACTIVATED))
237 {
238 rt_spin_unlock_irqrestore(&_spinlock, level);
239 return -RT_ERROR;
240 }
241
242 rt_list_remove(&timer->node);
243 timer->flag &= ~RT_TIMER_FLAG_ACTIVATED;
244 _set_next_timeout_locked();
245
246 rt_spin_unlock_irqrestore(&_spinlock, level);
247
248 return RT_EOK;
249 }
250
rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer,int cmd,void * arg)251 rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg)
252 {
253 rt_base_t level;
254
255 /* parameter check */
256 RT_ASSERT(timer != RT_NULL);
257
258 level = rt_spin_lock_irqsave(&_spinlock);
259 switch (cmd)
260 {
261
262 case RT_TIMER_CTRL_GET_TIME:
263 *(unsigned long *)arg = timer->delay_cnt;
264 break;
265
266 case RT_TIMER_CTRL_SET_TIME:
267 RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2));
268 timer->delay_cnt = *(unsigned long *)arg;
269 timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt();
270 break;
271
272 case RT_TIMER_CTRL_SET_ONESHOT:
273 timer->flag &= ~RT_TIMER_FLAG_PERIODIC;
274 break;
275
276 case RT_TIMER_CTRL_SET_PERIODIC:
277 timer->flag |= RT_TIMER_FLAG_PERIODIC;
278 break;
279
280 case RT_TIMER_CTRL_GET_STATE:
281 if (timer->flag & RT_TIMER_FLAG_ACTIVATED)
282 {
283 /*timer is start and run*/
284 *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
285 }
286 else
287 {
288 /*timer is stop*/
289 *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
290 }
291 break;
292
293 case RT_TIMER_CTRL_GET_REMAIN_TIME:
294 *(unsigned long *)arg = timer->timeout_cnt;
295 break;
296 case RT_TIMER_CTRL_GET_FUNC:
297 arg = (void *)timer->timeout_func;
298 break;
299
300 case RT_TIMER_CTRL_SET_FUNC:
301 timer->timeout_func = (void (*)(void *))arg;
302 break;
303
304 case RT_TIMER_CTRL_GET_PARM:
305 *(void **)arg = timer->parameter;
306 break;
307
308 case RT_TIMER_CTRL_SET_PARM:
309 timer->parameter = arg;
310 break;
311
312 default:
313 break;
314 }
315 rt_spin_unlock_irqrestore(&_spinlock, level);
316
317 return RT_EOK;
318 }
319
rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)320 rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)
321 {
322 rt_base_t level;
323
324 /* parameter check */
325 RT_ASSERT(timer != RT_NULL);
326
327 /* notify the timer stop event */
328 rt_completion_wakeup_by_errno(&timer->completion, RT_ERROR);
329
330 level = rt_spin_lock_irqsave(&_spinlock);
331
332 /* stop timer */
333 timer->flag &= ~RT_TIMER_FLAG_ACTIVATED;
334 /* when interrupted */
335 if (timer->error == -RT_EINTR || timer->error == RT_EINTR)
336 {
337 rt_list_remove(&timer->node);
338 _set_next_timeout_locked();
339 }
340
341 rt_spin_unlock_irqrestore(&_spinlock, level);
342
343 return RT_EOK;
344 }
345
346 /************************** delay ***************************/
347
rt_ktime_hrtimer_delay_init(struct rt_ktime_hrtimer * timer)348 void rt_ktime_hrtimer_delay_init(struct rt_ktime_hrtimer *timer)
349 {
350 rt_ktime_hrtimer_init(timer, "hrtimer_sleep", RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
351 _sleep_timeout, timer);
352 }
353
rt_ktime_hrtimer_delay_detach(struct rt_ktime_hrtimer * timer)354 void rt_ktime_hrtimer_delay_detach(struct rt_ktime_hrtimer *timer)
355 {
356 rt_ktime_hrtimer_detach(timer);
357 }
358
rt_ktime_hrtimer_sleep(struct rt_ktime_hrtimer * timer,unsigned long cnt)359 rt_err_t rt_ktime_hrtimer_sleep(struct rt_ktime_hrtimer *timer, unsigned long cnt)
360 {
361 rt_err_t err;
362
363 if (cnt == 0)
364 return -RT_EINVAL;
365
366 err = rt_ktime_hrtimer_start(timer, cnt);
367 if (err)
368 return err;
369
370 err = rt_completion_wait_flags(&(timer->completion), RT_WAITING_FOREVER,
371 RT_INTERRUPTIBLE);
372 rt_ktime_hrtimer_keep_errno(timer, err);
373
374 return err;
375 }
376
rt_ktime_hrtimer_ndelay(struct rt_ktime_hrtimer * timer,unsigned long ns)377 rt_err_t rt_ktime_hrtimer_ndelay(struct rt_ktime_hrtimer *timer, unsigned long ns)
378 {
379 rt_uint64_t res = rt_ktime_cputimer_getres();
380 return rt_ktime_hrtimer_sleep(timer, (ns * RT_KTIME_RESMUL) / res);
381 }
382
rt_ktime_hrtimer_udelay(struct rt_ktime_hrtimer * timer,unsigned long us)383 rt_err_t rt_ktime_hrtimer_udelay(struct rt_ktime_hrtimer *timer, unsigned long us)
384 {
385 return rt_ktime_hrtimer_ndelay(timer, us * 1000);
386 }
387
rt_ktime_hrtimer_mdelay(struct rt_ktime_hrtimer * timer,unsigned long ms)388 rt_err_t rt_ktime_hrtimer_mdelay(struct rt_ktime_hrtimer *timer, unsigned long ms)
389 {
390 return rt_ktime_hrtimer_ndelay(timer, ms * 1000000);
391 }
392