From 32c203577a5e89ed1e5849d1a5e81abf501cfb50 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Thu, 11 Mar 1999 15:09:51 +0000 Subject: [PATCH] Make even more of the PPSAPI implementations generic. FLL support in hardpps() Various magic shuffles and improved comments Style fixes from Bruce. --- sys/dev/ppbus/pps.c | 75 +++++---------- sys/kern/kern_clock.c | 201 +++++++++++++++++++++++++++++----------- sys/kern/kern_ntptime.c | 51 ++-------- sys/kern/kern_tc.c | 201 +++++++++++++++++++++++++++++----------- sys/pci/xrpu.c | 79 ++++++---------- sys/sys/systm.h | 4 +- sys/sys/time.h | 3 +- sys/sys/timepps.h | 85 ++++++++++++++++- sys/sys/timetc.h | 3 +- sys/sys/timex.h | 27 +++--- 10 files changed, 450 insertions(+), 279 deletions(-) diff --git a/sys/dev/ppbus/pps.c b/sys/dev/ppbus/pps.c index 24be094eaf04..f50714322504 100644 --- a/sys/dev/ppbus/pps.c +++ b/sys/dev/ppbus/pps.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: pps.c,v 1.12 1998/12/07 21:58:16 archie Exp $ + * $Id: pps.c,v 1.13 1999/01/30 15:35:39 nsouch Exp $ * * This driver implements a draft-mogul-pps-api-02.txt PPS source. * @@ -16,7 +16,6 @@ */ #include "opt_devfs.h" -#include "opt_ntp.h" #include #include @@ -36,20 +35,11 @@ static struct pps_data { int pps_unit; struct ppb_device pps_dev; - pps_params_t ppsparam; - pps_info_t ppsinfo; + struct pps_state pps; } *softc[NPPS]; -static int ppscap = - PPS_CAPTUREASSERT | -#ifdef PPS_SYNC - PPS_HARDPPSONASSERT | -#endif /* PPS_SYNC */ - PPS_OFFSETASSERT | - PPS_ECHOASSERT | - PPS_TSFMT_TSPEC; - static int npps; +static pps_devsw_installed = 0; /* * Make ourselves visible as a ppbus driver @@ -77,6 +67,7 @@ static struct cdevsw pps_cdevsw = seltrue, nommap, nostrat, PPS_NAME, NULL, -1 }; + static struct ppb_device * ppsprobe(struct ppb_data *ppb) { @@ -99,12 +90,16 @@ ppsprobe(struct ppb_data *ppb) sc->pps_dev.name = ppsdriver.name; sc->pps_dev.intr = ppsintr; + sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; + pps_init(&sc->pps); return (&sc->pps_dev); } static int ppsattach(struct ppb_device *dev) { + dev_t devt; + /* * Report ourselves */ @@ -116,7 +111,11 @@ ppsattach(struct ppb_device *dev) dev->id_unit, DV_CHR, UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); #endif - + if( ! pps_devsw_installed ) { + devt = makedev(CDEV_MAJOR, 0); + cdevsw_add(&devt, &pps_cdevsw, NULL); + pps_devsw_installed = 1; + } return (1); } @@ -145,7 +144,7 @@ ppsclose(dev_t dev, int flags, int fmt, struct proc *p) { struct pps_data *sc = softc[minor(dev)]; - sc->ppsparam.mode = 0; + sc->pps.ppsparam.mode = 0; /* PHK ??? */ ppb_wdtr(&sc->pps_dev, 0); ppb_wctr(&sc->pps_dev, 0); @@ -158,32 +157,17 @@ static void ppsintr(int unit) { struct pps_data *sc = softc[unit]; - struct timespec tc; + struct timecounter *tc; + unsigned count; - nanotime(&tc); + tc = timecounter; + count = timecounter->tc_get_timecount(tc); if (!(ppb_rstr(&sc->pps_dev) & nACK)) return; - if (sc->ppsparam.mode & PPS_ECHOASSERT) + if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); - if (sc->ppsparam.mode & PPS_OFFSETASSERT) { - timespecadd(&tc, &sc->ppsparam.assert_offset); - if (tc.tv_nsec < 0) { - tc.tv_sec--; - tc.tv_nsec += 1000000000; - } - } - sc->ppsinfo.assert_timestamp = tc; - sc->ppsinfo.assert_sequence++; -#ifdef PPS_SYNC - if (sc->ppsparam.mode & PPS_HARDPPSONASSERT) { - struct timeval tv; - - tv.tv_sec = tc.tv_sec; - tv.tv_usec = tc.tv_nsec / 1000; - hardpps(&tv, tv.tv_usec); - } -#endif /* PPS_SYNC */ - if (sc->ppsparam.mode & PPS_ECHOASSERT) + pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); + if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(&sc->pps_dev, IRQENABLE); } @@ -192,21 +176,6 @@ ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct pps_data *sc = softc[minor(dev)]; - return (std_pps_ioctl(cmd, data, &sc->ppsparam, &sc->ppsinfo, ppscap)); + return (pps_ioctl(cmd, data, &sc->pps)); } -static pps_devsw_installed = 0; - -static void -pps_drvinit(void *unused) -{ - dev_t dev; - - if( ! pps_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev, &pps_cdevsw, NULL); - pps_devsw_installed = 1; - } -} - -SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL) diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 1c536ee4724c..da424e5c2c4d 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -37,9 +37,11 @@ * SUCH DAMAGE. * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 - * $Id: kern_clock.c,v 1.88 1999/02/19 19:34:49 luoqi Exp $ + * $Id: kern_clock.c,v 1.89 1999/03/08 12:35:58 phk Exp $ */ +#include "opt_ntp.h" + #include #include #include @@ -50,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -509,11 +512,14 @@ tco_delta(struct timecounter *tc) } /* - * We have four functions for looking at the clock, two for microseconds - * and two for nanoseconds. For each there is fast but less precise - * version "get{nano|micro}time" which will return a time which is up - * to 1/HZ previous to the call, whereas the raw version "{nano|micro}time" - * will return a timestamp which is as precise as possible. + * We have eight functions for looking at the clock, four for + * microseconds and four for nanoseconds. For each there is fast + * but less precise version "get{nano|micro}[up]time" which will + * return a time which is up to 1/HZ previous to the call, whereas + * the raw version "{nano|micro}[up]time" will return a timestamp + * which is as precise as possible. The "up" variants return the + * time relative to system boot, these are well suited for time + * interval measurements. */ void @@ -582,29 +588,6 @@ nanotime(struct timespec *ts) ts->tv_nsec = delta; } -void -timecounter_timespec(unsigned count, struct timespec *ts) -{ - u_int64_t delta; - struct timecounter *tc; - - tc = (struct timecounter *)timecounter; - ts->tv_sec = tc->tc_offset_sec; - count -= tc->tc_offset_count; - count &= tc->tc_counter_mask; - delta = tc->tc_offset_nano; - delta += ((u_int64_t)count * tc->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)count * tc->tc_scale_nano_i); - delta += boottime.tv_usec * 1000; - ts->tv_sec += boottime.tv_sec; - while (delta >= 1000000000) { - delta -= 1000000000; - ts->tv_sec++; - } - ts->tv_nsec = delta; -} - void getmicrouptime(struct timeval *tvp) { @@ -805,8 +788,6 @@ tco_forward(int force) while (tc->tc_offset_nano >= 1000000000ULL << 32) { tc->tc_offset_nano -= 1000000000ULL << 32; tc->tc_offset_sec++; - tc->tc_frequency = tc->tc_tweak->tc_frequency; - tc->tc_adjustment = tc->tc_tweak->tc_adjustment; ntp_update_second(tc); /* XXX only needed if xntpd runs */ tco_setscales(tc); force++; @@ -832,24 +813,6 @@ tco_forward(int force) timecounter = tc; } -static int -sysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS -{ - - return (sysctl_handle_opaque(oidp, - &timecounter->tc_tweak->tc_frequency, - sizeof(timecounter->tc_tweak->tc_frequency), req)); -} - -static int -sysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS -{ - - return (sysctl_handle_opaque(oidp, - &timecounter->tc_tweak->tc_adjustment, - sizeof(timecounter->tc_tweak->tc_adjustment), req)); -} - SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0, @@ -859,8 +822,140 @@ SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0, ); -SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", ""); -SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", ""); +int +pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) +{ + pps_params_t *app; + pps_info_t *api; + + switch (cmd) { + case PPS_IOC_CREATE: + return (0); + case PPS_IOC_DESTROY: + return (0); + case PPS_IOC_SETPARAMS: + app = (pps_params_t *)data; + if (app->mode & ~pps->ppscap) + return (EINVAL); + pps->ppsparam = *app; + return (0); + case PPS_IOC_GETPARAMS: + app = (pps_params_t *)data; + *app = pps->ppsparam; + return (0); + case PPS_IOC_GETCAP: + *(int*)data = pps->ppscap; + return (0); + case PPS_IOC_FETCH: + api = (pps_info_t *)data; + pps->ppsinfo.current_mode = pps->ppsparam.mode; + *api = pps->ppsinfo; + return (0); + case PPS_IOC_WAIT: + return (EOPNOTSUPP); + default: + return (ENOTTY); + } +} + +void +pps_init(struct pps_state *pps) +{ + pps->ppscap |= PPS_TSFMT_TSPEC; + if (pps->ppscap & PPS_CAPTUREASSERT) + pps->ppscap |= PPS_OFFSETASSERT; + if (pps->ppscap & PPS_CAPTURECLEAR) + pps->ppscap |= PPS_OFFSETCLEAR; +#ifdef PPS_SYNC + if (pps->ppscap & PPS_CAPTUREASSERT) + pps->ppscap |= PPS_HARDPPSONASSERT; + if (pps->ppscap & PPS_CAPTURECLEAR) + pps->ppscap |= PPS_HARDPPSONCLEAR; +#endif +} + +void +pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event) +{ + struct timespec ts, *tsp, *osp; + u_int64_t delta; + unsigned tcount, *pcount; + int foff, fhard; + pps_seq_t *pseq; + + /* Things would be easier with arrays... */ + if (event == PPS_CAPTUREASSERT) { + tsp = &pps->ppsinfo.assert_timestamp; + osp = &pps->ppsparam.assert_offset; + foff = pps->ppsparam.mode & PPS_OFFSETASSERT; + fhard = pps->ppsparam.mode & PPS_HARDPPSONASSERT; + pcount = &pps->ppscount[0]; + pseq = &pps->ppsinfo.assert_sequence; + } else { + tsp = &pps->ppsinfo.clear_timestamp; + osp = &pps->ppsparam.clear_offset; + foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; + fhard = pps->ppsparam.mode & PPS_HARDPPSONCLEAR; + pcount = &pps->ppscount[1]; + pseq = &pps->ppsinfo.clear_sequence; + } + + /* The timecounter changed: bail */ + if (!pps->ppstc || + pps->ppstc->tc_name != tc->tc_name || + tc->tc_name != timecounter->tc_name) { + pps->ppstc = tc; + *pcount = count; + return; + } + + /* Now, make sure we have the right instance */ + tc = timecounter; + + /* Nothing really happened */ + if (*pcount == count) + return; + + *pcount = count; + + /* Convert the count to timespec */ + ts.tv_sec = tc->tc_offset_sec; + tcount = count - tc->tc_offset_count; + tcount &= tc->tc_counter_mask; + delta = tc->tc_offset_nano; + delta += ((u_int64_t)tcount * tc->tc_scale_nano_f); + delta >>= 32; + delta += ((u_int64_t)tcount * tc->tc_scale_nano_i); + delta += boottime.tv_usec * 1000; + ts.tv_sec += boottime.tv_sec; + while (delta >= 1000000000) { + delta -= 1000000000; + ts.tv_sec++; + } + ts.tv_nsec = delta; + + (*pseq)++; + *tsp = ts; + + if (foff) { + timespecadd(tsp, osp); + if (tsp->tv_nsec < 0) { + tsp->tv_nsec += 1000000000; + tsp->tv_sec -= 1; + } + } +#ifdef PPS_SYNC + if (fhard) { + /* magic, at its best... */ + tcount = count - pps->ppscount[2]; + pps->ppscount[2] = count; + tcount &= tc->tc_counter_mask; + delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f); + delta >>= 32; + delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i); + hardpps(tsp, delta); + } +#endif +} + diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index ec98387201b7..56ad6fffb360 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -18,7 +18,7 @@ /* * Adapted from the original sources for FreeBSD and timecounters by: - * Poul-Henning Kamp + * Poul-Henning Kamp . * * The 32bit version of the "LP" macros seems a bit past its "sell by" * date so I have retained only the 64bit version and included it directly @@ -27,11 +27,10 @@ * Only minor changes done to interface with the timecounters over in * sys/kern/kern_clock.c. Some of the comments below may be (even more) * confusing and/or plain wrong in that context. - * - * The PPS_SYNC/hardpps() is currently not supported. - * */ +#include "opt_ntp.h" + #include #include #include @@ -167,7 +166,6 @@ struct ppstime { static struct ppstime pps_tf[3]; /* phase median filter */ static struct ppstime pps_filt; /* phase offset */ static l_fp pps_freq; /* scaled frequency offset (ns/s) */ -static long pps_lastfreq; /* last scaled freq offset (ns/s) */ static long pps_offacc; /* offset accumulator */ static long pps_jitter; /* scaled time dispersion (ns) */ static long pps_stabil; /* scaled frequency dispersion (ns/s) */ @@ -382,7 +380,7 @@ void ntp_update_second(struct timecounter *tcp) { u_int32_t *newsec; - l_fp ftemp, time_adj; /* 32/64-bit temporary */ + l_fp ftemp, time_adj; /* 32/64-bit temporaries */ newsec = &tcp->tc_offset_sec; time_maxerror += MAXFREQ / 1000; @@ -654,16 +652,17 @@ hardpps(tsp, nsec) * boundary during the last second, so correct the tick. Very * intricate. */ - u_nsec = nsec - pps_lastcount; - pps_lastcount = nsec; + u_nsec = nsec; if (u_nsec > (NANOSECOND >> 1)) u_nsec -= NANOSECOND; else if (u_nsec < -(NANOSECOND >> 1)) u_nsec += NANOSECOND; +#if 0 if (u_nsec > (time_tick >> 1)) u_nsec -= time_tick; else if (u_nsec < -(time_tick >> 1)) u_nsec += time_tick; +#endif pps_tf[0].count = pps_tf[1].count + u_nsec; if (v_nsec > MAXFREQ) { return; @@ -812,39 +811,3 @@ hardpps(tsp, nsec) time_freq = pps_freq; } #endif /* PPS_SYNC */ - -int -std_pps_ioctl(u_long cmd, caddr_t data, pps_params_t *pp, pps_info_t *pi, int ppscap) -{ - pps_params_t *app; - pps_info_t *api; - - switch (cmd) { - case PPS_IOC_CREATE: - return (0); - case PPS_IOC_DESTROY: - return (0); - case PPS_IOC_SETPARAMS: - app = (pps_params_t *)data; - if (app->mode & ~ppscap) - return (EINVAL); - *pp = *app; - return (0); - case PPS_IOC_GETPARAMS: - app = (pps_params_t *)data; - *app = *pp; - return (0); - case PPS_IOC_GETCAP: - *(int*)data = ppscap; - return (0); - case PPS_IOC_FETCH: - api = (pps_info_t *)data; - *api = *pi; - pi->current_mode = pp->mode; - return (0); - case PPS_IOC_WAIT: - return (EOPNOTSUPP); - default: - return (ENODEV); - } -} diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 1c536ee4724c..da424e5c2c4d 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -37,9 +37,11 @@ * SUCH DAMAGE. * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 - * $Id: kern_clock.c,v 1.88 1999/02/19 19:34:49 luoqi Exp $ + * $Id: kern_clock.c,v 1.89 1999/03/08 12:35:58 phk Exp $ */ +#include "opt_ntp.h" + #include #include #include @@ -50,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -509,11 +512,14 @@ tco_delta(struct timecounter *tc) } /* - * We have four functions for looking at the clock, two for microseconds - * and two for nanoseconds. For each there is fast but less precise - * version "get{nano|micro}time" which will return a time which is up - * to 1/HZ previous to the call, whereas the raw version "{nano|micro}time" - * will return a timestamp which is as precise as possible. + * We have eight functions for looking at the clock, four for + * microseconds and four for nanoseconds. For each there is fast + * but less precise version "get{nano|micro}[up]time" which will + * return a time which is up to 1/HZ previous to the call, whereas + * the raw version "{nano|micro}[up]time" will return a timestamp + * which is as precise as possible. The "up" variants return the + * time relative to system boot, these are well suited for time + * interval measurements. */ void @@ -582,29 +588,6 @@ nanotime(struct timespec *ts) ts->tv_nsec = delta; } -void -timecounter_timespec(unsigned count, struct timespec *ts) -{ - u_int64_t delta; - struct timecounter *tc; - - tc = (struct timecounter *)timecounter; - ts->tv_sec = tc->tc_offset_sec; - count -= tc->tc_offset_count; - count &= tc->tc_counter_mask; - delta = tc->tc_offset_nano; - delta += ((u_int64_t)count * tc->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)count * tc->tc_scale_nano_i); - delta += boottime.tv_usec * 1000; - ts->tv_sec += boottime.tv_sec; - while (delta >= 1000000000) { - delta -= 1000000000; - ts->tv_sec++; - } - ts->tv_nsec = delta; -} - void getmicrouptime(struct timeval *tvp) { @@ -805,8 +788,6 @@ tco_forward(int force) while (tc->tc_offset_nano >= 1000000000ULL << 32) { tc->tc_offset_nano -= 1000000000ULL << 32; tc->tc_offset_sec++; - tc->tc_frequency = tc->tc_tweak->tc_frequency; - tc->tc_adjustment = tc->tc_tweak->tc_adjustment; ntp_update_second(tc); /* XXX only needed if xntpd runs */ tco_setscales(tc); force++; @@ -832,24 +813,6 @@ tco_forward(int force) timecounter = tc; } -static int -sysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS -{ - - return (sysctl_handle_opaque(oidp, - &timecounter->tc_tweak->tc_frequency, - sizeof(timecounter->tc_tweak->tc_frequency), req)); -} - -static int -sysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS -{ - - return (sysctl_handle_opaque(oidp, - &timecounter->tc_tweak->tc_adjustment, - sizeof(timecounter->tc_tweak->tc_adjustment), req)); -} - SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0, @@ -859,8 +822,140 @@ SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0, ); -SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", ""); -SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", ""); +int +pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) +{ + pps_params_t *app; + pps_info_t *api; + + switch (cmd) { + case PPS_IOC_CREATE: + return (0); + case PPS_IOC_DESTROY: + return (0); + case PPS_IOC_SETPARAMS: + app = (pps_params_t *)data; + if (app->mode & ~pps->ppscap) + return (EINVAL); + pps->ppsparam = *app; + return (0); + case PPS_IOC_GETPARAMS: + app = (pps_params_t *)data; + *app = pps->ppsparam; + return (0); + case PPS_IOC_GETCAP: + *(int*)data = pps->ppscap; + return (0); + case PPS_IOC_FETCH: + api = (pps_info_t *)data; + pps->ppsinfo.current_mode = pps->ppsparam.mode; + *api = pps->ppsinfo; + return (0); + case PPS_IOC_WAIT: + return (EOPNOTSUPP); + default: + return (ENOTTY); + } +} + +void +pps_init(struct pps_state *pps) +{ + pps->ppscap |= PPS_TSFMT_TSPEC; + if (pps->ppscap & PPS_CAPTUREASSERT) + pps->ppscap |= PPS_OFFSETASSERT; + if (pps->ppscap & PPS_CAPTURECLEAR) + pps->ppscap |= PPS_OFFSETCLEAR; +#ifdef PPS_SYNC + if (pps->ppscap & PPS_CAPTUREASSERT) + pps->ppscap |= PPS_HARDPPSONASSERT; + if (pps->ppscap & PPS_CAPTURECLEAR) + pps->ppscap |= PPS_HARDPPSONCLEAR; +#endif +} + +void +pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event) +{ + struct timespec ts, *tsp, *osp; + u_int64_t delta; + unsigned tcount, *pcount; + int foff, fhard; + pps_seq_t *pseq; + + /* Things would be easier with arrays... */ + if (event == PPS_CAPTUREASSERT) { + tsp = &pps->ppsinfo.assert_timestamp; + osp = &pps->ppsparam.assert_offset; + foff = pps->ppsparam.mode & PPS_OFFSETASSERT; + fhard = pps->ppsparam.mode & PPS_HARDPPSONASSERT; + pcount = &pps->ppscount[0]; + pseq = &pps->ppsinfo.assert_sequence; + } else { + tsp = &pps->ppsinfo.clear_timestamp; + osp = &pps->ppsparam.clear_offset; + foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; + fhard = pps->ppsparam.mode & PPS_HARDPPSONCLEAR; + pcount = &pps->ppscount[1]; + pseq = &pps->ppsinfo.clear_sequence; + } + + /* The timecounter changed: bail */ + if (!pps->ppstc || + pps->ppstc->tc_name != tc->tc_name || + tc->tc_name != timecounter->tc_name) { + pps->ppstc = tc; + *pcount = count; + return; + } + + /* Now, make sure we have the right instance */ + tc = timecounter; + + /* Nothing really happened */ + if (*pcount == count) + return; + + *pcount = count; + + /* Convert the count to timespec */ + ts.tv_sec = tc->tc_offset_sec; + tcount = count - tc->tc_offset_count; + tcount &= tc->tc_counter_mask; + delta = tc->tc_offset_nano; + delta += ((u_int64_t)tcount * tc->tc_scale_nano_f); + delta >>= 32; + delta += ((u_int64_t)tcount * tc->tc_scale_nano_i); + delta += boottime.tv_usec * 1000; + ts.tv_sec += boottime.tv_sec; + while (delta >= 1000000000) { + delta -= 1000000000; + ts.tv_sec++; + } + ts.tv_nsec = delta; + + (*pseq)++; + *tsp = ts; + + if (foff) { + timespecadd(tsp, osp); + if (tsp->tv_nsec < 0) { + tsp->tv_nsec += 1000000000; + tsp->tv_sec -= 1; + } + } +#ifdef PPS_SYNC + if (fhard) { + /* magic, at its best... */ + tcount = count - pps->ppscount[2]; + pps->ppscount[2] = count; + tcount &= tc->tc_counter_mask; + delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f); + delta >>= 32; + delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i); + hardpps(tsp, delta); + } +#endif +} + diff --git a/sys/pci/xrpu.c b/sys/pci/xrpu.c index 25a90a471d8f..a6964bd375b6 100644 --- a/sys/pci/xrpu.c +++ b/sys/pci/xrpu.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: xrpu.c,v 1.5 1998/12/14 06:32:58 dillon Exp $ + * $Id: xrpu.c,v 1.6 1999/01/12 01:42:43 eivind Exp $ * * A very simple device driver for PCI cards based on Xilinx 6200 series * FPGA/RPU devices. Current Functionality is to allow you to open and @@ -17,6 +17,8 @@ * */ +#include "opt_devfs.h" + #include "xrpu.h" #include #include @@ -24,7 +26,9 @@ #include #include #include +#ifdef DEFVFS #include +#endif #include #include #include @@ -64,13 +68,8 @@ static struct softc { u_int *virbase62; struct timecounter tc; u_int *trigger, *latch, dummy; - struct { - pps_params_t params; - pps_info_t info; - int cap; - u_int *assert, last_assert; - u_int *clear, last_clear; - } pps[XRPU_MAX_PPS]; + struct pps_state pps[XRPU_MAX_PPS]; + u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS]; } *softc[NXRPU]; static unsigned @@ -90,45 +89,21 @@ xrpu_poll_pps(struct timecounter *tc) unsigned count1, ppscount; for (i = 0; i < XRPU_MAX_PPS; i++) { - if (sc->pps[i].assert) { - ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; + if (sc->assert[i]) { + ppscount = *(sc->assert[i]) & tc->tc_counter_mask; do { count1 = ppscount; - ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; + ppscount = *(sc->assert[i]) & tc->tc_counter_mask; } while (ppscount != count1); - if (ppscount != sc->pps[i].last_assert) { - timecounter_timespec(ppscount, &sc->pps[i].info.assert_timestamp); - if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { - timespecadd(&sc->pps[i].info.assert_timestamp, - &sc->pps[i].params.assert_offset); - if (sc->pps[i].info.assert_timestamp.tv_nsec < 0) { - sc->pps[i].info.assert_timestamp.tv_nsec += 1000000000; - sc->pps[i].info.assert_timestamp.tv_sec -= 1; - } - } - sc->pps[i].info.assert_sequence++; - sc->pps[i].last_assert = ppscount; - } + pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTUREASSERT); } - if (sc->pps[i].clear) { - ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; + if (sc->clear[i]) { + ppscount = *(sc->clear[i]) & tc->tc_counter_mask; do { count1 = ppscount; - ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; + ppscount = *(sc->clear[i]) & tc->tc_counter_mask; } while (ppscount != count1); - if (ppscount != sc->pps[i].last_clear) { - timecounter_timespec(ppscount, &sc->pps[i].info.clear_timestamp); - if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { - timespecadd(&sc->pps[i].info.clear_timestamp, - &sc->pps[i].params.clear_offset); - if (sc->pps[i].info.clear_timestamp.tv_nsec < 0) { - sc->pps[i].info.clear_timestamp.tv_nsec += 1000000000; - sc->pps[i].info.clear_timestamp.tv_sec -= 1; - } - } - sc->pps[i].info.clear_sequence++; - sc->pps[i].last_clear = ppscount; - } + pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTURECLEAR); } } } @@ -164,10 +139,7 @@ xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr) i = dev2pps(dev); if (i < 0 || i >= XRPU_MAX_PPS) return ENODEV; - if (!sc->pps[i].cap) - return ENODEV; - error = std_pps_ioctl(cmd, arg, &sc->pps[i].params, - &sc->pps[i].info, sc->pps[i].cap); + error = pps_ioctl(cmd, arg, &sc->pps[i]); return (error); } @@ -191,17 +163,20 @@ xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr) if (xt->xt_pps[i].xt_addr_assert == 0 && xt->xt_pps[i].xt_addr_clear == 0) continue; - devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL, 0600, - "xpps%d", i); - /* DEVFS */ +#ifdef DEVFS + devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL, + 0600, "xpps%d", i); +#endif + sc->pps[i].ppscap = 0; if (xt->xt_pps[i].xt_addr_assert) { - sc->pps[i].assert = sc->virbase62 + xt->xt_pps[i].xt_addr_assert; - sc->pps[i].cap |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT; + sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert; + sc->pps[i].ppscap |= PPS_CAPTUREASSERT; } if (xt->xt_pps[i].xt_addr_clear) { - sc->pps[i].clear = sc->virbase62 + xt->xt_pps[i].xt_addr_clear; - sc->pps[i].cap |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; + sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear; + sc->pps[i].ppscap |= PPS_CAPTURECLEAR; } + pps_init(&sc->pps[i]); } sc->mode = TIMECOUNTER; init_timecounter(&sc->tc); @@ -266,6 +241,8 @@ xrpu_attach (pcici_t tag, int unit) if (!unit) cdevsw_add(&cdev, &xrpudevsw, NULL); +#ifdef DEVFS devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit); +#endif } diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 5724747f1c6f..99539f15d17b 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)systm.h 8.7 (Berkeley) 3/29/95 - * $Id: systm.h,v 1.85 1999/01/28 00:57:54 dillon Exp $ + * $Id: systm.h,v 1.86 1999/03/05 19:27:22 bde Exp $ */ #ifndef _SYS_SYSTM_H_ @@ -160,8 +160,6 @@ void startprofclock __P((struct proc *)); void stopprofclock __P((struct proc *)); void setstatclockrate __P((int hzrate)); -void hardpps __P((struct timeval *tvp, long usec)); - char *getenv __P((char *name)); int getenv_int __P((char *name, int *data)); extern char *kern_envp; diff --git a/sys/sys/time.h b/sys/sys/time.h index e117c74a796a..712fffe12fa5 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)time.h 8.5 (Berkeley) 5/4/95 - * $Id: time.h,v 1.35 1998/12/15 17:38:32 des Exp $ + * $Id: time.h,v 1.36 1999/03/08 12:36:14 phk Exp $ */ #ifndef _SYS_TIME_H_ @@ -277,7 +277,6 @@ void microtime __P((struct timeval *tv)); void nanouptime __P((struct timespec *ts)); void nanotime __P((struct timespec *ts)); void set_timecounter __P((struct timespec *ts)); -void timecounter_timespec __P((unsigned count, struct timespec *ts)); void timevaladd __P((struct timeval *, struct timeval *)); void timevalsub __P((struct timeval *, struct timeval *)); int tvtohz __P((struct timeval *)); diff --git a/sys/sys/timepps.h b/sys/sys/timepps.h index cc0e9ff21b5a..ba752d7cb425 100644 --- a/sys/sys/timepps.h +++ b/sys/sys/timepps.h @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: timepps.h,v 1.3 1998/06/13 09:30:24 phk Exp $ + * $Id: timepps.h,v 1.4 1998/06/22 21:09:10 phk Exp $ * * The is a FreeBSD protype version of the "draft-mogul-pps-api-02.txt" * specification for Pulse Per Second timing interfaces. @@ -92,8 +92,85 @@ struct pps_wait_args { #define PPS_IOC_WAIT _IOWR('1', 6, struct pps_wait_args) #ifdef KERNEL -int std_pps_ioctl __P((u_long cmd, caddr_t data, pps_params_t *pp, - pps_info_t *pi, int ppscap)); +struct pps_state { + pps_params_t ppsparam; + pps_info_t ppsinfo; + int ppscap; + struct timecounter *ppstc; + unsigned ppscount[3]; +}; -#endif /* KERNEL */ +void pps_event __P((struct pps_state *pps, struct timecounter *tc, unsigned count, int event)); +void pps_init __P((struct pps_state *pps)); +int pps_ioctl __P((u_long cmd, caddr_t data, struct pps_state *pps)); +void hardpps __P((struct timespec *tsp, long nsec)); + +#else /* !KERNEL */ + +int time_pps_create(int filedes, pps_handle_t *handle); +int time_pps_destroy(pps_handle_t handle); +int time_pps_setparams(pps_handle_t handle, const pps_params_t *ppsparams); +int time_pps_getparams(pps_handle_t handle, pps_params_t *ppsparams); +int time_pps_getcap(pps_handle_t handle, int *mode); +int time_pps_fetch(pps_handle_t handle, pps_info_t *ppsinfobuf); +int time_pps_wait(pps_handle_t handle, const struct timespec *timeout, + pps_info_t *ppsinfobuf); + +static __inline int +time_pps_create(int filedes, pps_handle_t *handle) +{ + int error; + + *handle = -1; + error = ioctl(filedes, PPS_IOC_CREATE, 0); + if (error < 0) + return (-1); + *handle = filedes; + return (0); +} + +static __inline int +time_pps_destroy(pps_handle_t handle) +{ + return (ioctl(handle, PPS_IOC_DESTROY, 0)); +} + +static __inline int +time_pps_setparams(pps_handle_t handle, const pps_params_t *ppsparams) +{ + return (ioctl(handle, PPS_IOC_SETPARAMS, ppsparams)); +} + +static __inline int +time_pps_getparams(pps_handle_t handle, pps_params_t *ppsparams) +{ + return (ioctl(handle, PPS_IOC_GETPARAMS, ppsparams)); +} + +static __inline int +time_pps_getcap(pps_handle_t handle, int *mode) +{ + return (ioctl(handle, PPS_IOC_GETCAP, mode)); +} + +static __inline int +time_pps_fetch(pps_handle_t handle, pps_info_t *ppsinfobuf) +{ + return (ioctl(handle, PPS_IOC_FETCH, ppsinfobuf)); +} + +static __inline int +time_pps_wait(pps_handle_t handle, const struct timespec *timeout, + pps_info_t *ppsinfobuf) +{ + int error; + struct pps_wait_args arg; + + arg.timeout = *timeout; + error = ioctl(handle, PPS_IOC_WAIT, &arg); + *ppsinfobuf = arg.pps_info_buf; + return (error); +} + +#endif /* !KERNEL */ #endif /* _SYS_TIMEPPS_H_ */ diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h index e117c74a796a..712fffe12fa5 100644 --- a/sys/sys/timetc.h +++ b/sys/sys/timetc.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)time.h 8.5 (Berkeley) 5/4/95 - * $Id: time.h,v 1.35 1998/12/15 17:38:32 des Exp $ + * $Id: time.h,v 1.36 1999/03/08 12:36:14 phk Exp $ */ #ifndef _SYS_TIME_H_ @@ -277,7 +277,6 @@ void microtime __P((struct timeval *tv)); void nanouptime __P((struct timespec *ts)); void nanotime __P((struct timespec *ts)); void set_timecounter __P((struct timespec *ts)); -void timecounter_timespec __P((unsigned count, struct timespec *ts)); void timevaladd __P((struct timeval *, struct timeval *)); void timevalsub __P((struct timeval *, struct timeval *)); int tvtohz __P((struct timeval *)); diff --git a/sys/sys/timex.h b/sys/sys/timex.h index a829045aa8fe..af926d3ec413 100644 --- a/sys/sys/timex.h +++ b/sys/sys/timex.h @@ -59,14 +59,11 @@ * * SYNOPSIS * #include - * #include * - * int syscall(SYS_ntp_gettime, tptr); - * int SYS_ntp_gettime; - * struct ntptimeval *tptr; + * int ntp_gettime(struct ntptimeval *ntv); * * DESCRIPTION - * The time returned by ntp_gettime() is in a timeval structure, + * The time returned by ntp_gettime() is in a timespec structure, * but may be in either microsecond (seconds and microseconds) or * nanosecond (seconds and nanoseconds) format. The particular * format in use is determined by the STA_NANO bit of the status @@ -80,6 +77,7 @@ * #include * * int syscall(SYS_ntp_adjtime, tptr); + * int SYS_ntp_adjtime; * struct timex *tptr; * * DESCRIPTION @@ -89,7 +87,7 @@ * further information. */ #ifndef _SYS_TIMEX_H_ -#define _SYS_TIMEX_H_ 1 +#define _SYS_TIMEX_H_ #ifndef MSDOS /* Microsoft specific */ #include @@ -171,7 +169,7 @@ * nanoseconds if not. */ struct ntptimeval { - struct timespec time; /* current time (ns) (ro) */ + struct timespec time; /* current time (ns/us) (ro) */ long maxerror; /* maximum error (us) (ro) */ long esterror; /* estimated error (us) (ro) */ int time_state; /* time status */ @@ -214,16 +212,17 @@ struct timex { #ifdef __FreeBSD__ #ifdef KERNEL -void ntp_update_second __P((struct timecounter *tc)); -#else +struct timecounter; +void ntp_update_second __P((struct timecounter *tc)); +#else /* !KERNEL */ #include __BEGIN_DECLS -extern int ntp_gettime __P((struct ntptimeval *)); -extern int ntp_adjtime __P((struct timex *)); +int ntp_adjtime __P((struct timex *)); +int ntp_gettime __P((struct ntptimeval *)); __END_DECLS - -#endif /* not KERNEL */ +#endif /* KERNEL */ #endif /* __FreeBSD__ */ -#endif /* _SYS_TIMEX_H_ */ + +#endif /* !_SYS_TIMEX_H_ */