Deleted Added
full compact
kern_clock.c (57182) kern_clock.c (58377)
1/*-
1/*-
2 * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org>
3 * Copyright (c) 1982, 1986, 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 * (c) UNIX System Laboratories, Inc.
6 * All or some portions of this file are derived from material licensed
7 * to the University of California by American Telephone and Telegraph
8 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
9 * the permission of UNIX System Laboratories, Inc.
10 *

--- 21 unchanged lines hidden (view full) ---

32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
2 * Copyright (c) 1982, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *

--- 21 unchanged lines hidden (view full) ---

31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
40 * $FreeBSD: head/sys/kern/kern_clock.c 57182 2000-02-13 10:56:32Z phk $
39 * $FreeBSD: head/sys/kern/kern_clock.c 58377 2000-03-20 14:09:06Z phk $
41 */
42
43#include "opt_ntp.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/dkstat.h>
48#include <sys/callout.h>
49#include <sys/kernel.h>
50#include <sys/proc.h>
51#include <sys/malloc.h>
52#include <sys/resourcevar.h>
53#include <sys/signalvar.h>
40 */
41
42#include "opt_ntp.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/dkstat.h>
47#include <sys/callout.h>
48#include <sys/kernel.h>
49#include <sys/proc.h>
50#include <sys/malloc.h>
51#include <sys/resourcevar.h>
52#include <sys/signalvar.h>
54#include <sys/timex.h>
53#include <sys/timetc.h>
55#include <sys/timepps.h>
56#include <vm/vm.h>
57#include <sys/lock.h>
58#include <vm/pmap.h>
59#include <vm/vm_map.h>
60#include <sys/sysctl.h>
61
62#include <machine/cpu.h>
63#include <machine/limits.h>
64
65#ifdef GPROF
66#include <sys/gmon.h>
67#endif
68
69#if defined(SMP) && defined(BETTER_CLOCK)
70#include <machine/smp.h>
71#endif
72
54#include <sys/timepps.h>
55#include <vm/vm.h>
56#include <sys/lock.h>
57#include <vm/pmap.h>
58#include <vm/vm_map.h>
59#include <sys/sysctl.h>
60
61#include <machine/cpu.h>
62#include <machine/limits.h>
63
64#ifdef GPROF
65#include <sys/gmon.h>
66#endif
67
68#if defined(SMP) && defined(BETTER_CLOCK)
69#include <machine/smp.h>
70#endif
71
73/*
74 * Number of timecounters used to implement stable storage
75 */
76#ifndef NTIMECOUNTER
77#define NTIMECOUNTER 5
78#endif
79
80static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter",
81 "Timecounter stable storage");
82
83static void initclocks __P((void *dummy));
84SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
85
72static void initclocks __P((void *dummy));
73SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
74
86static void tco_forward __P((int force));
87static void tco_setscales __P((struct timecounter *tc));
88static __inline unsigned tco_delta __P((struct timecounter *tc));
89
90/* Some of these don't belong here, but it's easiest to concentrate them. */
91#if defined(SMP) && defined(BETTER_CLOCK)
92long cp_time[CPUSTATES];
93#else
94static long cp_time[CPUSTATES];
95#endif
96
97long tk_cancc;
98long tk_nin;
99long tk_nout;
100long tk_rawcc;
101
75/* Some of these don't belong here, but it's easiest to concentrate them. */
76#if defined(SMP) && defined(BETTER_CLOCK)
77long cp_time[CPUSTATES];
78#else
79static long cp_time[CPUSTATES];
80#endif
81
82long tk_cancc;
83long tk_nin;
84long tk_nout;
85long tk_rawcc;
86
102time_t time_second;
103
104struct timeval boottime;
105SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD,
106 &boottime, timeval, "System boottime");
107
108/*
87/*
109 * Which update policy to use.
110 * 0 - every tick, bad hardware may fail with "calcru negative..."
111 * 1 - more resistent to the above hardware, but less efficient.
112 */
113static int tco_method;
114
115/*
116 * Implement a dummy timecounter which we can use until we get a real one
117 * in the air. This allows the console and other early stuff to use
118 * timeservices.
119 */
120
121static unsigned
122dummy_get_timecount(struct timecounter *tc)
123{
124 static unsigned now;
125 return (++now);
126}
127
128static struct timecounter dummy_timecounter = {
129 dummy_get_timecount,
130 0,
131 ~0u,
132 1000000,
133 "dummy"
134};
135
136struct timecounter *timecounter = &dummy_timecounter;
137
138/*
139 * Clock handling routines.
140 *
141 * This code is written to operate with two timers that run independently of
142 * each other.
143 *
144 * The main timer, running hz times per second, is used to trigger interval
145 * timers, timeouts and rescheduling as needed.
146 *

--- 84 unchanged lines hidden (view full) ---

231#endif
232
233 /*
234 * If no separate statistics clock is available, run it from here.
235 */
236 if (stathz == 0)
237 statclock(frame);
238
88 * Clock handling routines.
89 *
90 * This code is written to operate with two timers that run independently of
91 * each other.
92 *
93 * The main timer, running hz times per second, is used to trigger interval
94 * timers, timeouts and rescheduling as needed.
95 *

