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 * Sysctl for the Feed-Forward Clock. 152 */ 153 154 static int ffclock_version = 2; 155 SYSCTL_NODE(_kern, OID_AUTO, ffclock, CTLFLAG_RW, 0, 156 "Feed-Forward Clock Support"); 157 SYSCTL_INT(_kern_ffclock, OID_AUTO, version, CTLFLAG_RD, &ffclock_version, 0, 158 "Version of Feed-Forward Clock Support"); 159 160 /* 161 * Sysctl to select which clock is read when calling any of the 162 * [get]{bin,nano,micro}[up]time() functions. 163 */ 164 char *sysclocks[] = {"feedback", "feed-forward"}; 165 166 #define NUM_SYSCLOCKS (sizeof(sysclocks) / sizeof(*sysclocks)) 167 168 /* Report or change the active timecounter hardware. */ 169 static int 170 sysctl_kern_ffclock_choice(SYSCTL_HANDLER_ARGS) 171 { 172 struct sbuf *s; 173 int clk, error; 174 175 s = sbuf_new_for_sysctl(NULL, NULL, 16 * NUM_SYSCLOCKS, req); 176 if (s == NULL) 177 return (ENOMEM); 178 179 for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 180 sbuf_cat(s, sysclocks[clk]); 181 if (clk + 1 < NUM_SYSCLOCKS) 182 sbuf_cat(s, " "); 183 } 184 error = sbuf_finish(s); 185 sbuf_delete(s); 186 187 return (error); 188 } 189 190 SYSCTL_PROC(_kern_ffclock, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, 191 0, 0, sysctl_kern_ffclock_choice, "A", "Clock paradigms available"); 192 193 extern int sysclock_active; 194 195 static int 196 sysctl_kern_ffclock_active(SYSCTL_HANDLER_ARGS) 197 { 198 char newclock[32]; 199 int error; 200 201 switch (sysclock_active) { 202 case SYSCLOCK_FBCK: 203 strlcpy(newclock, sysclocks[SYSCLOCK_FBCK], sizeof(newclock)); 204 break; 205 case SYSCLOCK_FFWD: 206 strlcpy(newclock, sysclocks[SYSCLOCK_FFWD], sizeof(newclock)); 207 break; 208 } 209 210 error = sysctl_handle_string(oidp, &newclock[0], sizeof(newclock), req); 211 if (error != 0 || req->newptr == NULL) 212 return (error); 213 if (strncmp(newclock, sysclocks[SYSCLOCK_FBCK], 214 sizeof(sysclocks[SYSCLOCK_FBCK])) == 0) 215 sysclock_active = SYSCLOCK_FBCK; 216 else if (strncmp(newclock, sysclocks[SYSCLOCK_FFWD], 217 sizeof(sysclocks[SYSCLOCK_FFWD])) == 0) 218 sysclock_active = SYSCLOCK_FFWD; 219 else 220 return (EINVAL); 221 222 return (error); 223 } 224 225 SYSCTL_PROC(_kern_ffclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW, 226 0, 0, sysctl_kern_ffclock_active, "A", "Kernel clock selected"); 227 228 int sysctl_kern_ffclock_ffcounter_bypass = 0; 229 230 SYSCTL_INT(_kern_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 231 &sysctl_kern_ffclock_ffcounter_bypass, 0, 232 "Use reliable hardware timecounter as the Feed-Forward Counter"); 233 234 /* 235 * High level functions to access the Feed-Forward Clock. 236 */ 237 void 238 ffclock_bintime(struct bintime *bt) 239 { 240 241 ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 242 } 243 244 void 245 ffclock_nanotime(struct timespec *tsp) 246 { 247 struct bintime bt; 248 249 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 250 bintime2timespec(&bt, tsp); 251 } 252 253 void 254 ffclock_microtime(struct timeval *tvp) 255 { 256 struct bintime bt; 257 258 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 259 bintime2timeval(&bt, tvp); 260 } 261 262 void 263 ffclock_getbintime(struct bintime *bt) 264 { 265 266 ffclock_abstime(NULL, bt, NULL, 267 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 268 } 269 270 void 271 ffclock_getnanotime(struct timespec *tsp) 272 { 273 struct bintime bt; 274 275 ffclock_abstime(NULL, &bt, NULL, 276 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 277 bintime2timespec(&bt, tsp); 278 } 279 280 void 281 ffclock_getmicrotime(struct timeval *tvp) 282 { 283 struct bintime bt; 284 285 ffclock_abstime(NULL, &bt, NULL, 286 FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 287 bintime2timeval(&bt, tvp); 288 } 289 290 void 291 ffclock_binuptime(struct bintime *bt) 292 { 293 294 ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 295 } 296 297 void 298 ffclock_nanouptime(struct timespec *tsp) 299 { 300 struct bintime bt; 301 302 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 303 bintime2timespec(&bt, tsp); 304 } 305 306 void 307 ffclock_microuptime(struct timeval *tvp) 308 { 309 struct bintime bt; 310 311 ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 312 bintime2timeval(&bt, tvp); 313 } 314 315 void 316 ffclock_getbinuptime(struct bintime *bt) 317 { 318 319 ffclock_abstime(NULL, bt, NULL, 320 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 321 } 322 323 void 324 ffclock_getnanouptime(struct timespec *tsp) 325 { 326 struct bintime bt; 327 328 ffclock_abstime(NULL, &bt, NULL, 329 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 330 bintime2timespec(&bt, tsp); 331 } 332 333 void 334 ffclock_getmicrouptime(struct timeval *tvp) 335 { 336 struct bintime bt; 337 338 ffclock_abstime(NULL, &bt, NULL, 339 FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 340 bintime2timeval(&bt, tvp); 341 } 342 343 void 344 ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 345 { 346 347 ffclock_difftime(ffdelta, bt, NULL); 348 } 349 350 void 351 ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 352 { 353 struct bintime bt; 354 355 ffclock_difftime(ffdelta, &bt, NULL); 356 bintime2timespec(&bt, tsp); 357 } 358 359 void 360 ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 361 { 362 struct bintime bt; 363 364 ffclock_difftime(ffdelta, &bt, NULL); 365 bintime2timeval(&bt, tvp); 366 } 367 368 /* 369 * System call allowing userland applications to retrieve the current value of 370 * the Feed-Forward Clock counter. 371 */ 372 #ifndef _SYS_SYSPROTO_H_ 373 struct ffclock_getcounter_args { 374 ffcounter *ffcount; 375 }; 376 #endif 377 /* ARGSUSED */ 378 int 379 sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 380 { 381 ffcounter ffcount; 382 int error; 383 384 ffcount = 0; 385 ffclock_read_counter(&ffcount); 386 if (ffcount == 0) 387 return (EAGAIN); 388 error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 389 390 return (error); 391 } 392 393 /* 394 * System call allowing the synchronisation daemon to push new feed-foward clock 395 * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 396 * and ensure data consistency. 397 * NOTE: ffclock_updated signals the fftimehands that new estimates are 398 * available. The updated estimates are picked up by the fftimehands on next 399 * tick, which could take as long as 1/hz seconds (if ticks are not missed). 400 */ 401 #ifndef _SYS_SYSPROTO_H_ 402 struct ffclock_setestimate_args { 403 struct ffclock_estimate *cest; 404 }; 405 #endif 406 /* ARGSUSED */ 407 int 408 sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 409 { 410 struct ffclock_estimate cest; 411 int error; 412 413 /* Reuse of PRIV_CLOCK_SETTIME. */ 414 if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 415 return (error); 416 417 if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 418 != 0) 419 return (error); 420 421 mtx_lock(&ffclock_mtx); 422 memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 423 ffclock_updated++; 424 mtx_unlock(&ffclock_mtx); 425 return (error); 426 } 427 428 /* 429 * System call allowing userland applications to retrieve the clock estimates 430 * stored within the kernel. It is useful to kickstart the synchronisation 431 * daemon with the kernel's knowledge of hardware timecounter. 432 */ 433 #ifndef _SYS_SYSPROTO_H_ 434 struct ffclock_getestimate_args { 435 struct ffclock_estimate *cest; 436 }; 437 #endif 438 /* ARGSUSED */ 439 int 440 sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 441 { 442 struct ffclock_estimate cest; 443 int error; 444 445 mtx_lock(&ffclock_mtx); 446 memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 447 mtx_unlock(&ffclock_mtx); 448 error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 449 return (error); 450 } 451 452 #else /* !FFCLOCK */ 453 454 int 455 sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 456 { 457 458 return (ENOSYS); 459 } 460 461 int 462 sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 463 { 464 465 return (ENOSYS); 466 } 467 468 int 469 sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 470 { 471 472 return (ENOSYS); 473 } 474 475 #endif /* FFCLOCK */ 476