[PATCH 2/2] arm64: Add support for CLOCK_MONOTONIC_RAW in clock_gettime() vDSO
Dave Martin
Dave.Martin at arm.com
Fri Jul 1 06:48:12 PDT 2016
On Mon, May 09, 2016 at 01:37:01PM +0100, Kevin Brodsky wrote:
> So far the arm64 clock_gettime() vDSO implementation only supported
> the following clocks, falling back to the syscall for the others:
> - CLOCK_REALTIME{,_COARSE}
> - CLOCK_MONOTONIC{,_COARSE}
>
> This patch adds support for the CLOCK_MONOTONIC_RAW clock, taking
> advantage of the recent refactoring of the vDSO time functions. Like
> the non-_COARSE clocks, this only works when the "arch_sys_counter"
> clocksource is in use (allowing us to read the current time from the
> virtual counter register), otherwise we also have to fall back to the
> syscall.
>
> Most of the data is shared with CLOCK_MONOTONIC, and the algorithm is
> similar. The reference implementation in kernel/time/timekeeping.c
> shows that:
> - CLOCK_MONOTONIC = tk->wall_to_monotonic + tk->xtime_sec +
> timekeeping_get_ns(&tk->tkr_mono)
> - CLOCK_MONOTONIC_RAW = tk->raw_time + timekeeping_get_ns(&tk->tkr_raw)
> - tkr_mono and tkr_raw are identical (in particular, same
> clocksource), except these members:
> * mult (only mono's multiplier is NTP-adjusted)
> * xtime_nsec (always 0 for raw)
>
> Therefore, tk->raw_time and tkr_raw->mult are now also stored in the
> vDSO data page.
>
> Cc: Will Deacon <will.deacon at arm.com>
> Cc: Dave Martin <dave.martin at arm.com>
> Cc: Ali Saidi <ali.saidi at arm.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
Reviewed-by: Dave Martin <Dave.Martin at arm.com>
> ---
> arch/arm64/include/asm/vdso_datapage.h | 8 +++--
> arch/arm64/kernel/asm-offsets.c | 6 +++-
> arch/arm64/kernel/vdso.c | 8 ++++-
> arch/arm64/kernel/vdso/gettimeofday.S | 57 +++++++++++++++++++++++++++-------
> 4 files changed, 64 insertions(+), 15 deletions(-)
>
> diff --git a/arch/arm64/include/asm/vdso_datapage.h b/arch/arm64/include/asm/vdso_datapage.h
> index de66199673d7..2b9a63771eda 100644
> --- a/arch/arm64/include/asm/vdso_datapage.h
> +++ b/arch/arm64/include/asm/vdso_datapage.h
> @@ -22,6 +22,8 @@
>
> struct vdso_data {
> __u64 cs_cycle_last; /* Timebase at clocksource init */
> + __u64 raw_time_sec; /* Raw time */
> + __u64 raw_time_nsec;
> __u64 xtime_clock_sec; /* Kernel time */
> __u64 xtime_clock_nsec;
> __u64 xtime_coarse_sec; /* Coarse time */
> @@ -29,8 +31,10 @@ struct vdso_data {
> __u64 wtm_clock_sec; /* Wall to monotonic time */
> __u64 wtm_clock_nsec;
> __u32 tb_seq_count; /* Timebase sequence counter */
> - __u32 cs_mult; /* Clocksource multiplier */
> - __u32 cs_shift; /* Clocksource shift */
> + /* cs_* members must be adjacent and in this order (ldp accesses) */
> + __u32 cs_mono_mult; /* NTP-adjusted clocksource multiplier */
> + __u32 cs_shift; /* Clocksource shift (mono = raw) */
> + __u32 cs_raw_mult; /* Raw clocksource multiplier */
> __u32 tz_minuteswest; /* Whacky timezone stuff */
> __u32 tz_dsttime;
> __u32 use_syscall;
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index 3ae6b310ac9b..5ff88560e5ef 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -76,6 +76,7 @@ int main(void)
> BLANK();
> DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
> DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
> + DEFINE(CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_RAW);
> DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
> DEFINE(CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE);
> DEFINE(CLOCK_MONOTONIC_COARSE,CLOCK_MONOTONIC_COARSE);
> @@ -83,6 +84,8 @@ int main(void)
> DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
> BLANK();
> DEFINE(VDSO_CS_CYCLE_LAST, offsetof(struct vdso_data, cs_cycle_last));
> + DEFINE(VDSO_RAW_TIME_SEC, offsetof(struct vdso_data, raw_time_sec));
> + DEFINE(VDSO_RAW_TIME_NSEC, offsetof(struct vdso_data, raw_time_nsec));
> DEFINE(VDSO_XTIME_CLK_SEC, offsetof(struct vdso_data, xtime_clock_sec));
> DEFINE(VDSO_XTIME_CLK_NSEC, offsetof(struct vdso_data, xtime_clock_nsec));
> DEFINE(VDSO_XTIME_CRS_SEC, offsetof(struct vdso_data, xtime_coarse_sec));
> @@ -90,7 +93,8 @@ int main(void)
> DEFINE(VDSO_WTM_CLK_SEC, offsetof(struct vdso_data, wtm_clock_sec));
> DEFINE(VDSO_WTM_CLK_NSEC, offsetof(struct vdso_data, wtm_clock_nsec));
> DEFINE(VDSO_TB_SEQ_COUNT, offsetof(struct vdso_data, tb_seq_count));
> - DEFINE(VDSO_CS_MULT, offsetof(struct vdso_data, cs_mult));
> + DEFINE(VDSO_CS_MONO_MULT, offsetof(struct vdso_data, cs_mono_mult));
> + DEFINE(VDSO_CS_RAW_MULT, offsetof(struct vdso_data, cs_raw_mult));
> DEFINE(VDSO_CS_SHIFT, offsetof(struct vdso_data, cs_shift));
> DEFINE(VDSO_TZ_MINWEST, offsetof(struct vdso_data, tz_minuteswest));
> DEFINE(VDSO_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime));
> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
> index 97bc68f4c689..54f7b327fd18 100644
> --- a/arch/arm64/kernel/vdso.c
> +++ b/arch/arm64/kernel/vdso.c
> @@ -212,10 +212,16 @@ void update_vsyscall(struct timekeeper *tk)
> vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
>
> if (!use_syscall) {
> + /* tkr_mono.cycle_last == tkr_raw.cycle_last */
> vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
> + vdso_data->raw_time_sec = tk->raw_time.tv_sec;
> + vdso_data->raw_time_nsec = tk->raw_time.tv_nsec;
> vdso_data->xtime_clock_sec = tk->xtime_sec;
> vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
> - vdso_data->cs_mult = tk->tkr_mono.mult;
> + /* tkr_raw.xtime_nsec == 0 */
> + vdso_data->cs_mono_mult = tk->tkr_mono.mult;
> + vdso_data->cs_raw_mult = tk->tkr_raw.mult;
> + /* tkr_mono.shift == tkr_raw.shift */
> vdso_data->cs_shift = tk->tkr_mono.shift;
> }
>
> diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S
> index caff9dd6ba78..f49b6755058a 100644
> --- a/arch/arm64/kernel/vdso/gettimeofday.S
> +++ b/arch/arm64/kernel/vdso/gettimeofday.S
> @@ -87,6 +87,15 @@ x_tmp .req x8
> msub \res_nsec, x_tmp, \nsec_to_sec, \res_nsec
> .endm
>
> + /*
> + * Returns in res_{sec,nsec} the timespec based on the clock_raw delta,
> + * used for CLOCK_MONOTONIC_RAW.
> + */
> + .macro get_ts_clock_raw res_sec, res_nsec, clock_nsec, nsec_to_sec
> + udiv \res_sec, \clock_nsec, \nsec_to_sec
> + msub \res_nsec, \res_sec, \nsec_to_sec, \clock_nsec
> + .endm
> +
> /* sec and nsec are modified in place. */
> .macro add_ts sec, nsec, ts_sec, ts_nsec, nsec_to_sec
> /* Add timespec. */
> @@ -126,7 +135,8 @@ ENTRY(__kernel_gettimeofday)
> 1: seqcnt_acquire
> syscall_check fail=4f
> ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
> - ldp w11, w12, [vdso_data, #VDSO_CS_MULT]
> + /* w11 = cs_mono_mult, w12 = cs_shift */
> + ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
> ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
> seqcnt_check fail=1b
>
> @@ -163,19 +173,19 @@ ENDPROC(__kernel_gettimeofday)
> /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
> ENTRY(__kernel_clock_gettime)
> .cfi_startproc
> - cmp w0, #JUMPSLOT_MAX
> - b.hi syscall
> + cmp w0, #JUMPSLOT_MAX
> + b.hi syscall
> adr vdso_data, _vdso_data
> - adr x_tmp, jumptable
> - add x_tmp, x_tmp, w0, uxtw #2
> - br x_tmp
> + adr x_tmp, jumptable
> + add x_tmp, x_tmp, w0, uxtw #2
> + br x_tmp
>
> jumptable:
> jump_slot jumptable, CLOCK_REALTIME, realtime
> jump_slot jumptable, CLOCK_MONOTONIC, monotonic
> - b syscall
> - b syscall
> - b syscall
> + b syscall
> + b syscall
> + jump_slot jumptable, CLOCK_MONOTONIC_RAW, monotonic_raw
> jump_slot jumptable, CLOCK_REALTIME_COARSE, realtime_coarse
> jump_slot jumptable, CLOCK_MONOTONIC_COARSE, monotonic_coarse
>
> @@ -187,7 +197,8 @@ realtime:
> seqcnt_acquire
> syscall_check fail=syscall
> ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
> - ldp w11, w12, [vdso_data, #VDSO_CS_MULT]
> + /* w11 = cs_mono_mult, w12 = cs_shift */
> + ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
> ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
> seqcnt_check fail=realtime
>
> @@ -205,7 +216,8 @@ monotonic:
> seqcnt_acquire
> syscall_check fail=syscall
> ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
> - ldp w11, w12, [vdso_data, #VDSO_CS_MULT]
> + /* w11 = cs_mono_mult, w12 = cs_shift */
> + ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT]
> ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
> ldp x3, x4, [vdso_data, #VDSO_WTM_CLK_SEC]
> seqcnt_check fail=monotonic
> @@ -223,6 +235,28 @@ monotonic:
>
> b shift_store
>
> +monotonic_raw:
> + seqcnt_acquire
> + syscall_check fail=syscall
> + ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
> + /* w11 = cs_raw_mult, w12 = cs_shift */
> + ldp w12, w11, [vdso_data, #VDSO_CS_SHIFT]
> + ldp x13, x14, [vdso_data, #VDSO_RAW_TIME_SEC]
> + seqcnt_check fail=monotonic_raw
> +
> + /* All computations are done with left-shifted nsecs. */
> + lsl x14, x14, x12
> + get_nsec_per_sec res=x9
> + lsl x9, x9, x12
> +
> + get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11
> + get_ts_clock_raw res_sec=x10, res_nsec=x11, \
> + clock_nsec=x15, nsec_to_sec=x9
> +
> + add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9
> +
> + b shift_store
> +
> realtime_coarse:
> seqcnt_acquire
> ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC]
> @@ -261,6 +295,7 @@ ENTRY(__kernel_clock_getres)
> .cfi_startproc
> cmp w0, #CLOCK_REALTIME
> ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
> + ccmp w0, #CLOCK_MONOTONIC_RAW, #0x4, ne
> b.ne 1f
>
> ldr x2, 5f
> --
> 2.8.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
More information about the linux-arm-kernel
mailing list