--- 84 unchanged lines hidden (view full) ---

180#endif
181
182 /*
183 * If no separate statistics clock is available, run it from here.
184 */
185 if (stathz == 0)
186 statclock(frame);
187
239 tco_forward(0);
188 tc_windup();
240 ticks++;
241
242 /*
243 * Process callouts at a very low cpu priority, so we don't keep the
244 * relatively high clock interrupt priority any longer than necessary.
245 */
246 if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {
247 if (CLKF_BASEPRI(frame)) {

--- 230 unchanged lines hidden (view full) ---

478 clkinfo.tickadj = tickadj;
479 clkinfo.profhz = profhz;
480 clkinfo.stathz = stathz ? stathz : hz;
481 return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req));
482}
483
484SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
485 0, 0, sysctl_kern_clockrate, "S,clockinfo","");
189 ticks++;
190
191 /*
192 * Process callouts at a very low cpu priority, so we don't keep the
193 * relatively high clock interrupt priority any longer than necessary.
194 */
195 if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {
196 if (CLKF_BASEPRI(frame)) {

--- 230 unchanged lines hidden (view full) ---

427 clkinfo.tickadj = tickadj;
428 clkinfo.profhz = profhz;
429 clkinfo.stathz = stathz ? stathz : hz;
430 return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req));
431}
432
433SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
434 0, 0, sysctl_kern_clockrate, "S,clockinfo","");
486
487static __inline unsigned
488tco_delta(struct timecounter *tc)
489{
490
491 return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) &
492 tc->tc_counter_mask);
493}
494
495/*
496 * We have eight functions for looking at the clock, four for
497 * microseconds and four for nanoseconds. For each there is fast
498 * but less precise version "get{nano|micro}[up]time" which will
499 * return a time which is up to 1/HZ previous to the call, whereas
500 * the raw version "{nano|micro}[up]time" will return a timestamp
501 * which is as precise as possible. The "up" variants return the
502 * time relative to system boot, these are well suited for time
503 * interval measurements.
504 */
505
506void
507getmicrotime(struct timeval *tvp)
508{
509 struct timecounter *tc;
510
511 if (!tco_method) {
512 tc = timecounter;
513 *tvp = tc->tc_microtime;
514 } else {
515 microtime(tvp);
516 }
517}
518
519void
520getnanotime(struct timespec *tsp)
521{
522 struct timecounter *tc;
523
524 if (!tco_method) {
525 tc = timecounter;
526 *tsp = tc->tc_nanotime;
527 } else {
528 nanotime(tsp);
529 }
530}
531
532void
533microtime(struct timeval *tv)
534{
535 struct timecounter *tc;
536
537 tc = timecounter;
538 tv->tv_sec = tc->tc_offset_sec;
539 tv->tv_usec = tc->tc_offset_micro;
540 tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
541 tv->tv_usec += boottime.tv_usec;
542 tv->tv_sec += boottime.tv_sec;
543 while (tv->tv_usec >= 1000000) {
544 tv->tv_usec -= 1000000;
545 tv->tv_sec++;
546 }
547}
548
549void
550nanotime(struct timespec *ts)
551{
552 unsigned count;
553 u_int64_t delta;
554 struct timecounter *tc;
555
556 tc = timecounter;
557 ts->tv_sec = tc->tc_offset_sec;
558 count = tco_delta(tc);
559 delta = tc->tc_offset_nano;
560 delta += ((u_int64_t)count * tc->tc_scale_nano_f);
561 delta >>= 32;
562 delta += ((u_int64_t)count * tc->tc_scale_nano_i);
563 delta += boottime.tv_usec * 1000;
564 ts->tv_sec += boottime.tv_sec;
565 while (delta >= 1000000000) {
566 delta -= 1000000000;
567 ts->tv_sec++;
568 }
569 ts->tv_nsec = delta;
570}
571
572void
573getmicrouptime(struct timeval *tvp)
574{
575 struct timecounter *tc;
576
577 if (!tco_method) {
578 tc = timecounter;
579 tvp->tv_sec = tc->tc_offset_sec;
580 tvp->tv_usec = tc->tc_offset_micro;
581 } else {
582 microuptime(tvp);
583 }
584}
585
586void
587getnanouptime(struct timespec *tsp)
588{
589 struct timecounter *tc;
590
591 if (!tco_method) {
592 tc = timecounter;
593 tsp->tv_sec = tc->tc_offset_sec;
594 tsp->tv_nsec = tc->tc_offset_nano >> 32;
595 } else {
596 nanouptime(tsp);
597 }
598}
599
600void
601microuptime(struct timeval *tv)
602{
603 struct timecounter *tc;
604
605 tc = timecounter;
606 tv->tv_sec = tc->tc_offset_sec;
607 tv->tv_usec = tc->tc_offset_micro;
608 tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
609 if (tv->tv_usec >= 1000000) {
610 tv->tv_usec -= 1000000;
611 tv->tv_sec++;
612 }
613}
614
615void
616nanouptime(struct timespec *ts)
617{
618 unsigned count;
619 u_int64_t delta;
620 struct timecounter *tc;
621
622 tc = timecounter;
623 ts->tv_sec = tc->tc_offset_sec;
624 count = tco_delta(tc);
625 delta = tc->tc_offset_nano;
626 delta += ((u_int64_t)count * tc->tc_scale_nano_f);
627 delta >>= 32;
628 delta += ((u_int64_t)count * tc->tc_scale_nano_i);
629 if (delta >= 1000000000) {
630 delta -= 1000000000;
631 ts->tv_sec++;
632 }
633 ts->tv_nsec = delta;
634}
635
636static void
637tco_setscales(struct timecounter *tc)
638{
639 u_int64_t scale;
640
641 scale = 1000000000LL << 32;
642 scale += tc->tc_adjustment;
643 scale /= tc->tc_tweak->tc_frequency;
644 tc->tc_scale_micro = scale / 1000;
645 tc->tc_scale_nano_f = scale & 0xffffffff;
646 tc->tc_scale_nano_i = scale >> 32;
647}
648
649void
650update_timecounter(struct timecounter *tc)
651{
652 tco_setscales(tc);
653}
654
655void
656init_timecounter(struct timecounter *tc)
657{
658 struct timespec ts1;
659 struct timecounter *t1, *t2, *t3;
660 int i;
661
662 tc->tc_adjustment = 0;
663 tc->tc_tweak = tc;
664 tco_setscales(tc);
665 tc->tc_offset_count = tc->tc_get_timecount(tc);
666 if (timecounter == &dummy_timecounter)
667 tc->tc_avail = tc;
668 else {
669 tc->tc_avail = timecounter->tc_tweak->tc_avail;
670 timecounter->tc_tweak->tc_avail = tc;
671 }
672 MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK);
673 tc->tc_other = t1;
674 *t1 = *tc;
675 t2 = t1;
676 for (i = 1; i < NTIMECOUNTER; i++) {
677 MALLOC(t3, struct timecounter *, sizeof *t3,
678 M_TIMECOUNTER, M_WAITOK);
679 *t3 = *tc;
680 t3->tc_other = t2;
681 t2 = t3;
682 }
683 t1->tc_other = t3;
684 tc = t1;
685
686 printf("Timecounter \"%s\" frequency %lu Hz\n",
687 tc->tc_name, (u_long)tc->tc_frequency);
688
689 /* XXX: For now always start using the counter. */
690 tc->tc_offset_count = tc->tc_get_timecount(tc);
691 nanouptime(&ts1);
692 tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32;
693 tc->tc_offset_micro = ts1.tv_nsec / 1000;
694 tc->tc_offset_sec = ts1.tv_sec;
695 timecounter = tc;
696}
697
698void
699set_timecounter(struct timespec *ts)
700{
701 struct timespec ts2;
702
703 nanouptime(&ts2);
704 boottime.tv_sec = ts->tv_sec - ts2.tv_sec;
705 boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000;
706 if (boottime.tv_usec < 0) {
707 boottime.tv_usec += 1000000;
708 boottime.tv_sec--;
709 }
710 /* fiddle all the little crinkly bits around the fiords... */
711 tco_forward(1);
712}
713
714static void
715switch_timecounter(struct timecounter *newtc)
716{
717 int s;
718 struct timecounter *tc;
719 struct timespec ts;
720
721 s = splclock();
722 tc = timecounter;
723 if (newtc->tc_tweak == tc->tc_tweak) {
724 splx(s);
725 return;
726 }
727 newtc = newtc->tc_tweak->tc_other;
728 nanouptime(&ts);
729 newtc->tc_offset_sec = ts.tv_sec;
730 newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32;
731 newtc->tc_offset_micro = ts.tv_nsec / 1000;
732 newtc->tc_offset_count = newtc->tc_get_timecount(newtc);
733 tco_setscales(newtc);
734 timecounter = newtc;
735 splx(s);
736}
737
738static struct timecounter *
739sync_other_counter(void)
740{
741 struct timecounter *tc, *tcn, *tco;
742 unsigned delta;
743
744 tco = timecounter;
745 tc = tco->tc_other;
746 tcn = tc->tc_other;
747 *tc = *tco;
748 tc->tc_other = tcn;
749 delta = tco_delta(tc);
750 tc->tc_offset_count += delta;
751 tc->tc_offset_count &= tc->tc_counter_mask;
752 tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f;
753 tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32;
754 return (tc);
755}
756
757static void
758tco_forward(int force)
759{
760 struct timecounter *tc, *tco;
761 struct timeval tvt;
762
763 tco = timecounter;
764 tc = sync_other_counter();
765 /*
766 * We may be inducing a tiny error here, the tc_poll_pps() may
767 * process a latched count which happens after the tco_delta()
768 * in sync_other_counter(), which would extend the previous
769 * counters parameters into the domain of this new one.
770 * Since the timewindow is very small for this, the error is
771 * going to be only a few weenieseconds (as Dave Mills would
772 * say), so lets just not talk more about it, OK ?
773 */
774 if (tco->tc_poll_pps)
775 tco->tc_poll_pps(tco);
776 if (timedelta != 0) {
777 tvt = boottime;
778 tvt.tv_usec += tickdelta;
779 if (tvt.tv_usec >= 1000000) {
780 tvt.tv_sec++;
781 tvt.tv_usec -= 1000000;
782 } else if (tvt.tv_usec < 0) {
783 tvt.tv_sec--;
784 tvt.tv_usec += 1000000;
785 }
786 boottime = tvt;
787 timedelta -= tickdelta;
788 }
789
790 while (tc->tc_offset_nano >= 1000000000ULL << 32) {
791 tc->tc_offset_nano -= 1000000000ULL << 32;
792 tc->tc_offset_sec++;
793 ntp_update_second(tc); /* XXX only needed if xntpd runs */
794 tco_setscales(tc);
795 force++;
796 }
797
798 if (tco_method && !force)
799 return;
800
801 tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32;
802
803 /* Figure out the wall-clock time */
804 tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec;
805 tc->tc_nanotime.tv_nsec =
806 (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000;
807 tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec;
808 if (tc->tc_nanotime.tv_nsec >= 1000000000) {
809 tc->tc_nanotime.tv_nsec -= 1000000000;
810 tc->tc_microtime.tv_usec -= 1000000;
811 tc->tc_nanotime.tv_sec++;
812 }
813 time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec;
814
815 timecounter = tc;
816}
817
818SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
819
820SYSCTL_INT(_kern_timecounter, OID_AUTO, method, CTLFLAG_RW, &tco_method, 0,
821 "This variable determines the method used for updating timecounters. "
822 "If the default algorithm (0) fails with \"calcru negative...\" messages "
823 "try the alternate algorithm (1) which handles bad hardware better."
824
825);
826
827static int
828sysctl_kern_timecounter_hardware SYSCTL_HANDLER_ARGS
829{
830 char newname[32];
831 struct timecounter *newtc, *tc;
832 int error;
833
834 tc = timecounter->tc_tweak;
835 strncpy(newname, tc->tc_name, sizeof(newname));
836 error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
837 if (error == 0 && req->newptr != NULL &&
838 strcmp(newname, tc->tc_name) != 0) {
839 for (newtc = tc->tc_avail; newtc != tc;
840 newtc = newtc->tc_avail) {
841 if (strcmp(newname, newtc->tc_name) == 0) {
842 /* Warm up new timecounter. */
843 (void)newtc->tc_get_timecount(newtc);
844
845 switch_timecounter(newtc);
846 return (0);
847 }
848 }
849 return (EINVAL);
850 }
851 return (error);
852}
853
854SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
855 0, 0, sysctl_kern_timecounter_hardware, "A", "");
856
857
858int
859pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
860{
861 pps_params_t *app;
862 struct pps_fetch_args *fapi;
863#ifdef PPS_SYNC
864 struct pps_kcbind_args *kapi;
865#endif
866
867 switch (cmd) {
868 case PPS_IOC_CREATE:
869 return (0);
870 case PPS_IOC_DESTROY:
871 return (0);
872 case PPS_IOC_SETPARAMS:
873 app = (pps_params_t *)data;
874 if (app->mode & ~pps->ppscap)
875 return (EINVAL);
876 pps->ppsparam = *app;
877 return (0);
878 case PPS_IOC_GETPARAMS:
879 app = (pps_params_t *)data;
880 *app = pps->ppsparam;
881 app->api_version = PPS_API_VERS_1;
882 return (0);
883 case PPS_IOC_GETCAP:
884 *(int*)data = pps->ppscap;
885 return (0);
886 case PPS_IOC_FETCH:
887 fapi = (struct pps_fetch_args *)data;
888 if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
889 return (EINVAL);
890 if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec)
891 return (EOPNOTSUPP);
892 pps->ppsinfo.current_mode = pps->ppsparam.mode;
893 fapi->pps_info_buf = pps->ppsinfo;
894 return (0);
895 case PPS_IOC_KCBIND:
896#ifdef PPS_SYNC
897 kapi = (struct pps_kcbind_args *)data;
898 /* XXX Only root should be able to do this */
899 if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC)
900 return (EINVAL);
901 if (kapi->kernel_consumer != PPS_KC_HARDPPS)
902 return (EINVAL);
903 if (kapi->edge & ~pps->ppscap)
904 return (EINVAL);
905 pps->kcmode = kapi->edge;
906 return (0);
907#else
908 return (EOPNOTSUPP);
909#endif
910 default:
911 return (ENOTTY);
912 }
913}
914
915void
916pps_init(struct pps_state *pps)
917{
918 pps->ppscap |= PPS_TSFMT_TSPEC;
919 if (pps->ppscap & PPS_CAPTUREASSERT)
920 pps->ppscap |= PPS_OFFSETASSERT;
921 if (pps->ppscap & PPS_CAPTURECLEAR)
922 pps->ppscap |= PPS_OFFSETCLEAR;
923}
924
925void
926pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event)
927{
928 struct timespec ts, *tsp, *osp;
929 u_int64_t delta;
930 unsigned tcount, *pcount;
931 int foff, fhard;
932 pps_seq_t *pseq;
933
934 /* Things would be easier with arrays... */
935 if (event == PPS_CAPTUREASSERT) {
936 tsp = &pps->ppsinfo.assert_timestamp;
937 osp = &pps->ppsparam.assert_offset;
938 foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
939 fhard = pps->kcmode & PPS_CAPTUREASSERT;
940 pcount = &pps->ppscount[0];
941 pseq = &pps->ppsinfo.assert_sequence;
942 } else {
943 tsp = &pps->ppsinfo.clear_timestamp;
944 osp = &pps->ppsparam.clear_offset;
945 foff = pps->ppsparam.mode & PPS_OFFSETCLEAR;
946 fhard = pps->kcmode & PPS_CAPTURECLEAR;
947 pcount = &pps->ppscount[1];
948 pseq = &pps->ppsinfo.clear_sequence;
949 }
950
951 /* The timecounter changed: bail */
952 if (!pps->ppstc ||
953 pps->ppstc->tc_name != tc->tc_name ||
954 tc->tc_name != timecounter->tc_name) {
955 pps->ppstc = tc;
956 *pcount = count;
957 return;
958 }
959
960 /* Nothing really happened */
961 if (*pcount == count)
962 return;
963
964 *pcount = count;
965
966 /* Convert the count to timespec */
967 ts.tv_sec = tc->tc_offset_sec;
968 tcount = count - tc->tc_offset_count;
969 tcount &= tc->tc_counter_mask;
970 delta = tc->tc_offset_nano;
971 delta += ((u_int64_t)tcount * tc->tc_scale_nano_f);
972 delta >>= 32;
973 delta += ((u_int64_t)tcount * tc->tc_scale_nano_i);
974 delta += boottime.tv_usec * 1000;
975 ts.tv_sec += boottime.tv_sec;
976 while (delta >= 1000000000) {
977 delta -= 1000000000;
978 ts.tv_sec++;
979 }
980 ts.tv_nsec = delta;
981
982 (*pseq)++;
983 *tsp = ts;
984
985 if (foff) {
986 timespecadd(tsp, osp);
987 if (tsp->tv_nsec < 0) {
988 tsp->tv_nsec += 1000000000;
989 tsp->tv_sec -= 1;
990 }
991 }
992#ifdef PPS_SYNC
993 if (fhard) {
994 /* magic, at its best... */
995 tcount = count - pps->ppscount[2];
996 pps->ppscount[2] = count;
997 tcount &= tc->tc_counter_mask;
998 delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f);
999 delta >>= 32;
1000 delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i);
1001 hardpps(tsp, delta);
1002 }
1003#endif
1004}