| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2011 The University of Melbourne |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * This software was developed by Julien Ridoux at the University of Melbourne |
| 8 | * under sponsorship from the FreeBSD Foundation. |
| 9 | * |
| 10 | * Redistribution and use in source and binary forms, with or without |
| 11 | * modification, are permitted provided that the following conditions |
| 12 | * are met: |
| 13 | * 1. Redistributions of source code must retain the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer. |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer in the |
| 17 | * documentation and/or other materials provided with the distribution. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 29 | * SUCH DAMAGE. |
| 30 | */ |
| 31 | |
| 32 | #ifndef _SYS_TIMEFF_H_ |
| 33 | #define _SYS_TIMEFF_H_ |
| 34 | |
| 35 | #include <sys/_ffcounter.h> |
| 36 | |
| 37 | /* |
| 38 | * Feed-forward clock estimate |
| 39 | * Holds time mark as a ffcounter and conversion to bintime based on current |
| 40 | * timecounter period and offset estimate passed by the synchronization daemon. |
| 41 | * Provides time of last daemon update, clock status and bound on error. |
| 42 | */ |
| 43 | struct ffclock_estimate { |
| 44 | 	struct bintime	update_time;	/* Time of last estimates update. */ |
| 45 | 	ffcounter	update_ffcount;	/* Counter value at last update. */ |
| 46 | 	ffcounter	leapsec_next;	/* Counter value of next leap second. */ |
| 47 | 	uint64_t	period;		/* Estimate of counter period. */ |
| 48 | 	uint32_t	errb_abs;	/* Bound on absolute clock error [ns]. */ |
| 49 | 	uint32_t	errb_rate;	/* Bound on counter rate error [ps/s]. */ |
| 50 | 	uint32_t	status;		/* Clock status. */ |
| 51 | 	int16_t		leapsec_total;	/* All leap seconds seen so far. */ |
| 52 | 	int8_t		leapsec;	/* Next leap second (in {-1,0,1}). */ |
| 53 | }; |
| 54 | |
| 55 | #if __BSD_VISIBLE |
| 56 | #ifdef _KERNEL |
| 57 | |
| 58 | /* Define the kern.sysclock sysctl tree. */ |
| 59 | SYSCTL_DECL(_kern_sysclock); |
| 60 | |
| 61 | /* Define the kern.sysclock.ffclock sysctl tree. */ |
| 62 | SYSCTL_DECL(_kern_sysclock_ffclock); |
| 63 | |
| 64 | /* |
| 65 | * Index into the sysclocks array for obtaining the ASCII name of a particular |
| 66 | * sysclock. |
| 67 | */ |
| 68 | #define	SYSCLOCK_FBCK	0 |
| 69 | #define	SYSCLOCK_FFWD	1 |
| 70 | extern int sysclock_active; |
| 71 | |
| 72 | /* |
| 73 | * Parameters of counter characterisation required by feed-forward algorithms. |
| 74 | */ |
| 75 | #define	FFCLOCK_SKM_SCALE	1024 |
| 76 | |
| 77 | /* |
| 78 | * Feed-forward clock status |
| 79 | */ |
| 80 | #define	FFCLOCK_STA_UNSYNC	1 |
| 81 | #define	FFCLOCK_STA_WARMUP	2 |
| 82 | |
| 83 | /* |
| 84 | * Flags for use by sysclock_snap2bintime() and various ffclock_ functions to |
| 85 | * control how the timecounter hardware is read and how the hardware snapshot is |
| 86 | * converted into absolute time. |
| 87 | * {FB|FF}CLOCK_FAST:	Do not read the hardware counter, instead using the |
| 88 | *			value at last tick. The time returned has a resolution |
| 89 | *			of the kernel tick timer (1/hz [s]). |
| 90 | * FFCLOCK_LERP:	Linear interpolation of ffclock time to guarantee |
| 91 | *			monotonic time. |
| 92 | * {FB|FF}CLOCK_LEAPSEC: Include leap seconds. |
| 93 | * {FB|FF}CLOCK_UPTIME:	Time stamp should be relative to system boot, not epoch. |
| 94 | */ |
| 95 | #define	FFCLOCK_FAST		0x00000001 |
| 96 | #define	FFCLOCK_LERP		0x00000002 |
| 97 | #define	FFCLOCK_LEAPSEC		0x00000004 |
| 98 | #define	FFCLOCK_UPTIME		0x00000008 |
| 99 | #define	FFCLOCK_MASK		0x0000ffff |
| 100 | |
| 101 | #define	FBCLOCK_FAST		0x00010000 /* Currently unused. */ |
| 102 | #define	FBCLOCK_UPTIME		0x00020000 |
| 103 | #define	FBCLOCK_LEAPSEC		0x00040000 |
| 104 | #define	FBCLOCK_MASK		0xffff0000 |
| 105 | |
| 106 | /* |
| 107 | * Feedback clock specific info structure. The feedback clock's estimation of |
| 108 | * clock error is an absolute figure determined by the NTP algorithm. The status |
| 109 | * is determined by the userland daemon. |
| 110 | */ |
| 111 | struct fbclock_info { |
| 112 | 	struct bintime		error; |
| 113 | 	struct bintime		tick_time; |
| 114 | 	uint64_t		th_scale; |
| 115 | 	long			th_tai_offset; |
| 116 | 	int			status; |
| 117 | }; |
| 118 | |
| 119 | /* |
| 120 | * Feed-forward clock specific info structure. The feed-forward clock's |
| 121 | * estimation of clock error is an upper bound, which although potentially |
| 122 | * looser than the feedback clock equivalent, is much more reliable. The status |
| 123 | * is determined by the userland daemon. |
| 124 | */ |
| 125 | struct ffclock_info { |
| 126 | 	struct bintime		error; |
| 127 | 	struct bintime		tick_time; |
| 128 | 	struct bintime		tick_time_lerp; |
| 129 | 	uint64_t		period; |
| 130 | 	uint64_t		period_lerp; |
| 131 | 	int			leapsec_adjustment; |
| 132 | 	int			status; |
| 133 | }; |
| 134 | |
| 135 | /* |
| 136 | * Snapshot of system clocks and related information. Holds time read from each |
| 137 | * clock based on a single read of the active hardware timecounter, as well as |
| 138 | * respective clock information such as error estimates and the ffcounter value |
| 139 | * at the time of the read. |
| 140 | */ |
| 141 | struct sysclock_snap { |
| 142 | 	struct fbclock_info	fb_info; |
| 143 | 	struct ffclock_info	ff_info; |
| 144 | 	ffcounter		ffcount; |
| 145 | 	unsigned int		delta; |
| 146 | 	int			sysclock_active; |
| 147 | }; |
| 148 | |
| 149 | /* Take a snapshot of the system clocks and related information. */ |
| 150 | void sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast); |
| 151 | |
| 152 | /* Convert a timestamp from the selected system clock into bintime. */ |
| 153 | int sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, |
| 154 | int whichclock, uint32_t flags); |
| 155 | |
| 156 | /* Resets feed-forward clock from RTC */ |
| 157 | void ffclock_reset_clock(struct timespec *ts); |
| 158 | |
| 159 | /* |
| 160 | * Return the current value of the feed-forward clock counter. Essential to |
| 161 | * measure time interval in counter units. If a fast timecounter is used by the |
| 162 | * system, may also allow fast but accurate timestamping. |
| 163 | */ |
| 164 | void ffclock_read_counter(ffcounter *ffcount); |
| 165 | |
| 166 | /* |
| 167 | * Retrieve feed-forward counter value and time of last kernel tick. This |
| 168 | * accepts the FFCLOCK_LERP flag. |
| 169 | */ |
| 170 | void ffclock_last_tick(ffcounter *ffcount, struct bintime *bt, uint32_t flags); |
| 171 | |
| 172 | /* |
| 173 | * Low level routines to convert a counter timestamp into absolute time and a |
| 174 | * counter timestamp interval into an interval in seconds. The absolute time |
| 175 | * conversion accepts the FFCLOCK_LERP flag. |
| 176 | */ |
| 177 | void ffclock_convert_abs(ffcounter ffcount, struct bintime *bt, uint32_t flags); |
| 178 | void ffclock_convert_diff(ffcounter ffdelta, struct bintime *bt); |
| 179 | |
| 180 | /* |
| 181 | * Feed-forward clock routines. |
| 182 | * |
| 183 | * These functions rely on the timecounters and ffclock_estimates stored in |
| 184 | * fftimehands. Note that the error_bound parameter is not the error of the |
| 185 | * clock but an upper bound on the error of the absolute time or time interval |
| 186 | * returned. |
| 187 | * |
| 188 | * ffclock_abstime(): retrieves current time as counter value and convert this |
| 189 | * timestamp in seconds. The value (in seconds) of the converted timestamp |
| 190 | * depends on the flags passed: for a given counter value, different |
| 191 | * conversions are possible. Different clock models can be selected by |
| 192 | * combining flags (for example (FFCLOCK_LERP|FFCLOCK_UPTIME) produces |
| 193 | * linearly interpolated uptime). |
| 194 | * ffclock_difftime(): computes a time interval in seconds based on an interval |
| 195 | * measured in ffcounter units. This should be the preferred way to measure |
| 196 | * small time intervals very accurately. |
| 197 | */ |
| 198 | void ffclock_abstime(ffcounter *ffcount, struct bintime *bt, |
| 199 | struct bintime *error_bound, uint32_t flags); |
| 200 | void ffclock_difftime(ffcounter ffdelta, struct bintime *bt, |
| 201 | struct bintime *error_bound); |
| 202 | |
| 203 | /* |
| 204 | * Wrapper routines to return current absolute time using the feed-forward |
| 205 | * clock. These functions are named after those defined in <sys/time.h>, which |
| 206 | * contains a description of the original ones. |
| 207 | */ |
| 208 | void ffclock_bintime(struct bintime *bt); |
| 209 | void ffclock_nanotime(struct timespec *tsp); |
| 210 | void ffclock_microtime(struct timeval *tvp); |
| 211 | |
| 212 | void ffclock_getbintime(struct bintime *bt); |
| 213 | void ffclock_getnanotime(struct timespec *tsp); |
| 214 | void ffclock_getmicrotime(struct timeval *tvp); |
| 215 | |
| 216 | void ffclock_binuptime(struct bintime *bt); |
| 217 | void ffclock_nanouptime(struct timespec *tsp); |
| 218 | void ffclock_microuptime(struct timeval *tvp); |
| 219 | |
| 220 | void ffclock_getbinuptime(struct bintime *bt); |
| 221 | void ffclock_getnanouptime(struct timespec *tsp); |
| 222 | void ffclock_getmicrouptime(struct timeval *tvp); |
| 223 | |
| 224 | /* |
| 225 | * Wrapper routines to convert a time interval specified in ffcounter units into |
| 226 | * seconds using the current feed-forward clock estimates. |
| 227 | */ |
| 228 | void ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt); |
| 229 | void ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp); |
| 230 | void ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp); |
| 231 | |
| 232 | /* |
| 233 | * When FFCLOCK is enabled in the kernel, [get]{bin,nano,micro}[up]time() become |
| 234 | * wrappers around equivalent feedback or feed-forward functions. Provide access |
| 235 | * outside of kern_tc.c to the feedback clock equivalent functions for |
| 236 | * specialised use i.e. these are not for general consumption. |
| 237 | */ |
| 238 | void fbclock_bintime(struct bintime *bt); |
| 239 | void fbclock_nanotime(struct timespec *tsp); |
| 240 | void fbclock_microtime(struct timeval *tvp); |
| 241 | |
| 242 | void fbclock_getbintime(struct bintime *bt); |
| 243 | void fbclock_getnanotime(struct timespec *tsp); |
| 244 | void fbclock_getmicrotime(struct timeval *tvp); |
| 245 | |
| 246 | void fbclock_binuptime(struct bintime *bt); |
| 247 | void fbclock_nanouptime(struct timespec *tsp); |
| 248 | void fbclock_microuptime(struct timeval *tvp); |
| 249 | |
| 250 | void fbclock_getbinuptime(struct bintime *bt); |
| 251 | void fbclock_getnanouptime(struct timespec *tsp); |
| 252 | void fbclock_getmicrouptime(struct timeval *tvp); |
| 253 | |
| 254 | /* |
| 255 | * Public system clock wrapper API which allows consumers to select which clock |
| 256 | * to obtain time from, independent of the current default system clock. These |
| 257 | * wrappers should be used instead of directly calling the underlying fbclock_ |
| 258 | * or ffclock_ functions. |
| 259 | */ |
| 260 | static inline void |
| 261 | bintime_fromclock(struct bintime *bt, int whichclock) |
| 262 | { |
| 263 | |
| 264 | 	if (whichclock == SYSCLOCK_FFWD) |
| 265 | 		ffclock_bintime(bt); |
| 266 | 	else |
| 267 | 		fbclock_bintime(bt); |
| 268 | } |
| 269 | |
| 270 | static inline void |
| 271 | nanotime_fromclock(struct timespec *tsp, int whichclock) |
| 272 | { |
| 273 | |
| 274 | 	if (whichclock == SYSCLOCK_FFWD) |
| 275 | 		ffclock_nanotime(tsp); |
| 276 | 	else |
| 277 | 		fbclock_nanotime(tsp); |
| 278 | } |
| 279 | |
| 280 | static inline void |
| 281 | microtime_fromclock(struct timeval *tvp, int whichclock) |
| 282 | { |
| 283 | |
| 284 | 	if (whichclock == SYSCLOCK_FFWD) |
| 285 | 		ffclock_microtime(tvp); |
| 286 | 	else |
| 287 | 		fbclock_microtime(tvp); |
| 288 | } |
| 289 | |
| 290 | static inline void |
| 291 | getbintime_fromclock(struct bintime *bt, int whichclock) |
| 292 | { |
| 293 | |
| 294 | 	if (whichclock == SYSCLOCK_FFWD) |
| 295 | 		ffclock_getbintime(bt); |
| 296 | 	else |
| 297 | 		fbclock_getbintime(bt); |
| 298 | } |
| 299 | |
| 300 | static inline void |
| 301 | getnanotime_fromclock(struct timespec *tsp, int whichclock) |
| 302 | { |
| 303 | |
| 304 | 	if (whichclock == SYSCLOCK_FFWD) |
| 305 | 		ffclock_getnanotime(tsp); |
| 306 | 	else |
| 307 | 		fbclock_getnanotime(tsp); |
| 308 | } |
| 309 | |
| 310 | static inline void |
| 311 | getmicrotime_fromclock(struct timeval *tvp, int whichclock) |
| 312 | { |
| 313 | |
| 314 | 	if (whichclock == SYSCLOCK_FFWD) |
| 315 | 		ffclock_getmicrotime(tvp); |
| 316 | 	else |
| 317 | 		fbclock_getmicrotime(tvp); |
| 318 | } |
| 319 | |
| 320 | static inline void |
| 321 | binuptime_fromclock(struct bintime *bt, int whichclock) |
| 322 | { |
| 323 | |
| 324 | 	if (whichclock == SYSCLOCK_FFWD) |
| 325 | 		ffclock_binuptime(bt); |
| 326 | 	else |
| 327 | 		fbclock_binuptime(bt); |
| 328 | } |
| 329 | |
| 330 | static inline void |
| 331 | nanouptime_fromclock(struct timespec *tsp, int whichclock) |
| 332 | { |
| 333 | |
| 334 | 	if (whichclock == SYSCLOCK_FFWD) |
| 335 | 		ffclock_nanouptime(tsp); |
| 336 | 	else |
| 337 | 		fbclock_nanouptime(tsp); |
| 338 | } |
| 339 | |
| 340 | static inline void |
| 341 | microuptime_fromclock(struct timeval *tvp, int whichclock) |
| 342 | { |
| 343 | |
| 344 | 	if (whichclock == SYSCLOCK_FFWD) |
| 345 | 		ffclock_microuptime(tvp); |
| 346 | 	else |
| 347 | 		fbclock_microuptime(tvp); |
| 348 | } |
| 349 | |
| 350 | static inline void |
| 351 | getbinuptime_fromclock(struct bintime *bt, int whichclock) |
| 352 | { |
| 353 | |
| 354 | 	if (whichclock == SYSCLOCK_FFWD) |
| 355 | 		ffclock_getbinuptime(bt); |
| 356 | 	else |
| 357 | 		fbclock_getbinuptime(bt); |
| 358 | } |
| 359 | |
| 360 | static inline void |
| 361 | getnanouptime_fromclock(struct timespec *tsp, int whichclock) |
| 362 | { |
| 363 | |
| 364 | 	if (whichclock == SYSCLOCK_FFWD) |
| 365 | 		ffclock_getnanouptime(tsp); |
| 366 | 	else |
| 367 | 		fbclock_getnanouptime(tsp); |
| 368 | } |
| 369 | |
| 370 | static inline void |
| 371 | getmicrouptime_fromclock(struct timeval *tvp, int whichclock) |
| 372 | { |
| 373 | |
| 374 | 	if (whichclock == SYSCLOCK_FFWD) |
| 375 | 		ffclock_getmicrouptime(tvp); |
| 376 | 	else |
| 377 | 		fbclock_getmicrouptime(tvp); |
| 378 | } |
| 379 | |
| 380 | #else /* !_KERNEL */ |
| 381 | |
| 382 | /* Feed-Forward Clock system calls. */ |
| 383 | __BEGIN_DECLS |
| 384 | int ffclock_getcounter(ffcounter *ffcount); |
| 385 | int ffclock_getestimate(struct ffclock_estimate *cest); |
| 386 | int ffclock_setestimate(struct ffclock_estimate *cest); |
| 387 | __END_DECLS |
| 388 | |
| 389 | #endif /* _KERNEL */ |
| 390 | #endif /* __BSD_VISIBLE */ |
| 391 | #endif /* _SYS_TIMEFF_H_ */ |