kern_tc.c revision 90362
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sys/kern/kern_tc.c 90362 2002-02-07 21:21:55Z phk $
10 */
11
12#include "opt_ntp.h"
13
14#include <sys/param.h>
15#include <sys/timetc.h>
16#include <sys/malloc.h>
17#include <sys/kernel.h>
18#include <sys/sysctl.h>
19#include <sys/systm.h>
20#include <sys/timex.h>
21#include <sys/timepps.h>
22
23/*
24 * Number of timecounters used to implement stable storage
25 */
26#ifndef NTIMECOUNTER
27#define NTIMECOUNTER	hz
28#endif
29
30static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter",
31	"Timecounter stable storage");
32
33static void tco_setscales __P((struct timecounter *tc));
34static __inline unsigned tco_delta __P((struct timecounter *tc));
35
36time_t time_second;
37
38struct	bintime boottimebin;
39struct	timeval boottime;
40SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD,
41    &boottime, timeval, "System boottime");
42
43SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
44
45static unsigned nmicrotime;
46static unsigned nnanotime;
47static unsigned ngetmicrotime;
48static unsigned ngetnanotime;
49static unsigned nmicrouptime;
50static unsigned nnanouptime;
51static unsigned ngetmicrouptime;
52static unsigned ngetnanouptime;
53SYSCTL_INT(_kern_timecounter, OID_AUTO, nmicrotime, CTLFLAG_RD, &nmicrotime, 0, "");
54SYSCTL_INT(_kern_timecounter, OID_AUTO, nnanotime, CTLFLAG_RD, &nnanotime, 0, "");
55SYSCTL_INT(_kern_timecounter, OID_AUTO, nmicrouptime, CTLFLAG_RD, &nmicrouptime, 0, "");
56SYSCTL_INT(_kern_timecounter, OID_AUTO, nnanouptime, CTLFLAG_RD, &nnanouptime, 0, "");
57SYSCTL_INT(_kern_timecounter, OID_AUTO, ngetmicrotime, CTLFLAG_RD, &ngetmicrotime, 0, "");
58SYSCTL_INT(_kern_timecounter, OID_AUTO, ngetnanotime, CTLFLAG_RD, &ngetnanotime, 0, "");
59SYSCTL_INT(_kern_timecounter, OID_AUTO, ngetmicrouptime, CTLFLAG_RD, &ngetmicrouptime, 0, "");
60SYSCTL_INT(_kern_timecounter, OID_AUTO, ngetnanouptime, CTLFLAG_RD, &ngetnanouptime, 0, "");
61
62/*
63 * Implement a dummy timecounter which we can use until we get a real one
64 * in the air.  This allows the console and other early stuff to use
65 * timeservices.
66 */
67
68static unsigned
69dummy_get_timecount(struct timecounter *tc)
70{
71	static unsigned now;
72
73	return (++now);
74}
75
76static struct timecounter dummy_timecounter = {
77	dummy_get_timecount,
78	0,
79	~0u,
80	1000000,
81	"dummy"
82};
83
84struct timecounter *volatile timecounter = &dummy_timecounter;
85
86static __inline unsigned
87tco_delta(struct timecounter *tc)
88{
89
90	return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) &
91	    tc->tc_counter_mask);
92}
93
94/*
95 * We have eight functions for looking at the clock, four for
96 * microseconds and four for nanoseconds.  For each there is fast
97 * but less precise version "get{nano|micro}[up]time" which will
98 * return a time which is up to 1/HZ previous to the call, whereas
99 * the raw version "{nano|micro}[up]time" will return a timestamp
100 * which is as precise as possible.  The "up" variants return the
101 * time relative to system boot, these are well suited for time
102 * interval measurements.
103 */
104
105void
106binuptime(struct bintime *bt)
107{
108	struct timecounter *tc;
109
110	tc = timecounter;
111	*bt = tc->tc_offset;
112	bintime_addx(bt, tc->tc_scale * tco_delta(tc));
113}
114
115void
116bintime(struct bintime *bt)
117{
118
119	binuptime(bt);
120	bintime_add(bt, &boottimebin);
121}
122
123void
124getmicrotime(struct timeval *tvp)
125{
126	struct timecounter *tc;
127
128	ngetmicrotime++;
129	tc = timecounter;
130	*tvp = tc->tc_microtime;
131}
132
133void
134getnanotime(struct timespec *tsp)
135{
136	struct timecounter *tc;
137
138	ngetnanotime++;
139	tc = timecounter;
140	*tsp = tc->tc_nanotime;
141}
142
143void
144microtime(struct timeval *tv)
145{
146	struct bintime bt;
147
148	nmicrotime++;
149	bintime(&bt);
150	bintime2timeval(&bt, tv);
151}
152
153void
154nanotime(struct timespec *ts)
155{
156	struct bintime bt;
157
158	nnanotime++;
159	bintime(&bt);
160	bintime2timespec(&bt, ts);
161}
162
163void
164getmicrouptime(struct timeval *tvp)
165{
166	struct timecounter *tc;
167
168	ngetmicrouptime++;
169	tc = timecounter;
170	bintime2timeval(&tc->tc_offset, tvp);
171}
172
173void
174getnanouptime(struct timespec *tsp)
175{
176	struct timecounter *tc;
177
178	ngetnanouptime++;
179	tc = timecounter;
180	bintime2timespec(&tc->tc_offset, tsp);
181}
182
183void
184microuptime(struct timeval *tv)
185{
186	struct bintime bt;
187
188	nmicrouptime++;
189	binuptime(&bt);
190	bintime2timeval(&bt, tv);
191}
192
193void
194nanouptime(struct timespec *ts)
195{
196	struct bintime bt;
197
198	nnanouptime++;
199	binuptime(&bt);
200	bintime2timespec(&bt, ts);
201}
202
203static void
204tco_setscales(struct timecounter *tc)
205{
206	u_int64_t scale;
207
208	/* Sacrifice the lower bit to the deity for code clarity */
209	scale = 1ULL << 63;
210	scale += (tc->tc_adjustment * 4295LL) / 1000LL;
211	scale /= tc->tc_tweak->tc_frequency;
212	tc->tc_scale = scale * 2;
213}
214
215void
216tc_update(struct timecounter *tc)
217{
218	tco_setscales(tc);
219}
220
221void
222tc_init(struct timecounter *tc)
223{
224	struct timecounter *t1, *t2, *t3;
225	int i;
226
227	tc->tc_adjustment = 0;
228	tc->tc_tweak = tc;
229	tco_setscales(tc);
230	tc->tc_offset_count = tc->tc_get_timecount(tc);
231	if (timecounter == &dummy_timecounter)
232		tc->tc_avail = tc;
233	else {
234		tc->tc_avail = timecounter->tc_tweak->tc_avail;
235		timecounter->tc_tweak->tc_avail = tc;
236	}
237	MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK);
238	tc->tc_other = t1;
239	*t1 = *tc;
240	t2 = t1;
241	t3 = NULL;
242	for (i = 1; i < NTIMECOUNTER; i++) {
243		MALLOC(t3, struct timecounter *, sizeof *t3,
244		    M_TIMECOUNTER, M_WAITOK);
245		*t3 = *tc;
246		t3->tc_other = t2;
247		t2 = t3;
248	}
249	t1->tc_other = t3;
250	tc = t1;
251
252	printf("Timecounter \"%s\"  frequency %lu Hz\n",
253	    tc->tc_name, (u_long)tc->tc_frequency);
254
255	/* XXX: For now always start using the counter. */
256	tc->tc_offset_count = tc->tc_get_timecount(tc);
257	binuptime(&tc->tc_offset);
258	timecounter = tc;
259}
260
261void
262tc_setclock(struct timespec *ts)
263{
264	struct timespec ts2;
265
266	nanouptime(&ts2);
267	boottime.tv_sec = ts->tv_sec - ts2.tv_sec;
268	boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000;
269	if (boottime.tv_usec < 0) {
270		boottime.tv_usec += 1000000;
271		boottime.tv_sec--;
272	}
273	timeval2bintime(&boottime, &boottimebin);
274	/* fiddle all the little crinkly bits around the fiords... */
275	tc_windup();
276}
277
278static void
279switch_timecounter(struct timecounter *newtc)
280{
281	int s;
282	struct timecounter *tc;
283
284	s = splclock();
285	tc = timecounter;
286	if (newtc->tc_tweak == tc->tc_tweak) {
287		splx(s);
288		return;
289	}
290	newtc = newtc->tc_tweak->tc_other;
291	binuptime(&newtc->tc_offset);
292	newtc->tc_offset_count = newtc->tc_get_timecount(newtc);
293	tco_setscales(newtc);
294	timecounter = newtc;
295	splx(s);
296}
297
298static struct timecounter *
299sync_other_counter(void)
300{
301	struct timecounter *tc, *tcn, *tco;
302	unsigned delta;
303
304	tco = timecounter;
305	tc = tco->tc_other;
306	tcn = tc->tc_other;
307	*tc = *tco;
308	tc->tc_other = tcn;
309	delta = tco_delta(tc);
310	tc->tc_offset_count += delta;
311	tc->tc_offset_count &= tc->tc_counter_mask;
312	bintime_addx(&tc->tc_offset, tc->tc_scale * delta);
313	return (tc);
314}
315
316void
317tc_windup(void)
318{
319	struct timecounter *tc, *tco;
320	struct bintime bt;
321	struct timeval tvt;
322	int i;
323
324	tco = timecounter;
325	tc = sync_other_counter();
326	/*
327	 * We may be inducing a tiny error here, the tc_poll_pps() may
328	 * process a latched count which happens after the tco_delta()
329	 * in sync_other_counter(), which would extend the previous
330	 * counters parameters into the domain of this new one.
331	 * Since the timewindow is very small for this, the error is
332	 * going to be only a few weenieseconds (as Dave Mills would
333	 * say), so lets just not talk more about it, OK ?
334	 */
335	if (tco->tc_poll_pps)
336		tco->tc_poll_pps(tco);
337	if (timedelta != 0) {
338		tvt = boottime;
339		tvt.tv_usec += tickdelta;
340		if (tvt.tv_usec >= 1000000) {
341			tvt.tv_sec++;
342			tvt.tv_usec -= 1000000;
343		} else if (tvt.tv_usec < 0) {
344			tvt.tv_sec--;
345			tvt.tv_usec += 1000000;
346		}
347		boottime = tvt;
348		timeval2bintime(&boottime, &boottimebin);
349		timedelta -= tickdelta;
350	}
351	for (i = tc->tc_offset.sec - tco->tc_offset.sec; i > 0; i--) {
352		ntp_update_second(tc);	/* XXX only needed if xntpd runs */
353		tco_setscales(tc);
354	}
355
356	bt = tc->tc_offset;
357	bintime_add(&bt, &boottimebin);
358	bintime2timeval(&bt, &tc->tc_microtime);
359	bintime2timespec(&bt, &tc->tc_nanotime);
360	time_second = tc->tc_microtime.tv_sec;
361	timecounter = tc;
362}
363
364static int
365sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
366{
367	char newname[32];
368	struct timecounter *newtc, *tc;
369	int error;
370
371	tc = timecounter->tc_tweak;
372	strncpy(newname, tc->tc_name, sizeof(newname));
373	error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
374	if (error == 0 && req->newptr != NULL &&
375	    strcmp(newname, tc->tc_name) != 0) {
376		for (newtc = tc->tc_avail; newtc != tc;
377		    newtc = newtc->tc_avail) {
378			if (strcmp(newname, newtc->tc_name) == 0) {
379				/* Warm up new timecounter. */
380				(void)newtc->tc_get_timecount(newtc);
381
382				switch_timecounter(newtc);
383				return (0);
384			}
385		}
386		return (EINVAL);
387	}
388	return (error);
389}
390
391SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
392    0, 0, sysctl_kern_timecounter_hardware, "A", "");
393
394
395int
396pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
397{
398	pps_params_t *app;
399	struct pps_fetch_args *fapi;
400#ifdef PPS_SYNC
401	struct pps_kcbind_args *kapi;
402#endif
403
404	switch (cmd) {
405	case PPS_IOC_CREATE:
406		return (0);
407	case PPS_IOC_DESTROY:
408		return (0);
409	case PPS_IOC_SETPARAMS:
410		app = (pps_params_t *)data;
411		if (app->mode & ~pps->ppscap)
412			return (EINVAL);
413		pps->ppsparam = *app;
414		return (0);
415	case PPS_IOC_GETPARAMS:
416		app = (pps_params_t *)data;
417		*app = pps->ppsparam;
418		app->api_version = PPS_API_VERS_1;
419		return (0);
420	case PPS_IOC_GETCAP:
421		*(int*)data = pps->ppscap;
422		return (0);
423	case PPS_IOC_FETCH:
424		fapi = (struct pps_fetch_args *)data;
425		if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
426			return (EINVAL);
427		if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec)
428			return (EOPNOTSUPP);
429		pps->ppsinfo.current_mode = pps->ppsparam.mode;
430		fapi->pps_info_buf = pps->ppsinfo;
431		return (0);
432	case PPS_IOC_KCBIND:
433#ifdef PPS_SYNC
434		kapi = (struct pps_kcbind_args *)data;
435		/* XXX Only root should be able to do this */
436		if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC)
437			return (EINVAL);
438		if (kapi->kernel_consumer != PPS_KC_HARDPPS)
439			return (EINVAL);
440		if (kapi->edge & ~pps->ppscap)
441			return (EINVAL);
442		pps->kcmode = kapi->edge;
443		return (0);
444#else
445		return (EOPNOTSUPP);
446#endif
447	default:
448		return (ENOTTY);
449	}
450}
451
452void
453pps_init(struct pps_state *pps)
454{
455	pps->ppscap |= PPS_TSFMT_TSPEC;
456	if (pps->ppscap & PPS_CAPTUREASSERT)
457		pps->ppscap |= PPS_OFFSETASSERT;
458	if (pps->ppscap & PPS_CAPTURECLEAR)
459		pps->ppscap |= PPS_OFFSETCLEAR;
460}
461
462void
463pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event)
464{
465	struct timespec ts, *tsp, *osp;
466	unsigned tcount, *pcount;
467	struct bintime bt;
468	int foff, fhard;
469	pps_seq_t	*pseq;
470
471	/* Things would be easier with arrays... */
472	if (event == PPS_CAPTUREASSERT) {
473		tsp = &pps->ppsinfo.assert_timestamp;
474		osp = &pps->ppsparam.assert_offset;
475		foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
476		fhard = pps->kcmode & PPS_CAPTUREASSERT;
477		pcount = &pps->ppscount[0];
478		pseq = &pps->ppsinfo.assert_sequence;
479	} else {
480		tsp = &pps->ppsinfo.clear_timestamp;
481		osp = &pps->ppsparam.clear_offset;
482		foff = pps->ppsparam.mode & PPS_OFFSETCLEAR;
483		fhard = pps->kcmode & PPS_CAPTURECLEAR;
484		pcount = &pps->ppscount[1];
485		pseq = &pps->ppsinfo.clear_sequence;
486	}
487
488	/* The timecounter changed: bail */
489	if (!pps->ppstc ||
490	    pps->ppstc->tc_name != tc->tc_name ||
491	    tc->tc_name != timecounter->tc_name) {
492		pps->ppstc = tc;
493		*pcount = count;
494		return;
495	}
496
497	/* Nothing really happened */
498	if (*pcount == count)
499		return;
500
501	*pcount = count;
502
503	/* Convert the count to timespec */
504	tcount = count - tc->tc_offset_count;
505	tcount &= tc->tc_counter_mask;
506	bt = tc->tc_offset;
507	bintime_addx(&bt, tc->tc_scale * tcount);
508	bintime2timespec(&bt, &ts);
509
510	(*pseq)++;
511	*tsp = ts;
512
513	if (foff) {
514		timespecadd(tsp, osp);
515		if (tsp->tv_nsec < 0) {
516			tsp->tv_nsec += 1000000000;
517			tsp->tv_sec -= 1;
518		}
519	}
520#ifdef PPS_SYNC
521	if (fhard) {
522		u_int64_t delta;
523		/* magic, at its best... */
524		tcount = count - pps->ppscount[2];
525		pps->ppscount[2] = count;
526		tcount &= tc->tc_counter_mask;
527		bt.sec = 0;
528		bt.frac = 0;
529		bintime_addx(&bt, tc->tc_scale * tcount);
530		bintime2timespec(&bt, &ts);
531		hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
532	}
533#endif
534}
535