Make even more of the PPSAPI implementations generic.

FLL support in hardpps()

Various magic shuffles and improved comments

Style fixes from Bruce.
This commit is contained in:
Poul-Henning Kamp 1999-03-11 15:09:51 +00:00
parent d492694916
commit 32c203577a
10 changed files with 450 additions and 279 deletions

View File

@ -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 <sys/param.h>
#include <sys/kernel.h>
@ -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)

View File

@ -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 <sys/param.h>
#include <sys/systm.h>
#include <sys/dkstat.h>
@ -50,6 +52,7 @@
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/timex.h>
#include <sys/timepps.h>
#include <vm/vm.h>
#include <sys/lock.h>
#include <vm/pmap.h>
@ -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
}

View File

@ -18,7 +18,7 @@
/*
* Adapted from the original sources for FreeBSD and timecounters by:
* Poul-Henning Kamp <phk@FreeBSD.org>
* Poul-Henning Kamp <phk@FreeBSD.org>.
*
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
@ -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);
}
}

View File

@ -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 <sys/param.h>
#include <sys/systm.h>
#include <sys/dkstat.h>
@ -50,6 +52,7 @@
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/timex.h>
#include <sys/timepps.h>
#include <vm/vm.h>
#include <sys/lock.h>
#include <vm/pmap.h>
@ -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
}

View File

@ -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 <sys/param.h>
#include <sys/systm.h>
@ -24,7 +26,9 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/timepps.h>
#ifdef DEFVFS
#include <sys/devfsext.h>
#endif
#include <sys/xrpuio.h>
#include <pci/pcireg.h>
#include <pci/pcivar.h>
@ -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
}

View File

@ -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;

View File

@ -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 *));

View File

@ -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_ */

View File

@ -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 *));

View File

@ -59,14 +59,11 @@
*
* SYNOPSIS
* #include <sys/timex.h>
* #include <sys/syscall.h>
*
* 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 <sys/syscall.h>
*
* 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 <sys/syscall.h>
@ -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 <sys/cdefs.h>
__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_ */