This source file includes following definitions.
- dummy_get_timecount
- tc_delta
- binuptime
- nanouptime
- microuptime
- bintime
- nanotime
- microtime
- getnanouptime
- getmicrouptime
- getnanotime
- getmicrotime
- tc_init
- tc_getfrequency
- tc_setclock
- tc_windup
- sysctl_tc_hardware
- sysctl_tc_choice
- tc_ticktock
- inittimecounter
- sysctl_tc
- ntp_update_second
- tc_adjfreq
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <sys/param.h>
14 #include <sys/kernel.h>
15 #include <sys/sysctl.h>
16 #include <sys/syslog.h>
17 #include <sys/systm.h>
18 #include <sys/timetc.h>
19 #include <sys/malloc.h>
20
21 #ifdef __HAVE_TIMECOUNTER
22
23
24
25
26
27
28 #define LARGE_STEP 200
29
30 u_int dummy_get_timecount(struct timecounter *);
31
32 void ntp_update_second(int64_t *, time_t *);
33 int sysctl_tc_hardware(void *, size_t *, void *, size_t);
34 int sysctl_tc_choice(void *, size_t *, void *, size_t);
35
36
37
38
39
40
41
42 u_int
43 dummy_get_timecount(struct timecounter *tc)
44 {
45 static u_int now;
46
47 return (++now);
48 }
49
50 static struct timecounter dummy_timecounter = {
51 dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
52 };
53
54 struct timehands {
55
56 struct timecounter *th_counter;
57 int64_t th_adjustment;
58 u_int64_t th_scale;
59 u_int th_offset_count;
60 struct bintime th_offset;
61 struct timeval th_microtime;
62 struct timespec th_nanotime;
63
64 volatile u_int th_generation;
65 struct timehands *th_next;
66 };
67
68 extern struct timehands th0;
69 static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0};
70 static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9};
71 static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8};
72 static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7};
73 static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6};
74 static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5};
75 static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4};
76 static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3};
77 static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2};
78 static struct timehands th0 = {
79 &dummy_timecounter,
80 0,
81 (uint64_t)-1 / 1000000,
82 0,
83 {1, 0},
84 {0, 0},
85 {0, 0},
86 1,
87 &th1
88 };
89
90 static struct timehands *volatile timehands = &th0;
91 struct timecounter *timecounter = &dummy_timecounter;
92 static struct timecounter *timecounters = &dummy_timecounter;
93
94 volatile time_t time_second = 1;
95 volatile time_t time_uptime = 0;
96
97 extern struct timeval adjtimedelta;
98 static struct bintime boottimebin;
99 static int timestepwarnings;
100
101 void tc_windup(void);
102
103
104
105
106
107 static __inline u_int
108 tc_delta(struct timehands *th)
109 {
110 struct timecounter *tc;
111
112 tc = th->th_counter;
113 return ((tc->tc_get_timecount(tc) - th->th_offset_count) &
114 tc->tc_counter_mask);
115 }
116
117
118
119
120
121
122
123 void
124 binuptime(struct bintime *bt)
125 {
126 struct timehands *th;
127 u_int gen;
128
129 do {
130 th = timehands;
131 gen = th->th_generation;
132 *bt = th->th_offset;
133 bintime_addx(bt, th->th_scale * tc_delta(th));
134 } while (gen == 0 || gen != th->th_generation);
135 }
136
137 void
138 nanouptime(struct timespec *tsp)
139 {
140 struct bintime bt;
141
142 binuptime(&bt);
143 bintime2timespec(&bt, tsp);
144 }
145
146 void
147 microuptime(struct timeval *tvp)
148 {
149 struct bintime bt;
150
151 binuptime(&bt);
152 bintime2timeval(&bt, tvp);
153 }
154
155 void
156 bintime(struct bintime *bt)
157 {
158
159 binuptime(bt);
160 bintime_add(bt, &boottimebin);
161 }
162
163 void
164 nanotime(struct timespec *tsp)
165 {
166 struct bintime bt;
167
168 bintime(&bt);
169 bintime2timespec(&bt, tsp);
170 }
171
172 void
173 microtime(struct timeval *tvp)
174 {
175 struct bintime bt;
176
177 bintime(&bt);
178 bintime2timeval(&bt, tvp);
179 }
180
181 void
182 getnanouptime(struct timespec *tsp)
183 {
184 struct timehands *th;
185 u_int gen;
186
187 do {
188 th = timehands;
189 gen = th->th_generation;
190 bintime2timespec(&th->th_offset, tsp);
191 } while (gen == 0 || gen != th->th_generation);
192 }
193
194 void
195 getmicrouptime(struct timeval *tvp)
196 {
197 struct timehands *th;
198 u_int gen;
199
200 do {
201 th = timehands;
202 gen = th->th_generation;
203 bintime2timeval(&th->th_offset, tvp);
204 } while (gen == 0 || gen != th->th_generation);
205 }
206
207 void
208 getnanotime(struct timespec *tsp)
209 {
210 struct timehands *th;
211 u_int gen;
212
213 do {
214 th = timehands;
215 gen = th->th_generation;
216 *tsp = th->th_nanotime;
217 } while (gen == 0 || gen != th->th_generation);
218 }
219
220 void
221 getmicrotime(struct timeval *tvp)
222 {
223 struct timehands *th;
224 u_int gen;
225
226 do {
227 th = timehands;
228 gen = th->th_generation;
229 *tvp = th->th_microtime;
230 } while (gen == 0 || gen != th->th_generation);
231 }
232
233
234
235
236 void
237 tc_init(struct timecounter *tc)
238 {
239 u_int u;
240
241 u = tc->tc_frequency / tc->tc_counter_mask;
242
243 u *= 11;
244 u /= 10;
245 if (tc->tc_quality >= 0) {
246 if (u > hz) {
247 tc->tc_quality = -2000;
248 printf("Timecounter \"%s\" frequency %lu Hz",
249 tc->tc_name, (unsigned long)tc->tc_frequency);
250 printf(" -- Insufficient hz, needs at least %u\n", u);
251 }
252 }
253
254 tc->tc_next = timecounters;
255 timecounters = tc;
256
257
258
259
260
261 if (tc->tc_quality < 0)
262 return;
263 if (tc->tc_quality < timecounter->tc_quality)
264 return;
265 if (tc->tc_quality == timecounter->tc_quality &&
266 tc->tc_frequency < timecounter->tc_frequency)
267 return;
268 (void)tc->tc_get_timecount(tc);
269 (void)tc->tc_get_timecount(tc);
270 timecounter = tc;
271 }
272
273
274 u_int64_t
275 tc_getfrequency(void)
276 {
277
278 return (timehands->th_counter->tc_frequency);
279 }
280
281
282
283
284
285
286 void
287 tc_setclock(struct timespec *ts)
288 {
289 struct timespec ts2;
290 struct bintime bt, bt2;
291
292 binuptime(&bt2);
293 timespec2bintime(ts, &bt);
294 bintime_sub(&bt, &bt2);
295 bintime_add(&bt2, &boottimebin);
296 boottimebin = bt;
297 bintime2timeval(&bt, &boottime);
298
299
300 tc_windup();
301 if (timestepwarnings) {
302 bintime2timespec(&bt2, &ts2);
303 log(LOG_INFO, "Time stepped from %ld.%09ld to %ld.%09ld\n",
304 (long)ts2.tv_sec, ts2.tv_nsec,
305 (long)ts->tv_sec, ts->tv_nsec);
306 }
307 }
308
309
310
311
312
313
314 void
315 tc_windup(void)
316 {
317 struct bintime bt;
318 struct timehands *th, *tho;
319 u_int64_t scale;
320 u_int delta, ncount, ogen;
321 int i;
322 #ifdef leapsecs
323 time_t t;
324 #endif
325
326
327
328
329
330
331 tho = timehands;
332 th = tho->th_next;
333 ogen = th->th_generation;
334 th->th_generation = 0;
335 bcopy(tho, th, offsetof(struct timehands, th_generation));
336
337
338
339
340
341
342 delta = tc_delta(th);
343 if (th->th_counter != timecounter)
344 ncount = timecounter->tc_get_timecount(timecounter);
345 else
346 ncount = 0;
347 th->th_offset_count += delta;
348 th->th_offset_count &= th->th_counter->tc_counter_mask;
349 bintime_addx(&th->th_offset, th->th_scale * delta);
350
351 #ifdef notyet
352
353
354
355
356
357
358
359
360 if (tho->th_counter->tc_poll_pps)
361 tho->th_counter->tc_poll_pps(tho->th_counter);
362 #endif
363
364
365
366
367
368
369
370
371
372
373 bt = th->th_offset;
374 bintime_add(&bt, &boottimebin);
375 i = bt.sec - tho->th_microtime.tv_sec;
376 if (i > LARGE_STEP)
377 i = 2;
378 for (; i > 0; i--)
379 ntp_update_second(&th->th_adjustment, &bt.sec);
380
381
382
383 bintime2timeval(&bt, &th->th_microtime);
384 bintime2timespec(&bt, &th->th_nanotime);
385
386
387 if (th->th_counter != timecounter) {
388 th->th_counter = timecounter;
389 th->th_offset_count = ncount;
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 scale = (u_int64_t)1 << 63;
416 scale += (th->th_adjustment / 1024) * 2199;
417 scale /= th->th_counter->tc_frequency;
418 th->th_scale = scale * 2;
419
420
421
422
423
424 if (++ogen == 0)
425 ogen = 1;
426 th->th_generation = ogen;
427
428
429 time_second = th->th_microtime.tv_sec;
430 time_uptime = th->th_offset.sec;
431 timehands = th;
432 }
433
434
435 int
436 sysctl_tc_hardware(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
437 {
438 char newname[32];
439 struct timecounter *newtc, *tc;
440 int error;
441
442 tc = timecounter;
443 strlcpy(newname, tc->tc_name, sizeof(newname));
444
445 error = sysctl_string(oldp, oldlenp, newp, newlen, newname, sizeof(newname));
446 if (error != 0 || strcmp(newname, tc->tc_name) == 0)
447 return (error);
448 for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
449 if (strcmp(newname, newtc->tc_name) != 0)
450 continue;
451
452
453 (void)newtc->tc_get_timecount(newtc);
454 (void)newtc->tc_get_timecount(newtc);
455
456 timecounter = newtc;
457 return (0);
458 }
459 return (EINVAL);
460 }
461
462
463 int
464 sysctl_tc_choice(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
465 {
466 char buf[32], *spc, *choices;
467 struct timecounter *tc;
468 int error, maxlen;
469
470 spc = "";
471 error = 0;
472 maxlen = 0;
473 for (tc = timecounters; tc != NULL; tc = tc->tc_next)
474 maxlen += sizeof(buf);
475 choices = malloc(maxlen, M_TEMP, M_WAITOK);
476 *choices = '\0';
477 for (tc = timecounters; tc != NULL; tc = tc->tc_next) {
478 snprintf(buf, sizeof(buf), "%s%s(%d)",
479 spc, tc->tc_name, tc->tc_quality);
480 spc = " ";
481 strlcat(choices, buf, maxlen);
482 }
483 error = sysctl_rdstring(oldp, oldlenp, newp, choices);
484 free(choices, M_TEMP);
485 return (error);
486 }
487
488
489
490
491
492
493
494 static int tc_tick;
495
496 void
497 tc_ticktock(void)
498 {
499 static int count;
500
501 if (++count < tc_tick)
502 return;
503 count = 0;
504 tc_windup();
505 }
506
507 void
508 inittimecounter(void)
509 {
510 u_int p;
511
512
513
514
515
516
517
518
519
520 if (hz > 1000)
521 tc_tick = (hz + 500) / 1000;
522 else
523 tc_tick = 1;
524 p = (tc_tick * 1000000) / hz;
525 #ifdef DEBUG
526 printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
527 #endif
528
529
530 (void)timecounter->tc_get_timecount(timecounter);
531 (void)timecounter->tc_get_timecount(timecounter);
532 }
533
534
535
536
537 int
538 sysctl_tc(int *name, u_int namelen, void *oldp, size_t *oldlenp,
539 void *newp, size_t newlen)
540 {
541 if (namelen != 1)
542 return (ENOTDIR);
543
544 switch (name[0]) {
545 case KERN_TIMECOUNTER_TICK:
546 return (sysctl_rdint(oldp, oldlenp, newp, tc_tick));
547 case KERN_TIMECOUNTER_TIMESTEPWARNINGS:
548 return (sysctl_int(oldp, oldlenp, newp, newlen,
549 ×tepwarnings));
550 case KERN_TIMECOUNTER_HARDWARE:
551 return (sysctl_tc_hardware(oldp, oldlenp, newp, newlen));
552 case KERN_TIMECOUNTER_CHOICE:
553 return (sysctl_tc_choice(oldp, oldlenp, newp, newlen));
554 default:
555 return (EOPNOTSUPP);
556 }
557
558 }
559
560 void
561 ntp_update_second(int64_t *adjust, time_t *sec)
562 {
563 struct timeval adj;
564
565
566 timerclear(&adj);
567 if (adjtimedelta.tv_sec > 0)
568 adj.tv_usec = 5000;
569 else if (adjtimedelta.tv_sec == 0)
570 adj.tv_usec = MIN(500, adjtimedelta.tv_usec);
571 else if (adjtimedelta.tv_sec < -1)
572 adj.tv_usec = -5000;
573 else if (adjtimedelta.tv_sec == -1)
574 adj.tv_usec = MAX(-500, adjtimedelta.tv_usec - 1000000);
575 timersub(&adjtimedelta, &adj, &adjtimedelta);
576 *adjust = ((int64_t)adj.tv_usec * 1000) << 32;
577 *adjust += timecounter->tc_freq_adj;
578 }
579
580 int
581 tc_adjfreq(int64_t *old, int64_t *new)
582 {
583 if (old != NULL) {
584 *old = timecounter->tc_freq_adj;
585 }
586 if (new != NULL) {
587 timecounter->tc_freq_adj = *new;
588 }
589 return 0;
590 }
591 #endif