1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include "opt_ffclock.h" 36 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/module.h> 42 #include <sys/mutex.h> 43 #include <sys/priv.h> 44 #include <sys/proc.h> 45 #include <sys/sbuf.h> 46 #include <sys/sysent.h> 47 #include <sys/sysproto.h> 48 #include <sys/sysctl.h> 49 #include <sys/systm.h> 50 #include <sys/timeffc.h> 51 52 #ifdef FFCLOCK 53 54 FEATURE(ffclock, "Feed-forward clock support"); 55 56 extern struct ffclock_estimate ffclock_estimate; 57 extern struct bintime ffclock_boottime; 58 extern int8_t ffclock_updated; 59 extern struct mtx ffclock_mtx; 60 61 /* 62 * Feed-forward clock absolute time. This should be the preferred way to read 63 * the feed-forward clock for "wall-clock" type time. The flags allow to compose 64 * various flavours of absolute time (e.g. with or without leap seconds taken 65 * into account). If valid pointers are provided, the ffcounter value and an 66 * upper bound on clock error associated with the bintime are provided. 67 * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value 68 * read earlier. 69 */ 70 void 71 ffclock_abstime(ffcounter *ffcount, struct bintime *bt, 72 struct bintime *error_bound, uint32_t flags) 73 { 74 struct ffclock_estimate cest; 75 ffcounter ffc; 76 ffcounter update_ffcount; 77 ffcounter ffdelta_error; 78 79 /* Get counter and corresponding time. */ 80 if ((flags & FFCLOCK_FAST) == FFCLOCK_FAST) 81 ffclock_last_tick(&ffc, bt, flags); 82 else { 83 ffclock_read_counter(&ffc); 84 ffclock_convert_abs(ffc, bt, flags); 85 } 86 87 /* Current ffclock estimate, use update_ffcount as generation number. */ 88 do { 89 update_ffcount = ffclock_estimate.update_ffcount; 90 bcopy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 91 } while (update_ffcount != ffclock_estimate.update_ffcount); 92 93 /* 94 * Leap second adjustment. Total as seen by synchronisation algorithm 95 * since it started. cest.leapsec_next is the ffcounter prediction of 96 * when the next leapsecond occurs. 97 */ 98 if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { 99 bt->sec -= cest.leapsec_total; 100 if (ffc > cest.leapsec_next) 101 bt->sec -= cest.leapsec; 102 } 103 104 /* Boot time adjustment, for uptime/monotonic clocks. */ 105 if ((flags & FFCLOCK_UPTIME) == FFCLOCK_UPTIME) { 106 bintime_sub(bt, &ffclock_boottime); 107 } 108 109 /* Compute error bound if a valid pointer has been passed. */ 110 if (error_bound) { 111 ffdelta_error = ffc - cest.update_ffcount; 112 ffclock_convert_diff(ffdelta_error, error_bound); 113 /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 114 bintime_mul(error_bound, cest.errb_rate * 115 (uint64_t)18446744073709LL); 116 /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns] */ 117 bintime_addx(error_bound, cest.errb_abs * 118 (uint64_t)18446744073LL); 119 } 120 121 if (ffcount) 122 *ffcount = ffc; 123 } 124 125 /* 126 * Feed-forward difference clock. This should be the preferred way to convert a 127 * time interval in ffcounter values into a time interval in seconds. If a valid 128 * pointer is passed, an upper bound on the error in computing the time interval 129 * in seconds is provided. 130 */ 131 void 132 ffclock_difftime(ffcounter ffdelta, struct bintime *bt, 133 struct bintime *error_bound) 134 { 135 ffcounter update_ffcount; 136 uint32_t err_rate; 137 138 ffclock_convert_diff(ffdelta, bt); 139 140 if (error_bound) { 141 do { 142 update_ffcount = ffclock_estimate.update_ffcount; 143 err_rate = ffclock_estimate.errb_rate; 144 } while (update_ffcount != ffclock_estimate.update_ffcount); 145 146 ffclock_convert_diff(ffdelta, error_bound); 147 /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 148 bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL); 149 } 150 } 151 152 /* 153 * Create a new kern.sysclock sysctl node, which will be home to some generic 154 * sysclock configuration variables. Feed-forward clock specific variables will 155 * live under the ffclock subnode. 156 */ 157 158 SYSCTL_NODE(_kern, OID_AUTO, sysclock, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 159 "System clock related configuration"); 160 SYSCTL_NODE(_kern_sysclock, OID_AUTO, ffclock, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 161 "Feed-forward clock configuration"); 162 163 static char *sysclocks[] = {"feedback", "feed-forward"}; 164 #define MAX_SYSCLOCK_NAME_LEN 16 165 #define NUM_SYSCLOCKS nitems(sysclocks) 166 167 static int ffclock_version = 2; 168 SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, version, CTLFLAG_RD, 169 &ffclock_version, 0, "Feed-forward clock kernel version"); 170 171 /* List available sysclocks. */ 172 static int 173 sysctl_kern_sysclock_available(SYSCTL_HANDLER_ARGS) 174 { 175 struct sbuf *s; 176 int clk, error; 177 178 s = sbuf_new_for_sysctl(NULL, NULL, 179 MAX_SYSCLOCK_NAME_LEN * NUM_SYSCLOCKS, req); 180 if (s == NULL) 181 return (ENOMEM); 182 183 for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 184 sbuf_cat(s, sysclocks[clk]); 185 if (clk + 1 < NUM_SYSCLOCKS) 186 sbuf_cat(s, " "); 187 } 188 error = sbuf_finish(s); 189 sbuf_delete(s); 190 191 return (error); 192 } 193 194 SYSCTL_PROC(_kern_sysclock, OID_AUTO, available, 195 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 0, 0, 196 sysctl_kern_sysclock_available, "A", 197 "List of available system clocks"); 198 199 /* 200 * Return the name of the active system clock if read, or attempt to change 201 * the active system clock to the user specified one if written to. The active 202 * system clock is read when calling any of the [get]{bin,nano,micro}[up]time() 203 * functions. 204 */ 205 static int 206 sysctl_kern_sysclock_active(SYSCTL_HANDLER_ARGS) 207 { 208 char newclock[MAX_SYSCLOCK_NAME_LEN]; 209 int error; 210 int clk; 211 212 /* Return the name of the current active sysclock. */ 213 strlcpy(newclock, sysclocks[sysclock_active], sizeof(newclock)); 214 error = sysctl_handle_string(oidp, newclock, sizeof(newclock), req); 215 216 /* Check for error or no change */ 217 if (error != 0 || req->newptr == NULL) 218 goto done; 219 220 /* Change the active sysclock to the user specified one: */ 221 error = EINVAL; 222 for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 223 if (strncmp(newclock, sysclocks[clk], 224 MAX_SYSCLOCK_NAME_LEN - 1)) { 225 continue; 226 } 227 sysclock_active = clk; 228 error = 0; 229 break; 230 } 231 done: 232 return (error); 233 } 234 235 SYSCTL_PROC(_kern_sysclock, OID_AUTO, active, 236 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, 0, 237 sysctl_kern_sysclock_active, "A", 238 "Name of the active system clock which is currently serving time"); 239 240 static int sysctl_kern_ffclock_ffcounter_bypass = 0; 241 SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 242 &sysctl_kern_ffclock_ffcounter_bypass, 0, 243 "Use reliable hardware timecounter as the feed-forward counter"); 244 245 /* 246 * High level functions to access the Feed-Forward Clock. 247 */ 248 void 249 ffclock_bintime(struct bintime *bt) 250 { 251 252 ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 253 } 254 255 void 256 ffclock_nanotime(struct timespec *tsp) 257 { 258 struct bintime bt; 259 260 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 261 bintime2timespec(&bt, tsp); 262 } 263 264 void 265 ffclock_microtime(struct timeval *tvp) 266 { 267 struct bintime bt; 268 269 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 270 bintime2timeval(&bt, tvp); 271 } 272 273 void 274 ffclock_getbintime(struct bintime *bt) 275 { 276 277 ffclock_abstime(NULL, bt, NULL, 278 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 279 } 280 281 void 282 ffclock_getnanotime(struct timespec *tsp) 283 { 284 struct bintime bt; 285 286 ffclock_abstime(NULL, &bt, NULL, 287 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 288 bintime2timespec(&bt, tsp); 289 } 290 291 void 292 ffclock_getmicrotime(struct timeval *tvp) 293 { 294 struct bintime bt; 295 296 ffclock_abstime(NULL, &bt, NULL, 297 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 298 bintime2timeval(&bt, tvp); 299 } 300 301 void 302 ffclock_binuptime(struct bintime *bt) 303 { 304 305 ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 306 } 307 308 void 309 ffclock_nanouptime(struct timespec *tsp) 310 { 311 struct bintime bt; 312 313 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 314 bintime2timespec(&bt, tsp); 315 } 316 317 void 318 ffclock_microuptime(struct timeval *tvp) 319 { 320 struct bintime bt; 321 322 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 323 bintime2timeval(&bt, tvp); 324 } 325 326 void 327 ffclock_getbinuptime(struct bintime *bt) 328 { 329 330 ffclock_abstime(NULL, bt, NULL, 331 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 332 } 333 334 void 335 ffclock_getnanouptime(struct timespec *tsp) 336 { 337 struct bintime bt; 338 339 ffclock_abstime(NULL, &bt, NULL, 340 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 341 bintime2timespec(&bt, tsp); 342 } 343 344 void 345 ffclock_getmicrouptime(struct timeval *tvp) 346 { 347 struct bintime bt; 348 349 ffclock_abstime(NULL, &bt, NULL, 350 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 351 bintime2timeval(&bt, tvp); 352 } 353 354 void 355 ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 356 { 357 358 ffclock_difftime(ffdelta, bt, NULL); 359 } 360 361 void 362 ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 363 { 364 struct bintime bt; 365 366 ffclock_difftime(ffdelta, &bt, NULL); 367 bintime2timespec(&bt, tsp); 368 } 369 370 void 371 ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 372 { 373 struct bintime bt; 374 375 ffclock_difftime(ffdelta, &bt, NULL); 376 bintime2timeval(&bt, tvp); 377 } 378 379 /* 380 * System call allowing userland applications to retrieve the current value of 381 * the Feed-Forward Clock counter. 382 */ 383 #ifndef _SYS_SYSPROTO_H_ 384 struct ffclock_getcounter_args { 385 ffcounter *ffcount; 386 }; 387 #endif 388 /* ARGSUSED */ 389 int 390 sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 391 { 392 ffcounter ffcount; 393 int error; 394 395 ffcount = 0; 396 ffclock_read_counter(&ffcount); 397 if (ffcount == 0) 398 return (EAGAIN); 399 error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 400 401 return (error); 402 } 403 404 /* 405 * System call allowing the synchronisation daemon to push new feed-foward clock 406 * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 407 * and ensure data consistency. 408 * NOTE: ffclock_updated signals the fftimehands that new estimates are 409 * available. The updated estimates are picked up by the fftimehands on next 410 * tick, which could take as long as 1/hz seconds (if ticks are not missed). 411 */ 412 #ifndef _SYS_SYSPROTO_H_ 413 struct ffclock_setestimate_args { 414 struct ffclock_estimate *cest; 415 }; 416 #endif 417 /* ARGSUSED */ 418 int 419 sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 420 { 421 struct ffclock_estimate cest; 422 int error; 423 424 /* Reuse of PRIV_CLOCK_SETTIME. */ 425 if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 426 return (error); 427 428 if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 429 != 0) 430 return (error); 431 432 mtx_lock(&ffclock_mtx); 433 memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 434 ffclock_updated++; 435 mtx_unlock(&ffclock_mtx); 436 return (error); 437 } 438 439 /* 440 * System call allowing userland applications to retrieve the clock estimates 441 * stored within the kernel. It is useful to kickstart the synchronisation 442 * daemon with the kernel's knowledge of hardware timecounter. 443 */ 444 #ifndef _SYS_SYSPROTO_H_ 445 struct ffclock_getestimate_args { 446 struct ffclock_estimate *cest; 447 }; 448 #endif 449 /* ARGSUSED */ 450 int 451 sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 452 { 453 struct ffclock_estimate cest; 454 int error; 455 456 mtx_lock(&ffclock_mtx); 457 memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 458 mtx_unlock(&ffclock_mtx); 459 error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 460 return (error); 461 } 462 463 #else /* !FFCLOCK */ 464 465 int 466 sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 467 { 468 469 return (ENOSYS); 470 } 471 472 int 473 sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 474 { 475 476 return (ENOSYS); 477 } 478 479 int 480 sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 481 { 482 483 return (ENOSYS); 484 } 485 486 #endif /* FFCLOCK */ 487