Here is the arm64 version. Again I've taken the approach of copying the kernel timecounter code verbatim. Technically we don't need the Cortex-A73 errata workaround here since the timecounter only uses the low 32 bits. But that is true for the kernel as well! If people think it is worth avoiding this, I'd propose to introduce agtimer_readcnt32() and use that for the timecounter in both the kernel and userland.
I modified Scott's test program and ran it on machine with both Cortex-A53 and Cortex-A73 cores. That didn't reveal any glitches. So it seems that indeed the ARM design removes any detectable skew between the cores. ok? Index: lib/libc/arch/aarch64/gen/usertc.c =================================================================== RCS file: /cvs/src/lib/libc/arch/aarch64/gen/usertc.c,v retrieving revision 1.1 diff -u -p -r1.1 usertc.c --- lib/libc/arch/aarch64/gen/usertc.c 6 Jul 2020 13:33:05 -0000 1.1 +++ lib/libc/arch/aarch64/gen/usertc.c 9 Jul 2020 08:12:44 -0000 @@ -1,6 +1,6 @@ -/* $OpenBSD: usertc.c,v 1.1 2020/07/06 13:33:05 pirofti Exp $ */ +/* $OpenBSD$ */ /* - * Copyright (c) 2020 Paul Irofti <[email protected]> + * Copyright (c) 2020 Mark Kettenis <[email protected]> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,4 +18,39 @@ #include <sys/types.h> #include <sys/timetc.h> -int (*const _tc_get_timecount)(struct timekeep *, u_int *) = NULL; +static inline uint64_t +agtimer_readcnt64(void) +{ + uint64_t val0, val1; + + /* + * Work around Cortex-A73 errata 858921, where there is a + * one-cycle window where the read might return the old value + * for the low 32 bits and the new value for the high 32 bits + * upon roll-over of the low 32 bits. + */ + __asm volatile("isb" : : : "memory"); + __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val0)); + __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val1)); + return ((val0 ^ val1) & 0x100000000ULL) ? val0 : val1; +} + +static inline u_int +agtimer_get_timecount(struct timecounter *tc) +{ + return agtimer_readcnt64(); +} + +static int +tc_get_timecount(struct timekeep *tk, u_int *tc) +{ + switch (tk->tk_user) { + case TC_AGTIMER: + *tc = agtimer_get_timecount(NULL); + return 0; + } + + return -1; +} + +int (*const _tc_get_timecount)(struct timekeep *, u_int *) = tc_get_timecount; Index: sys/arch/arm64/dev/agtimer.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/agtimer.c,v retrieving revision 1.13 diff -u -p -r1.13 agtimer.c --- sys/arch/arm64/dev/agtimer.c 6 Jul 2020 13:33:06 -0000 1.13 +++ sys/arch/arm64/dev/agtimer.c 9 Jul 2020 08:12:45 -0000 @@ -43,7 +43,8 @@ int32_t agtimer_frequency = TIMER_FREQUE u_int agtimer_get_timecount(struct timecounter *); static struct timecounter agtimer_timecounter = { - agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0 + agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, + TC_AGTIMER }; struct agtimer_pcpu_softc { Index: sys/arch/arm64/include/timetc.h =================================================================== RCS file: /cvs/src/sys/arch/arm64/include/timetc.h,v retrieving revision 1.1 diff -u -p -r1.1 timetc.h --- sys/arch/arm64/include/timetc.h 6 Jul 2020 13:33:07 -0000 1.1 +++ sys/arch/arm64/include/timetc.h 9 Jul 2020 08:12:45 -0000 @@ -18,6 +18,6 @@ #ifndef _MACHINE_TIMETC_H_ #define _MACHINE_TIMETC_H_ -#define TC_LAST 0 +#define TC_AGTIMER 1 #endif /* _MACHINE_TIMETC_H_ */
