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