144f57d78SVincenzo Frascino // SPDX-License-Identifier: GPL-2.0
244f57d78SVincenzo Frascino /*
344f57d78SVincenzo Frascino * Copyright 2019 ARM Ltd.
444f57d78SVincenzo Frascino *
544f57d78SVincenzo Frascino * Generic implementation of update_vsyscall and update_vsyscall_tz.
644f57d78SVincenzo Frascino *
744f57d78SVincenzo Frascino * Based on the x86 specific implementation.
844f57d78SVincenzo Frascino */
944f57d78SVincenzo Frascino
1044f57d78SVincenzo Frascino #include <linux/hrtimer.h>
1144f57d78SVincenzo Frascino #include <linux/timekeeper_internal.h>
1244f57d78SVincenzo Frascino #include <vdso/datapage.h>
1344f57d78SVincenzo Frascino #include <vdso/helpers.h>
1444f57d78SVincenzo Frascino #include <vdso/vsyscall.h>
1544f57d78SVincenzo Frascino
1619d0070aSThomas Gleixner #include "timekeeping_internal.h"
1719d0070aSThomas Gleixner
update_vdso_data(struct vdso_data * vdata,struct timekeeper * tk)1844f57d78SVincenzo Frascino static inline void update_vdso_data(struct vdso_data *vdata,
1944f57d78SVincenzo Frascino struct timekeeper *tk)
2044f57d78SVincenzo Frascino {
2144f57d78SVincenzo Frascino struct vdso_timestamp *vdso_ts;
22b99328a6SThomas Gleixner u64 nsec, sec;
2344f57d78SVincenzo Frascino
2444f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].cycle_last = tk->tkr_mono.cycle_last;
2544f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].mask = tk->tkr_mono.mask;
2644f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].mult = tk->tkr_mono.mult;
2744f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].shift = tk->tkr_mono.shift;
2844f57d78SVincenzo Frascino vdata[CS_RAW].cycle_last = tk->tkr_raw.cycle_last;
2944f57d78SVincenzo Frascino vdata[CS_RAW].mask = tk->tkr_raw.mask;
3044f57d78SVincenzo Frascino vdata[CS_RAW].mult = tk->tkr_raw.mult;
3144f57d78SVincenzo Frascino vdata[CS_RAW].shift = tk->tkr_raw.shift;
3244f57d78SVincenzo Frascino
3344f57d78SVincenzo Frascino /* CLOCK_MONOTONIC */
3444f57d78SVincenzo Frascino vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC];
3544f57d78SVincenzo Frascino vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
3644f57d78SVincenzo Frascino
3744f57d78SVincenzo Frascino nsec = tk->tkr_mono.xtime_nsec;
3844f57d78SVincenzo Frascino nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift);
3944f57d78SVincenzo Frascino while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
4044f57d78SVincenzo Frascino nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
4144f57d78SVincenzo Frascino vdso_ts->sec++;
4244f57d78SVincenzo Frascino }
4344f57d78SVincenzo Frascino vdso_ts->nsec = nsec;
4444f57d78SVincenzo Frascino
45b99328a6SThomas Gleixner /* Copy MONOTONIC time for BOOTTIME */
46b99328a6SThomas Gleixner sec = vdso_ts->sec;
47b99328a6SThomas Gleixner /* Add the boot offset */
48b99328a6SThomas Gleixner sec += tk->monotonic_to_boot.tv_sec;
49b99328a6SThomas Gleixner nsec += (u64)tk->monotonic_to_boot.tv_nsec << tk->tkr_mono.shift;
5044f57d78SVincenzo Frascino
5144f57d78SVincenzo Frascino /* CLOCK_BOOTTIME */
5244f57d78SVincenzo Frascino vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_BOOTTIME];
53b99328a6SThomas Gleixner vdso_ts->sec = sec;
54b99328a6SThomas Gleixner
5544f57d78SVincenzo Frascino while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
5644f57d78SVincenzo Frascino nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
5744f57d78SVincenzo Frascino vdso_ts->sec++;
5844f57d78SVincenzo Frascino }
5944f57d78SVincenzo Frascino vdso_ts->nsec = nsec;
6044f57d78SVincenzo Frascino
61b99328a6SThomas Gleixner /* CLOCK_MONOTONIC_RAW */
62b99328a6SThomas Gleixner vdso_ts = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
63b99328a6SThomas Gleixner vdso_ts->sec = tk->raw_sec;
64b99328a6SThomas Gleixner vdso_ts->nsec = tk->tkr_raw.xtime_nsec;
65b99328a6SThomas Gleixner
6644f57d78SVincenzo Frascino /* CLOCK_TAI */
6744f57d78SVincenzo Frascino vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_TAI];
6844f57d78SVincenzo Frascino vdso_ts->sec = tk->xtime_sec + (s64)tk->tai_offset;
6944f57d78SVincenzo Frascino vdso_ts->nsec = tk->tkr_mono.xtime_nsec;
7044f57d78SVincenzo Frascino }
7144f57d78SVincenzo Frascino
update_vsyscall(struct timekeeper * tk)7244f57d78SVincenzo Frascino void update_vsyscall(struct timekeeper *tk)
7344f57d78SVincenzo Frascino {
7444f57d78SVincenzo Frascino struct vdso_data *vdata = __arch_get_k_vdso_data();
7544f57d78SVincenzo Frascino struct vdso_timestamp *vdso_ts;
765d51bee7SThomas Gleixner s32 clock_mode;
7744f57d78SVincenzo Frascino u64 nsec;
7844f57d78SVincenzo Frascino
7944f57d78SVincenzo Frascino /* copy vsyscall data */
8044f57d78SVincenzo Frascino vdso_write_begin(vdata);
8144f57d78SVincenzo Frascino
825d51bee7SThomas Gleixner clock_mode = tk->tkr_mono.clock->vdso_clock_mode;
835d51bee7SThomas Gleixner vdata[CS_HRES_COARSE].clock_mode = clock_mode;
845d51bee7SThomas Gleixner vdata[CS_RAW].clock_mode = clock_mode;
8544f57d78SVincenzo Frascino
869f24c540SThomas Gleixner /* CLOCK_REALTIME also required for time() */
879f24c540SThomas Gleixner vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];
889f24c540SThomas Gleixner vdso_ts->sec = tk->xtime_sec;
899f24c540SThomas Gleixner vdso_ts->nsec = tk->tkr_mono.xtime_nsec;
909f24c540SThomas Gleixner
9144f57d78SVincenzo Frascino /* CLOCK_REALTIME_COARSE */
9244f57d78SVincenzo Frascino vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME_COARSE];
9344f57d78SVincenzo Frascino vdso_ts->sec = tk->xtime_sec;
9444f57d78SVincenzo Frascino vdso_ts->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
9544f57d78SVincenzo Frascino
9644f57d78SVincenzo Frascino /* CLOCK_MONOTONIC_COARSE */
9744f57d78SVincenzo Frascino vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC_COARSE];
9844f57d78SVincenzo Frascino vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
9944f57d78SVincenzo Frascino nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
10044f57d78SVincenzo Frascino nsec = nsec + tk->wall_to_monotonic.tv_nsec;
1010df1c986SArnd Bergmann vdso_ts->sec += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &vdso_ts->nsec);
10244f57d78SVincenzo Frascino
1039f24c540SThomas Gleixner /*
1049f24c540SThomas Gleixner * Read without the seqlock held by clock_getres().
1059f24c540SThomas Gleixner * Note: No need to have a second copy.
1069f24c540SThomas Gleixner */
1079f24c540SThomas Gleixner WRITE_ONCE(vdata[CS_HRES_COARSE].hrtimer_res, hrtimer_resolution);
1089f24c540SThomas Gleixner
1099f24c540SThomas Gleixner /*
110c7a18100SThomas Gleixner * If the current clocksource is not VDSO capable, then spare the
111*4bf07f65SIngo Molnar * update of the high resolution parts.
1129f24c540SThomas Gleixner */
113c7a18100SThomas Gleixner if (clock_mode != VDSO_CLOCKMODE_NONE)
11444f57d78SVincenzo Frascino update_vdso_data(vdata, tk);
11544f57d78SVincenzo Frascino
11644f57d78SVincenzo Frascino __arch_update_vsyscall(vdata, tk);
11744f57d78SVincenzo Frascino
11844f57d78SVincenzo Frascino vdso_write_end(vdata);
11944f57d78SVincenzo Frascino
12044f57d78SVincenzo Frascino __arch_sync_vdso_data(vdata);
12144f57d78SVincenzo Frascino }
12244f57d78SVincenzo Frascino
update_vsyscall_tz(void)12344f57d78SVincenzo Frascino void update_vsyscall_tz(void)
12444f57d78SVincenzo Frascino {
12544f57d78SVincenzo Frascino struct vdso_data *vdata = __arch_get_k_vdso_data();
12644f57d78SVincenzo Frascino
12744f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].tz_minuteswest = sys_tz.tz_minuteswest;
12844f57d78SVincenzo Frascino vdata[CS_HRES_COARSE].tz_dsttime = sys_tz.tz_dsttime;
12944f57d78SVincenzo Frascino
13044f57d78SVincenzo Frascino __arch_sync_vdso_data(vdata);
13144f57d78SVincenzo Frascino }
13219d0070aSThomas Gleixner
13319d0070aSThomas Gleixner /**
13419d0070aSThomas Gleixner * vdso_update_begin - Start of a VDSO update section
13519d0070aSThomas Gleixner *
13619d0070aSThomas Gleixner * Allows architecture code to safely update the architecture specific VDSO
13719d0070aSThomas Gleixner * data. Disables interrupts, acquires timekeeper lock to serialize against
13819d0070aSThomas Gleixner * concurrent updates from timekeeping and invalidates the VDSO data
13919d0070aSThomas Gleixner * sequence counter to prevent concurrent readers from accessing
14019d0070aSThomas Gleixner * inconsistent data.
14119d0070aSThomas Gleixner *
14219d0070aSThomas Gleixner * Returns: Saved interrupt flags which need to be handed in to
14319d0070aSThomas Gleixner * vdso_update_end().
14419d0070aSThomas Gleixner */
vdso_update_begin(void)14519d0070aSThomas Gleixner unsigned long vdso_update_begin(void)
14619d0070aSThomas Gleixner {
14719d0070aSThomas Gleixner struct vdso_data *vdata = __arch_get_k_vdso_data();
14819d0070aSThomas Gleixner unsigned long flags;
14919d0070aSThomas Gleixner
15019d0070aSThomas Gleixner raw_spin_lock_irqsave(&timekeeper_lock, flags);
15119d0070aSThomas Gleixner vdso_write_begin(vdata);
15219d0070aSThomas Gleixner return flags;
15319d0070aSThomas Gleixner }
15419d0070aSThomas Gleixner
15519d0070aSThomas Gleixner /**
15619d0070aSThomas Gleixner * vdso_update_end - End of a VDSO update section
15719d0070aSThomas Gleixner * @flags: Interrupt flags as returned from vdso_update_begin()
15819d0070aSThomas Gleixner *
15919d0070aSThomas Gleixner * Pairs with vdso_update_begin(). Marks vdso data consistent, invokes data
16019d0070aSThomas Gleixner * synchronization if the architecture requires it, drops timekeeper lock
16119d0070aSThomas Gleixner * and restores interrupt flags.
16219d0070aSThomas Gleixner */
vdso_update_end(unsigned long flags)16319d0070aSThomas Gleixner void vdso_update_end(unsigned long flags)
16419d0070aSThomas Gleixner {
16519d0070aSThomas Gleixner struct vdso_data *vdata = __arch_get_k_vdso_data();
16619d0070aSThomas Gleixner
16719d0070aSThomas Gleixner vdso_write_end(vdata);
16819d0070aSThomas Gleixner __arch_sync_vdso_data(vdata);
16919d0070aSThomas Gleixner raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
17019d0070aSThomas Gleixner }
171