summaryrefslogtreecommitdiff
path: root/components/ktime/src
diff options
context:
space:
mode:
authorxqyjlj <[email protected]>2023-07-17 20:11:58 +0800
committerGitHub <[email protected]>2023-07-17 20:11:58 +0800
commit0eb75ced70a514051fcc6a8f1d232e195b15b4a0 (patch)
treea025fe349198fa0fe6f972ea1100ac31ba64787a /components/ktime/src
parentb424169e1742c1b19d039f9871dd3c672ea7b729 (diff)
[time]时钟框架重构 (#7794)
Diffstat (limited to 'components/ktime/src')
-rw-r--r--components/ktime/src/aarch64/cputimer.c32
-rw-r--r--components/ktime/src/boottime.c51
-rw-r--r--components/ktime/src/cputimer.c31
-rw-r--r--components/ktime/src/hrtimer.c382
-rw-r--r--components/ktime/src/risc-v/virt64/cputimer.c33
5 files changed, 529 insertions, 0 deletions
diff --git a/components/ktime/src/aarch64/cputimer.c b/components/ktime/src/aarch64/cputimer.c
new file mode 100644
index 0000000000..53c60736d4
--- /dev/null
+++ b/components/ktime/src/aarch64/cputimer.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-07-10 xqyjlj The first version.
+ */
+
+#include "gtimer.h"
+#include "ktime.h"
+
+unsigned long rt_ktime_cputimer_getres(void)
+{
+ return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq();
+}
+
+unsigned long rt_ktime_cputimer_getfrq(void)
+{
+ return rt_hw_get_gtimer_frq();
+}
+
+unsigned long rt_ktime_cputimer_getcnt(void)
+{
+ return rt_hw_get_cntpct_val();
+}
+
+unsigned long rt_ktime_cputimer_getstep(void)
+{
+ return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND;
+}
diff --git a/components/ktime/src/boottime.c b/components/ktime/src/boottime.c
new file mode 100644
index 0000000000..9d05266d71
--- /dev/null
+++ b/components/ktime/src/boottime.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-07-10 xqyjlj The first version.
+ */
+
+#include "ktime.h"
+
+#define __KTIME_MUL ((1000UL * 1000 * 1000) / RT_TICK_PER_SECOND)
+
+rt_err_t rt_ktime_boottime_get_us(struct timeval *tv)
+{
+ RT_ASSERT(tv != RT_NULL);
+
+ rt_tick_t ms = rt_tick_get();
+ unsigned long ns =
+ ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;
+ ns = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns;
+
+ tv->tv_sec = ms / RT_TICK_PER_SECOND;
+ tv->tv_usec = ns / 1000;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_boottime_get_s(time_t *t)
+{
+ RT_ASSERT(t != RT_NULL);
+
+ *t = rt_tick_get() / RT_TICK_PER_SECOND;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_boottime_get_ns(struct timespec *ts)
+{
+ RT_ASSERT(ts != RT_NULL);
+
+ rt_tick_t ms = rt_tick_get();
+ unsigned long ns =
+ ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;
+
+ ts->tv_sec = ms / RT_TICK_PER_SECOND;
+ ts->tv_nsec = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns;
+
+ return RT_EOK;
+}
diff --git a/components/ktime/src/cputimer.c b/components/ktime/src/cputimer.c
new file mode 100644
index 0000000000..c878581cdf
--- /dev/null
+++ b/components/ktime/src/cputimer.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-07-10 xqyjlj The first version.
+ */
+
+#include "ktime.h"
+
+rt_weak unsigned long rt_ktime_cputimer_getres(void)
+{
+ return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
+}
+
+rt_weak unsigned long rt_ktime_cputimer_getfrq(void)
+{
+ return RT_TICK_PER_SECOND;
+}
+
+rt_weak unsigned long rt_ktime_cputimer_getcnt(void)
+{
+ return rt_tick_get();
+}
+
+rt_weak unsigned long rt_ktime_cputimer_getstep(void)
+{
+ return 1;
+}
diff --git a/components/ktime/src/hrtimer.c b/components/ktime/src/hrtimer.c
new file mode 100644
index 0000000000..81954c3e00
--- /dev/null
+++ b/components/ktime/src/hrtimer.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-07-10 xqyjlj The first version.
+ */
+
+#include <rtdevice.h>
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "ktime.h"
+
+#ifdef ARCH_CPU_64BIT
+#define _HRTIMER_MAX_CNT UINT64_MAX
+#else
+#define _HRTIMER_MAX_CNT UINT32_MAX
+#endif
+
+static rt_list_t _timer_list = RT_LIST_OBJECT_INIT(_timer_list);
+static rt_ktime_hrtimer_t _nowtimer = RT_NULL;
+static struct rt_spinlock _spinlock;
+
+rt_weak unsigned long rt_ktime_hrtimer_getres(void)
+{
+ return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
+}
+
+rt_weak unsigned long rt_ktime_hrtimer_getfrq(void)
+{
+ return RT_TICK_PER_SECOND;
+}
+
+rt_weak unsigned long rt_ktime_hrtimer_getcnt(void)
+{
+ return rt_tick_get();
+}
+
+static void (*_outcb)(void *param) = RT_NULL;
+
+static void _hrtimer_timeout(void *parameter)
+{
+ if (_outcb)
+ _outcb(parameter);
+}
+
+rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param)
+{
+ static rt_timer_t timer = RT_NULL;
+
+ if (timer == RT_NULL)
+ {
+ timer = rt_timer_create("shrtimer", _hrtimer_timeout, param, cnt, RT_TIMER_FLAG_ONE_SHOT);
+ }
+ else
+ {
+ rt_tick_t tick = cnt;
+ rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick);
+ rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, param);
+ }
+
+ _outcb = timeout;
+ if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
+ {
+ rt_timer_stop(timer);
+ }
+ rt_timer_start(timer);
+ return RT_EOK;
+}
+
+/**
+ * @brief convert cnt from cputimer cnt to hrtimer cnt
+ *
+ * @param cnt
+ * @return unsigned long
+ */
+static unsigned long _cnt_convert(unsigned long cnt)
+{
+ int64_t count = cnt - rt_ktime_cputimer_getcnt();
+ if (count <= 0)
+ return 0;
+
+ return (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres();
+}
+
+static void _sleep_timeout(void *parameter)
+{
+ struct rt_semaphore *sem;
+ sem = (struct rt_semaphore *)parameter;
+ rt_sem_release(sem);
+}
+
+static void _set_next_timeout(void);
+static void _timeout_callback(void *parameter)
+{
+ rt_ktime_hrtimer_t timer;
+ timer = (rt_ktime_hrtimer_t)parameter;
+ rt_base_t level;
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ _nowtimer = RT_NULL;
+ rt_list_remove(&(timer->row));
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+ if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
+ {
+ timer->timeout_func(timer->parameter);
+ }
+
+ _set_next_timeout();
+}
+
+static void _set_next_timeout(void)
+{
+ rt_ktime_hrtimer_t t;
+ rt_base_t level;
+
+ if (&_timer_list != _timer_list.prev)
+ {
+ level = rt_spin_lock_irqsave(&_spinlock);
+ t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row);
+ if (_nowtimer != RT_NULL)
+ {
+ if (t != _nowtimer && t->timeout_cnt < _nowtimer->timeout_cnt)
+ {
+ _nowtimer = t;
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+ rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
+ }
+ else
+ {
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+ }
+ }
+ else
+ {
+ _nowtimer = t;
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+ rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
+ }
+ }
+ else
+ {
+ _nowtimer = RT_NULL;
+ rt_ktime_hrtimer_settimeout(RT_NULL, RT_NULL, RT_NULL);
+ }
+}
+
+void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer,
+ const char *name,
+ unsigned long cnt,
+ rt_uint8_t flag,
+ void (*timeout)(void *parameter),
+ void *parameter)
+{
+ /* parameter check */
+ RT_ASSERT(timer != RT_NULL);
+ RT_ASSERT(timeout != RT_NULL);
+ RT_ASSERT(cnt < (_HRTIMER_MAX_CNT / 2));
+
+ /* set flag */
+ timer->parent.flag = flag;
+
+ /* set deactivated */
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+ timer->timeout_func = timeout;
+ timer->parameter = parameter;
+ timer->timeout_cnt = cnt + rt_ktime_cputimer_getcnt();
+ timer->init_cnt = cnt;
+
+ rt_list_init(&(timer->row));
+ rt_sem_init(&(timer->sem), "hrtimer", 0, RT_IPC_FLAG_PRIO);
+}
+
+rt_err_t rt_ktime_hrtimer_delete(rt_ktime_hrtimer_t timer)
+{
+ rt_base_t level;
+
+ /* parameter check */
+ RT_ASSERT(timer != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ rt_list_remove(&timer->row);
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* stop timer */
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+
+ _set_next_timeout();
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer)
+{
+ rt_list_t *timer_list;
+ rt_base_t level;
+
+ /* parameter check */
+ RT_ASSERT(timer != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ rt_list_remove(&timer->row); /* remove timer from list */
+ /* change status of timer */
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+ timer_list = &_timer_list;
+ for (; timer_list != _timer_list.prev; timer_list = timer_list->next)
+ {
+ rt_ktime_hrtimer_t t;
+ rt_list_t *p = timer_list->next;
+
+ t = rt_list_entry(p, struct rt_ktime_hrtimer, row);
+
+ if ((t->timeout_cnt - timer->timeout_cnt) == 0)
+ {
+ continue;
+ }
+ else if ((t->timeout_cnt - timer->timeout_cnt) < (_HRTIMER_MAX_CNT / 2))
+ {
+ break;
+ }
+ }
+ rt_list_insert_after(timer_list, &(timer->row));
+ timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+
+ _set_next_timeout();
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)
+{
+ rt_base_t level;
+
+ RT_ASSERT(timer != RT_NULL); /* timer check */
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
+ {
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+ return -RT_ERROR;
+ }
+ rt_list_remove(&timer->row);
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* change status */
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+
+ _set_next_timeout();
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg)
+{
+ rt_base_t level;
+
+ /* parameter check */
+ RT_ASSERT(timer != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ switch (cmd)
+ {
+ case RT_TIMER_CTRL_GET_TIME:
+ *(unsigned long *)arg = timer->init_cnt;
+ break;
+
+ case RT_TIMER_CTRL_SET_TIME:
+ RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2));
+ timer->init_cnt = *(unsigned long *)arg;
+ timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt();
+ break;
+
+ case RT_TIMER_CTRL_SET_ONESHOT:
+ timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
+ break;
+
+ case RT_TIMER_CTRL_SET_PERIODIC:
+ timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
+ break;
+
+ case RT_TIMER_CTRL_GET_STATE:
+ if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
+ {
+ /*timer is start and run*/
+ *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
+ }
+ else
+ {
+ /*timer is stop*/
+ *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
+ }
+ break;
+
+ case RT_TIMER_CTRL_GET_REMAIN_TIME:
+ *(unsigned long *)arg = timer->timeout_cnt;
+ break;
+ case RT_TIMER_CTRL_GET_FUNC:
+ arg = (void *)timer->timeout_func;
+ break;
+
+ case RT_TIMER_CTRL_SET_FUNC:
+ timer->timeout_func = (void (*)(void *))arg;
+ break;
+
+ case RT_TIMER_CTRL_GET_PARM:
+ *(void **)arg = timer->parameter;
+ break;
+
+ case RT_TIMER_CTRL_SET_PARM:
+ timer->parameter = arg;
+ break;
+
+ default:
+ break;
+ }
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)
+{
+ rt_base_t level;
+
+ /* parameter check */
+ RT_ASSERT(timer != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&_spinlock);
+ rt_list_remove(&timer->row);
+ /* stop timer */
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
+ rt_spin_unlock_irqrestore(&_spinlock, level);
+
+ _set_next_timeout();
+
+ rt_sem_detach(&(timer->sem));
+
+ return RT_EOK;
+}
+
+/************************** delay ***************************/
+
+rt_err_t rt_ktime_hrtimer_sleep(unsigned long cnt)
+{
+ struct rt_ktime_hrtimer timer;
+
+ if (cnt == 0)
+ return -RT_EINVAL;
+
+ rt_ktime_hrtimer_init(&timer, "hrtimer_sleep", cnt, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
+ _sleep_timeout, &(timer.sem));
+
+ rt_ktime_hrtimer_start(&timer); /* reset the timeout of thread timer and start it */
+ rt_sem_take_interruptible(&(timer.sem), RT_WAITING_FOREVER);
+
+ rt_ktime_hrtimer_detach(&timer);
+ return RT_EOK;
+}
+
+rt_err_t rt_ktime_hrtimer_ndelay(unsigned long ns)
+{
+ unsigned long res = rt_ktime_cputimer_getres();
+ return rt_ktime_hrtimer_sleep((ns * RT_KTIME_RESMUL) / res);
+}
+
+rt_err_t rt_ktime_hrtimer_udelay(unsigned long us)
+{
+ return rt_ktime_hrtimer_ndelay(us * 1000);
+}
+
+rt_err_t rt_ktime_hrtimer_mdelay(unsigned long ms)
+{
+ return rt_ktime_hrtimer_ndelay(ms * 1000000);
+}
+
+static int rt_ktime_hrtimer_lock_init(void)
+{
+ RT_UNUSED(_spinlock);
+ rt_spin_lock_init(&_spinlock);
+ return 0;
+}
+INIT_BOARD_EXPORT(rt_ktime_hrtimer_lock_init);
diff --git a/components/ktime/src/risc-v/virt64/cputimer.c b/components/ktime/src/risc-v/virt64/cputimer.c
new file mode 100644
index 0000000000..9b0f754751
--- /dev/null
+++ b/components/ktime/src/risc-v/virt64/cputimer.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-07-10 xqyjlj The first version.
+ */
+
+#include "ktime.h"
+
+unsigned long rt_ktime_cputimer_getres(void)
+{
+ return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / CPUTIME_TIMER_FREQ;
+}
+
+unsigned long rt_ktime_cputimer_getfrq(void)
+{
+ return CPUTIME_TIMER_FREQ;
+}
+
+unsigned long rt_ktime_cputimer_getcnt(void)
+{
+ unsigned long time_elapsed;
+ __asm__ __volatile__("rdtime %0" : "=r"(time_elapsed));
+ return time_elapsed;
+}
+
+unsigned long rt_ktime_cputimer_getstep(void)
+{
+ return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND;
+}