Even if RISC-V has supported the vDSO feature, the latency of the functions for obtaining the system time is still expensive. It is because these functions still trigger a corresponding system call in the process, which slows down the response time. If we want to remove the system call to reduce the latency, the kernel should have the ability to output the system clock information to userspace. This patch introduces the vDSO common flow to enable the kernel to achieve the above feature and uses "rdtime" instruction to obtain the current time in the user space. Under this condition, the latency cost by the ecall from U-mode to S-mode can be eliminated. After applying this patch, the latency of gettimeofday() measured on the HiFive unleashed board can be reduced by %61. Signed-off-by: Vincent Chen <vincent.chen@sifive.com> Reviewed-by: Atish Patra <atish.patra@wdc.com> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
80 lines
1.9 KiB
C
80 lines
1.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __ASM_VDSO_GETTIMEOFDAY_H
|
|
#define __ASM_VDSO_GETTIMEOFDAY_H
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <asm/unistd.h>
|
|
#include <asm/csr.h>
|
|
#include <uapi/linux/time.h>
|
|
|
|
#define VDSO_HAS_CLOCK_GETRES 1
|
|
|
|
static __always_inline
|
|
int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
|
|
struct timezone *_tz)
|
|
{
|
|
register struct __kernel_old_timeval *tv asm("a0") = _tv;
|
|
register struct timezone *tz asm("a1") = _tz;
|
|
register long ret asm("a0");
|
|
register long nr asm("a7") = __NR_gettimeofday;
|
|
|
|
asm volatile ("ecall\n"
|
|
: "=r" (ret)
|
|
: "r"(tv), "r"(tz), "r"(nr)
|
|
: "memory");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static __always_inline
|
|
long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|
{
|
|
register clockid_t clkid asm("a0") = _clkid;
|
|
register struct __kernel_timespec *ts asm("a1") = _ts;
|
|
register long ret asm("a0");
|
|
register long nr asm("a7") = __NR_clock_gettime;
|
|
|
|
asm volatile ("ecall\n"
|
|
: "=r" (ret)
|
|
: "r"(clkid), "r"(ts), "r"(nr)
|
|
: "memory");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static __always_inline
|
|
int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|
{
|
|
register clockid_t clkid asm("a0") = _clkid;
|
|
register struct __kernel_timespec *ts asm("a1") = _ts;
|
|
register long ret asm("a0");
|
|
register long nr asm("a7") = __NR_clock_getres;
|
|
|
|
asm volatile ("ecall\n"
|
|
: "=r" (ret)
|
|
: "r"(clkid), "r"(ts), "r"(nr)
|
|
: "memory");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
|
|
{
|
|
/*
|
|
* The purpose of csr_read(CSR_TIME) is to trap the system into
|
|
* M-mode to obtain the value of CSR_TIME. Hence, unlike other
|
|
* architecture, no fence instructions surround the csr_read()
|
|
*/
|
|
return csr_read(CSR_TIME);
|
|
}
|
|
|
|
static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
|
|
{
|
|
return _vdso_data;
|
|
}
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
|